Lesson 6: Part 3: USART - Transmit Using DMA

In previous USART example, both transmit and receive will requie significant MCU invovlment in moving data in and out the buffer. This is (receiving example) what we usually perform in old days.

But now with a DMA(Direct Memory Access), a lot of processing can be offload to hardware instead. Using DMA, automated the byte transfer between USART buffer to RAM.

This is what we will be doing in this tutorial, we will be sending data out(TX) using DMA.

The sample code will read character being received and retranmist received characters back to sender using DMA. The receiving section remain as previous example, using interrupt and MCU to read the bytes from USART receiving buffer and place into dedicated variable.

Please take note this example only use DMA for TX(transmit), and not RX(receive).

Source Code Explaination

The sample code can get obtain from here.

 Code Initialisation

During code initialisation, below peripheral has to be initialised.
  1. GPIOA - Enable USART Tx/Rx pin and use as USART function
  2. USART - Enable USART block and related USART settings (e.g. baud rate, stop bits)
  3. DMA - Enable DMA function in USART transmission
  4. At the end of initilisation code , a message " Hello World" will be transmit out.
One changes on USART SFR is to enable a DMA transmit mode as shown in below:
USART1->CR3 |= USART_CR3_DMAT;

Some of the key settings in DMA includes:
  1. Source address: when the data come from
  2. Destination address: when the data should transfer to
  3. Transfer bytes: number of data to transfer
  4. Data size: Data size for each transfer : 8/16/32bits
  5. Transfer type: Peripheral to memory or vice versa, memory to memory
  6. Interrupt type: Half transfer or complete transfer

 Main Loop

In the main loop, MCU will continue check if there is any data being received. If data has been recevied, then it will read the received data and perform data transmission using DMA.

The configuration of DMA block is perform in USART1_Tx().

To ensure next DMA sending is only start when last sending is complete, a variable TXBuffers.Complete is using. Before start of transmission, this flag will be turn to 0. Upon complete of data sending, an DMA interrupt will be generated, and a call back function will be called to turn this flag into 1. Before data transmission, this flag will be check and system will enter a while loop if this flag has value 0 (meaning previous transmission is still in progress).

**This may cause a problem if previous transmission has large number of data to be send while system waited and eventually timeout and discard current data. To solve this, change in such a way reading on received data only happen when last DMA send is complete.

Lastly, I found a similar tutorial on here. This tutorial is more detail with oscilloscope measurement to prove the advantage of using DMA.

Lesson 6: Part 2: USART - Receiving Data From PC

In previous tutorial I am showing STM32F030 sending data and receive by PC. This tutorial will be working on the other way: PC sending data and receive by STM32F030. As USART is full duplex, while PC is sending data, STM32F030 also can send data simultaneously.

I have expand the code from previous tutorial to include the receiving section. And in this tutorial, we will be perform a character echo. Characters receive from PC will be transmit back to PC. Thus, we should expect character that we type in transmit section will be appear on receiving window of the software.

SFR Configurations

Refer to source code here for SFR configurations, all the related SFR on receiving is grouped in function name IntUSARTInit_RX in source file name int_usart.c.

Source Code Explanation

To avoid a blocking read that would occupied the whole MCU cycles, this example demonstrate the usage of interrupt (without DMA) on character receiving. 

When character is being received, interrupt routine ISR name USART1_IRQHandler will be called and this routine will read the character from buffer (USART1->RDR) and save into local buffer. Then the pointer PtrProd will be increment. The method use here is the producer/consumer model.

In the main program, the program will constant check if a data is available in buffer. When there is data available, a read from buffer will perform, then data read will be transmit out (using past tutorial).

Below is the video showing the code is running


Lesson 6: Part 1: USART - Transmitting Data Out To PC

To expand the capability of the embedded system, a communication channel is always require. For example, to communicate with a PC, usually a Serial Port (RS232) will be use. Machine to machine communication usually is realise using RS232 or RS485/RS422 (longer distance). In embedded system, the peripheral that incharge of such function is UART(Universal asynchronous receiver transmitter) or USART (Universal synchronous asynchronous receiver transmitter)

As Debugging Tool

One useful usage of USART is in debugging. But inserting code that print debugging message, we can always know what is the value of variable, which part of the code MCU is running. Sometimes, it is more efficient by looking at the debug message instead of stepping through the program.

The down side of this is that a dedicated buffer has to be allocated to keep the debugging buffer(as sending USART speed is slow).

Physical Connection

USB To Serial Port < --> Max232 <--> USART/UART

In this tutorial, we will be looking at enabling communication between STM32F030 with PC through RS232. We will be enabling USART1 on MCU part. To enable communication with PC, an additional voltage converter(MAX232 chipset) circuit is require as shown below:

RS232 Circuit
The above image is take from here. It also include a good introduction of interfacing with PC.

Currently most of the PC/laptop no longer come with DB-9 Serial Port. And a replacement of this would be a USB to Serial converter as shown below:
USB to Serial Converter

USB To TTL

The easiest converter to use is shown below, which enabling direct interface into STM32F030, without requiring MAX232 as shown below:
USB to TTL
Enabling direct connection to STM32F030 USART

STM32F030 SFR Configurations

We will be using the following settings on STM32F030:
  • Baud Rate: 115200bps
  • Data bits: 8
  • Stop bits: 1
  • Parity : None
  • Handshake : None
On PC, you can use teraterm, hyperterminal or similar software to open the Serial Port and accept data send from STM32F030. The above settings must be configure in software to ensure proper communication between PC and STM board.

As for the SFR section, it would be too lengthy to go through each of the register. I have heavily comment on the source code instead to provide explanation of each SFR. Refer here for the source code.

Source Code Explained

Below are the key actions implemented in source code to enable data transmission.

1. SFR configurations
  • Enable GPIO block that contain USART TX/RX pn
  •  Configure TX/RX pin to use as USART (so that is will not use as general purpose input/output)
  • Enable USART block
  • USART settings (baud rate, data bits, stop bits, parity, handshake)
  • Enable USART function, and transmit, receive function
2.  Data Transmit Function (call by application)
  • Putting first byte into transmit buffer
  • Waiting first byte transmit complete
  • Putting subsequenct byte into transmit buffer and wait until byte is transmit out. Repeating this until all bytes has been transmit
The example will be continuing printing out message 'Hello World!" through USART1.

Below is the image of my connection, using an USB to TTL device, directly connect to STM32
  • White cable: 3V
  • Blue cable: GND
  • Grey cable: PA9, USART_TX
  • Purple cable: PA10:USART_RX
Physical Connection

Source Code Implementation

The above source code is implementing a blocking transmit. Which means that the MCU will be waiting(a while loop) when current chracter being transmit out. Thus when sending full length of 'Hello World!', no other process can be executed (except ISR). This is inefficient but this is the simpliest way to ensure character transmitting is working.

Apart from blocking transmit, we can also perform USART transmit using:
  • Interrupt: allow interrupt occur when current data has been transfer to transmit buffer(it would take some time to transmit out), so we can load next data into TDR. This is better than blocking, but still require ISR code to loadbuffer into TDR
  • DMA: enabling DMA auto transfer when current data has been transfer to transmit buffer. This is the most efficient method, but also more complex as it involve interrupt + DMA control.
Later stage we shall be looking for DMA method. For now, we should get things work in the simpliest method: blocking transmit/receive.

Lastly, I attached a short video on my capture on data transmit from STM32 on this tutorial.