2018-05-26 07:04 AM
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.
Solved! Go to Solution.
2018-05-27 02:17 AM
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.
2018-05-26 07:49 AM
>>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) } }}2018-05-26 08:00 AM
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?
2018-05-26 10:01 AM
Our posts overlapped, but I'll try as suggested.
2018-05-26 10:35 AM
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?
2018-05-26 05:15 PM
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
2018-05-26 08:33 PM
Assuming Nucleo STM32F722ZE
2018-05-26 09:14 PM
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 */
}
}
}
} �?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
2018-05-27 01:36 AM
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 answerHAL_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?
2018-05-27 02:17 AM
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.