cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 , 115200 uart and missing data

Posted on January 30, 2018 at 12:30

Hi, I have an uart at 115300 baud rate and I miss data.

I have implemented the rx callback where I grab one byte at time.

How can I grab more than one byte till the end of the receive?

HAL_UART_Receive_DMA(&huart1, (uint8_t*)&MicroBufferSerial0Read, 1);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {

    if (huart->Instance== USART1) {

        BufferSerial0Read[BufferSerial0ReadLength++]= MicroBufferSerial0Read[0];

        ...

7 REPLIES 7
Rafiq Rahman
Associate
Posted on January 30, 2018 at 13:15

Hi Denis,

One way of doing it is to set your rx DMA buffer to more than one (the buffer should be more than your frame byte size, meaning if you expect 10 bytes to be received at any time, set it to more than 10, e.g 15). And you also need to enable the rx idle line detection interrupt. This is can be done easily using the LL_USART library and has to be done manually. The HAL version of receive_IT or receive_DMA will not enable the idle line enable interrupt.

Next, once the idle line interrupt is fired, in the isr of the uart which triggered it, disable the dma stream (or channel for the F103 series). On the F4, the DMA isr is automatically called upon disabling the channel. Hence, in that DMA isr routine (assuming it's an F4), check the remaining bytes to transfer in the stream by dereferencing the rx dma handle's NDTR (0 indicating everything's been transfered, non zero numbers indicate how many bytes/words/half-words space left to trigger the TC (DMA transfer complete) flag.

Clear all the interrupts associated to the DMA stream and fire the RX dma receive function again within the DMA isr to start receving via DMA.

For the F103, the DMA channel disabling has to be done withing the UART isr, where you should clear the idle line flag first (using ll_usart saves you time) and disable the dma channel. Read the CNDTR of the DMA channel handle, clear the flags, recall the rx receive dma and you're good to go.

Please refer to Tilen Majerle's write up on this issue. That guy is a STM32 wizard. Links to the article as follows:

https://community.st.com/thread/42689-efficiently-use-dma-with-uart-rx-on-stm32

One more thing, write your offsets correctly when copying the rx DMA buffer input to your global variable buffer. (Learned that the hard way).

Cheers.

Posted on January 30, 2018 at 16:26

Hi, many thanks for your quickly reply but I don't find the LL_USART library. I'm using a STM32F091RCT microcontroller.

Where can I find it in order to have an event when the received is ended?
Posted on January 30, 2018 at 17:09

Hi Denis,

If your using CubeMX, under ''Project Setting'', select the second tab and make sure the radio button is on ''Copy all used libraries into the project folder''.

0690X00000604ESQAY.jpg

All the files for the LL Libraries are now in the [''You're Project Folder''\Drivers\STM32F0xx_HAL_Driver\Src] and 

[

''You're Project Folder''

\Drivers\STM32F0xx_HAL_Driver\Inc] folders upon code generation in CubeMX. The src folder houses the .c files while the Inc folder contains all the .h files. Add the 

necessary .c and .h files to your IDE Project Items (stm32f0xx_ll_usart.c, stm32f0xx_ll_usart.h, stm32f0xx_ll_dma.c and 

stm32f0xx_ll_

dma

.h), preferably in the ''Drivers/STM32F0xx_HAL_Driver'' group item.

And last but not least, include the header files in your main.c and stm32f0xx_it.c files or wherever you wish to call the LL_Library functions.

♯ include ''stm32f0xx_ll_usart.h''

♯ include ''

stm32f0xx_ll_dma.h''

That's all to it. Good luck!

Posted on January 30, 2018 at 17:38

Use STM32CubeMX and generated project where in advanced setting you can select LL instead of default HAL drivers. Your MCU is supported.

Posted on January 30, 2018 at 21:50

Many thanks for your explanations but, after having tried the examples and the docs on the ll library approach I haven't got a solution.

Now I haven't got so much time to spend on.

At the moment I have defined a dma buffer of 2 bytes that has improved the situation.

My device sends a 0x00 ad the end of each trasmission so if I haven't got it I can work equally.

Many times I have a not well formed trasmission.

Finally the problem that the HAL uart implementation hasen't got a way to have the idle line event?

T J
Lead
Posted on January 31, 2018 at 00:33

My new revision of this has the RxDMA buffer at 256bytes.

// init

#define U1RxBufSize 256

#define U1TxBufSize 4096

void initUart1RxDMABuffer(void) {

    if (HAL_UART_Receive_DMA(&huart1, (uint8_t *)Usart1RxDMABuffer, U1RxBufSize) != HAL_OK)

    {

        // Transfer error in reception process

        //_Error_Handler(__FILE__, __LINE__);

        char string[32];

        sprintf(string, 'initUart1RxDMABuffer Failed\n');

       puts1(string);        

    }

    else

    {

        char string[32];

        sprintf(string, 'initUart1RxDMABuffer OK!\n');

       puts1(string);

    }

}

// runtime

char readableU1(void){

    U1RxBufferPtrIN =  U1RxBufSize - huart1.hdmarx->Instance->CNDTR;

    return U1RxBufferPtrIN - U1RxBufferPtrOUT;

}

char readU1(void){

    char readByte = Usart1RxDMABuffer[U1RxBufferPtrOUT++];

    if (U1RxBufferPtrOUT >= U1RxBufSize) U1RxBufferPtrOUT = 0;

    return readByte;

}
Posted on February 01, 2018 at 21:53

This approach seems to not be necessary anymore for me. My device now is working at 115200 Baud without any problem.

I had accidentially changed something int the clock configuration of CubeMX of my demo board. Now with the normal values everyting is working perfectly.

Many thanks for your time.