cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 FreeRTOS UART interrupt

zmayac
Associate II
Posted on April 15, 2014 at 22:30

Using:

  • STM32F407VG
  • FreeRTOS 7.6.0

I am trying to read value of RFID card via UART interrupt. Problem is that data read by UART is somehow corrupted. If i don't use FreeRTOS this code works, which makes it even more strange.

The RFID communicates using rs232 and transmits a 12-byte ASCII string. The first byte (start byte) in my case is always 0x To be more precise.. when the card is

approximated

to the reader interrupt is normally triggered, but when i try to read this 12-byte ASCII i never get start byte (0x02), instead of that in most of the cases i get 0x80, so reading is never successfully. What am i doing wrong?


extern
unsigned 
char
tagValue[12];

extern
xSemaphoreHandle xUsartRead;


void
USART1_IRQHandler(
void
) {

unsigned 
char
sign = 
'\0'
;

uint8_t k = 0;


if
(USART_GetITStatus(USART1, USART_IT_RXNE)) {

if
(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)){ 

sign = USART_ReceiveData(USART1);

if
(sign == 0x02) {

while
(k < 12) { 

if
(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))

tagValue[k++] = USART_ReceiveData(USART1);

}



portBASE_TYPE xHigherPriorityTaskWoken;

xHigherPriorityTaskWoken = pdFALSE;

xSemaphoreGiveFromISR(xUsartRead, &xHigherPriorityTaskWoken);


portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

}

} 

}

}

#freertos-uart-interrupt #usart
7 REPLIES 7
Posted on April 15, 2014 at 23:21

You don't buffer the input in a way that permits multiple entry into the IRQ.

You dwell in the IRQ excessively in a manner that blocks everything.

You yield execution to lower priority processing, with live data.

Suggest you capture the characters in a more state-full fashion. ie one character per interrupt.

You wait until you have accumulated all the characters, then copy that in to a processing buffer/queue, and let a deferred worker thread process it.

The interrupt does not have to yield, the worker thread can get to it in it's own time quanta.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jpeacock2399
Associate II
Posted on April 16, 2014 at 00:12

Some items:

if

(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
 
You don't need this, it's implicit after the irq flag test. However, if you check for errors you need to read the SR register before DR in order to capture PE, FE and ORE errors (it's in the errata for the F4). The call to get flag status will erase the other flags;you don't know if you have overruns or frame errors.


sign = USART_ReceiveData(USART1);

if
(sign == 0x02) {

while
(k < 12) { 

if
(USART_GetFlagStatus(USART1, USART_FLAG_RXNE))

tagValue[k++] = USART_ReceiveData(USART1);

This isn't very good practice for an RTOS. Instead, set up a flag to look for the 0x02 leadin character, then copy the rest of the data to a message queue or some kind of buffer as it arrives. Set the completion flag when you reach the end and reset the 0x02 detect flag. Never, ever, stall in a polling loop inside an irq handler. It killsthe response time for other tasks. Jack Peacock
carl2399
Associate II
Posted on April 16, 2014 at 01:37

The use of an RTOS, while it can lead to code that easier to maintain and extend, can also lead to stuff like you've done - which is not as good.

While allowing nested interrupts is a very powerful feature, I've never used it. It opens you up to a whole other level of pain.

I would support Clive by saying that you should process one character per interrupt! You can go slightly better by processing 1 Rx and 1 Tx character per interrupt, but don't go any further than that. Create (and use) some FIFOs to manage the flow of characters around your system. You could use DMA, but personally I find interrupts easier to use for asynchronous comms. 

The processor is orders of magnitude faster than a serial stream, so wanting to switch tasks is correct, but not within the interrupt. Make the interrupt as brief as possible:

1. read the status register

2. if RXNE then Rx a pending character into FIFO

3. if TXE then Tx a character (if required) from FIFO

4. exit the interrupt

The only other magic that I'd put into an interrupt is setting a flag when detecting a magic character (eg. ETX to delimit the end of an incoming packet) or comms status error.

Posted on April 16, 2014 at 02:52

In the general sense the FIFO would be the way I'd go, but in this case a simple line accumulation, and posting that to a queue, has about zero cost in the IRQ handler.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
zmayac
Associate II
Posted on April 19, 2014 at 23:31

I changed ISR like you said, reading and storing 1 char per irq (having just RX requests). But the problem still presists. Characters i read are not ''correct'', 0x02 is never read, also 0x03. Exact same code works without FreeRTOS, i didn't change any USART initialization code. Any ideas what could be wrong. Priorities and other basic settings are ok.

Posted on April 19, 2014 at 23:46

Ok, then output characters and check the timing with a scope. If you've broken system_stm32f4xx.c with the wrong PLL settings, or HSE_VALUE is wrong, the timings will be off.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
zmayac
Associate II
Posted on April 22, 2014 at 19:08

For STM32F4-Discovery you have to edit stm32f4xx.h and go to line 92 ad change

 

#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */

 

to

 

#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

 

25MHz oscillator is for STM32-EVAL board

This was the problem. Thank you all for help.