Questions and discussions about the software that runs on the TD RF module itself.
arnaudw
 
Posts: 17
Joined: Fri Jun 12, 2015 8:18 pm

LEUART in interrupt handler

by arnaudw Mon Nov 09, 2015 3:11 pm

Hello,

I have a problem while using LEUART in an interrupt handler.
The function "TD_UART_GetChar()" does not return any characters while it is in the interrupt handler function.
Works great if the program si not on interrupt.

I would like to read in the "LETIMER0_IRQHandler" which runs periodically.

The UART is initalized like this in the main program, while TD_UART_GEtchar() is called via a function called in the LETIMER0_IRQHandler :
Code: Select all
void TD_USER_Setup(void) {

init_printf(TD_UART_Init(9600, true, false), TD_UART_Putc, TD_UART_Start,
         TD_UART_Stop);

// init letimer
LEtimer_start();
}


Thanks for your help :)


Arnaud.
User avatar
mstempin
 
Posts: 168
Joined: Thu May 07, 2015 9:24 am

Re: LEUART in interrupt handler

by mstempin Mon Nov 09, 2015 4:41 pm

You should not try to read the LEUART in the IRQ handler!

The TD SDK programming model is using a non-preemptive multi-tasking model, i.e. you won't be interrupted (preempted) randomly in a task to give back the CPU to another task by a dedicated timer running in a privileged mode.

OTOH, this means that your task has to be nice and collaborate with other ones, and give back the CPU on a voluntary manner for the system to continue working. This is generally not a problem with embedded systems, where tasks are pre-defined and cooperate to do the job.

This also means that you should not be blocking in your task, and in particular that you should not go to sleep within your task, or this will then add preemption points to the single existing one in the main loop, where you possibly would have to handle all possible events upon wake up in several places in the code, leading you to complex reentrancy problems.

This mode of operation was chosen because it is the only one that works for ultra-low power operation, where you just can't afford to have a cyclic timer waking you up to do nothing because of the increased power consumption. Another good reason is that each preempted task would require a large amount of RAM to store the task status (all CPU registers, stack, heap if there are real tasks and not simpler threads, file / stream descriptors...), where we only have 16 KB RAM total.

Besides this collaborative multi-tasking model, there is another concept used by the TD SDK: it uses 2 separate processing domains for handling asynchronous events:
  • The hard real-time interrupt domain: this is where the IRQ handlers are located, The processing here must be as fast as possible and non blocking in order to guarantee the lowest possible IRQ latency, This is to keep the time required for an IRQ to be taken into account to the minimum possible, i.e. to keep good responsiveness
  • The soft real-time event domain: this is where the main loop (TD_USER_Loop()) is called: even if you need to be decently fast here to do the required job, you don't need to be as fast as when in the interrupt domain. This is where the main processing is taking place.
In your case, you need to separate your processing between interrupt and event domains: you should not try to read characters directly into the IRQ handler: instead, only set a volatile flag there. Upon IRQ handler exit, the TD_USER_Loop() function will eventually be called back in the relaxed event domain, where you can check for this flag and read characters on the UART, then reset the flag for further processing, or give hand to other tasks if you don't have anything to do.

However, you should not need to go so low in the API to perform the task of reading characters on the UART: by default, the CPU is in sleep mode and will be awaken when a character is received on the UART, the LEUART IRQ handler will be called in the interrupt domain, put the read characters in a FIFO, then the TD_USER_Loop() function will be called while in the event domain and will check for available characters and perform the required processing.

If you really want to check for incoming characters at strict intervals, you would better use the scheduler to register a callback function that will be called at regular intervals in the relaxed event domain to check for incoming characters on the UART.
arnaudw
 
Posts: 17
Joined: Fri Jun 12, 2015 8:18 pm

Re: LEUART in interrupt handler

by arnaudw Tue Nov 10, 2015 1:07 pm

Wow thanks, very clear !
As i am a beginner i try to find informations on Silabs examples/forum and didn't understand that most things can be done directly through your SDK.

So i only need to use "TD_SCHEDULER_AppendIrq" function which abstract notion of timers (letimer, uart...) and is energy friendly.
Now simply set the volatile flag in the function called by AppendIrq and works like a charm :)

Thanks again, your help is greatly appreciated :!: :mrgreen:

Arnaud.
ramon2015
 
Posts: 51
Joined: Mon Jul 06, 2015 4:06 pm

Re: LEUART in interrupt handler

by ramon2015 Wed Sep 21, 2016 11:22 am

Hi,

Really good explanation of the system. It is much appreciated.

However, I still have a question about the interrupt handling. Say we have 2 type of interruptions:

- Asynchronous (attached to the signal edges in a pin): TD_GPIO_SetCallback(type, VacSensorInterrupt, VAC_SENSOR_MASK);
- Synchronous (attached to a perdioic timer): TD_SCHEDULER_Append(1, 0 , 0, TD_SCHEDULER_INFINITE, measurement_TimerEnded, 1);

I know it is very difficult that both events happen at the very same time (if the code inside the callbcaks is kept at minimun) but what if this happens?

- Both interrupt are serviced? one after the other? Is there any priority defined somewhere?
- Only one is erviced? Is there any priority defined somewhere?

Regards, Ramon.
User avatar
mstempin
 
Posts: 168
Joined: Thu May 07, 2015 9:24 am

Re: LEUART in interrupt handler

by mstempin Mon Nov 28, 2016 3:29 pm

Both interrupts will be serviced one after the other, there is no priority defined.

However, both interrupts will be memorized into a flag. The danger is if the interrupt handling sensitive code is lasting to long and you miss a repeated interrupt of a given kind, which is unlikely, unless you do a very long processing within the interrupt handler.

This is why the interrupt handlers are kept to the bare minimum, and long processing tasks are delayed until out of interrupt context in the main loop.
Return to Firmware

Who is online

Users browsing this forum: No registered users and 23 guests