You are on page 1of 14

M2H620495 Digital and Programmable Systems 1

Laboratory 5 – UART Communications

1 Overview and Goals


In the previous laboratories we have covered digitial I/O within the MSP430, using both polled and
interrupt based methods. In this laboratory we will cover the UART module in the MSP430 to enable
communications with external devices. The Universal Asynchronous Receiver/Transmitter (UART)
module is part of both the Universal Serial Communication Interface (USCI) Module and the
universal synchronous / asynchronous receive/transmit(USART) module.

There are several specific objectives in this lab:

1. Transfer data between two MSP430 devices


2. Setup interrupt handlers to deal with the incoming data
3. Develop test methods for ensuring correct operation of the software

2 Introduction
To provide design flexibility the MSP430 comes with a number of functional units which enable
communications with the outside world. Within this laboratory we will be using the Universal
Asynchronous Receiver/Transmitter (UART) within the Universal Serial Communication Interface.
The generic setup of the system for UART communications is shown in Figure 1.

Figure 1 Generic MSP430 UART communications

Lab Question 1. Find the communications protocols supported by the MSP430F5438 and
discuss reasons why multiple protocols are included on the device.
There are three communication protocols that are supported by MSP430F5438.
1- UART
2- SPI
3- I2C
Reason:
Each of them have its own advantages and disadvantages. UART does not need a clock.
It has error checking mechanism. SPI is fastest and simple. It supports only one master.
I2C is slower, but it supports multiple masters and it is complicated as compared to SPI
and UART. That’s why all these protocols are included in the device to provide flexibility
to the user.

G Morison page 1
M2H620495 Digital and Programmable Systems 1

From the name of the interface you can easily guess that UART sends bit, one bit after the other
(serially), as opposed to parallel. However we don’t usually send individual bits because of the fact
that they convey little information by themselves. Rather, the UART uses a buffer that is one byte (8
bits) long to which information is written.

Lab Question 2. Describe the type of circuit which you think is used to create the buffer for
the UART.
8 bit registers are used to create buffer for the UART.

UART communications is an asynchronous protocol, so there is no clock signal available to


synchronize two devices, therefore the module requires some additional information to be sent, to
tell a device when information transfer begins, the data, possible error checking, then when
information transfer terminates. To achieve this UART Typically sends a start bit, seven or eight data
bits, an even/odd/no parity bit, an address bit (address-bit mode), and one or two stop bits. The
extra bits depend on the configuration of the UART module, but the most common configuration is
8 data bits, one stop bit and no parity (this is commonly written as 8N1). Extra bits that are sent are
ultimately discarded and not stored at the destination buffer. The result of the parity check
is however available. Figure 1 shows the bit arrangement in the MSP430’s UART Module:

Figure 2 Bit arrangement for UART showing optional parameters

As a timing diagram this is show as follows in Figure 2:

Figure 3 Bit Timing Diagram for UART

Lab Question 3. The start bit in the system is always required to be a low value, why is this?
Start bit indicates the start of communication. Before it, system is in idle state which is
typically logic high. That’s why start bit is always logic low to indicate the start of
communication.

Once these parameters have been agreed upon, the final parameter to be chosen is the baud rate
(the speed of transmission). This ultimately determines how fast data can be transmitted.

2.1 Useful Documentation

G Morison page 2
M2H620495 Digital and Programmable Systems 1

To help new developers get up to speed with the rich set of functionality that is available with the
MSP430 there exists extensive documentation, relating to both the MCU and the Experimenter
board. The following wiki is populated by TI and is a good place to begin to find documentation and
software examples.

http://processors.wiki.ti.com/index.php/MSP-EXP430F5438_Experimenter_Board

The following documents (pdfs) will be required for this and any subsequent laboratories, they are
available at the following website and copies are available on GCU Learn.

http://www.ti.com/tool/msp-exp430f5438
 MSPF5438 Experimenter User Guide (Rev G.)

