What Cortex-M3 interrupts can I use for general purpose work?

I will have some code that needs to be run as a result of interrupting a specific interrupt.

I do not want to execute it in the context of the interrupt itself, but I also do not want it to be executed in thread mode.

I would like to run it with a priority that is lower than a high-level interrupt that accelerated its execution, but also a priority that exceeds the thread level (and some other interrupts).

I think I need to use one of the other interrupt handlers.

Which ones are best used and what is the best way to call them?

At the moment, I plan to use only interrupt handlers for some peripheral devices, which I do not use or call them by setting bits directly through NVIC, but I was hoping there would be a better, more official way.

Thanks,

+7
interrupt embedded cortex-m3
source share
5 answers

ARM Cortex supports a special kind of PendSV exception. It seems that you can use this exception specifically to do your job. Almost all preventative RTOS for ARM Cortex use PendSV to implement a context switch.

For it to work, you need to set PendSV low priority (write 0xFF to PRI_14 in NVIC). You should also give priority to all IRQs above PendSV (write lower numbers in the corresponding priority registers in NVIC). When you are ready to process the entire message, start PendSV from the high priority ISR:

*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV 

The ARM Cortex processor will then complete your ISR and all other ISRs that it may have unloaded, and ultimately it will be tied to the PendSV exception. This is where your code to parse the message should be.

Please note that PendSV can be uploaded by other ISRs. Everything is in order, but you need to remember that you need to protect all shared resources with the critical part of the code (briefly disabling and allowing interrupts). In ARM Cortex, you disable interrupts by running __asm ​​("cpsid i"), and you enable interruptions __asm ​​("cpsie i"). (Most C compilers provide built-in built-in functions or macros.)

+15
source share

Do you use RTOS? Typically, this type of thing will be handled by a high priority thread that receives an alarm to do some interrupt work.

If you do not use RTOS, you only have a few tasks, and the work performed by the interrupt is not too resource intensive, it can be easier if your high-priority work is performed in the context of an interrupt handler. If these conditions are not met, then the implementation of what you are talking about will be the beginning of the basic multi-tasking OS. It may be an interesting project in its own right, but if you just want to get the job done, you may need a simple RTOS.

Since you mentioned some of the features of the work you do, here is an overview of how I dealt with a similar problem in the past:

To process the received data via UART, one method that I used when working with a simpler system that does not have full support for the task (i.e. tasks are round, I na simple while loop) should have a common queue for data received from UART . When a UART interrupt occurs, data is read from the UDR RDR (Receive Data Register) and queued. The trick to dealing with this so that the queue pointers are not corrupted is to carefully make the queue pointers unstable and make sure that only the interrupt handler changes the pointer to the tail and that only the “foreground” task that reads the data in Queue has changed the pointer to the head. High Level Review:

  • manufacturer (UART interrupt handler):

    • read queue.head and queue.tail in locals;
    • The increment of the local tail pointer (and not the actual queue.tail pointer). Wrap it before the start of the queue buffer if you increment it to the end of the queue buffer.
    • compare local.tail and local.head - if they are equal, the queue is full, and you will need to do everything possible to handle the errors.
    • otherwise you can write new data to where local.tail indicates
    • only now can you set queue.tail == local.tail
    • return from the interrupt (or handle other UART-related tasks, if necessary, for example, reading from the transfer queue)
  • consumer (foreground task)

    • read queue.head and queue.tail in locals;
    • if local.head == local.tail queue is empty; come back so that the next task does some work.
    • read the byte pointed to by local.head
    • increment local.head and wrap it if necessary;
    • set queue.head = local.head
    • go to step 1

Make sure that queue.head and queue.tail are volatile (or write these bits to the assembly) to make sure there are no problems with sequencing.

Now just make sure that your data queue received by UART is large enough to keep all the bytes that could be received before the foreground task gets a chance to run. The foreground task should print the data from the queue to its own buffers in order to create messages for the task "message processor".

+3
source share

A more official way, or rather a regular method, is to use the priority multi-task scheduler with priority and the template “delayed interrupt handler”.

+1
source share

What you're asking for is pretty simple on the Cortex-M3. You need to enable the STIR register so that you can run the low priority ISR with the software. When a high-priority ISR runs with critical material, it simply triggers a low-priority interrupt and terminates. Then NVIC will be bound to a low-level handler if there is nothing more important.

+1
source share

Check your processor documentation. Some processors will interrupt if you write a bit, which you usually should clear inside the interrupt. I am currently using SiLabs c8051F344 and in specification section 9.3.1:

"The software can simulate an interrupt by setting any interrupt flag to logic 1. If interrupts are enabled for the flag, an interrupt request will be generated and the CPU will be bound to the ISR address associated with the interrupt flag."

0
source share

All Articles