diff --git a/examples/standby_autowake/README.md b/examples/standby_autowake/README.md index 70e71b4e6f3b0eca3fa503a13ec204e42025b5df..2fe3d123f79270038312627ab679fc4e3442c57e 100644 --- a/examples/standby_autowake/README.md +++ b/examples/standby_autowake/README.md @@ -6,8 +6,7 @@ This example serves to show how to put the CH32V003 into its lowest power state Power consumption should be around 10uA. -The MCU only toggles the LED and prints a message, then it goes to sleep. -The LED staying on demonstrates that GPIO keeps its state even when the rest of the mcu is in a coma. +Refer to the standby_btn example for GPIO settings. Based on the groundwork of Marek M. diff --git a/examples/standby_autowake/standby_autowake.c b/examples/standby_autowake/standby_autowake.c index 4cfaaf34c1248cd27cac5e82a3cef6d78d754a5e..9e41489a4b595d10fec04f28871180dc49fffa92 100644 --- a/examples/standby_autowake/standby_autowake.c +++ b/examples/standby_autowake/standby_autowake.c @@ -3,30 +3,56 @@ #include "ch32v003fun.h" #include <stdio.h> -/* somehow this ISR won't get called?? -void AWU_IRQHandler( void ) __attribute__((interrupt)); -void AWU_IRQHandler( void ) { - GPIOD->OUTDR ^= (1 << 4); -} -*/ int main() { SystemInit(); - Delay_Ms(100); - printf("\r\n\r\nlow power example\r\n\r\n"); + // This delay gives us some time to reprogram the device. + // Otherwise if the device enters standby mode we can't + // program it any more. + Delay_Ms(5000); - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - // GPIO D4 Push-Pull - GPIOD->CFGLR &= ~(0xf<<(4*4)); - GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - GPIOD->OUTDR |= (1 << 4); + printf("\r\n\r\nlow power example\r\n\r\n"); - // give the user time to open the terminal connection - //Delay_Ms(5000); - printf("5000ms wait over\r\n"); + // Set all GPIOs to input pull up + RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD; + // GPIOA: Set to output + GPIOA->CFGLR = (GPIO_CNF_IN_PUPD<<(4*2)) | + (GPIO_CNF_IN_PUPD<<(4*1)); + GPIOA->BSHR = GPIO_BSHR_BS2 | GPIO_BSHR_BR1; + GPIOC->CFGLR = (GPIO_CNF_IN_PUPD<<(4*7)) | + (GPIO_CNF_IN_PUPD<<(4*6)) | + (GPIO_CNF_IN_PUPD<<(4*5)) | + (GPIO_CNF_IN_PUPD<<(4*4)) | + (GPIO_CNF_IN_PUPD<<(4*3)) | + (GPIO_CNF_IN_PUPD<<(4*2)) | + (GPIO_CNF_IN_PUPD<<(4*1)) | + (GPIO_CNF_IN_PUPD<<(4*0)); + GPIOC->BSHR = GPIO_BSHR_BS7 | + GPIO_BSHR_BS6 | + GPIO_BSHR_BS5 | + GPIO_BSHR_BS4 | + GPIO_BSHR_BS3 | + GPIO_BSHR_BS2 | + GPIO_BSHR_BS1 | + GPIO_BSHR_BS0; + GPIOD->CFGLR = (GPIO_CNF_IN_PUPD<<(4*7)) | + (GPIO_CNF_IN_PUPD<<(4*6)) | + (GPIO_CNF_IN_PUPD<<(4*5)) | + (GPIO_CNF_IN_PUPD<<(4*4)) | + (GPIO_CNF_IN_PUPD<<(4*3)) | + (GPIO_CNF_IN_PUPD<<(4*2)) | + (GPIO_CNF_IN_PUPD<<(4*0)); + GPIOD->BSHR = GPIO_BSHR_BS7 | + GPIO_BSHR_BS6 | + GPIO_BSHR_BS5 | + GPIO_BSHR_BS4 | + GPIO_BSHR_BS3 | + GPIO_BSHR_BS2 | + GPIO_BSHR_BS0; + // enable power interface module clock RCC->APB1PCENR |= RCC_APB1Periph_PWR; @@ -62,6 +88,5 @@ int main() // restore clock to full speed SystemInit(); printf("\r\nawake, %u\r\n", counter++); - GPIOD->OUTDR ^= (1 << 4); } } diff --git a/examples/standby_btn/README.md b/examples/standby_btn/README.md index 794e8b4ccc30b278904c12658a303c200170b380..4b6421c99cef584df8d4a0f91fde4b1418dbe453 100644 --- a/examples/standby_btn/README.md +++ b/examples/standby_btn/README.md @@ -1,15 +1,30 @@ # the deepest slumber +**WARNING: You MUST hard-reboot the CH32V003 to allow it to go into deep sleep. You cannot go from flashing to deep sleep without a hard power cycle.** + This example serves to show how to put the CH32V003 into its lowest power state (standby) and have it wake with a button press. -Power consumption should be around 10uA. +Power consumption should be around 9uA. + +To enter 10uA standby mode you must perform these steps: + +1. GPIOs other than the wake up pin can be set to either input or output mode (see notes). +2. Set GPIO(s) for wake up to input mode with appropriate pull up/down. +3. Enable AFIO clock and set AFIO_EXTICR to the wakeup channel. +4. Configure EXTI event. +5. Set PWR_CTLR_PDDS bit in PWR_CTLR (Setting PWREN in RCC_APB1PCENR is not required hum?) +6. Set SLEEPDEEP bit in PFIC_SCTLR +7. Call __WFE() to enter standby mode. -The MCU only toggles the LED and prints a message, then it goes back to sleep. -The LED staying on demonstrates that GPIO keeps its state even when the rest of the mcu is in a coma. +Note: +* GPIOs in output mode will retain state during standby. +* GPIO if set to input mode must have internal or external pulling resistor. Floating input pin will cause 100uA standby current. +* Once CH32V003 enters standby mode, it won't respond to any SWDIO command, therefor cannot be reprogrammed. User must provide a way to have the processor stay awake for reprogramming, e.g. some delay at startup. +* Debug circuitry will consume power. If minichlink terminal is active (including immediately after flashing), standby current will stay around 1.2mA until power cycle. Based on the groundwork of Marek M. ## circuit -Connect LED to PD4 (with resistor), connect button to GND and PD2. +Connect button to GND and PD2. There is no debouncing but it should suffice for waking the chip. diff --git a/examples/standby_btn/standby_btn.c b/examples/standby_btn/standby_btn.c index 33f55a89cb8c29e7ae7991cb01c0fac41ed183cb..be6c99b7f109db9e04af80dea2d94618a5aac4d8 100644 --- a/examples/standby_btn/standby_btn.c +++ b/examples/standby_btn/standby_btn.c @@ -3,40 +3,60 @@ #include "ch32v003fun.h" #include <stdio.h> -void EXTI7_0_IRQHandler( void ) __attribute__((interrupt)); -void EXTI7_0_IRQHandler( void ) { - //GPIOD->OUTDR ^= (1 << 4); -} - - int main() { SystemInit(); - Delay_Ms(100); + + // This delay gives us some time to reprogram the device. + // Otherwise if the device enters standby mode we can't + // program it any more. + Delay_Ms(5000); printf("\n\nlow power example\n\n"); + RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD; + // GPIOA: Set to output + GPIOA->CFGLR = ((GPIO_CNF_OUT_PP | GPIO_Speed_2MHz)<<(4*2)) | + ((GPIO_CNF_OUT_PP | GPIO_Speed_2MHz)<<(4*1)); + GPIOA->BSHR = GPIO_BSHR_BS2 | GPIO_BSHR_BR1; + // GPIOC: Set to input with mixed pull-up / pull-down + GPIOC->CFGLR = (GPIO_CNF_IN_PUPD<<(4*7)) | + (GPIO_CNF_IN_PUPD<<(4*6)) | + (GPIO_CNF_IN_PUPD<<(4*5)) | + (GPIO_CNF_IN_PUPD<<(4*4)) | + (GPIO_CNF_IN_PUPD<<(4*3)) | + (GPIO_CNF_IN_PUPD<<(4*2)) | + (GPIO_CNF_IN_PUPD<<(4*1)) | + (GPIO_CNF_IN_PUPD<<(4*0)); + GPIOC->BSHR = GPIO_BSHR_BS7 | + GPIO_BSHR_BR6 | + GPIO_BSHR_BS5 | + GPIO_BSHR_BR4 | + GPIO_BSHR_BS3 | + GPIO_BSHR_BR2 | + GPIO_BSHR_BS1 | + GPIO_BSHR_BR0; + // GPIOD: D2 set to input pull-up + GPIOD->CFGLR = (GPIO_CNF_IN_PUPD<<(4*7)) | + (GPIO_CNF_IN_PUPD<<(4*6)) | + (GPIO_CNF_IN_PUPD<<(4*5)) | + (GPIO_CNF_IN_PUPD<<(4*4)) | + (GPIO_CNF_IN_PUPD<<(4*3)) | + (GPIO_CNF_IN_PUPD<<(4*2)) | + (GPIO_CNF_IN_PUPD<<(4*0)); + GPIOD->BSHR = GPIO_BSHR_BR7 | + GPIO_BSHR_BS6 | + GPIO_BSHR_BR5 | + GPIO_BSHR_BS4 | + GPIO_BSHR_BR3 | + GPIO_BSHR_BS2 | + GPIO_BSHR_BR0; - RCC->APB2PCENR |= RCC_APB2Periph_GPIOD; - // GPIO D4 Push-Pull - GPIOD->CFGLR &= ~(0xf<<(4*4)); - GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); - GPIOD->OUTDR |= (1 << 4); - - // give the user time to open the terminal connection - //Delay_Ms(5000); - //printf("5000ms wait over\r\n"); - - // enable alternate IO function module clock + // AFIO is needed for EXTI RCC->APB2PCENR |= RCC_AFIOEN; - // configure button on PD2 as input, pullup - GPIOD->CFGLR &= ~(0xf<<(2*4)); - GPIOD->CFGLR |= (GPIO_CNF_IN_PUPD)<<(2*4); - GPIOD->BSHR = (1 << 2); - // assign pin 2 interrupt from portD (0b11) to EXTI channel 2 - AFIO->EXTICR |= (uint32_t)(0b11 << (2 * 2)); + AFIO->EXTICR |= (uint32_t)(0b11 << (2*2)); // enable line2 interrupt event EXTI->EVENR |= EXTI_Line2; @@ -56,6 +76,6 @@ int main() // restore clock to full speed SystemInit(); printf("\nawake, %u\n", counter++); - GPIOD->OUTDR ^= (1 << 4); + Delay_Ms(5000); // wake and reflash can happen here } }