You need to do 2 things:
Set pll multiplier to 6
Set USB peripheral divider /1
That’s all for the mcu to run at 48. Then you may need some other adjustments for timing and serial, but you will get SerialUSB at 48 with just the changes above.
Find this 2 lines in boards_setup:
#define BOARD_RCC_PLLMUL RCC_PLLMUL_9
and
rcc_set_prescaler(RCC_PRESCALER_USB, RCC_USB_SYSCLK_DIV_1_5);
And change them to:
#define BOARD_RCC_PLLMUL RCC_PLLMUL_6
and
rcc_set_prescaler(RCC_PRESCALER_USB, RCC_USB_SYSCLK_DIV_1);
Last but not least. Make sure you use the very latest core downloaded from Roger’s repo, as we made several changes for that to work. I added a few things, and Roger added a ton.
I use the C code
WFI()
libmaple sets the clock for most if not all of them (spis, uarts, usb, etc) on init.
If you disable their clock, they dont use any power. The datasheet shows the power consumption in the different sleep modes, speeds, and peripherals enabled or disabled.
I added this function to the core to disable clocks, to be able to change the usb multiplier after it’s enabled by the bootloader:
rcc_clk_disable(RCC_USB)
Right now is used only for disabling the usb clock before changing the multiplier and enabling it again, so I have not tested with the rest of peripherals, but it is copied from the existin rcc_clk_enable(), which is used to enable the clocks of all peripherals, so I expect it to work for disabling any peripheral clock.
If you have any trouble with it let me know.
There is another thread about low power modes, that shows some of the savings by using WFI like Stevech recommended. If you use a low quiescent voltage regulator it can do wonders.
The sketch doesn’t do anything particularly useful, it simply monitors a PIR, or other switch and makes an LED react according to the trigger it sees from the switch. Obviously the idea can be expanded. The power saving figures are in the comments at the start of the code. I added a disableClocks() function, which appears to work, but doesn’t reduce the power significantly.
Without power saving, the sketch uses >46mA or more with power saving it drops to 12mA, so it drops to about 26% of the full power routine.
The challenge now would be to squeeze a few more mA savings without going to power down (deepsleep) mode.
I also need to work on recovering the clock back to 72MHz smoothly, without a reset, as my attempts so far have been a little hit and miss.
For what it’s worth deepsleep mode drops the power significantly, but when we wakeup, the board resets. This is not ideal for some scenarios, but would be perfectly OK for my sunset camera trigger.
// STM32_PIR_Blink - Simple Low Power demo using a PIR or other "button"
//
// Board speed is reduced to 8MHz, sketch responds to interrupt on pin BOARD_BUTTON and changes the state of the LED.
//
// At 72 MHz, the sketch consumes between 44.3mA and 46.5mA
// Slowing the clock and using WFI, the sketch consumes ~12mA - around 4mA of this will be the voltage regulator + the power LED,
// so the STM32F103R8T6 used for testing was only drawing about 8mA, while still running 32 bit ARM code at 8MHz. Not too shabby.
//
// Ensure you set the correct mode for the input, depending on your "button", one of INPUT, INPUT_PULLUP or INPUT_PULLDOWN
// Ths sketch was tested with with a button to ground (set the type to INPUT_PULLUP), and also with an HC-SR591 PIR (set the type to INPUT)
// HC-SR591 PIR => http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&_sop=15&_nkw=hc-sr501%20pir%20motion%20sensor&rt=nc&LH_BIN=1&_trksid=p2045573.m1684
// These will generally operate down to 3.3V. Output *should* be 3.3 safe with VCC <20V, but check the spec. of the PIR or you may release the magic smoke.
// Defined for power and sleep functions pwr.h and scb.h
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
int BOARD_LED_PIN = PB0;
int BOARD_BUTTON = PA15;
//int but = PA4;
volatile bool buttonInterruptFlag = false;
void buttonInterrupt() {
buttonInterruptFlag = true;
}
void setup() {
// Slow down to 8MHz (current drops to ~ 18mA
clockARM8();
disableClocks();
pinMode(BOARD_LED_PIN, OUTPUT);
digitalWrite(BOARD_LED_PIN, 1);
delay(1000);
pinMode(BOARD_BUTTON, INPUT);
attachInterrupt(BOARD_BUTTON, buttonInterrupt, CHANGE);
}
void loop() {
// WFI - current drops to ~12mA
asm("wfi");
if (buttonInterruptFlag)
{
// Someone pressed or released the button... Do stuff... wake up the dog, photgraph the wild life, switch on the air raid siren.. or whatever.
toggleLED();
buttonInterruptFlag = false;
}
}
void toggleLED()
{
digitalWrite(BOARD_LED_PIN, (!digitalRead(BOARD_LED_PIN)));
}
void clockARM8()
{
// Switch to the 8MHz external clock. We loose USB, but we consume 2/3 less power.
rcc_switch_sysclk(RCC_CLKSRC_HSE);
}
void disableClocks()
{
// Disable all peripheral clocks except GPIOA, GPIOB and TIMER1
rcc_clk_disable(RCC_ADC1);
rcc_clk_disable(RCC_ADC2);
rcc_clk_disable(RCC_ADC3);
rcc_clk_disable(RCC_AFIO);
rcc_clk_disable(RCC_BKP);
rcc_clk_disable(RCC_CRC);
rcc_clk_disable(RCC_DAC);
rcc_clk_disable(RCC_DMA1);
rcc_clk_disable(RCC_DMA2);
rcc_clk_disable(RCC_FLITF);
rcc_clk_disable(RCC_FSMC);
//rcc_clk_disable(RCC_GPIOA);
//rcc_clk_disable(RCC_GPIOB);
rcc_clk_disable(RCC_GPIOC);
rcc_clk_disable(RCC_GPIOD);
rcc_clk_disable(RCC_GPIOE);
rcc_clk_disable(RCC_GPIOF);
rcc_clk_disable(RCC_GPIOG);
rcc_clk_disable(RCC_I2C1);
rcc_clk_disable(RCC_I2C2);
rcc_clk_disable(RCC_PWR);
rcc_clk_disable(RCC_SDIO);
rcc_clk_disable(RCC_SPI1);
rcc_clk_disable(RCC_SPI2);
rcc_clk_disable(RCC_SPI3);
rcc_clk_disable(RCC_SRAM);
//rcc_clk_disable(RCC_TIMER1);
rcc_clk_disable(RCC_TIMER2);
rcc_clk_disable(RCC_TIMER3);
rcc_clk_disable(RCC_TIMER4);
rcc_clk_disable(RCC_TIMER5);
rcc_clk_disable(RCC_TIMER6);
rcc_clk_disable(RCC_TIMER7);
rcc_clk_disable(RCC_TIMER8);
rcc_clk_disable(RCC_TIMER9);
rcc_clk_disable(RCC_TIMER10);
rcc_clk_disable(RCC_TIMER11);
rcc_clk_disable(RCC_TIMER12);
rcc_clk_disable(RCC_TIMER13);
rcc_clk_disable(RCC_TIMER14);
rcc_clk_disable(RCC_USART1);
rcc_clk_disable(RCC_USART2);
rcc_clk_disable(RCC_USART3);
rcc_clk_disable(RCC_UART4);
rcc_clk_disable(RCC_UART5);
rcc_clk_disable(RCC_USB);
}
void systemHardReset(void) {
// Perform a system reset, see ../libmaple/nvic.c for the method
nvic_sys_reset();
// We will never get any further than this.
}
Also need a better voltage regulator.
I’m interested in writing to an SD card and keep the current down to a minimum. My idea is to use a capacitor for the short current peaks while the actual write command is executed by the card.
How efficient are they with no load? Is there much leakage current?
That’s a pretty useful figure. I think I’ll have to order a couple of those. I have a bunch of USB Power Bank (18650) devices hacked for various purposes, they are fine for +5V only projects, but something that can do a rock solid 3.3V from 5V would be very useful, particularly if it doesn’t guzzle power when the load is sleeping. It might also make a useful solar power regulator for micro-powered devices.
BTW that’s looks like the mother of all breadboards in the background of that youtube clip.
<…>
BTW that’s looks like the mother of all breadboards in the background of that youtube clip.
https://github.com/rogerclarkmelbourne/ … r.cpp#L112
I think the main clock has to become a variable and we need methods like
uint32 getMainClock();
setMainClock( uint32 frequency);
to access this var? As an alternative a class would work, too. So we could add utility methods, like getMaxFreq(), getMinFreq(), getAvailableFreqs() etc.

