From: Keith Packard Date: Sun, 20 Nov 2016 10:59:40 +0000 (-0800) Subject: altos/stm: Use basepri instead of primask for controlling interrupts X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=552ea09fe7f9ce6c6b5f412cb2fcf603be2836c3 altos/stm: Use basepri instead of primask for controlling interrupts This allows for high priority interrupts (priority 0) to run, even when other interrupts are blocked. Code executing in such interrupt handlers must not attempt to control task execution as that will race with the scheduler. Signed-off-by: Keith Packard --- diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c index eecf58f0..0e9c6706 100644 --- a/src/drivers/ao_vga.c +++ b/src/drivers/ao_vga.c @@ -89,7 +89,6 @@ int vblank_off = 25; void stm_tim2_isr(void) { - ao_arch_block_interrupts(); if (!vblank) { /* Disable */ stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0); @@ -101,18 +100,17 @@ void stm_tim2_isr(void) } stm_tim2.sr = ~(1 << STM_TIM234_SR_CC2IF); line = stm_tim3.cnt; - if (vblank_off <= line && line < (AO_VGA_HEIGHT << 1) + vblank_off) { + if (vblank_off <= line && line < ((AO_VGA_HEIGHT-1) << 1) + vblank_off) { vblank = 0; if (((line - vblank_off) & 1) == 0) scanline += AO_VGA_STRIDE; } else { if (!vblank) { - stm_systick_isr(); +// stm_systick_isr(); scanline = ao_vga_fb; vblank = 1; } } - ao_arch_release_interrupts(); } static void @@ -359,9 +357,9 @@ ao_vga_enable(int enable) vblank_off = enable; ao_vga_fb_init(); stm_tim2.cr1 |= (1 << STM_TIM234_CR1_CEN); - stm_systick.csr &= ~(1 << STM_SYSTICK_CSR_ENABLE); +// stm_systick.csr &= ~(1 << STM_SYSTICK_CSR_ENABLE); } else { stm_tim2.cr1 &= ~(1 << STM_TIM234_CR1_CEN); - stm_systick.csr |= (1 << STM_SYSTICK_CSR_ENABLE); +// stm_systick.csr |= (1 << STM_SYSTICK_CSR_ENABLE); } } diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 0cc29376..1527014a 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -85,9 +85,6 @@ extern const uint32_t ao_radio_cal; #define ao_arch_task_members\ uint32_t *sp; /* saved stack pointer */ -#define ao_arch_block_interrupts() asm("cpsid i") -#define ao_arch_release_interrupts() asm("cpsie i") - /* * For now, we're running at a weird frequency diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 18ca20da..0872fc9c 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -345,17 +345,29 @@ extern struct ao_stm_usart ao_stm_usart3; typedef uint32_t ao_arch_irq_t; +static inline void +ao_arch_block_interrupts(void) { + uint32_t basepri = AO_STM_NVIC_BASEPRI_MASK; + asm("msr basepri,%0" : : "r" (basepri)); +} + +static inline void +ao_arch_release_interrupts(void) { + uint32_t basepri = 0x00; + asm("msr basepri,%0" : : "r" (basepri)); +} + static inline uint32_t ao_arch_irqsave(void) { - uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); + uint32_t basepri; + asm("mrs %0,basepri" : "=r" (basepri)); ao_arch_block_interrupts(); - return primask; + return basepri; } static inline void -ao_arch_irqrestore(uint32_t primask) { - asm("msr primask,%0" : : "r" (primask)); +ao_arch_irqrestore(uint32_t basepri) { + asm("msr basepri,%0" : : "r" (basepri)); } static inline void @@ -365,9 +377,9 @@ ao_arch_memory_barrier() { static inline void ao_arch_irq_check(void) { - uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); - if ((primask & 1) == 0) + uint32_t basepri; + asm("mrs %0,basepri" : "=r" (basepri)); + if (basepri == 0) ao_panic(AO_PANIC_IRQ); } @@ -390,7 +402,7 @@ ao_arch_init_stack(struct ao_task *task, void *start) /* APSR */ ARM_PUSH32(sp, 0); - /* PRIMASK with interrupts enabled */ + /* BASEPRI with interrupts enabled */ ARM_PUSH32(sp, 0); task->sp = sp; @@ -404,8 +416,8 @@ static inline void ao_arch_save_regs(void) { asm("mrs r0,apsr"); asm("push {r0}"); - /* Save PRIMASK */ - asm("mrs r0,primask"); + /* Save BASEPRI */ + asm("mrs r0,basepri"); asm("push {r0}"); } @@ -424,9 +436,9 @@ static inline void ao_arch_restore_stack(void) { /* Switch stacks */ asm("mov sp, %0" : : "r" (sp) ); - /* Restore PRIMASK */ + /* Restore BASEPRI */ asm("pop {r0}"); - asm("msr primask,r0"); + asm("msr basepri,r0"); /* Restore APSR */ asm("pop {r0}"); @@ -468,7 +480,7 @@ static inline void ao_arch_start_scheduler(void) { asm("mrs %0,msp" : "=&r" (sp)); asm("msr psp,%0" : : "r" (sp)); - asm("mrs %0,control" : "=&r" (control)); + asm("mrs %0,control" : "=r" (control)); control |= (1 << 1); asm("msr control,%0" : : "r" (control)); asm("isb"); @@ -479,12 +491,21 @@ static inline void ao_arch_start_scheduler(void) { #endif -#define ao_arch_wait_interrupt() do { \ - asm("\twfi\n"); \ - ao_arch_release_interrupts(); \ - asm(".global ao_idle_loc\nao_idle_loc:"); \ - ao_arch_block_interrupts(); \ - } while (0) +static inline void +ao_arch_wait_interrupt(void) { + uint32_t enable_int = 0x00; + uint32_t disable_int = AO_STM_NVIC_BASEPRI_MASK; + + asm( + "dsb\n" /* Serialize data */ + "isb\n" /* Serialize instructions */ + "cpsid i\n" /* Block all interrupts */ + "msr basepri,%0\n" /* Allow all interrupts through basepri */ + "wfi\n" /* Wait for an interrupt */ + "cpsie i\n" /* Allow all interrupts */ + "msr basepri,%1\n" /* Block interrupts through basepri */ + : : "r" (enable_int), "r" (disable_int)); +} #define ao_arch_critical(b) do { \ uint32_t __mask = ao_arch_irqsave(); \