cancel
Showing results for 
Search instead for 
Did you mean: 

Help in writing a bare metal code for implementing a UART RX interrupt routine in SMT32F767ZI ?

SSRIN.1
Associate III

I started writing embedded code 7 months back for a robotics project. Till now , I was able to handle most of the stuff with HAL libraries. I hit a snag when trying to interface with a AHRS(Microstrain CX5-25) unit. There were time when only first few bytes will be received and the device won't receive any more bytes, even thought the IMU status shows streaming. Suspecting something is wrong with the IMU, I tried reading it from PC using Pyserial and it worked. I suspect something is wrong with HAL Receive IT Function call.

Either way,After inputs from previous posts regarding handling of frames with different sizes. I decided to shift to bare metal register based programming at least for interfacing this device.

Currently I have the following hardware setup.

STM324767ZI Nucleo Uart 5 port is connected to pc via USB-TTL device. I will be using pyserial from PC side to send some arbitrary data. This will help me check the Uart receive isr routine written in STM32 micro controller.

Initial peripheral initialisation code is set using cubemx pre-generated code.

In main.c

I call

__HAL_UART_ENABLE_IT(&huart5,UART_IT_RXNE);

__HAL_UART_ENABLE_IT(&huart5,UART_IT_ERR);

to enable interrupts

Then I write a customisr routine which is called from 

void UART5_IRQHandler(void)

custom_isr(UART_HandleTypeDef * huart)

{

uint32_t isrflags = huart->Instance->ISR;

uint32_t crlits = huart->Instance->CR1;

if (((isrflags & USART_ISR_RXNE) != RESET) )//&& ((crlits & USART_CR1_RXNEIE) != RESET))

{unsigned char a = huart->Instance->RDR;

store_ring (a , rbuf);

}

}

I could verify that when ever, I send a byte from pc. The interrupt is triggered, But RDR register is empty.

When I checked the ISR register following bits were set : IDLE,TC complete,Transmit Data,End of Block,Busy flag,character match flag.

Strangely I have enabled interrupt only for error and rx not empty. However after interrupt trigger, when I check the ISR flag, rx not empty flag is not set.

I think, I am making a mistake in the sequence of how its done. Can any one advice on what I am missing ?

Thank you

Yours Sincerely,

S.Shyam

11 REPLIES 11
MFran.4
Senior

If your clock is running fast enough you could still use the api by calling HAL_UART_RECEIVE_IT(huart, &byteBuf, 1U)

You'll get "received callback" for each byte, and at the end of the callback you have to put hal receive it again.

SSRIN.1
Associate III

Actually the callback is not even triggering

MFran.4
Senior

Try sending one character, placing a breakpoint in the IRQHandler and following the program flow. It's possible that it could have something to do with Overrun (which if not managed can cause some headaches, so if you don't use overrun error you should disable it).

Anyway, if you want to try from scratch:

Try creating a new project with cube, then (still in CubeMX) enable the desired uart, enable the relative NVIC uart interrupt, and then in your main do as I wrote.

Would suggest clearing Noise,Framing or Parity errors whenever you encounter them, as these WILL block reception.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

Reading RDR in the debugger will clear the flag. Make sure you're not doing that.

If the ISR is getting triggered, there's a reason. There are not glaring hardware issues. Recheck your assumptions.

If you feel a post has answered your question, please click "Accept as Solution".
Pavel A.
Evangelist III

> There were time when only first few bytes will be received and the device won't receive any more bytes, even thought the IMU status shows streaming.

As @Community member​ wrote, this likely is the notorious UART overrun bug, still not resolved in the HAL libraries.

The HAL library takes care of other error flags mentioned by Tesla.

Set OVRDIS bit in the USART_CR3 or disable overrun detection in Cube configuration.

If you want continuous receive (you likely do for the IMU) consider DMA.

HAL_UART_RECEIVE_IT(huart, &byteBuf, 1U) is never a good idea, because it will enable and disable RX interrupt for every byte, after every byte there's a window when the interrupt is disabled.

You are right, I omitted that I also set USART IRQ priority to max (0 or 1) and usually I have fast clock frequency so it did not represent a problem even with higher baudrates (e.g. 115200).

If it's better to stick to DMA, how would one implement it?

Not that I don't know how to use DMA, it's more a design question.

Consider that I use my Received_Callback each byte to put a byte in a fifo and nothing more. I always receive variable length packets so I really can't tell how to configure DMA for generic use. I know there are two callbacks but they fire only in certain moments of DMA transfer (half, full).

My particular use case is a generic C++ St UART driver, that's why I have a problem with packet length and the single-byte-put-in-fifo-callback worked well.

I guess the alternative to using DMA would be at least write bare metal code and handlers like this post suggests.

> If it's better to stick to DMA, how would one implement it?

There are examples:

https://github.com/MaJerle/stm32-usart-uart-dma-rx-tx/tree/master/projects/usart_rx_idle_line_irq_ringbuff_tx_H7

I don't have F7, would expect its UARTs to be similar to H7.

The HAL library also has DMA variant of receive; someone wrote that if the DMA is programmed in circular mode then the HAL function will work as continuous receiver (no size limit).

Re: interrupt priority:

> I also set USART IRQ priority to max (0 or 1) 

The priority does not matter if there are other interrupt sources.

Consider what if a low priority interrupt hits during the window when the UART interrupt is disabled by HAL_UART_RECEIVE_IT.

And its ISR runs long enough (for example does some I2C i/o 🙂 Then incoming UART data may be lost.