altos/stm: Allow use basepri instead of primask for masking interrupts
authorKeith Packard <keithp@keithp.com>
Sun, 20 Nov 2016 10:59:40 +0000 (02:59 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 20 Feb 2017 20:32:50 +0000 (12:32 -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.

Select this by defining AO_NONMASK_INTERRUPT in ao_pins.h.
non-maskable interrupt priority is AO_STM_NVIC_NONMASK_PRIORITY

Signed-off-by: Keith Packard <keithp@keithp.com>
src/stm/ao_arch.h
src/stm/ao_arch_funcs.h
src/stm/ao_usb_stm.c

index 3d09af3c8e27de12f9fa24ce3486c18d920a4dd6..5f033b66219e36719164e7864b8e4121977b8934 100644 (file)
@@ -85,10 +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
  */
@@ -124,6 +120,15 @@ extern const uint32_t ao_radio_cal;
 
 /* The stm32l implements only 4 bits of the priority fields */
 
+#if AO_NONMASK_INTERRUPT
+#define AO_STM_NVIC_NONMASK_PRIORITY   0x00
+
+/* Set the basepri register to this value to mask all
+ * non-maskable priorities
+ */
+#define AO_STM_NVIC_BASEPRI_MASK       0x10
+#endif
+
 #define AO_STM_NVIC_HIGH_PRIORITY      0x40
 #define AO_STM_NVIC_MED_PRIORITY       0x80
 #define AO_STM_NVIC_LOW_PRIORITY       0xC0
index a9d0fa34f02fed0ab58159eb6f7293f059a00a16..88097406a3e104d835719dda073923299eb3e25b 100644 (file)
@@ -345,17 +345,43 @@ extern struct ao_stm_usart        ao_stm_usart3;
 
 typedef uint32_t       ao_arch_irq_t;
 
+static inline void
+ao_arch_block_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+       asm("cpsid i");
+#endif
+}
+
+static inline void
+ao_arch_release_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (0x0));
+#else
+       asm("cpsie i");
+#endif
+}
+
 static inline uint32_t
 ao_arch_irqsave(void) {
-       uint32_t        primask;
-       asm("mrs %0,primask" : "=&r" (primask));
+       uint32_t        val;
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("mrs %0,basepri" : "=r" (val));
+#else
+       asm("mrs %0,primask" : "=r" (val));
+#endif
        ao_arch_block_interrupts();
-       return primask;
+       return val;
 }
 
 static inline void
-ao_arch_irqrestore(uint32_t primask) {
-       asm("msr primask,%0" : : "r" (primask));
+ao_arch_irqrestore(uint32_t basepri) {
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("msr basepri,%0" : : "r" (basepri));
+#else
+       asm("msr primask,%0" : : "r" (basepri));
+#endif
 }
 
 static inline void
@@ -365,10 +391,17 @@ ao_arch_memory_barrier() {
 
 static inline void
 ao_arch_irq_check(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+       uint32_t        basepri;
+       asm("mrs %0,basepri" : "=r" (basepri));
+       if (basepri == 0)
+               ao_panic(AO_PANIC_IRQ);
+#else
        uint32_t        primask;
-       asm("mrs %0,primask" : "=&r" (primask));
+       asm("mrs %0,primask" : "=r" (primask));
        if ((primask & 1) == 0)
                ao_panic(AO_PANIC_IRQ);
+#endif
 }
 
 #if HAS_TASK
@@ -390,7 +423,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 +437,13 @@ static inline void ao_arch_save_regs(void) {
        asm("mrs r0,apsr");
        asm("push {r0}");
 
+#ifdef AO_NONMASK_INTERRUPTS
+       /* Save BASEPRI */
+       asm("mrs r0,basepri");
+#else
        /* Save PRIMASK */
        asm("mrs r0,primask");
+#endif
        asm("push {r0}");
 }
 
@@ -419,9 +457,15 @@ static inline void ao_arch_restore_stack(void) {
        /* Switch stacks */
        asm("mov sp, %0" : : "r" (ao_cur_task->sp) );
 
+#ifdef AO_NONMASK_INTERRUPTS
+       /* Restore BASEPRI */
+       asm("pop {r0}");
+       asm("msr basepri,r0");
+#else
        /* Restore PRIMASK */
        asm("pop {r0}");
        asm("msr primask,r0");
+#endif
 
        /* Restore APSR */
        asm("pop {r0}");
@@ -463,7 +507,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");
@@ -474,12 +518,24 @@ 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) {
+#ifdef AO_NONMASK_INTERRUPTS
+       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" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+       asm("\twfi\n");
+       ao_arch_release_interrupts();
+       ao_arch_block_interrupts();
+#endif
+}
 
 #define ao_arch_critical(b) do {                       \
                uint32_t __mask = ao_arch_irqsave();    \
index 2abaf10fddefe415a2c4d5d25eeda6606facb2a4..33e0617c8c4faa44cda6f73387b46aabe773546e 100644 (file)
@@ -1109,7 +1109,7 @@ struct ao_usb_dbg {
        int             line;
        char            *msg;
        uint32_t        value;
-       uint32_t        primask;
+       uint32_t        prival;
 #if TX_DBG
        uint16_t        in_count;
        uint32_t        in_epr;
@@ -1125,19 +1125,23 @@ struct ao_usb_dbg {
 #endif
 };
 
-#define NUM_USB_DBG    128
+#define NUM_USB_DBG    16
 
-static struct ao_usb_dbg dbg[128];
+static struct ao_usb_dbg dbg[NUM_USB_DBG];
 static int dbg_i;
 
 static void _dbg(int line, char *msg, uint32_t value)
 {
-       uint32_t        primask;
+       uint32_t        prival;
        dbg[dbg_i].line = line;
        dbg[dbg_i].msg = msg;
        dbg[dbg_i].value = value;
-       asm("mrs %0,primask" : "=&r" (primask));
-       dbg[dbg_i].primask = primask;
+#if AO_NONMASK_INTERRUPT
+       asm("mrs %0,basepri" : "=&r" (prival));
+#else
+       asm("mrs %0,primask" : "=&r" (prival));
+#endif
+       dbg[dbg_i].prival = prival;
 #if TX_DBG
        dbg[dbg_i].in_count = in_count;
        dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR];