/* firmware template for STM8S microcontroller * Copyright (C) 2019-2020 King Kévin * SPDX-License-Identifier: GPL-3.0-or-later */ #include #include #include "stm8s.h" // get length of array #define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) // blocking wait (in 10 us steps, up to UINT32_MAX / 10) static void wait_10us(uint32_t us10) { us10 = ((us10 / (1 << CLK->CKDIVR.fields.HSIDIV)) * 1000) / 206; // calibrated for 1 ms for (volatile uint32_t t = 0; t < us10; t++); // burn energy } void main(void) { sim(); // disable interrupts (while we reconfigure them) CLK->CKDIVR.fields.HSIDIV = CLK_CKDIVR_HSIDIV_DIV0; // don't divide internal 16 MHz clock CLK->CKDIVR.fields.CPUDIV = CLK_CKDIVR_CPUDIV_DIV0; // don't divide CPU frequency to 16 MHz while (!CLK->ICKR.fields.HSIRDY); // wait for internal oscillator to be ready // configure auto-wakeup (AWU) to be able to refresh the watchdog // 128 kHz LSI used by default in option bytes CKAWUSEL // we skip measuring the LS clock frequency since there is no need to be precise AWU->TBR.fields.AWUTB = 10; // interval range: 128-256 ms AWU->APR.fields.APR = 0x3e; // set time to 256 ms AWU_CSR |= AWU_CSR_AWUEN; // enable AWU (start only when entering wait or active halt mode) // configure independent watchdog (very loose, just it case the firmware hangs) IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog IWDG->KR.fields.KEY = IWDG_KR_KEY_ENABLE; // start watchdog IWDG->KR.fields.KEY = IWDG_KR_KEY_ACCESS; // allows changing the prescale IWDG->PR.fields.PR = IWDG_PR_DIV256; // set prescale to longest time (1.02s) IWDG->KR.fields.KEY = IWDG_KR_KEY_REFRESH; // reset watchdog rim(); // re-enable interrupts bool action = false; // if an action has been performed while (true) { IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog if (action) { // something has been performed, check if other flags have been set meanwhile action = false; // clear flag } else { // nothing down wfi(); // go to sleep (wait for any interrupt, including periodic AWU) } } } void awu(void) __interrupt(IRQ_AWU) // auto wakeup { volatile uint8_t awuf = AWU_CSR; // clear interrupt flag by reading it (reading is required, and volatile prevents compiler optimization) // let the main loop kick the dog }