Interrupt priority/premption.

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Interrupt priority/premption.

Post by rew »

Hi,

I have an SPI master-slave system with the slave being an STM32 running chibios.

Chibios doesn't support SPI slave mode, so I'm handling the hardware myself. No problem. :-)

I have to implement the SPI protocol which is not ideal: after the master sends a byte the slave has to figure out what to send back during the following byte (frame). This cannot be done in advance, as the data depends on what the master sends.

So... all is fine and dandy, except that I also have an ADC running. The DMA complete interrupts from those cause enough delay to mess up the SPI protocol. I have already moved the processing of the ADC data to a thread and just wake up the thread instead of processing it in the callback. But still the interrupt overhead is too much. (My ADC callback is now taking 4 microseconds, in my current trace 8 microseconds are available, so the "tail" of the adc interrupt seems to be taking at least 4 microseconds too. )

Anyway... I want the SPI interrupts to have a higher priority than the ADC interrupts, so that the ADC interrupt is .... well... interrupted by the higher priority interrupt.

How can I achieve this? I have tried:

Code: Select all

#define STM32_ADC_ADC1_DMA_PRIORITY         1
#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY     1
#define STM32_SPI_SPI1_IRQ_PRIORITY         2
#define STM32_SPI_SPI2_IRQ_PRIORITY         2
but still the SPI interrupt is postponed until it is too late....

Image
larger version: http://prive.bitwizard.nl/spi_vs_adc.png
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Interrupt priority/premption.

Post by Giovanni »

Hi,

Are you using an M0? if not, the following apply.

You should not use priorities 0 and 1, those can preempt the kernel and require special care, also the ISR declaration is different.

If you use priority 0 or 1 you have the advantage that the ISR has no critical zones and is served immediately (no IRQ-related jitter), however the code cannot call RTOS functions directly from fast ISRs. What you can do is to "delegate" the calls to a lower priority ISR by triggering a SW interrupt.

Giovanni
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Interrupt priority/premption.

Post by Giovanni »

If you are using an M0 then you should know that the ISR epilogue code leaves the ISR, performs the context switch then another exception is called after the switch, this happens in a critical zone and could be the delay you are seeing.

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Interrupt priority/premption.

Post by rew »

Yes, I'm using an M0. STM32F072RB at the moment, possibly this will be ported to an STM32F030F when it's done.

Yes, I've found that the epilog is quite "big" and might preform a context switch. But even then... the ADC interrupt takes about 4 microseconds (in my code), which is too long: On AVR there needs to be a delay between the bytes of about 10 microseconds. And on STM I was hoping to be a lot quicker. But with the ADC interrupt there, I have to be even slower than the AVR.

So.. reading: http://chibios.sourceforge.net/html/concepts.html, I think I would like the SPI interrupt to be a "fast interrupt": no chibios calls just internal processing. So http://www.chibios.org/dokuwiki/doku.ph ... interrupts tells me "some architectures". Where can I find which architectures that is referring to?
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Interrupt priority/premption.

Post by Giovanni »

Hi,

Fast interrupts are available on ARM classic and on M3, M4 and M7 using the BASEPRI register.

M0 and M0+ lack the BASEPRI register (huge mistake to remove that IMHO) so it is not possible to only mask some priority levels. You may consider one for the lower F3 devices, they have also a much better ADC. Are those out of your target price?

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Interrupt priority/premption.

Post by rew »

So... let me get this clear.

To protect the (OS) code in the interrupt you "disable interrupts".

On M3 and higher, you "disable interrupts" by putting a "block all interrupts except the /fast/ ones" value in the BASEPRI register.

On M0 you "disable interrupts" by ... disabling interrupts altogether.

Correct?
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Interrupt priority/premption.

Post by Giovanni »

Correct, On M3 and higher the priority masked are 2...15, 0 and 1 are never masked and have the minimum jitter.

M0 does not allow this.

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Interrupt priority/premption.

Post by rew »

ok.... I've decided I'm going to disable ADC interrupts during the SPI transaction. I'm now doing:

Code: Select all

 NVIC_DisableIRQ(DMA1_Channel1_IRQn);
but that doesn't seem to do anything.

The ADC interrupts stop happening if I do that by "hand" from the debugger, but they remain active, and the register doesn't seem to change when I do it in the "SPI CS Has become active". Even when I do *(int *)0xE000E180 = 0x200; (no defines that could be interfering, exactly the same as what I do from the debugger to kill those interrupts..... )

Any ideas?
User avatar
Giovanni
Site Admin
Posts: 14893
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 997 times

Re: Interrupt priority/premption.

Post by Giovanni »

Are you disabling the right interrupt?

You could just stop the ADC conversion and resume it. You could also "interleave" SPI and ADC.

Start ADC, from the ADC callback start SPI, while the ADC is converting the SPI transmits.

With timings well calculated the interrupts will never overlap because ADC and SPI start at the same time.

Giovanni
rew
Posts: 383
Joined: Sat Jul 19, 2014 12:59 pm
Has thanked: 2 times
Been thanked: 14 times

Re: Interrupt priority/premption.

Post by rew »

You might not remember that I'm implmenting an SPI slave. So I cannot force the master to contact my STM32 at the moments that are convenient.....

I spent some time figuring out what interrupt triggers the ADC callback. Stopping the CPU in the ADC callback shows a call stack that starts with "Vector64" Divide by 4, subtract the 0x10 reset, NMI and other system vectors, I think that this is IRQ9. (The math checks out for my SPI2 IRQ, where VectorA8 divide by 4, subtract 0x10, ends up at 0x1A or 26, the correct number for SPI2.).

And clearing bit 9 by hand from the debugger will quiet down the ADC callbacks for 100%....

Is there a bit in the ADC that would cause it to suspend operations (during the SPI transfer)? ADEN? Would it resume where it left off if that's the only thing I touch? This is a much worse workaround than just disabling the ADC interrupts for the time of the SPI transaction. The ADC interrupt can easily be served after the SPI transaction. The service time is just around 8 microseconds (including the context switch), and it needs to happen about once every 1.4 ms. A long-ish SPI transaction takes around 0.4 miliseconds (*). So postponing the ADC interrupt for 0.4 ms is completely possible. Stopping the ADC altogether means I'm... ehh.. stopping the ADC.


(*) This is slow enough for an 8 MHz AVR to be able to keep up. So I am still hoping that this implementation on STM32 would allow it to be faster.... But at the moment the master is still at AVR speeds....
Post Reply