http://www.ti.com/product/msp430f5438a
 MSP430F543xA, MSP430F541xA Mixed Signal Microcontroller (Rev. B) 

Datasheet for the MSP430F5438


http://www.ti.com/lit/ds/symlink/msp430f5438.pdf

User Guide for the MSP430F5438


http://www.ti.com/lit/ug/slau208j/slau208j.pdf

The Universal Serial Communication Interface – UART Mode section in the above document will be
used extensively within this laboratory.

3 UART connectivity on the MSP430F5438


The MSP430F5438 includes two USCI modules, USCI A0 and USCI B0. Only USCI A0 is has
UART functionality and and uses P3.4/UCA 0TXD /UCA 0SIMO as TX and P3.5/UCA 0RXD
/UCA 0SOMI as RX.

Lab Question 4. For pins are P3.4 and P3.5, which pins are these located next to on the chip?

Within this laboratory we will be extending the code that was used in the previous laboratory. The
previous code, had an interrupt respond to the push button s1, this set the value in a variable, which
was subsequently put onto LEDS 1 & 2. The extension in this laboratory will be to send the value that
is set by the interrupt over the serial link.

Before we can use the UART successfully to send data, both the UART Modules must be configured.
Because the communication is asynchronous, if the two are not configured correctly then errors will
occur because the interpretation of the timing of the bits will be off. To better explain how to
configure the UART module, we will use the following code as an example.

P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD


UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK

G Morison page 3
M2H620495 Digital and Programmable Systems 1

UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)


UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

The code above demonstrates that the following steps are needed:
1. Select the I/O pins for UART
2. Reset the internal state machine.
3. Source the UART Module with a clock of a certain frequency
5. Set the baud generator correctly so as to get a correct baud rate from the clock sourced
6. Enable the UART module state machine
7. Enable Interrupts if required

We will take the code and improve upon it to understand it and adapt it to most any MSP430 UART
Modules.

3.1 Pin Multiplexing and UART setup

As we mentioned previously, the MSP430 (and many other microcontrollers) multiplexes the
functionalityof various modules at the physical pins. In our case the we can select between general
I/O and the internal modules . This means that we can either use a pin as a General Purpose
Input/Output (HIGH or LOW) or one of the internal modules.

The functionality selected is determined by PxSEL registers, where x can represent 1,2,3 ... ports,
depending on which port the UART module is located. Each of the 8 bits in the register controls
the functionality of the pin. As an example, the MSP430F5438 has two modules which support
UART functionality. From the MSP430F5438 datasheet, pages 7 and 8, you can see that the UART
pins that can be used:
P3.4/UTXD0
P3.5/URXD0
P3.6/UTXD1
P3.7/URXD1

P3.4 indicates pin 4 on port 3, while P3.5 indicates the same port but pin 5 and as you can see,
they can be a General Purpose digital I/O pin or a UART pin. Because the pins are in port 3, we
need to modify P3SEL. The question is how should we modify it? In the User’s Guide for the
MSP430F5438 we find that:
Bit = 0: I/O Function is selected for the pin
Bit = 1: Peripheral module function is selected for the pin

To select UART functionality for P3.4 and P3.5 we use the following c language statement that
sets the two bits for pins 4 and 5, selecting them for the UART module:

P3SEL |= BIT4 + BIT5;

Lab Question 5. The example code will setup the system for 8N1 with a baud rate of 115300,
yet the 8N1 section is not explicitly written in the setup code. Why is this?
UART is configured for 8N1 by default. So, this configuration is not explicitly written in the

G Morison page 4
M2H620495 Digital and Programmable Systems 1

setup code.

Lab Question 6. By referring to the register USCI_Ax Control Register 0 (UCAxCTL0) in the
User Guide for the MSP430F5438, write the code to explicitly set the register for 8N1.
UCA0CTL0 &= ~UC7BIT;

