60 lines
2.2 KiB
C
60 lines
2.2 KiB
C
/* firmware template for STM8S microcontroller
|
|
* Copyright (C) 2019-2020 King Kévin <kingkevin@cuvoodoo.info>
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "stm8s.h"
|
|
#include "main.h"
|
|
|
|
|
|
|
|
// 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
|
|
while (us10--); // 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
|
|
}
|