In an embedded ARM project using a STM32f1 controller, I started to use a coroutine framework (https://github.com/xhawk18/s_task). It works well and simplifies my application.
However, each coroutine has its own stack, and I need to size the stack so that it can accommodate potentially nested interrupt calls.
One of the interrupt routines handles USB communication and the USB stack is a bit of a stack hog. Alone this is not an issue, but it seems to be quite a RAM waste to size many coroutine stacks for the worst case. I therefore thought I would give this ISR a separate stack.
The solution I came up with is this:
#define stringify(s) xstringify(s)
#define xstringify(s) #s
extern "C" {
void USB_LP_CAN1_RX0_IRQHandler_impl(void);
#define USB_STACK_SIZE 128
void* _usb_old_sp;
void* _usb_stack[USB_STACK_SIZE];
__attribute__((naked)) void USB_LP_CAN1_RX0_IRQHandler(void) {
__asm__ volatile(" push {r0, lr} ");
__asm__ volatile(" ldr r0, =_usb_old_sp ");
__asm__ volatile(" str sp, [r0]");
__asm__ volatile(" ldr sp, =_usb_stack+" stringify(USB_STACK_SIZE) "*4 ");
USB_LP_CAN1_RX0_IRQHandler_impl();
__asm__ volatile(" ldr r0, =_usb_old_sp ");
__asm__ volatile(" ldr sp, [r0]");
__asm__ volatile(" pop {r0, pc} ");
}
void USB_LP_CAN1_RX0_IRQHandler_impl(void) {
// ...code here...
}
}
It seems to work.
However, I wonder whether there could be simpler solutions. In particular, I am interested whether I could avoid the extra nested function call. I have it there because in the C routine the code to save the necessary registers will automatically be generated by the compiler. I therefore cannot declare the actual C code in the ISR naked, which I need to switch stack.
The other thing is that I will have to do this for every ISRs separately, at least for the ones that are stack-hungry. In an ideal world, all ISRs would share a single stack that is separate from the one of the coroutines.
I know there is a Main and a Process Stack Pointer, and these maybe could be used for such a switch? On the other hand, I do shy away from re-writing/changing the coroutine framework I now use. But maybe there is a simple solution to this?
Any ideas and hints are appreciated!