dspic33f different interrupt priority levels for freertos api calling ISR

swissembedded wrote on Tuesday, November 05, 2013:

Hi

is it possible to use different interrupt priority levels for the interrupt service routines? All ISR must be able to call freertos api (e.g. queues)?
What must be changed in the kernel?

best regards

Dani

davedoors wrote on Tuesday, November 05, 2013:

According to the documentation - in the current implementation any interrupt that calls FreeRTOS functions must run at the lowest interrupt priority level. Any other interrupt can run at any priority level.

swissembedded wrote on Tuesday, November 05, 2013:

Hi Dave

thank you for the fast response. How can the kernel be modified to overcome this limitation?

best regards

Dani

rtel wrote on Tuesday, November 05, 2013:

I would have to re-familiarise myself with the architecture, when you support so many it becomes a bit of a blur, but basically:

When you enter a critical section you have to disable interrupts only up to a certain priority level, rather than globally, so when you are inside an interrupt you can enter critical sections without stopping other interrupts from nesting.

When a context switch is required in an interrupt you have to hold it pending until the interrupt nesting has unwound. That means you will have to create your own interrupt entry and exit code, rather than using the compiler generated code.

You can look at the PIC32 port as a reference, albeit for a completely dissimilar architecture, the principals are the same. The PIC32 supports a full interrupt nesting model.

Regards.

swissembedded wrote on Wednesday, November 06, 2013:

If I understand you correct, I can call API from a higher interrupt priority level as long as portEND_SWITCHING_ISR is never called with pdTRUE?

richard_damon wrote on Wednesday, November 06, 2013:

I don’t think so, the problem is that I don’t think the port doesn’t implement critical sections in interrupt routines, because interrupt that call FreeRTOS do not nest. Interrupt nesting requires that the ISR critical section block off all interrupts that might interface with FreeRTOS. This could be fixed also.

swissembedded wrote on Wednesday, November 06, 2013:

looks like I’m not the only one :wink:
http://www.freertos.org/FreeRTOS_Support_Forum_Archive/May_2011/freertos_FreeRTOS_queue_issue_4548926.html

Unfortunately I need nesting.
All the ISRs basically only use xQueueReceiveFromISR, xQueueSendToBackFromISR, uxQueueMessagesWaitingFromISR.
There is only one interrupt routine that is running every 125us which is critical. So I could add critical section around RTOS API calls on the lower priority interrupt routines, tick timer does not need extra sections?

swissembedded wrote on Wednesday, November 06, 2013:

I disabled all lower priority interrupt routines and test the critical ISR with higher priority level. Looks like this is not working :frowning:

dragonflight1 wrote on Wednesday, November 06, 2013:

There is no way to call a FreeRTOS function from a higher than configKERNEL_INTERRUPT_PRIORITY interrupt, but all you need to do is to modify configKERNEL_INTERRUPT_PRIORITY in FreeRTOSConfig.c to some level (I use 5).

If you want to stick with the current supported port then you also need to change the line
MOV #32, W0
in the appropriate portasm file in Source/portable/MPLAB (in your case portasm_dsPIC.s )to
MOV #PRIO<<5
where PRIO is your new configKERNEL_INTERRUPT_PRIORITY setting and as a side note make sure that you have the symbol
MPLAB_DSPIC_PORT
in your project settings when using a dsPIC.
(edit) I forgot, you also need to change port.c line
#if configKERNEL_INTERRUPT_PRIORITY != 1
to your new priority

If you are feeling a little adventurous, you can instead use my port.c file, no changes, no asm file and as a bonus get hardware stack checking! Please see

http://interactive.freertos.org/entries/28123677-FreeRTOS-V7-5-3-port-for-ALL-16-bit-pics-with-hardware-stack-checking-SPLIM-

mike

swissembedded wrote on Wednesday, November 06, 2013:

Hi Mike

thank you for your reply. Now I’m totally confused. See text vom RTOS page below, claiming all must be running at configKERNEL_INTERRUPT_PRIORITY. So you use 5 and place tick timer on a much lower interrupt priority level (e.g. 1) and the interrupt service routines something between 2 and 5?

best regards

Dani

“For ports that only implement configKERNEL_INTERRUPT_PRIORITY
configKERNEL_INTERRUPT_PRIORITY sets the interrupt priority used by the RTOS kernel itself. Interrupts that call API functions must also execute at this priority. Interrupts that do not call API functions can execute at higher priorities and therefore never have their execution delayed by the RTOS kernel activity (within the limits of the hardware itself).”

rtel wrote on Wednesday, November 06, 2013:

Mike’s port is a different port - or at least - a greatly modified port. Note he has posted a link to his code in the FreeRTOS Interactive site.

Regards.

dragonflight1 wrote on Wednesday, November 06, 2013:

I can’t unequivocally contradict that quote (I’ve only been using FreeRTOS for 2 weeks, but I believe they mean to say at this priority or lower).
The kernel uses this priority (it actually uses a port routine) to effectively disable all interrupts at configKERNEL_INTERRUPT_PRIORITY or lower during critical sections, which is why you can’t call a RTOS function from a higher priority interrupt - the kernel could be in a critical section.
I don’t know why the initial port used interrupt level 1 in the PICS given they have 7 levels, but…

