altos/stm32f4: Need to read-back register after clock enable
[fw/altos] / src / stm32f4 / ao_arch_funcs.h
index 252fe77a5330eaa81b7783cd9bda4188f44a125f..6fa654973842877a59325e94cd3a991e6d1750d0 100644 (file)
 #ifndef _AO_ARCH_FUNCS_H_
 #define _AO_ARCH_FUNCS_H_
 
+/* task functions */
+
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+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        val;
+#ifdef AO_NONMASK_INTERRUPTS
+       asm("mrs %0,basepri" : "=r" (val));
+#else
+       asm("mrs %0,primask" : "=r" (val));
+#endif
+       ao_arch_block_interrupts();
+       return val;
+}
+
+static inline void
+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
+ao_arch_memory_barrier(void) {
+       asm volatile("" ::: "memory");
+}
+
+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));
+       if ((primask & 1) == 0)
+               ao_panic(AO_PANIC_IRQ);
+#endif
+}
+
+#if HAS_TASK
+static inline void
+ao_arch_init_stack(struct ao_task *task, void *start)
+{
+       uint32_t        *sp = &task->stack32[AO_STACK_SIZE>>2];
+       uint32_t        a = (uint32_t) start;
+       int             i;
+
+       /* Return address (goes into LR) */
+       ARM_PUSH32(sp, a);
+
+       /* Clear register values r0-r12 */
+       i = 13;
+       while (i--)
+               ARM_PUSH32(sp, 0);
+
+       /* APSR */
+       ARM_PUSH32(sp, 0);
+
+       /* Clear register values s0-s31 */
+       i = 32;
+       while (i--)
+               ARM_PUSH32(sp, 0);
+
+       /* FPSCR */
+       ARM_PUSH32(sp, 0);
+
+       /* BASEPRI with interrupts enabled */
+       ARM_PUSH32(sp, 0);
+
+       task->sp32 = sp;
+}
+
+static inline void ao_arch_save_regs(void) {
+       /* Save general registers */
+       asm("push {r0-r12,lr}");
+
+       /* Save APSR */
+       asm("mrs r0,apsr");
+       asm("push {r0}");
+
+       /* Save FPU registers */
+       asm("vpush {s0-s15}");
+       asm("vpush {s16-s31}");
+
+       /* Save FPSCR */
+       asm("vmrs r0,fpscr");
+       asm("push {r0}");
+
+#ifdef AO_NONMASK_INTERRUPTS
+       /* Save BASEPRI */
+       asm("mrs r0,basepri");
+#else
+       /* Save PRIMASK */
+       asm("mrs r0,primask");
+#endif
+       asm("push {r0}");
+}
+
+static inline void ao_arch_save_stack(void) {
+       uint32_t        *sp;
+       asm("mov %0,sp" : "=&r" (sp) );
+       ao_cur_task->sp32 = (sp);
+}
+
+static inline void ao_arch_restore_stack(void) {
+       /* Switch stacks */
+       asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
+
+#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 FPSCR */
+       asm("pop {r0}");
+       asm("vmsr fpscr,r0");
+
+       /* Restore FPU registers */
+       asm("vpop {s16-s31}");
+       asm("vpop {s0-s15}");
+
+       /* Restore APSR */
+       asm("pop {r0}");
+       asm("msr apsr_nczvq,r0");
+
+       /* Restore general registers */
+       asm("pop {r0-r12,lr}\n");
+
+       /* Return to calling function */
+       asm("bx lr");
+}
+
+#ifndef HAS_SAMPLE_PROFILE
+#define HAS_SAMPLE_PROFILE 0
+#endif
+
+#if DEBUG
+#define HAS_ARCH_VALIDATE_CUR_STACK    1
+
+static inline void
+ao_validate_cur_stack(void)
+{
+       uint8_t         *psp;
+
+       asm("mrs %0,psp" : "=&r" (psp));
+       if (ao_cur_task &&
+           psp <= ao_cur_task->stack &&
+           psp >= ao_cur_task->stack - 256)
+               ao_panic(AO_PANIC_STACK);
+}
+#endif
+
+#if !HAS_SAMPLE_PROFILE
+#define HAS_ARCH_START_SCHEDULER       1
+
+static inline void ao_arch_start_scheduler(void) {
+       uint32_t        sp;
+       uint32_t        control;
+
+       asm("mrs %0,msp" : "=&r" (sp));
+       asm("msr psp,%0" : : "r" (sp));
+       asm("mrs %0,control" : "=r" (control));
+       control |= (1 << 1);
+       asm("msr control,%0" : : "r" (control));
+       asm("isb");
+}
+#endif
+
+#define ao_arch_isr_stack()
+
+#endif
+
+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();    \
+               do { b } while (0);                     \
+               ao_arch_irqrestore(__mask);             \
+       } while (0)
+
 /* GPIO functions */
 
 #define ao_power_register(gpio)
 static inline void ao_enable_port(struct stm_gpio *port)
 {
        if ((port) == &stm_gpioa) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPAEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPAEN);
                ao_power_register(&ao_power_gpioa);
        } else if ((port) == &stm_gpiob) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPBEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPBEN);
                ao_power_register(&ao_power_gpiob);
        } else if ((port) == &stm_gpioc) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPCEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPCEN);
                ao_power_register(&ao_power_gpioc);
        } else if ((port) == &stm_gpiod) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPDEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPDEN);
                ao_power_register(&ao_power_gpiod);
        } else if ((port) == &stm_gpioe) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPEEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPEEN);
                ao_power_register(&ao_power_gpioe);
        } else if ((port) == &stm_gpiof) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPFEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPFEN);
                ao_power_register(&ao_power_gpiof);
        } else if ((port) == &stm_gpiog) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPGEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPGEN);
                ao_power_register(&ao_power_gpiog);
        } else if ((port) == &stm_gpioh) {
-               stm_rcc.ahb1enr |= (1 << STM_RCC_AHB1ENR_IOPHEN);
+               stm_rcc_ahb1_clk_enable(1 << STM_RCC_AHB1ENR_IOPHEN);
                ao_power_register(&ao_power_gpioh);
        }
 }
