Hi, I am trying to implement a simple task switcher for SAMD21, I have Seeeduino XIAO, and my code works when i call my task switching logic from the main program but it doesn’t work when called in an interrupt - the board loses com port. I tried Keil and IAR emulators and it works fine but it doesn’t work on real hardware. I don’t have anything for hardware debugging, maybe someone could help me out and tell me what’s wrong with my code please? Thank you!
This is the Arduino IDE sketch for Seeeduino XIAO board
enum Ctx {
psr,
pc,
lr,
r12,
r3,
r2,
r1,
r0,
r7,
r6,
r5,
r4,
r11,
r10,
r9,
r8,
size
};
struct TaskInfo {
uint8_t* sp; // needs to be aligned
uint8_t stack[1024];
};
struct TaskInfo _tasks[2];
int current_task;
extern "C" {
uint8_t* switch_task(uint8_t* sp) {
_tasks[current_task].sp = sp;
current_task = (current_task + 1) % 2;
return _tasks[current_task].sp;
}
void __attribute__((naked)) PendSV_Handler() {
__asm volatile("cpsid i");
__asm volatile("push {r4-r7}");
__asm volatile("mov r4,r8");
__asm volatile("mov r5,r9");
__asm volatile("mov r6,r10");
__asm volatile("mov r7,r11");
__asm volatile("push {r4-r7}");
__asm volatile("mov r0, sp");
__asm volatile("push {lr}");
__asm volatile("bl switch_task");
__asm volatile("mov r12, r0");
__asm volatile("pop {r0}");
__asm volatile("mov lr, r0");
__asm volatile("mov sp, r12");
__asm volatile("pop {r4-r7}");
__asm volatile("mov r8,r4");
__asm volatile("mov r9,r5");
__asm volatile("mov r10,r6");
__asm volatile("mov r11,r7");
__asm volatile("pop {r4-r7}");
__asm volatile("cpsie i");
__asm volatile("bx lr");
}
int sysTickHook() {
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
return 0;
}
}
void start(TaskInfo* taskInfo) {
while (1);
}
void init_task(TaskInfo* taskInfo) {
// 8 bytes alignment per ARM Cortex+ requirement when entering interrupt
taskInfo->sp = (uint8_t*)&taskInfo->stack[1023];
taskInfo->sp -= sizeof(uint32_t);
taskInfo->sp = (uint8_t*)((uintptr_t)taskInfo->sp & ~0x7);
uint32_t* sp = ((uint32_t*)taskInfo->sp);
// clear registers
for (uint8_t i = 0; i < Ctx::size; ++i) {
*--sp = 0;
}
taskInfo->sp = (uint8_t*)sp;
// compiler/architecture specific, passing argument via registers
--sp;
sp[Ctx::size - Ctx::r0] = (uintptr_t)taskInfo;
sp[Ctx::size - Ctx::psr] = 0x01000000;
sp[Ctx::size - Ctx::pc] = (uintptr_t)start;
}
void setup() {
current_task = 0;
init_task(&_tasks[1]);
}
void loop() {
while(1);
}