Lab Question 7. How would the code in the setup example be changed to use the ACLK
clock.

UA0CTL1 |= 0X40;
Or,
UCA0CTL1 |= UCSSEL_1

Lab Question 8. Discuss why the setup code first resets the state machine
To provide the initial state to the state machine.

Lab Question 9. How this software relates to the hardware project your currently
undertaking?

3.1 UART Tx and Rx Buffers

As was mentioned above the UART uses a buffer that is one byte (8 bits) long to which information
is written to in receive mode (RX) UCA0RXBUF, and transmitted from in transmit mode (TX)
UCA0TXBUF. These can be read from and written to like variables in software. This is shown in the
following code examples from the TX and RX examples to follow.

RX Example
// Store the value in RX buffer
count=UCA0RXBUF;

TX Example
// TX -> count
UCA0TXBUF = count;

The following line of code ensures the transmitter is ready to send a character

// USCI_A0 TX buffer ready? Wait till it is!


while (!(UCA0IFG&UCTXIFG));

G Morison page 5
M2H620495 Digital and Programmable Systems 1

Lab Question 10. By referring to the User Guide for the MSP430F5438 explain the above line
of code
Above line of the code is waiting for the transmitter buffer to be empty. UCTXIFG is 0 in
UCA0IFG register when there is no interrupt pending. This means transmitter is ready to
transmit.

3.3 UART program

Now that the setup of the system has been explored we will now create two projects, the first is the
transmitter (TX) code, the second is the receiver (RX) code. To do this efficiently with the partner
that you have been paired with in the lab, one create a project for the TX code, compile then
download onto the board. The other does the same for the RX code. The lab assistant will aid you
with attaching the boards.

TX Code

//******************************************************************************
// Description: ........................
// Author:
// Date:
//******************************************************************************

#include "msp430x54x.h"

// Global variable accessible in interrupts


char count=0;

void main(void)
{
long int i=0;

// Stop WDT
WDTCTL = WDTPW + WDTHOLD;
// Setup P1.0 as an output port
P1DIR = P1DIR | BIT0;
P1SEL = P1SEL & ~BIT0;
// Setup P1.1 as an output port
P1DIR = P1DIR | BIT1;
P1SEL = P1SEL & ~BIT1;
// Setup P2.6 as an input port
P2DIR = P2DIR & ~BIT6;
P2SEL = P2SEL & ~BIT6;
// Enable the pull up resistor and set as a pullup
P2REN = P2REN | BIT6;
P2OUT = P2OUT | BIT6;
// P2.6 Hi/lo edge
P2IES |= BIT6;
// P2.6 IFG cleared
P2IFG &= ~BIT6;
// P2.6 Interrupt Enable

G Morison page 6
M2H620495 Digital and Programmable Systems 1

P2IE |= BIT6;

// USCI setup code


P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

// Enable interrupts
_EINT();

// Polling loop with software delay


for(;;)
{
switch(count)
{
case 0:
// 0: all lights off
P1OUT &= ~(BIT0+BIT1);
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 1:
// 1: bit 0 only
P1OUT |= BIT0;
P1OUT &= ~BIT1;
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 2:
// 2: bit 1 only
P1OUT &= ~BIT0;
P1OUT |= BIT1;
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 3:
// 2: bits 1 and 2
P1OUT |= (BIT0+BIT1);
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
}

// Spin round for n cycles


for(i=0;i<30000;i++){;}

G Morison page 7
M2H620495 Digital and Programmable Systems 1

}
}
// Port 2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
if((count>=0)&&(count<3))
{
count++;
}
else if(count==3)
{
count=0;
}

// P2.6 IFG cleared


P2IFG &= ~BIT6;
}

RX Code

