altos/stm: Use basepri instead of primask for controlling interrupts
authorKeith Packard <keithp@keithp.com>
Sun, 20 Nov 2016 10:59:40 +0000 (02:59 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 21 Nov 2016 04:48:40 +0000 (20:48 -0800)
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 <keithp@keithp.com>
src/drivers/ao_vga.c
src/stm/ao_arch.h
src/stm/ao_arch_funcs.h

index eecf58f0ed5014daf4cd72639c0de414eadcf448..0e9c6706996244d8d248360580b4aa003f17bbc4 100644 (file)
@@ -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);
        }
 }
index 0cc29376aaf271c7002f9bef72fa7e3fb1b7307c..1527014ab46e22999a486caab25f299a4f1ce57b 100644 (file)
@@ -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
index 18ca20dab69b2b2dec06a643a01372a92a141215..0872fc9c5e03089c05cb0d36ecef376b7f9a6bb2 100644 (file)
@@ -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();    \