cancel
Showing results for 
Search instead for 
Did you mean: 

STM32l4 UART driver

John3
Associate II

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

17 REPLIES 17
John3
Associate II

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);
}

Bob S
Principal

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).

T J
Lead

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;
}

T J
Lead

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);
    }
}

John3
Associate II

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

T J
Lead

I have answered this twice before, but it doesn't show on the site?

can you check my answers in this thread ?

https://community.st.com/s/question/0D50X00009sVTZFSA4/haluartreceivedma-calls-rxcpltcallback-but-receives-no-data

John3
Associate II

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

T J
Lead
The website is broken, I cannot login.
Please revise the posts,
Init Rx DMA is only run once at startup like this

* initialise: ( before while(1) )
* char U1RxBufferPtrIN ;
* char U1RxBufferPtrOUT=0;
* initUart1RxDMABuffer();
*

Then call to check the length of received bytes.


*
* char readableU1(void) {
* U1RxBufferPtrIN = U1RxBufSize - __HAL_DMA_GET_COUNTER(huart7.hdmarx);
* return U1RxBufferPtrIN - U1RxBufferPtrOUT;
* }


This is the init code
* 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);
* }
* }