2018-10-12 02:57 AM
Hi everyone,
I am using stm32l4xx UART driver. I can read and write data. I am using
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
API to read and write the data.
I am trying to know how many bytes written in "HAL_UART_Transmit", number of read bytes in API "HAL_UART_Receive" and count number of characters in receive buffer.
Could anyone please help me on this.
Thanks in advance.
John
2018-10-23 09:58 PM
Hi,
No issue, for me to use DMA, but the problem is I don't know how to return the number of recev and write bytes using DMA API's.
Could you please help to write API using DMA.
int uart_write(UART_HandleTypeDef *huart, char *pbyte, word16 count, word16 timeout)
{
HAL_StatusTypeDef status;
int retcode = 0;
if (count != 0) {
status = HAL_UART_Transmit( huart, (uint8_t *) pbyte, count, timeout);
if (status == HAL_OK)
retcode = count;
else
retcode = count - huart->TxXferCount;
}
return( retcode);
}
int uart_read(UART_HandleTypeDef *huart, char *pbyte, word16 count, word16 timeout)
{
HAL_StatusTypeDef status;
int retcode = 0;
if (count != 0) {
status = HAL_UART_Receive(huart, (uint8_t *) pbyte, count, timeout);
if (status == HAL_OK)
retcode = count;
else
retcode = count - huart->RxXferCount;
}
return( retcode);
}
uint16_t uart_recv_count(UART_HandleTypeDef *huart) /* count number of characters in receive buffer */
{
HAL_StatusTypeDef status;
int retcode = 0;
status = HAL_UART_Receive(huart, (uint8_t *)recv_buff, UART_RECV_SIZE, 1);
if ( status == HAL_OK)
retcode = UART_RECV_SIZE;
else
retcode = UART_RECV_SIZE - huart->RxXferCount;
return( retcode);
}
2018-10-24 08:09 AM
In the long code you posted on 22 Oct: there appears to be an incorrect # of open and close curly braces. Is this an EXACT copy of you real code? None the less, at the top of the while() loop you call uart_recv_count() to receive some data. If you got data, you then call uart_read() to get more data. Is that really what you intend to do? And uart_recv_count() has a timeout of 1 system tick (1 ms). Using polled Rx is really not the way to go unless you have well defined and well boundaried data packets.
Using DMA: configure RX for DMA in circular mode, pointing to a well sized buffer (much bigger than the # of bytes you think you could ever receive between checking for data). And make life easy on yourself and make the buffer size a power of 2 (say 32, 64 or 128 bytes), it makes it easy to wrap your index value when you reach the end of the buffer. The "data into this buffer" index (not pointer) is related to the DMA counter register. Declare your own "data coming out of this buffer" index. At init, your index = 0 (start of the buffer). Data is available when your index != [(buffer size) - (DMA CNDTR register), AS LONG AS YOU NEVER ALLOW THE BUFFER TO FILL COMPLETELY (see "well sized" comment above). Read your data and increment your index until it equals [(buffer size) - (DMA CNDTR)]. No enable/disable interrupts needed. And you can either poll the Rx buffer from a main polling loop, or from some periodic timer interrupt (or task if you run an RTOS).
And you can ignore all DMA interrupts, though you need the UART error callback. The HAL code DISABLES the UART and DMA Rx functions when it gets an error (framing, parity, etc.). On error you need to restart the DMA Rx. That error behavior is a pain, and I ended up editing the HAL code so errors just keep receiving (my data flow has provisions to detect missing/corrupted data).
2018-10-24 03:06 PM
DMA is not trivial, but once initialised, its trouble free
For this to work, you need to set the RxDMA to circular buffer. and TxDMA to normal buffer.
TxDMA is the most complicated... you can avoid it today and just get the RX DMA runnning.
only initialise the RxDMA once at startup before while(1)
initialize before while(1)
#define U1RxBufSize 256
#define U1TxBufSize 8192 // double the size of the largest string printed.
U1RxBufferPtrOUT = 0; // out pointer within the Rx buffer
HAL_UART_Receive_DMA(&huart1, (uint8_t *)Usart1RxDMABuffer, U1RxBufSize);
in your code:
you can Peek at the buffer level ;
U1RxBufferPtrIN this is pointing to the next Rx byte position.
char readableU1(void) {
U1RxBufferPtrIN = U1RxBufSize - __HAL_DMA_GET_COUNTER(huart7.hdmarx);
return U1RxBufferPtrIN - U1RxBufferPtrOUT;
}
char readU1(void) {
char readByte = Usart1RxDMABuffer[U1RxBufferPtrOUT++];
if (U1RxBufferPtrOUT >= U1RxBufSize) U1RxBufferPtrOUT = 0;
return readByte;
}
2018-10-24 07:16 PM
this is how I check the DMA buffer level, it returns length of unread Rx bytes in the DMA buffer.
initialise: ( before while(1) )
char U1RxBufferPtrIN ;
char U1RxBufferPtrOUT=0;
initUart1RxDMABuffer();
in your code:
unReadLength = readableU1();
char readableU1(void) {
U1RxBufferPtrIN = U1RxBufSize - __HAL_DMA_GET_COUNTER(huart7.hdmarx);
return U1RxBufferPtrIN - U1RxBufferPtrOUT;
}
void initUart1RxDMABuffer(void) {
if (HAL_UART_Receive_DMA(&huart7, (uint8_t *)Usart1RxDMABuffer, U1RxBufSize) != HAL_OK)
{
// Transfer error in reception process
//_Error_Handler(__FILE__, __LINE__);
sprintf(string, "initUart1RxDMABuffer Failed\n");
puts1(string);
}
else
{
//char string[32];
sprintf(string, "initUart1RxDMABuffer OK!\n");
puts1(string);
}
}
2018-10-24 07:21 PM
Hi Bob S & T J,
Many thanks for the support. I really appreciate you guys.
I have already fixed the issue on receiving side. I was reading in recv count and again i was reading to get whole data. I have just changed the code and using single uart_read() to read and return number of bytes read. But I am using without DMA & interrupt.
I don't see any issue but I want to implement using DMA.
I will look into DMA code and need your guys support if needed.
Many Thanks,
John
2018-10-24 07:52 PM
I have answered this twice before, but it doesn't show on the site?
can you check my answers in this thread ?
2018-12-01 11:41 PM
Hi @Community member
Thanks for the reply.
Now I was trying to change uart read to RxDMA to circular buffer.
Basically I have to change 2 function which is currently working without DMA as below:
int uart_read(UART_HandleTypeDef *huart, char *pbyte, word16 count, word16 timeout)
{
HAL_StatusTypeDef status;
int retcode = 0;
if (count != 0) {
status = HAL_UART_Receive(huart, (uint8_t *) pbyte, count, timeout);
if (status == HAL_OK)
retcode = count;
else
retcode = count - huart->RxXferCount;
}
return( retcode);
}
uint16_t uart_recv_count(UART_HandleTypeDef *huart) /* count number of characters in receive buffer */
{
HAL_StatusTypeDef status;
int retcode = 0;
//status = HAL_UART_Receive_IT(huart, (uint8_t *)recv_buff, 1);
status = HAL_UART_Receive(huart, (uint8_t *)recv_buff, UART_RECV_SIZE, 1);
if (status == HAL_OK)
retcode = UART_RECV_SIZE;
else
retcode = UART_RECV_SIZE - huart->RxXferCount;
return( retcode);
}
It returns number on read bytes.
I have changed code based on your post using DMA as below:
#define UART_RECV_SIZE 512
unsigned int U1RxBufferPtrOUT;
uint16_t uart_dma_recv_count(UART_HandleTypeDef *huart) /* count number of characters in receive buffer */
{
HAL_StatusTypeDef status;
int readByte;
status = HAL_UART_Receive_DMA(huart, (uint8_t *)recv_buff, UART_RECV_SIZE);
if (status == HAL_OK)
{
readByte = recv_buff[U1RxBufferPtrOUT++];
if (U1RxBufferPtrOUT >= UART_RECV_SIZE)
U1RxBufferPtrOUT = 0;
}
return readByte;
}
Could you please help to me correct above function to return number of receive bytes and recv count.
Thanks,
John
2018-12-02 01:20 PM