stm8s/main.c

58 lines
2.3 KiB
C
Raw Normal View History

2020-09-30 16:59:31 +02:00
/* 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 "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
}