Skip to content

Commit

Permalink
Merge pull request #235 from baoshi/master
Browse files Browse the repository at this point in the history
Update standby examples and add implementation notes.
  • Loading branch information
cnlohr authored Sep 24, 2023
2 parents c788f9a + e44c7f4 commit 42cb809
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 48 deletions.
3 changes: 1 addition & 2 deletions examples/standby_autowake/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
59 changes: 42 additions & 17 deletions examples/standby_autowake/standby_autowake.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -62,6 +88,5 @@ int main()
// restore clock to full speed
SystemInit();
printf("\r\nawake, %u\r\n", counter++);
GPIOD->OUTDR ^= (1 << 4);
}
}
23 changes: 19 additions & 4 deletions examples/standby_btn/README.md
Original file line number Diff line number Diff line change
@@ -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.
70 changes: 45 additions & 25 deletions examples/standby_btn/standby_btn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
}
}

0 comments on commit 42cb809

Please sign in to comment.