I can also tell you that I have my little system running with many interrupts running below and one running above priority 5 and it woks as long as I haven’t improved it recently!

(There used to be a sign outside my lab 40 years ago -
If it’s working it will be improved, if it isn’t working it was improved yesterday!

richard_damon wrote on Thursday, November 07, 2013:

There are two separate issues with using multiple interrupt levels and allowing interrupt that access FreeRTOS to nest. First is the need to be able to have a critical section inside the interrupts. The PIC24 port could define this operation, but doesn’t due to the second issue.

The second issue is task switching forced by an ISR. The method that the PIC24/dsPIC ports use, is not compatible with nesting interrupts.

It should be possible to come up with an alternate port layer which does implements interrupt nesting, but it is likely to come with a cost, both in complexity and speed. Since normally interrupt that interact with FreeRTOS tend to be short and quick, having only a single level for all of them isn’t normally a problem.

As to the interrupt that needs to run every 125us, does this NEED to call a FreeRTOS API function? Would it be possible to do at least most of the needed processing in the interrupt (I presume it isn’t much) using ordinary memory buffers, and using something slower (like a timer hook) to relay information to FreeRTOS. One trick that you can do is steal the interrupt vector from an unused device and manually trigger the interrupt to let your higher priority interrupt trigger something at configKERNEL_INTERRUPT_PRIORITY that can talk to FreeRTOS.

swissembedded wrote on Thursday, November 07, 2013:

Richard, thank you for the details. The codec gets audio and control data (e.g. change volume) over freertos queues. It does only pull one sample out of the queue sends it to codec and pulls one sample out of the codec into the queue. Then checks the control data queue, if it is not idle, it sends that control info to the codec as well and reads the results out and places that in another queue.
I understand the limitations and costs in speed that might arise. Of course this could be done without FreeRTOS calls, but honestly having such a great OS, does it make sense to do the same in two different ways?
I can’t remember having used different API in an ISR than Queues so far. So I think Queues are some special case. Maybe making a special type of Queues that overcomes the limitations and can be used in higher level ISR as well would solve the problem.

richard_damon wrote on Thursday, November 07, 2013:

It sounds like this is the common design mistake of passing too high speed of data through the FreeRTOS queue. It sounds like the data for this ISR could be stored in regular circular buffers, and the task level just needs to make sure it keeps far enough ahead that it can block for the next timer tick rather than for space in the queue. It then processes until it again has enough data in the queue before blocking again. This means that the ISR doesn’t need to talk to FreeRTOS, and thus can have a higher priority. It sounds like enough needs to be done that you can’t just use a DMA channel to do the transfer.

swissembedded wrote on Thursday, November 07, 2013:

Mike, I tried your solutions

  1. changed configKERNEL_INTERRUPT_PRIORITY to 5
  2. changed line to _vPortYield: MOV #160, W0
  3. changed #if configKERNEL_INTERRUPT_PRIORITY != 5

tick timer and all isr run now at configKERNEL_INTERRUPT_PRIORITY.
The scheduler never executes the tasks. _T1Interrupt routine is never called

What am I missing?

swissembedded wrote on Thursday, November 07, 2013:

Richard, the problem is that I need to generate a local echo for the headphones in the ISR which is done sample by sample. That delay must be as low as possible as the codec already introduces some delay due to internal filters. The DSPIC has enough power to waste some cycles with frequent ISR call overhead.

The problem is that there are other DMA interrupts already in the system. If using one interrupt priority level, those will block the system for too long (heavy data transfer over interface). No way to overcome this. So the most reasonable thing is to priorize the codec routine over the other isr, running into the problem of this topic :-(.

I would not say that this is a common design mistake. One reason for me to use a RTOS is the speed up development and use a hardware that has enough power to support this luxury.

swissembedded wrote on Thursday, November 07, 2013:

Richard, taking your advice I removed the queues and added some ringbuffer for audio data and simple struct for codec control. The ISR is not completely FreeRTOS API free :frowning:

It is working as it should with configKERNEL_INTERRUPT_PRIORITY (1), but if I increase the interrupt priority level of that ISR to configKERNEL_INTERRUPT_PRIORITY+1
(IPC15bits.DCIIP = (configKERNEL_INTERRUPT_PRIORITY+1):wink:
it does NOT anymore. (looks like the isr is never called)

Again what am I missing?

swissembedded wrote on Thursday, November 07, 2013:

Ok, found it, I’m overwriting SR in the ISR, which also contains IPL, so I assume Mike his mod would work as well.

dragonflight1 wrote on Thursday, November 07, 2013:

Just to clarify -
first - the instructions for changes relate to the current port.
secondly - while I would like to take credit for a vastly improved port, all I did was reorganize the code into a single file, and tidied up (IMHO) the ifdefs removing the configKERNEL_INTERRUPT_PRIORITY restriction using CPP macros.
The only real change was to add SPLIM which was a few lines of code.