From 44054415c82efa6bf8a8d4ce83a42eb94e51b0c2 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 17 Nov 2017 11:43:05 +0900 Subject: [PATCH] MCU specific sleep feature is now defined in MCU specific file. --- ChangeLog | 10 ++++ chopstx-cortex-m.c | 116 +------------------------------------------- chopstx-gnu-linux.c | 6 --- mcu/chx-gnu-linux.c | 5 ++ mcu/chx-mkl27z.c | 23 +++++++++ mcu/chx-stm32f0.c | 41 ++++++++++++++++ mcu/chx-stm32f103.c | 60 +++++++++++++++++++++++ mcu/stm32.h | 9 ++++ rules.mk | 6 +++ 9 files changed, 156 insertions(+), 120 deletions(-) create mode 100644 mcu/chx-gnu-linux.c create mode 100644 mcu/chx-mkl27z.c create mode 100644 mcu/chx-stm32f0.c create mode 100644 mcu/chx-stm32f103.c create mode 100644 mcu/stm32.h diff --git a/ChangeLog b/ChangeLog index 6cc92c0..cdac545 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2017-11-17 NIIBE Yutaka + * rules.mk (CSRC): Add mcu/chx-$(CHIP).c. + + * chopstx-cortex-m.c (idle, chx_sleep_mode): Remove. + (chx_sched, preempt): Call chx_idle. + * mcu/chx-mkl27z.c, mcu/chx-stm32f0.c, mcu/chx-stm32f103.c: New. + * mcu/stm32.h: New. + + * chopstx-gnu-linux.c (chx_sleep_mode): Move to... + * mcu/chx-gnu-linux.c: Here. + * mcu/stm32f103.h (DBGMCU): New. * mcu/cortex-m.h: New. diff --git a/chopstx-cortex-m.c b/chopstx-cortex-m.c index accd7f6..c6c23a1 100644 --- a/chopstx-cortex-m.c +++ b/chopstx-cortex-m.c @@ -229,24 +229,6 @@ chx_cpu_sched_unlock (void) } -static void __attribute__((naked, used)) -idle (void) -{ - int sleep_enabled; - - for (;;) - { - asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep)); - if (!sleep_enabled) - continue; - if ((sleep_enabled & 0x80)) - asm volatile ("wfe" : : : "memory"); - else - asm volatile ("wfi" : : : "memory"); - } -} - - void chx_handle_intr (void) { @@ -388,7 +370,7 @@ chx_sched (uint32_t yield) /* Spawn an IDLE thread. */ "ldr r1, =__main_stack_end__\n\t" "mov sp, r1\n\t" - "ldr r0, =idle\n\t" /* PC = idle */ + "ldr r0, =chx_idle\n\t" /* PC = idle */ /**/ /* Unmask interrupts. */ "cpsie i\n\t" @@ -637,7 +619,7 @@ preempt (void) "mov r3, #0\n\t" "stm r0!, {r1, r2, r3}\n\t" "stm r0!, {r1, r2, r3}\n\t" - "ldr r1, =idle\n\t" /* PC = idle */ + "ldr r1, =chx_idle\n\t" /* PC = idle */ "mov r2, #0x010\n\t" "lsl r2, r2, #20\n\t" /* xPSR = T-flag set (Thumb) */ "stm r0!, {r1, r2}\n\t" @@ -708,97 +690,3 @@ svc (void) : /* no output */ : "r" (tp) : "memory"); } #endif - -#ifdef MCU_STM32F0 -struct SCB -{ - volatile uint32_t CPUID; - volatile uint32_t ICSR; - volatile uint32_t VTOR; - volatile uint32_t AIRCR; - volatile uint32_t SCR; - volatile uint32_t CCR; - volatile uint8_t SHP[12]; - volatile uint32_t SHCSR; - volatile uint32_t CFSR; - volatile uint32_t HFSR; - volatile uint32_t DFSR; - volatile uint32_t MMFAR; - volatile uint32_t BFAR; - volatile uint32_t AFSR; - volatile uint32_t PFR[2]; - volatile uint32_t DFR; - volatile uint32_t ADR; - volatile uint32_t MMFR[4]; - volatile uint32_t ISAR[5]; - /* Cortex-M3 has more... */ -}; -static struct SCB *const SCB = ((struct SCB *)0xE000ED00); -#define SCB_SCR_SLEEPDEEP (1 << 2) - -struct PWR -{ - volatile uint32_t CR; - volatile uint32_t CSR; -}; -static struct PWR *const PWR = ((struct PWR *)0x40007000); -#define PWR_CR_LPDS 0x0001 /* Low-power deepsleep */ -#define PWR_CR_PDDS 0x0002 /* Power down deepsleep */ -#define PWR_CR_CWUF 0x0004 /* Clear wakeup flag */ - -void -chx_sleep_mode (int how) -{ - PWR->CR |= PWR_CR_CWUF; - PWR->CR &= ~(PWR_CR_PDDS|PWR_CR_LPDS); - - if (how == 0 || how == 1 /* Sleep only (not deepsleep) */) - SCB->SCR &= ~SCB_SCR_SLEEPDEEP; - else - { /* Deepsleep */ - /* how == 2: deepsleep but regulator ON */ - if (how == 3) - PWR->CR |= PWR_CR_LPDS; /* regulator low-power mode */ - else if (how == 4) - PWR->CR |= PWR_CR_PDDS; /* Power down: All OFF */ - - SCB->SCR |= SCB_SCR_SLEEPDEEP; - } -} -#else -struct RCC { - volatile uint32_t CR; - volatile uint32_t CFGR; - /* And more... */ -}; -static struct RCC *const RCC = (struct RCC *)0x40021000; -#define STM32_SW_PLL (2 << 0) -#define RCC_CFGR_SWS 0x0000000C - -/* - * Deepsleep is only useful with RTC, Watch Dog, or WKUP pin. - * So, we can't use deepsleep. - * - * On sleep mode, clock is HSI, while it's PLL when running. - * This can achieve lower power consumption on sleep. - */ -void -chx_sleep_mode (int how) -{ - uint32_t cfg_sw; - - if (how == 0) - { - RCC->CFGR |= STM32_SW_PLL; - cfg_sw = STM32_SW_PLL; - } - else - { - RCC->CFGR &= ~3; - cfg_sw = 0; - } - - while ((RCC->CFGR & RCC_CFGR_SWS) != (cfg_sw << 2)) - ; -} -#endif diff --git a/chopstx-gnu-linux.c b/chopstx-gnu-linux.c index 9392292..078f0db 100644 --- a/chopstx-gnu-linux.c +++ b/chopstx-gnu-linux.c @@ -342,9 +342,3 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size, chx_cpu_sched_unlock (); return tp; } - -void -chx_sleep_mode (int enable_sleep) -{ - (void)enable_sleep; -} diff --git a/mcu/chx-gnu-linux.c b/mcu/chx-gnu-linux.c new file mode 100644 index 0000000..51c8fc3 --- /dev/null +++ b/mcu/chx-gnu-linux.c @@ -0,0 +1,5 @@ +void +chx_sleep_mode (int enable_sleep) +{ + (void)enable_sleep; +} diff --git a/mcu/chx-mkl27z.c b/mcu/chx-mkl27z.c new file mode 100644 index 0000000..48d683b --- /dev/null +++ b/mcu/chx-mkl27z.c @@ -0,0 +1,23 @@ +extern int chx_allow_sleep; + +void +chx_sleep_mode (int enable_sleep) +{ + (void)enable_sleep; +} + +void __attribute__((naked)) +chx_idle (void) +{ + int sleep_enabled; + + for (;;) + { + asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep)); + if (sleep_enabled) + { + asm volatile ("wfi" : : : "memory"); + /* NOTE: it never comes here. Don't add lines after this. */ + } + } +} diff --git a/mcu/chx-stm32f0.c b/mcu/chx-stm32f0.c new file mode 100644 index 0000000..492acef --- /dev/null +++ b/mcu/chx-stm32f0.c @@ -0,0 +1,41 @@ +#include +#include +#include + +extern int chx_allow_sleep; + +void +chx_sleep_mode (int how) +{ + PWR->CR |= PWR_CR_CWUF; + PWR->CR &= ~(PWR_CR_PDDS|PWR_CR_LPDS); + + if (how == 0 || how == 1 /* Sleep only (not deepsleep) */) + SCB->SCR &= ~SCB_SCR_SLEEPDEEP; + else + { /* Deepsleep */ + /* how == 2: deepsleep but regulator ON */ + if (how == 3) + PWR->CR |= PWR_CR_LPDS; /* regulator low-power mode */ + else if (how == 4) + PWR->CR |= PWR_CR_PDDS; /* Power down: All OFF */ + + SCB->SCR |= SCB_SCR_SLEEPDEEP; + } +} + +void __attribute__((naked)) +chx_idle (void) +{ + int sleep_enabled; + + for (;;) + { + asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep)); + if (sleep_enabled) + { + asm volatile ("wfi" : : : "memory"); + /* NOTE: it never comes here. Don't add lines after this. */ + } + } +} diff --git a/mcu/chx-stm32f103.c b/mcu/chx-stm32f103.c new file mode 100644 index 0000000..3484ce0 --- /dev/null +++ b/mcu/chx-stm32f103.c @@ -0,0 +1,60 @@ +#include +#include + +extern int chx_allow_sleep; + +static void +configure_clock (uint32_t cfg_sw) +{ + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW_MASK) | cfg_sw; + while ((RCC->CFGR & RCC_CFGR_SWS) != (cfg_sw << 2)) + ; +} + +/* + * When HOW=0 or HOW=1, clock is PLL (72MHz). + * When HOW=2, clock will be HSI (8MHz) on sleep. + * + * With HSI clock, it can achieve lower power consumption. + * + * Implementation note: Deepsleep is only useful with RTC, Watch Dog, + * or WKUP pin. We can't use deepsleep for USB, it never wakes up. + * + */ +void +chx_sleep_mode (int how) +{ + if (how == 0 || how == 1) + configure_clock (RCC_CFGR_SW_PLL); + + /* how == 2: Defer setting to 8MHz clock to the idle function */ +} + +void __attribute__((naked)) +chx_idle (void) +{ + int sleep_enabled; + + for (;;) + { + asm ("ldr %0, %1" : "=r" (sleep_enabled): "m" (chx_allow_sleep)); + if (sleep_enabled) + { + asm volatile ("cpsid i" : : : "memory"); + if (sleep_enabled == 1) + { + /* Allow JTAG/SWD access on sleep. */ + DBGMCU->CR |= DBG_SLEEP; + } + else if (sleep_enabled == 2) + { + DBGMCU->CR &= ~DBG_SLEEP; /* Disable HCLK on sleep */ + configure_clock (RCC_CFGR_SW_HCI); + } + asm volatile ("cpsie i" : : : "memory"); + + asm volatile ("wfi" : : : "memory"); + /* NOTE: it never comes here. Don't add lines after this. */ + } + } +} diff --git a/mcu/stm32.h b/mcu/stm32.h new file mode 100644 index 0000000..d68189c --- /dev/null +++ b/mcu/stm32.h @@ -0,0 +1,9 @@ +struct PWR +{ + volatile uint32_t CR; + volatile uint32_t CSR; +}; +static struct PWR *const PWR = ((struct PWR *)0x40007000); +#define PWR_CR_LPDS 0x0001 /* Low-power deepsleep */ +#define PWR_CR_PDDS 0x0002 /* Power down deepsleep */ +#define PWR_CR_CWUF 0x0004 /* Clear wakeup flag */ diff --git a/rules.mk b/rules.mk index 78febc4..f71beb6 100644 --- a/rules.mk +++ b/rules.mk @@ -6,6 +6,12 @@ ifneq ($(USE_EVENTFLAG),) CSRC += $(CHOPSTX)/eventflag.c endif +ifeq ($(EMULATION),) +CSRC += $(CHOPSTX)/mcu/chx-$(CHIP).c +else +CSRC += $(CHOPSTX)/mcu/chx-gnu-linux.c +endif + ifneq ($(USE_SYS),) CSRC += $(CHOPSTX)/mcu/sys-$(CHIP).c endif