From e44c7f40c297c76ed6d457cb85977f01742cab8a Mon Sep 17 00:00:00 2001
From: Baoshi <baoshi@pancake.local>
Date: Sat, 23 Sep 2023 14:00:11 +0800
Subject: [PATCH] Demonstrate proper configuration of GPIO prior to standby.

---
 examples/standby_autowake/README.md          |  2 +-
 examples/standby_autowake/standby_autowake.c | 47 ++++++++++++-----
 examples/standby_btn/README.md               | 18 ++++---
 examples/standby_btn/standby_btn.c           | 54 ++++++++++++++------
 4 files changed, 84 insertions(+), 37 deletions(-)

diff --git a/examples/standby_autowake/README.md b/examples/standby_autowake/README.md
index 65e1f12..2fe3d12 100644
--- a/examples/standby_autowake/README.md
+++ b/examples/standby_autowake/README.md
@@ -6,7 +6,7 @@ This example serves to show how to put the CH32V003 into its lowest power state
 
 Power consumption should be around 10uA.  
 
-GPIO must be put into input pull-up / pull-down mode to have standby current reduced.
+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 d08effb..9e41489 100644
--- a/examples/standby_autowake/standby_autowake.c
+++ b/examples/standby_autowake/standby_autowake.c
@@ -3,12 +3,6 @@
 #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()
 {
@@ -23,12 +17,41 @@ int main()
 
 	// Set all GPIOs to input pull up
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD;
-	GPIOA->CFGLR = 0b10001000100010001000100010001000;
-	GPIOA->OUTDR = 0b11111111;
-	GPIOC->CFGLR = 0b10001000100010001000100010001000;
-	GPIOC->OUTDR = 0b11111111;
-	GPIOD->CFGLR = 0b10001000100010001000100010001000;
-	GPIOD->OUTDR = 0b11111111;
+	// 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;
diff --git a/examples/standby_btn/README.md b/examples/standby_btn/README.md
index 0e1a067..4b6421c 100644
--- a/examples/standby_btn/README.md
+++ b/examples/standby_btn/README.md
@@ -4,19 +4,21 @@
 
 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. Put all GPIOs in input mode (thus no output state can be preserved).
-2. Enable AFIO clock and set AFIO_EXTICR to the wakeup channel.
-3. Configure EXTI event.
-4. Set PWR_CTLR_PDDS bit in PWR_CTLR (Setting PWREN in RCC_APB1PCENR is not required hum?)
-5. Set SLEEPDEEP bit in PFIC_SCTLR
-6. Call __WFE() to enter standby mode.
+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.
 
 Note:
-* All GPIOs must be in input pull-up or pull-down mode before entering standby. Input floating mode result in 100uA current. 
+* 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.
 
diff --git a/examples/standby_btn/standby_btn.c b/examples/standby_btn/standby_btn.c
index 658e057..be6c99b 100644
--- a/examples/standby_btn/standby_btn.c
+++ b/examples/standby_btn/standby_btn.c
@@ -3,38 +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();
-
+	
 	// 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");
-
-	// Set all GPIOs to input pull up
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD;
-	GPIOA->CFGLR = 0b10001000100010001000100010001000;
-	GPIOA->OUTDR = 0b11111111;
-	GPIOC->CFGLR = 0b10001000100010001000100010001000;
-	GPIOC->OUTDR = 0b11111111;
-	GPIOD->CFGLR = 0b10001000100010001000100010001000;
-	GPIOD->OUTDR = 0b00000100;
+	// 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;
 
 	// AFIO is needed for EXTI
 	RCC->APB2PCENR |= RCC_AFIOEN;
 
 	// 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;
-- 
GitLab