Skip to content

Instantly share code, notes, and snippets.

@tomtor
Last active December 4, 2023 10:53
Show Gist options
  • Save tomtor/3dff8dd2f2514912aacbab1b1652be76 to your computer and use it in GitHub Desktop.
Save tomtor/3dff8dd2f2514912aacbab1b1652be76 to your computer and use it in GitHub Desktop.
stm32 low power sleep code
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
#include <RTClock.h>
// Define the Base address of the RTC registers (battery backed up CMOS Ram), so we can use them for config of touch screen or whatever.
// See http://stm32duino.com/viewtopic.php?f=15&t=132&hilit=rtc&start=40 for a more details about the RTC NVRam
// 10x 16 bit registers are available on the STM32F103CXXX more on the higher density device.
#define BKP_REG_BASE ((uint32_t *)(0x40006C00 + 0x04))
RTClock rt(RTCSEL_LSI, 39); // 1 milli second alarm
void storeBR(int i, uint32_t v) {
BKP_REG_BASE[2*i]= (v << 16);
BKP_REG_BASE[2*i+1]= (v & 0xFFFF);
}
uint32_t readBR(int i) {
return ((BKP_REG_BASE[2*i] & 0xFFFF) >> 16) | (BKP_REG_BASE[2*i+1] & 0xFFFF);
}
void sleepMode(bool deepSleepFlag)
{
// Clear PDDS and LPDS bits
PWR_BASE->CR &= ~(PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF); // Thanks @dalbert2 for spotting the missing ~
// Set PDDS and LPDS bits for standby mode, and set Clear WUF flag (required per datasheet):
PWR_BASE->CR |= PWR_CR_CWUF;
// Enable wakeup pin bit.
PWR_BASE->CR |= PWR_CSR_EWUP;
SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;
// System Control Register Bits. See...
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Cihhjgdh.html
if (deepSleepFlag) {
// Set Power down deepsleep bit.
PWR_BASE->CR |= PWR_CR_PDDS;
// Unset Low-power deepsleep.
PWR_BASE->CR &= ~PWR_CR_LPDS;
} else {
adc_disable(ADC1);
adc_disable(ADC2);
#if STM32_HAVE_DAC
dac_disable_channel(DAC, 1);
dac_disable_channel(DAC, 2);
#endif
// Unset Power down deepsleep bit.
PWR_BASE->CR &= ~PWR_CR_PDDS;
// set Low-power deepsleep.
PWR_BASE->CR |= PWR_CR_LPDS;
}
// Now go into stop mode, wake up on interrupt
asm(" wfi");
// Clear SLEEPDEEP bit so we can use SLEEP mode
SCB_BASE->SCR &= ~SCB_SCR_SLEEPDEEP;
}
uint32 sleepTime;
void AlarmFunction () {
// We always wake up with the 8Mhz HSI clock!
// So adjust the clock if needed...
#if F_CPU == 8000000UL
// nothing to do, using about 12 mA
#elif F_CPU == 16000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_2);
#elif F_CPU == 48000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_6);
#elif F_CPU == 72000000UL
rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_9); // 72MHz => 48 mA -- datasheet value => between 40 and 41mA
#else
#error "Unknown F_CPU!?"
#endif
extern volatile uint32 systick_uptime_millis;
systick_uptime_millis+= sleepTime;
}
void mdelay(int n, bool mode= false)
{
sleepTime= n;
time_t nextAlarm = (rt.getTime() + n); // Calculate from time now.
rt.createAlarm(&AlarmFunction, nextAlarm);
sleepMode(mode);
}
#define RCC_CFGR_HPRE_DIV1 0x00000000U
#define RCC_CFGR_HPRE_DIV2 0x00000080U
#define RCC_CFGR_HPRE_DIV4 0x00000090U
#define RCC_CFGR_HPRE_DIV8 0x000000A0U
#define RCC_CFGR_HPRE_DIV16 0x000000B0U
#define RCC_CFGR_HPRE_DIV64 0x000000C0U
#define RCC_CFGR_HPRE_DIV128 0x000000D0U
#define RCC_CFGR_HPRE_DIV256 0x000000E0U
#define RCC_CFGR_HPRE_DIV512 0x000000F0U
void msleep(uint32_t ms)
{
uint32_t start= rt.getTime();
while (rt.getTime() - start < ms) {
asm(" wfi");
}
}
void setup() {
//rcc_clk_init(RCC_CLKSRC_HSI, RCC_PLLSRC_HSE , RCC_PLLMUL_2);
pinMode(PA0, INPUT_ANALOG);
pinMode(PA1, INPUT_ANALOG);
pinMode(PA2, INPUT_ANALOG);
pinMode(PA3, INPUT_ANALOG);
pinMode(PA4, INPUT_ANALOG);
pinMode(PA5, INPUT_ANALOG);
pinMode(PA6, INPUT_ANALOG);
pinMode(PA7, INPUT_ANALOG);
pinMode(PA8, INPUT_ANALOG);
pinMode(PA9, INPUT_ANALOG);
pinMode(PA10, INPUT_ANALOG);
pinMode(PA11, INPUT_ANALOG);
pinMode(PA12, INPUT_ANALOG);
pinMode(PA13, INPUT_ANALOG);
pinMode(PA14, INPUT_ANALOG);
pinMode(PA15, INPUT_ANALOG);
pinMode(PB0, INPUT_ANALOG);
pinMode(PB1, INPUT_ANALOG);
pinMode(PB2, INPUT_ANALOG);
pinMode(PB3, INPUT_ANALOG);
pinMode(PB4, INPUT_ANALOG);
pinMode(PB5, INPUT_ANALOG);
pinMode(PB6, INPUT_ANALOG);
pinMode(PB7, INPUT_ANALOG);
pinMode(PB8, INPUT_ANALOG);
pinMode(PB9, INPUT_ANALOG);
pinMode(PB10, INPUT_ANALOG);
pinMode(PB11, INPUT_ANALOG);
pinMode(PB12, INPUT_ANALOG);
pinMode(PB13, INPUT_ANALOG);
pinMode(PB14, INPUT_ANALOG);
pinMode(PB15, INPUT_ANALOG);
// We have just started or woken up from sleep! System clock is set to 72MHz HSE.
Serial.begin(115200);
#if 0
delay(1000);
//#if 0
char str[100];
sprintf(str, "%x", *(uint32*)0xE0042004);
Serial.println(str);
pinMode(PA12, INPUT_ANALOG);
randomSeed(rt.getTime());
Serial.println("");
long m1= micros();
delayMicroseconds(2000);
long m2= micros();
Serial.println(m2-m1);
storeBR(0, readBR(0)+1);
Serial.print(readBR(0));
Serial.print(": ");
Serial.print(rt.getTime()/100/3600%24); Serial.print(':');
Serial.print(rt.getTime()/100/60%60); Serial.print(':');
Serial.println(rt.getTime()/100%60);
//delay(1500);
// for (int d= 0, e= random(10000); d < e; d++)
// millis();
//
// long t1= systick_get_count(), m1= millis(), mi1= micros();
// long sum= 0;
// for (int i= 0; i < 99; i++)
// sum+= i;
// long t2= systick_get_count(), m2= millis(), mi2= micros();
// Serial.println(sum);
// Serial.println(t1);
// Serial.println(t2);
// Serial.println(t1-t2);
// Serial.println(mi2-mi1);
#endif
}
void blinkN(int n, int d= 400, int t= 800)
{
pinMode(LED_BUILTIN, OUTPUT);
for (int i= 0; i < n; i++) {
digitalWrite(LED_BUILTIN, 0);
mdelay(5);
digitalWrite(LED_BUILTIN, 1);
mdelay(d);
}
pinMode(LED_BUILTIN, INPUT_ANALOG);
mdelay(t);
}
void blinkTemp(int n, int d= 500, int t= 800)
{
const int tempBlinkPin= PB7;
pinMode(tempBlinkPin, OUTPUT);
for (int i= 0; i < n; i++) {
digitalWrite(tempBlinkPin, 0);
mdelay(5);
digitalWrite(tempBlinkPin, 1);
mdelay(d);
}
pinMode(tempBlinkPin, INPUT_ANALOG);
mdelay(t);
}
#define tempPin PA0
#define powerPin PA2
void loop() {
adc_enable(ADC1);
adc_reg_map *regs = ADC1->regs;
regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and temp sensor
regs->SMPR1 = (ADC_SMPR1_SMP17 /* | ADC_SMPR1_SMP16 */); // sample rate for VREFINT ADC channel
//int vref= 3300;
int vref = 1200 * 4096 / adc_read(ADC1, 17); // ADC sample to millivolts
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
//float tempr;
// following 1.43 and 0.0043 parameters come from F103 datasheet - ch. 5.9.13
// and need to be calibrated for every chip (large fab parameters variance)
//tempr = (1.43 - (vref * adc_read(ADC1, 16) / 4096.0 / 1024)) / 0.0043 + 25.0;
pinMode(powerPin, OUTPUT);
digitalWrite(powerPin, 1);
int v= analogRead(tempPin);
pinMode(powerPin, INPUT_ANALOG);
double steinhart= v;
steinhart = 4095 / steinhart - 1;
steinhart = 10000 * steinhart;
steinhart = steinhart / 10000; // (R/Ro)
steinhart = log(steinhart); // ln(R/Ro)
steinhart /= 4050; // 1/B * ln(R/Ro)
steinhart += 1.0 / (25 + 273.15); // + (1/To)
steinhart = 1.0 / steinhart; // Invert
steinhart -= 273.15; // convert to C
double Temp= steinhart;
// double Temp = log(10000.0*((4096.0/v-1)));
// // =log(10000.0/(4096.0/v-1)) // for pull-up configuration
// Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
// Temp = Temp - 273.15; // Convert Kelvin to Celcius
//Serial.println(vref); delay(2);
vref+= 5;
if (vref < 2000 || vref >= 3000)
blinkN(vref / 1000);
blinkN(vref % 1000 / 100);
blinkN(vref % 100 / 10);
Temp+= 0.5; // round
blinkTemp(int(Temp) / 10);
blinkTemp(int(Temp) % 10);
//blinkTemp(int(Temp * 10) % 10);
//int power= (2 * (vref * v / 4095) / 10);
//Serial.println(power);
// delay(3000);
// rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_CFGR_HPRE_DIV8);
// delay(3000 / 8);
// rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_CFGR_HPRE_DIV1);
msleep(3000);
//mdelay(5000);
}
@dalbert2
Copy link

Line 25 looks like it has an error (you need to invert those bits to clear them):
PWR_BASE->CR &= ~(PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF);

@tomtor
Copy link
Author

tomtor commented Oct 20, 2022

Line 25 looks like it has an error (you need to invert those bits to clear them): PWR_BASE->CR &= ~(PWR_CR_LPDS | PWR_CR_PDDS | PWR_CR_CWUF);

They ARE inverted, the ~ is before (...)

@dalbert2
Copy link

The ~( ) was my suggestion....they aren't there at the moment; scroll up and take a look at line 25.

@tomtor
Copy link
Author

tomtor commented Oct 20, 2022

The ~( ) was my suggestion....they aren't there at the moment; scroll up and take a look at line 25.

Ah, I see.

I probably copied those specific lines from some piece of example code, because the comments are not my style.

I will change it, thanks for your feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment