Compare commits

...

6 Commits

Author SHA1 Message Date
a4ca0d30c3 Force the use of system's reset in openocd
Using the system's reset avoids the debug getting stuck when the chip
enters low power. Hopefully this works all the time
2024-08-04 20:14:34 +02:00
89c81b8c42 Integrate the RTC to the task module 2024-08-04 20:14:24 +02:00
24e412446d Implement bkp's rtc alarm configuration
Since the alarm must be set each time it is to be used, a separated
function is a better fit
2024-08-04 20:12:28 +02:00
7ab6622908 Rework exti module to use a simpler API
The "specific" lines configuration would not work due to index error in
the callback configuration. While fixing the error, simplifying the API
by moving the afio calls to the calling context seemed a cleaner way to
do things
2024-08-04 19:38:24 +02:00
ba9bc57a49 Add openocd configuration
The target's debug would sometime get stuck while in low-power, making
it difficult to resume communications, even after hardware resets. Some
peripherals were also kept running when halted. This config should fix
these issues
2024-08-04 15:52:24 +02:00
947df53ecb Add missing file documentation 2024-07-27 22:19:29 +02:00
6 changed files with 122 additions and 110 deletions

View File

@ -1,6 +1,11 @@
/** @file bkp.c
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
//--includes--------------------------------------------------------------------
@ -28,7 +33,7 @@ static BkpRtcCallback rtc_callback;
//--public functions------------------------------------------------------------
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback)
enum BkpRtcIrq irq_mask, BkpRtcCallback callback)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
@ -50,8 +55,6 @@ void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
//configure core registers
rtc_regs->PRLH.PRL = prescaler >> 16;
rtc_regs->PRLL.PRL = prescaler;
rtc_regs->ALRH.RTC_ALR = alarm_tick >> 16;
rtc_regs->ALRL.RTC_ALR = alarm_tick;
//apply irq config
rtc_regs->CRH.word |= irq_mask & 0x7;
@ -68,6 +71,27 @@ void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
}
}
void bkp_set_rtc_alam(uint32_t offset)
{
uint32_t alarm = bkp_read_rtc() + offset;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//write alarm value
rtc_regs->ALRH.RTC_ALR = alarm >> 16;
rtc_regs->ALRL.RTC_ALR = alarm;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
}
uint32_t bkp_read_rtc(void)
{
//wait for core registers to be synchronized, immediate most of the time

View File

@ -1,6 +1,11 @@
/** @file bkp.h
* Module handling the Backup (BKP) domain functionalities.
*
* This module includes management of the Real Time Clock (RTC), Tamper
* protection system and a limited space (20 bytes) for persistent data storage
*
* All features present in this module stay running in standby mode / when
* no-longer powered, so long as VBAT is maintained
*/
#ifndef _BKP_H_
@ -58,11 +63,23 @@ typedef void (*BkpRtcCallback)(enum BkpRtcIrq src);
* Clocks must be enabled prior to calling this function
*
* Mulitple IRQs can be enabled and redirected to single callback. The alarm
* IRQ, triggered at the specified tick value can be rerouted to an exti line
* for wakeup from stanby, in wich case it doesn't need to be enabled here.
* IRQ, triggered at the tick value specified by bkp_set_rtc_alam() can be
* rerouted to an exti line for wakeup from stop and standby, in wich case it
* doesn't need to be enabled here.
*
* Ensure backup domain writes are enabled (see pwr_configure_bkp_write()) while
* calling this function
*/
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback);
enum BkpRtcIrq irq_mask, BkpRtcCallback callback);
/**
* Configure the alarm to trigger after the specified time in ticks, which can
* be viewed as an offset to the current time value. This offset is only precise
* to the tick and thus if the tick changes right after this function is
* called, the observed offset will be close to 1 tick short
*/
void bkp_set_rtc_alam(uint32_t offset);
/**
* Returns the current counter value of the RTC

View File

@ -11,7 +11,6 @@
#include "exti_regs.h"
#include "nvic.h"
#include "afio.h"
//--local definitions-----------------------------------------------------------
@ -24,13 +23,11 @@ static ExtiCallback callbacks[19];
//--public functions------------------------------------------------------------
void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
enum ExtiConfig config_mask, ExtiCallback callback)
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback)
{
exti_reset(line_mask);
afio_map_exti(line_mask, port);
//configure edge detections
if (config_mask & EXTI_CONFIG_RISING_EDGE) {
regs->RTSR.word |= line_mask;
@ -48,7 +45,7 @@ void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
regs->EMR.word |= line_mask;
if (callback) {
//register callbacks for each line selected
for (uint8_t i = 0; i < 16; ++i) {
for (uint8_t i = 0; i < 19; ++i) {
if (line_mask & (0x1 << i)) {
callbacks[i] = callback;
}
@ -66,6 +63,15 @@ void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
if (line_mask & 0x7c00) {
nvic_enable(NVIC_IRQ_EXTI15_10);
}
if (line_mask & EXTI_LINE_PVD) {
nvic_enable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_enable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_enable(NVIC_IRQ_USB_WAKEUP);
}
//enable irqs in last to avoid triggers during config
regs->IMR.word |= line_mask;
@ -94,56 +100,6 @@ void exti_reset(enum ExtiLine line_mask)
nvic_disable(NVIC_IRQ_EXTI15_10);
}
afio_map_exti(0xFFFF, 0x0);
}
void exti_configure_specific(enum ExtiLineSpecific line_mask,
enum ExtiConfig config_mask, ExtiCallback callback)
{
//reset is identical to normal lines
exti_reset_specific(line_mask);
//configure edge detections
if (config_mask & EXTI_CONFIG_RISING_EDGE) {
regs->RTSR.word |= line_mask;
} else {
regs->RTSR.word &= ~line_mask;
}
if (config_mask & EXTI_CONFIG_FALLING_EDGE) {
regs->FTSR.word |= line_mask;
} else {
regs->FTSR.word &= ~line_mask;
}
//reconfigure events/irqs
regs->EMR.word |= line_mask;
if (callback) {
//register callbacks for each line selected
for (uint8_t i = 0; i < 16; ++i) {
if (line_mask & (0x1 << i)) {
callbacks[i] = callback;
}
}
//enable interrupts lines in nvic
if (line_mask & EXTI_LINE_PVD) {
nvic_enable(NVIC_IRQ_PVD);
}
if (line_mask & EXTI_LINE_RTC) {
nvic_enable(NVIC_IRQ_RTC_ALARM);
}
if (line_mask & EXTI_LINE_USB) {
nvic_enable(NVIC_IRQ_USB_WAKEUP);
}
//enable irqs in last to avoid triggers during config
regs->IMR.word |= line_mask;
}
}
void exti_reset_specific(enum ExtiLineSpecific line_mask)
{
//disable events/irqs
regs->IMR.word &= ~line_mask;
regs->EMR.word &= ~line_mask;
@ -163,6 +119,7 @@ void exti_reset_specific(enum ExtiLineSpecific line_mask)
}
}
void exti_reset_peripheral(void)
{
//reset peripheral config
@ -182,8 +139,6 @@ void exti_reset_peripheral(void)
nvic_disable(NVIC_IRQ_PVD);
nvic_disable(NVIC_IRQ_RTC_ALARM);
nvic_disable(NVIC_IRQ_USB_WAKEUP);
afio_map_exti(0xFFFF, 0x0);
}
//--local functions-------------------------------------------------------------

View File

@ -10,16 +10,11 @@
//--includes--------------------------------------------------------------------
#include "stdint.h"
#include "stdbool.h"
#include "gpio.h"
//--type definitions------------------------------------------------------------
/**
* Available exti lines. These lines correspond to gpios
* Available exti lines. The numbered lines correspond to gpios while the
* remaining are directly mapped to peripherals
*/
enum ExtiLine {
EXTI_LINE_0 = (0x1 << 0),
@ -38,12 +33,6 @@ enum ExtiLine {
EXTI_LINE_13 = (0x1 << 13),
EXTI_LINE_14 = (0x1 << 14),
EXTI_LINE_15 = (0x1 << 15),
};
/**
* Available exti lines. These lines correspond to specific peripherals
*/
enum ExtiLineSpecific {
EXTI_LINE_PVD = (0x1 << 16),
EXTI_LINE_RTC = (0x1 << 17),
EXTI_LINE_USB = (0x1 << 18),
@ -64,43 +53,31 @@ typedef void (*ExtiCallback)(void);
//--functions-------------------------------------------------------------------
/**
* Configure lines on a single GPIO port. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time. Every line can only be
* configured for a single port, reconfiguring it will override the previous
* configuration. Each line is linked to the pins of the same id (ex : pin 1 for
* exti 1). When possible, it is recommanded to use the lowest id possible for
* better performance. The ExtiConfig enum can be used as mask. If no callback
* is specified, the interrupt won't be enabled, but an event will still be sent
* to wake the cpu up.
* Configure lines to call a single callback. The ExtiLine enum can be used as a
* mask to configure multiple lines at the same time.
*
* Note: wich port is linked to a line can be changed atfer the fact using
* afio_map_exti()
* Every numbered line must be linked to a gpio port using afio_map_exti(). Each
* line is linked to the pins of the same id (ex : pin 1 for exti 1). When
* possible, it is recommended to use the lowest id possible for better
* performance. Each pin must be configured independently through the gpio
* driver module
*
* The remaining lines are linked to specific peripherals which must be
* configured independently through the corresponding driver module.
*
* The ExtiConfig enum can be used as mask. If no callback is specified, the
* interrupt won't be enabled, but an event will still be sent to wake the cpu
* up.
*/
void exti_configure(enum ExtiLine line_mask, enum GpioPort port,
enum ExtiConfig config_mask, ExtiCallback callback);
void exti_configure(enum ExtiLine line_mask, enum ExtiConfig config_mask,
ExtiCallback callback);
/**
* Resets lines. The ExtiLine enum can be used as a mask to configure multiple
* lines at the same time
* Resets lines. The ExtiLine enum can be used as a mask to reset multiple lines
* at the same time
*/
void exti_reset(enum ExtiLine line_mask);
/**
* Configure lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
* can be used as a mask to configure multiple lines at the same time. The
* ExtiConfig enum can be used as mask. If no callback is specified, the
* interrupt won't be enabled, but an event will still be sent to wake the cpu
* up
*/
void exti_configure_specific(enum ExtiLineSpecific line_mask,
enum ExtiConfig config_mask, ExtiCallback callback);
/**
* Resets lines for specific, non-gpio peripherals. The ExtiLineSpecific enum
* can be used as a mask to configure multiple lines at the same time.
*/
void exti_reset_specific(enum ExtiLineSpecific line_mask);
/**
* Resets all lines. The exti peripheral is returned to its reset configuration
*/

25
openocd.cfg Normal file
View File

@ -0,0 +1,25 @@
# using a STM32f103CB wich has 128kB of flash instead of the more common 64KB
set CHIPNAME stm32f103CB
set FLASH_SIZE 0x20000
# load default configurations
source [find interface/stlink.cfg]
source [find target/stm32f1x.cfg]
# override examine-end event
$CHIPNAME.cpu configure -event examine-end {
# write DBGMCU_CR, disable all peripherals (timers, dmas, watchdogs while
# halted by debug. Trace is not affected
mmw 0xE0042004 0x7E3FFF07 0
}
reset_config srst_only srst_nogate connect_assert_srst
# inits debugging, from that point, commands can be used
init
# resets the target and halt it immediately afterward. Stops debug from being
# inacessible due to low-power states
reset halt

View File

@ -26,6 +26,10 @@
#include "task.h"
#include "error.h"
#include "../drv/stk.h"
#include "../drv/pwr.h"
#include "../drv/rcc.h"
#include "../drv/bkp.h"
#include "../drv/exti.h"
//--local definitions-----------------------------------------------------------
@ -51,7 +55,13 @@ static volatile uint32_t timestamp;
void task_start_scheduler(void)
{
stk_configure(1000, callback_stk);
//TODO: configure RTC
rcc_configure_lsi(true);
pwr_configure_bkp_write(true);
bkp_reset();
bkp_configure_rtc(1000, BKP_RTC_CLOCK_SRC_LSI, BKP_RTC_IRQ_NONE, nullptr);
pwr_configure_bkp_write(false);
exti_configure(EXTI_LINE_RTC, EXTI_CONFIG_RISING_EDGE, callback_rtc);
while (true) {
uint8_t triggers = stk_irq << 0 | rtc_irq << 1;
@ -65,10 +75,13 @@ void task_start_scheduler(void)
if (stk_needed) {
stk_start();
__asm("wfi");
pwr_sleep();
} else {
pwr_configure_bkp_write(true);
bkp_set_rtc_alam(1);
pwr_configure_bkp_write(false);
stk_stop();
//TODO: enter deep sleep
pwr_sleep();
}
}
}
@ -158,4 +171,5 @@ static void callback_stk(void)
static void callback_rtc(void)
{
rtc_irq = true;
timestamp = bkp_read_rtc() * 1000;
}