cancel
Showing results for 
Search instead for 
Did you mean: 

Reading variable length strings from a usart with DMA

Harvey White
Senior III
Posted on October 05, 2017 at 22:44

I need to read variable length strings from a usart. The strings may be the result of local programming or not. I'm using the HAL DMA receive driver under FreeRTOS. I've found that the following approach works:

HAL_UART_Receive_DMA(&huart3, (unsigned char*)&WIFI.RXbuffer.data, _RX_BUFFER_SIZE);
xSemaphoreGive(WIFI_busy);
while (WIFI.RXbuffer.data[0] == 0)
{
 vTaskDelay(1);
}
comm_index = 0;
while (comm_index != huart3.hdmarx->Instance->NDTR)
{
 comm_index = huart3.hdmarx->Instance->NDTR;
 vTaskDelay(1);
}
// if was the result of a remote command, then command = AT_IP otherwise
// it's from the send routine and is a valid command
HAL_UART_AbortReceive_IT(&huart3);
switch (WIFI.TXbuffer.command)
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

This works as follows:

1) clear WIFI buffer if needed

2) start DMA reception before programmed transmit

3) loop, delaying, until reception starts (allows remote to respond)

4) read NDTR in chip for this transaction. NDTR starts high and decrements with each character transferred. Set transfer limit to max buffer size.

5) loop waiting for NDTR to stabilize. Note that this assumes variable length data transmitted in a burst (ESP8266 does).

6) abort reception to reset DMA flags and stabilize buffer

7) process data

comments?

5 REPLIES 5
Posted on October 05, 2017 at 23:32

I just create a Circular DMA in 16-bit mode, and of sufficient depth, once, and then harvest/process the content in a periodic task.

ie at 9600 baud, and 50 Hz task, 32 words.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on October 06, 2017 at 02:27

This is actually in a wifi slave task, designed to receive from the chip and then interpret.  It's useful in this application to start at the beginning of the buffer, receive a variable length message, effectively time out, and then process the message.  Part of the problem with the ESP8266 chip is that it has a variable (and unknown) time between the receipt of the command and the response, and even more unknown when the incoming message is unsolicited. 

While this is not the most sophisticated method, it does (within reason) keep from having to use a processor pin for a bit activity timer (unless you can purpose a pin to two different systems, USART RX and Timer event trigger).

Andrew Neil
Chief II
Posted on March 09, 2018 at 11:18

So what speed is the 

ESP8266

 comms running at?

Why not just have a 'conventional' received-byte interrupt that feeds a ring-buffer?

Seems like DMA is causing more trouble than gain ...

Posted on March 09, 2018 at 11:14

Part of the problem with the ESP8266 chip is that it has a variable (and unknown) time between the receipt of the command and the response, and even more unknown when the incoming message is unsolicited.

Using DMA under this circumstances requires periodic polling, at a rate above the command 'frequency'.

An interrupt-based approach would be an alternative with minimal latency.

Harvey White
Senior III
Posted on March 15, 2018 at 15:56

The ESP8266 is running at 115 Kbaud.  The idea behind using DMA and not just interrupts was that the operating system and (everything else) is using interrupts as well and is likely very busy.  There are some critical sections in the operating system where interrupts may be suppressed for a bit, so I was trying to minimize the possibility of missing data.  If there happened to be a decent FIFO in the usart, I wouldn't worry as much. 

However, the design idea was that this would set up, and run independently of anything else going on.  As far as the task is concerned, there's a separate receive task that is blocked by not having a message done,  that's fine since the entire ESP block is considered asynchronous.  DMA being used to reduce CPU loading. I figured it was worth it.

The entire system could receive either I2C commands, NRF24L01 commands, ESP8266 commands, or RS232 type commands, let alone being busy sending something out and processing data (or running the display).