//******************************************************************************
// MSP430F54x Demo - USCI_A0, 115200 UART Echo ISR, DCO SMCLK
//
// Description: Echo a received character, RX ISR used. Normal mode is LPM0.
// USCI_A0 RX interrupt triggers TX Echo.
// Baud rate divider with 1048576hz = 1048576/115200 = ~9.1 (009h|01h)
// ACLK = REFO = ~32768Hz, MCLK = SMCLK = default DCO = 32 x ACLK = 1048576Hz
// See User Guide for baud rate divider table
//
// MSP430F5438
// -----------------
// /|\| |
// | | |
// --|RST |
// | |
// | P3.4/UCA0TXD|------------>
// | | 115200 - 8N1
// | P3.5/UCA0RXD|<------------
//
// M Smertneck / W. Goh | G Morison (Updated for PDEET lab)
// Texas Instruments Inc.
// September 2008
// Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B
//******************************************************************************

#include "msp430x54x.h"

// Global variable accessible in the interrupt handler


char count=0;

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT

G Morison page 8
M2H620495 Digital and Programmable Systems 1

// Setup P1.0 as an output port


P1DIR = P1DIR | BIT0;
P1SEL = P1SEL & ~BIT0;
// Setup P1.1 as an output port
P1DIR = P1DIR | BIT1;
P1SEL = P1SEL & ~BIT1;
// Setup P2.6 as an input port
P2DIR = P2DIR & ~BIT6;
P2SEL = P2SEL & ~BIT6;
// Enable the pull up resistor and set as a pullup
P2REN = P2REN | BIT6;
P2OUT = P2OUT | BIT6;
// P2.6 Hi/lo edge
P2IES |= BIT6;
// P2.6 IFG cleared
P2IFG &= ~BIT6;
// P2.6 Interrupt Enable
P2IE |= BIT6;

// USCI setup code


P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled


__no_operation(); // For debugger
}

// Echo back RXed character, confirm TX buffer is ready first


#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
// Store the value in RX buffer
count=UCA0RXBUF;
switch(count)
{
case 0:
// 0: all lights off
P1OUT &= ~(BIT0+BIT1);
break;
case 1:
// 1: bit 0 only
P1OUT |= BIT0;
P1OUT &= ~BIT1;
// USCI_A0 TX buffer ready? Wait till it is!

break;
case 2:
// 2: bit 1 only

G Morison page 9
M2H620495 Digital and Programmable Systems 1

P1OUT &= ~BIT0;


P1OUT |= BIT1;
break;
case 3:
// 2: bits 1 and 2
P1OUT |= (BIT0+BIT1);
// USCI_A0 TX buffer ready? Wait till it is!
break;
}
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}

Lab Question 11. Change the RX code to only put on LED1 if the received value is even, and
to put on only LED2 if the received value is odd.
#include "msp430x54x.h"

// Global variable accessible in the interrupt handler


char count=0;

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT

// Setup P1.0 as an output port


P1DIR = P1DIR | BIT0;
P1SEL = P1SEL & ~BIT0;
// Setup P1.1 as an output port
P1DIR = P1DIR | BIT1;
P1SEL = P1SEL & ~BIT1;
// Setup P2.6 as an input port
P2DIR = P2DIR & ~BIT6;
P2SEL = P2SEL & ~BIT6;
// Enable the pull up resistor and set as a pullup
P2REN = P2REN | BIT6;
P2OUT = P2OUT | BIT6;
// P2.6 Hi/lo edge
P2IES |= BIT6;
// P2.6 IFG cleared
P2IFG &= ~BIT6;
// P2.6 Interrupt Enable
P2IE |= BIT6;

// USCI setup code


P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled


__no_operation(); // For debugger

G Morison page 10
M2H620495 Digital and Programmable Systems 1

// Echo back RXed character, confirm TX buffer is ready first


#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
// Store the value in RX buffer
count=UCA0RXBUF;
switch(count%2)
{
case 0:
// 0: turn on led1 only
P1OUT |= BIT0;
break;
case 1:
// 1: turn on led 2 only
P1OUT |= BIT1;
// USCI_A0 TX buffer ready? Wait till it is!

break;
}
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}

