Created
September 19, 2022 03:24
-
-
Save joeycastillo/97678bb1c151f4943203cfffb21a71eb to your computer and use it in GitHub Desktop.
Low power test for Feather M0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MIT license, Joey Castillo 2022 | |
// works with Alex Taradov's bare metal SAM D21 project: | |
// https://github.com/ataradov/mcu-starter-projects | |
//----------------------------------------------------------------------------- | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include "samd21.h" | |
#include "hal_gpio.h" | |
//----------------------------------------------------------------------------- | |
#define BLINK_PERIOD_SECONDS 15 | |
HAL_GPIO_PIN(LED, A, 17) | |
//----------------------------------------------------------------------------- | |
static void sys_init(void) { | |
// Switch to 8MHz clock (disable prescaler) | |
SYSCTRL->OSC8M.bit.PRESC = 0; | |
// make sure main oscillator stays off in standby | |
SYSCTRL->OSC8M.bit.RUNSTDBY = 0; | |
// set up external 32k crystal oscillator | |
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(0x7) | SYSCTRL_XOSC32K_EN32K | | |
SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_RUNSTDBY; | |
SYSCTRL->XOSC32K.bit.ENABLE = 1; | |
while(!SYSCTRL->PCLKSR.bit.XOSC32KRDY); | |
// connect external crystal to GCLK1 | |
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(1); | |
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_XOSC32K | | |
GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN; | |
while(GCLK->STATUS.bit.SYNCBUSY); | |
} | |
//----------------------------------------------------------------------------- | |
static void timer_init(void) { | |
PM->APBCMASK.reg |= PM_APBCMASK_TC3; | |
// clock TC3 with GCLK1 (the 32k crystal) | |
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC3_GCLK_ID) | GCLK_CLKCTRL_CLKEN | | |
GCLK_CLKCTRL_GEN(1); | |
// Run in standby, divide 32768 Hz clock by 1024 (32 ticks per second) | |
TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | | |
TC_CTRLA_PRESCSYNC_RESYNC | TC_CTRLA_RUNSTDBY | | |
TC_CTRLA_PRESCALER_DIV1024; | |
// set the counter to overflow at our desired interval | |
TC3->COUNT16.COUNT.reg = 0; | |
TC3->COUNT16.CC[0].reg = (32768 / 1024) * BLINK_PERIOD_SECONDS; | |
// at first boot, cheat the count so that the LED blinks on in a half second | |
TC3->COUNT16.COUNT.reg = TC3->COUNT16.CC[0].reg - (32768 / 2048); | |
// enable the counter | |
TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; | |
// and enable the interrupt | |
TC3->COUNT16.INTENSET.reg = TC_INTENSET_MC(1); | |
NVIC_EnableIRQ(TC3_IRQn); | |
} | |
//----------------------------------------------------------------------------- | |
void irq_handler_tc3(void) { | |
// if the interrupt flag is set | |
if (TC3->COUNT16.INTFLAG.reg & TC_INTFLAG_MC(1)) { | |
// clear the interrupt flag | |
TC3->COUNT16.INTFLAG.reg = TC_INTFLAG_MC(1); | |
} | |
} | |
//----------------------------------------------------------------------------- | |
int main(void) { | |
// initialize the clocks | |
sys_init(); | |
// initialize our counter | |
timer_init(); | |
// set up LED output and turn the LED off at first | |
HAL_GPIO_LED_out(); | |
HAL_GPIO_LED_clr(); | |
// set SLEEPDEEP bit so that __WFI enters standby | |
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; | |
while (1) { | |
// enter standby mode and stay there until the timer interrupt fires | |
__WFI(); | |
// at this point we just woke up! Toggle the LED. | |
HAL_GPIO_LED_toggle(); | |
// and if we just turned on the LED, set the count so that the interrupt | |
// fires again in a half-second, turning it back off. | |
if (HAL_GPIO_LED_read()) { | |
TC3->COUNT16.COUNT.reg = (32768 / 1024) * BLINK_PERIOD_SECONDS - (32768 / 2048); | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment