前回、「STM32F103C8T6をスリープ状態にする」について書きました。
今回、一定の時間から起きる状態に加えて、外部割込みからも起きるようにしたくて、色々試しました。
やはりstm32sleepライブラリーはうまくできず、前回のtomtorさんのコードをもとにテストプログラムをつくりました。
外部割込みを使うため、attachInterruptという関数を使います。
attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
BOARD_BUTTON_PINにスイッチをつけ、そのスイッチに変化があれば割込みが発生します。
そして、起きたら、何を実行するかは新たにactionという関数を設けました。
tomtorさんのAlarmFunctionという関数は、スリープから起きた際、クロックを再設定する操作があります。そのままactionの中に使います。
void action()
{
AlarmFunction ();
if (state == LOW) state = HIGH;
else state = LOW;
}
ここはただLEDの点灯状態を反対にするだけ。
全部のコードは以下の通りです。
#include <RTClock.h>
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
#define LED PC13
#define BOARD_BUTTON_PIN PB0
// 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))
// Setup RTClock for sleep
RTClock rt(RTCSEL_LSI, 39); // 1 milli second alarm
long int alarmDelay = 10;
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;
// 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");
}
}
int state = LOW;
void setup() {
pinMode(LED,OUTPUT);
pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
digitalWrite(LED,state);
delay(60);
attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
mdelay(alarmDelay * 1000);
}
void action()
{
AlarmFunction ();
if (state == LOW) state = HIGH;
else state = LOW;
}
今回、一定の時間から起きる状態に加えて、外部割込みからも起きるようにしたくて、色々試しました。
やはりstm32sleepライブラリーはうまくできず、前回のtomtorさんのコードをもとにテストプログラムをつくりました。
外部割込みを使うため、attachInterruptという関数を使います。
attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
BOARD_BUTTON_PINにスイッチをつけ、そのスイッチに変化があれば割込みが発生します。
そして、起きたら、何を実行するかは新たにactionという関数を設けました。
tomtorさんのAlarmFunctionという関数は、スリープから起きた際、クロックを再設定する操作があります。そのままactionの中に使います。
void action()
{
AlarmFunction ();
if (state == LOW) state = HIGH;
else state = LOW;
}
ここはただLEDの点灯状態を反対にするだけ。
全部のコードは以下の通りです。
#include <RTClock.h>
#include <libmaple/pwr.h>
#include <libmaple/scb.h>
#define LED PC13
#define BOARD_BUTTON_PIN PB0
// 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))
// Setup RTClock for sleep
RTClock rt(RTCSEL_LSI, 39); // 1 milli second alarm
long int alarmDelay = 10;
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;
// 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");
}
}
int state = LOW;
void setup() {
pinMode(LED,OUTPUT);
pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
digitalWrite(LED,state);
delay(60);
attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
mdelay(alarmDelay * 1000);
}
void action()
{
AlarmFunction ();
if (state == LOW) state = HIGH;
else state = LOW;
}
0 件のコメント:
コメントを投稿