Lab Question 12. Update the TX code so that it contains a RX section as well (this should use
an interrupt). The code should function as follows: it should repeat the above code so that
the TX side functions as before without the value appearing on the LEDS, but the RX side
only shows on the LEDS the value it received
#include "msp430x54x.h"

// Global variable accessible in interrupts


char count=0;

void main(void)
{
long int i=0;

// Stop WDT
WDTCTL = WDTPW + WDTHOLD;
// Setup P1.0 as an output port
P1DIR = P1DIR | BIT0;
P1SEL = P1SEL & ~BIT0;
// Setup P1.1 as an output port
P1DIR = P1DIR | BIT1;
P1SEL = P1SEL & ~BIT1;
// Setup P2.6 as an input port

G Morison page 11
M2H620495 Digital and Programmable Systems 1

P2DIR = P2DIR & ~BIT6;


P2SEL = P2SEL & ~BIT6;
// Enable the pull up resistor and set as a pullup
P2REN = P2REN | BIT6;
P2OUT = P2OUT | BIT6;
// P2.6 Hi/lo edge
P2IES |= BIT6;
// P2.6 IFG cleared
P2IFG &= ~BIT6;
// P2.6 Interrupt Enable
P2IE |= BIT6;

// USCI setup code


P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state
machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt

// Enable interrupts
_EINT();

// Polling loop with software delay


for(;;)
{
switch(count)
{
case 0:
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 1:
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 2:
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
case 3:
// USCI_A0 TX buffer ready? Wait till it is!
while (!(UCA0IFG&UCTXIFG));
// TX -> count
UCA0TXBUF = count;
break;
}

// Spin round for n cycles

G Morison page 12
M2H620495 Digital and Programmable Systems 1

for(i=0;i<30000;i++){;}
}
}
// Port 2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
if((count>=0)&&(count<3))
{
count++;
}
else if(count==3)
{
count=0;
}

// P2.6 IFG cleared


P2IFG &= ~BIT6;
}
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
// Store the value in RX buffer
count=UCA0RXBUF;
switch(count)
{
case 0:
// 0: all lights off
P1OUT &= ~(BIT0+BIT1);
break;
case 1:
// 1: bit 0 only
P1OUT |= BIT0;
P1OUT &= ~BIT1;
// USCI_A0 TX buffer ready? Wait till it is!

break;
case 2:
// 2: bit 1 only
P1OUT &= ~BIT0;
P1OUT |= BIT1;
break;
case 3:
// 2: bits 1 and 2
P1OUT |= (BIT0+BIT1);
// USCI_A0 TX buffer ready? Wait till it is!
break;
}
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}

G Morison page 13
M2H620495 Digital and Programmable Systems 1

Lab Question 14. Write the setup code that would be used to setup the MSP430 to interface
with the serial controller you have designed on the FPGA board.
// USCI setup code
P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 9; // 1MHz 115200 (see User's Guide)
UCA0BR1 = 0; // 1MHz 115200
UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx=1, UCBRFx=0
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state
machine**
UCA0IE |= UCTXIE; // Enable USCI_A0 TX interrupt

4 Lab Reflection

In general, your lab write-up should indicate that you have acquired a better understanding of the
topics treated by the laboratory assignment. You should write half a page of text that explains the
following aspects in the box below. Please create a cohesive piece of text and do not just provide
unconnected sentences in response to the following aspects of your learning experience.

Three new facts/concepts that you learnt while undertaking the lab.
The most useful thing that you learnt.
Explain how this lab specifically relates to the hardware project you have also been undertaking
within this class.
What understanding you already had of the material being explored.
How this laboratory experience relates to any other learning that you are also undertaking at the
moment, or have undertaken in the past.
A statement of anything additional that you would like to explore in this area of work. Has the
investigation given you any ideas about possible applications of this technology?

G Morison page 14

You might also like