@@ -52,28 +280,28 @@ static inline void ao_enable_port(struct stm_gpio *port)
 static inline void ao_disable_port(struct stm_gpio *port)
 {
        if ((port) == &stm_gpioa) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPAEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPAEN);
                ao_power_unregister(&ao_power_gpioa);
        } else if ((port) == &stm_gpiob) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPBEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPBEN);
                ao_power_unregister(&ao_power_gpiob);
        } else if ((port) == &stm_gpioc) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPCEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPCEN);
                ao_power_unregister(&ao_power_gpioc);
        } else if ((port) == &stm_gpiod) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPDEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPDEN);
                ao_power_unregister(&ao_power_gpiod);
        } else if ((port) == &stm_gpioe) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPEEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPEEN);
                ao_power_unregister(&ao_power_gpioe);
        } else if ((port) == &stm_gpiof) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPFEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPFEN);
                ao_power_unregister(&ao_power_gpiof);
        } else if ((port) == &stm_gpiog) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPGEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPGEN);
                ao_power_unregister(&ao_power_gpiog);
        } else if ((port) == &stm_gpioh) {
-               stm_rcc.ahb1enr &= ~(1 << STM_RCC_AHB1ENR_IOPHEN);
+               stm_rcc_ahb1_clk_disable(1 << STM_RCC_AHB1ENR_IOPHEN);
                ao_power_unregister(&ao_power_gpioh);
        }
 }
@@ -103,4 +331,30 @@ static inline void ao_disable_port(struct stm_gpio *port)
                ao_gpio_set_mode(port, bit, mode);                      \
        } while (0)
 
+/* usart */
+
+void
+ao_usart_init(void);
+
+void
+start(void);
+
+char
+ao_serial6_getchar(void);
+
+void
+ao_serial6_putchar(char c);
+
+int
+_ao_serial6_pollchar(void);
+
+uint8_t
+_ao_serial6_sleep_for(uint16_t timeout);
+
+void
+ao_serial6_set_speed(uint32_t speed);
+
+void
+ao_serial6_drain(void);
+
 #endif /* _AO_ARCH_FUNCS_H_ */