cancel
Showing results for 
Search instead for 
Did you mean: 

Communication between UART DMA and ESP8266 hangs after first response

Lars Beiderbecke
Senior III
Posted on May 26, 2018 at 16:04

I'm going crazy with this. I want to send some commands to an ESP8266, and search the response for 'OK'. Since the response is of arbitrary length, I'm receiving 400 bytes, and see if there's an 'OK' in there. If there isn't within a given timeout, the operation fails.

clearBuffer(buffer);

HAL_UART_Receive_DMA(&huart7, rxbuffer, 400);

HAL_UART_Transmit_DMA(&huart7, 'OK' CRLF, 4);

buf = waitOK(buffer, 3);  // wait 3 secs for 'OK'

HAL_UART_Transmit_DMA(&huart7, 'OK' CRLF, 4);

buf = waitOK(buf, 3);  // wait 3 secs for 'OK'

// ...

static uint8_t *waitOK(uint8_t *buf, int timeout) {

  uint8_t *found = 0;

  int count = 0;

  while (count++ < 2 * timeout) {

    found = strfind(buf, 'OK');  // search for 'OK' in remaining buffer

    if (found)

      break;

    HAL_Delay(500);

  }

  return found + 1;

}

Unfortunately, I can only get the first OK.  Subsequent commands don't receive ANY response, i.e., the buffer remains empty.

I configured UART7 with two DMA channels, but no interrupt. No callbacks have been defined.

What am I doing wrong here?  I've tried multiple variations, with IR or polling, but they all showed the same issue.

1 ACCEPTED SOLUTION

Accepted Solutions
Lars Beiderbecke
Senior III
Posted on May 27, 2018 at 11:17

I think I found the solution. I had to enable the UART7 interrupt for subsequent Rx's to work.

One wonders why CubeMX doesn't activate it automatically if it is required for DMA to function regularly.

View solution in original post

18 REPLIES 18
Posted on May 26, 2018 at 16:49

>>I've tried multiple variations, with IR or polling, but they all showed the same issue.

Perhaps there is something else going on?

Perhaps you should just implement a simple loop the forward the data back and forth between the ESP and a console attached USART, and then interact with the device via a terminal.  Output the bytes (in hex) transacted via the debugger SWV channel to be sure of what is being emitted.

void Forward(void) // Basic ESP / RS232(VCP) Forwarder

{

  while(1)

  {

    uint16_t Data;

    if (USART_ESP->ISR & USART_ISR_ORE)

      USART_ESP->ICR = USART_ICR_ORECF;

    if (USART_ESP->ISR & USART_ISR_NE)

      USART_ESP->ICR = USART_ICR_NCF;

    if (USART_ESP->ISR & USART_ISR_FE)

      USART_ESP->ICR = USART_ICR_FECF;

    if ((USART_ESP->ISR & USART_ISR_RXNE) != 0) // Wait for Char

    {

      Data = USART_ESP->RDR; // Collect Char (ESP)

      while((USART_RS232->ISR & USART_ISR_TXE) == 0); // Wait for Empty

      USART_RS232->TDR = Data & 0xFF; // Echo Char (RS232)

    }

    if (USART_RS232->ISR & USART_ISR_ORE)

      USART_RS232->ICR = USART_ICR_ORECF;

    if (USART_RS232->ISR & USART_ISR_NE)

      USART_RS232->ICR = USART_ICR_NCF;

    if (USART_RS232->ISR & USART_ISR_FE)

      USART_RS232->ICR = USART_ICR_FECF;

    if ((USART_RS232->ISR & USART_ISR_RXNE) != 0) // Wait for Char

    {

      Data = USART_RS232->RDR; // Collect Char (RS232)

      while((USART_ESP->ISR & USART_ISR_TXE) == 0); // Wait for Empty

      USART_ESP->TDR = Data & 0xFF; // Echo Char (ESP)

    }

  }

}
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Lars Beiderbecke
Senior III
Posted on May 26, 2018 at 17:00

I also noted that LD5 (over current) lights periodically for sub-second periods when the ESP8266 is connected.

Could that be the reason for my problems, i.e., do I have an electrical issue?

Posted on May 26, 2018 at 17:01

Our posts overlapped, but I'll try as suggested.

Posted on May 26, 2018 at 17:35

Clive, I added your Forward() to my code after HAL_Transmit_DMA(), replacing USART_ESP with UART7 and USART_RS232 with USART3 (my configured connections).

If I add Forward() after any Transmit, I get just a random response of 0-2 chars. This doesn't change when I power the ESP8266 with a separate FTDI232 module.

But when I remove the initial HAL_UART_Receive_DMA() from my code, I get the full response of the ESP8266.

Did I misconfigure something about UART DMA?

T J
Lead
Posted on May 27, 2018 at 02:15

Which processor are you using ?

Did you use the cube to setup ?

is the RxDMA set to circular buffer ?

is the TxDMA set to normal buffer ?

I have 2 implementations of Uart DMA working flawlessly, F0 and F7

Posted on May 27, 2018 at 03:33

Assuming Nucleo STM32F722ZE

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 27, 2018 at 04:14

void initSerialPorts();
// serial 1 ////////
void CheckTxDMABufferProgress(void);
void checkU1TxDMABufferLength();
void putc1(char saveByte);
void initUart1RxDMABuffer(void);
void setCursor1(int row, int column);
int puts1(const char * ptr);
char readableU1(void);
char readU1(void);

#define U1RxBufSize 256
#define U1TxBufSize 4096
 
char Usart1TxDMABuffer[U1TxBufSize];
int16_t U1RxBufferPtrIN, U1RxBufferPtrOUT, U1TxBufferPtrIN, U1TxBufferPtrOUT;
char TxDMA1BufHasData, DMA1BufAlmostFull;
char Usart1RxDMABuffer[U1RxBufSize];

void initSerialPorts() {
 TxDMA1BufHasData = false;
 U1TxBufferPtrIN = 0; U1TxBufferPtrOUT = 0;
 U1RxBufferPtrIN = 0; U1RxBufferPtrOUT = 0;
 
 DMA1BufAlmostFull = false;
 TxDMA1BufHasData = false;
 initUart1RxDMABuffer();
 TxDMA2BufHasData = false;
 U2TxBufferPtrIN = 0; U2TxBufferPtrOUT = 0;
 U2RxBufferPtrIN = 0; U2RxBufferPtrOUT = 0;
 
 DMA2BufAlmostFull = false;
 TxDMA2BufHasData = false;
 initUart2RxDMABuffer(); 
 TxDMA3BufHasData = false;
 U3TxBufferPtrIN = 0; U3TxBufferPtrOUT = 0;
 U3RxBufferPtrIN = 0; U3RxBufferPtrOUT = 0;
 
 DMA3BufAlmostFull = false;
 TxDMA3BufHasData = false;
 initUart3RxDMABuffer(); 
}
void initUart1RxDMABuffer(void) {
 if (HAL_UART_Receive_DMA(&huart1, (uint8_t *)Usart1RxDMABuffer, U1RxBufSize) != HAL_OK)
 {
 // Transfer error in reception process 
 //_Error_Handler(__FILE__, __LINE__);
 
 printf(string, 'initUart1RxDMABuffer Failed
');
 
 }
 else
 printf(string, 'initUart1RxDMABuffer OK!
');
}

char readU1(void) {
 char readByte = Usart1RxDMABuffer[U1RxBufferPtrOUT++];
 if (U1RxBufferPtrOUT >= U1RxBufSize) U1RxBufferPtrOUT = 0;
 return readByte;
}
char readableU1(void) {
 U1RxBufferPtrIN = U1RxBufSize - huart1.hdmarx->Instance->CNDTR;
 return U1RxBufferPtrIN - U1RxBufferPtrOUT;
}
char getc1(void) {
 char Rxbyte = Usart1RxDMABuffer[U1RxBufferPtrOUT++];
 if (U1RxBufferPtrOUT >= U1RxBufSize) U1RxBufferPtrOUT = 0;
 return Rxbyte;
}
void putc1(char saveByte) { 
 checkU1TxDMABufferLength();
 Usart1TxDMABuffer[U1TxBufferPtrIN++] = saveByte;
 U1TxBufferPtrIN &= U1TxBufSize - 1;
 TxDMA1BufHasData = true;
}

int puts1(const char * ptr) {
 int length = 0;
 // check String has data
 if(ptr[0]) { // does the first element have a char ?
 checkU1TxDMABufferLength(); // DMA Transmission buffer house keeping
 while(ptr[length] > 0) {
 // add this text too
 // transfer to DMA buffer to nul terminator 0x00
 // if PTRin actually gets to the end of the buffer we are toast.
 Usart1TxDMABuffer[U1TxBufferPtrIN++] = ptr[length++];
 if (U1TxBufferPtrIN >= 4096) U1TxBufferPtrIN = 0; // should never get here
 }
 //adding text into the stream here successfully
 //U1TxBufferPtrIN += sprintf(Usart1TxDMABuffer + U1TxBufferPtrIN,'PtrIN %04X, PtrOUT %04

X',U1TxBufferPtrIN,U1TxBufferPtrOUT); // this does work
 TxDMA1BufHasData = true;
 }
 return length;
}
void checkU1TxDMABufferLength(void) {
 DMA1BufAlmostFull = false;
 if (U1TxBufferPtrIN > ((U1TxBufSize * 3) / 4)) // we are about to run out of room in DMA Buffer
 DMA1BufAlmostFull = true;
 if (DMA1BufAlmostFull) {
 // we have a DMA in progress, so best leave it alone.
 
 // possibly, we have some text already waiting for the DMA to clear.
 // we have this text to go on too.
 
 // 1. ptr in - prt out is the current length and it needs to be shifted back to 0 position
 // 2. then this incoming text too
 
 
 // 1. ptr in - prt out is the current length and it needs to be shifted back to 0 position
 // we could use a MtoM DMA for this, but easier and fast anyway to do by hand.
 
 int currentBufferLength, newBufferLength;
 currentBufferLength = U1TxBufferPtrIN - U1TxBufferPtrOUT;
 
 newBufferLength = 0;
 
 if (currentBufferLength) {
 if (currentBufferLength < U1TxBufSize - 2) {
 while (U1TxBufferPtrIN > U1TxBufferPtrOUT)
 Usart1TxDMABuffer[newBufferLength++] = Usart1TxDMABuffer[U1TxBufferPtrOUT++];
 U1TxBufferPtrOUT = 0;
 U1TxBufferPtrIN = newBufferLength;
 }
 else {
 // this is a fatal error
 // reset and clean up
 U1TxBufferPtrOUT = 0;
 U1TxBufferPtrIN = 0;
 char errorMessage[96];
 int msg_length = 0;
 sprintf(errorMessage, '

currentBufferLength %d is too high, some of the string has been dumped

', currentBufferLength);
 while (errorMessage[msg_length] > 0) {
 // transfer to DMA buffer to nul terminator 0x00
 // if U1TxBufferPtrIN actually gets to the end of the buffer we are toast.
 Usart1TxDMABuffer[U1TxBufferPtrIN++] = errorMessage[msg_length++];
 if (U1TxBufferPtrIN >= U1TxBufSize) U1TxBufferPtrIN = 0; // should never get here
 U1TxBufferPtrIN &= U1TxBufSize - 1;
 }
 }
 }
 else {
 U1TxBufferPtrOUT = 0;
 U1TxBufferPtrIN = 0;
 }
 DMA1BufAlmostFull = false;
 }
}
void CheckTxDMABufferProgress(void) {
 if (TxDMA1BufHasData) {
 char uartState = HAL_UART_GetState(&huart1);
 if ((uartState == HAL_UART_STATE_READY) || (uartState == HAL_UART_STATE_BUSY_RX)) {
 TxDMA1BufHasData = false; // sending now
 if(HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Usart1TxDMABuffer + U1TxBufferPtrOUT, U1TxBufferPtrIN - U1TxBufferPtrOUT) == HAL_OK) {
 U1TxBufferPtrOUT = U1TxBufferPtrIN;
 Usart1TxDMABuffer[U1TxBufferPtrIN] = 0; // null
 }
 else {
 _Error_Handler(__FILE__, __LINE__); /* Transfer error in transmission process */
 }
 }
 }
 if (TxDMA2BufHasData) {
 char uartState = HAL_UART_GetState(&huart2);
 if ((uartState == HAL_UART_STATE_READY) || (uartState == HAL_UART_STATE_BUSY_RX)) {
 TxDMA2BufHasData = false; // sending now
 if(HAL_UART_Transmit_DMA(&huart2, (uint8_t *)Usart2TxDMABuffer + U2TxBufferPtrOUT, U2TxBufferPtrIN - U2TxBufferPtrOUT) == HAL_OK) {
 U2TxBufferPtrOUT = U2TxBufferPtrIN;
 Usart2TxDMABuffer[U2TxBufferPtrIN] = 0; // null
 }
 else {
 _Error_Handler(__FILE__, __LINE__); /* Transfer error in transmission process */
 }
 }
 }
 if (TxDMA3BufHasData) {
 char uartState = HAL_UART_GetState(&huart4);
 if ((uartState == HAL_UART_STATE_READY) || (uartState == HAL_UART_STATE_BUSY_RX)) {
 TxDMA3BufHasData = false; // sending now
 if(HAL_UART_Transmit_DMA(&huart4, (uint8_t *)Usart3TxDMABuffer + U3TxBufferPtrOUT, U3TxBufferPtrIN - U3TxBufferPtrOUT) == HAL_OK) {
 U3TxBufferPtrOUT = U3TxBufferPtrIN;
 Usart3TxDMABuffer[U3TxBufferPtrIN] = 0; // null
 }
 else {
 _Error_Handler(__FILE__, __LINE__); /* Transfer error in transmission process */
 }
 }
 }
} �?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Lars Beiderbecke
Senior III
Posted on May 27, 2018 at 10:36

I tried a slightly different approach. Instead of dealing with variable-length answers, I counted how many bytes I have to expect and used that number:

HAL_UART_Receive_DMA(&huart7, buffer, 11);  // answer has 11 bytes, including \r and \n

HAL_UART_Transmit_DMA(&huart7, 'AT' CRLF, 4);

checkBuffer();                              // waits some seconds before checking answer

HAL_UART_Receive_DMA(&huart7, buffer, 20);  // <---- doesn't work!

HAL_UART_Transmit_DMA(&huart7, 'AT+CWMODE=1' CRLF, 13);

checkBuffer();

Again, this works for the first command, but for the second command the buffer remains empty, i.e., not a single byte is received.

Do I need to do something in code to 'complete' the DMA transfer so that I can issue a new one?

Lars Beiderbecke
Senior III
Posted on May 27, 2018 at 11:17

I think I found the solution. I had to enable the UART7 interrupt for subsequent Rx's to work.

One wonders why CubeMX doesn't activate it automatically if it is required for DMA to function regularly.