From fb1c11132f55d01563781f471157b7df7b233a58 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 28 Apr 2024 19:14:28 +0200 Subject: [PATCH 01/35] Write first API macros --- srv/task.c | 8 ++++++++ srv/task.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 srv/task.c create mode 100644 srv/task.h diff --git a/srv/task.c b/srv/task.c new file mode 100644 index 0000000..4a2221d --- /dev/null +++ b/srv/task.c @@ -0,0 +1,8 @@ +/** @file task.c + * Module handling the task creation and management + * + * The module provides an API to create, run and manage lightweight, stack-less + * threads (tasks). This system is based on protothreads, + * see https://dunkels.com/adam/pt/index.html + */ + diff --git a/srv/task.h b/srv/task.h new file mode 100644 index 0000000..f91b782 --- /dev/null +++ b/srv/task.h @@ -0,0 +1,52 @@ +/** @file task.h + * Module handling the task creation and management + * + * The module provides an API to create, run and manage lightweight, stack-less + * threads (tasks). This system is based on protothreads, + * see https://dunkels.com/adam/pt/index.html + */ + +#ifndef _task_h_ +#define _task_h_ + +//--includes-------------------------------------------------------------------- + +#include + + +//--functions------------------------------------------------------------------- + +#define TASK(fct_name) uint8_t fct_name(uint8_t __task_context) + +#define task_begin() do { \ + _TASK_COUNT_INIT; \ + switch (__task_context) { \ + } while (0) + +#define task_end() do { \ + } \ + return _TASK_COUNT_STOP; \ + while (0) + +#define task_wait_until(cond) _task_wait_until(cond, _TASK_COUNT_INCR) + + +//--internal_functions---------------------------------------------------------- + +#define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } +#define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) +#define _TASK_COUNT_STOP UINT8_MAX + +#define _task(fct_name) + +#define _task_wait_until(cond, count) do { \ + case (count): \ + if (!(cond)) { \ + return count; \ + } \ + /* fall through */ \ + while (0) + + +#endif //_task_h_ + From 7ba9063d021ef973131b0bf97393ef8d15d11c68 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 28 Apr 2024 19:43:37 +0200 Subject: [PATCH 02/35] Define systick's registers --- drv/stk_regs.h | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 drv/stk_regs.h diff --git a/drv/stk_regs.h b/drv/stk_regs.h new file mode 100644 index 0000000..5739f0d --- /dev/null +++ b/drv/stk_regs.h @@ -0,0 +1,90 @@ +/** @file stk_regs.h + * Module defining systick (STK) registers. + * + * Mainly made to be used by the stk module. It is recommanded to go through + * the functions provided by that module instead of directly using the registers + * defined here. + */ + +#ifndef _STK_REGS_H_ +#define _STK_REGS_H_ + +//--includes-------------------------------------------------------------------- + +#include "reg.h" + +#include + + +//--type definitions------------------------------------------------------------ + +#define STK_BASE_ADDRESS 0xE000E010 + +union STK_CTRL { + struct __attribute__((packed)) { + uint32_t ENABLE:1; + uint32_t TICKINT:1; + uint32_t CLKSOURCE:1; + uint32_t reserved1:13; + uint32_t COUNTFLAG:1; + uint32_t reserved2:15; + }; + uint32_t word; +}; + +#define STK_CTRL_ENABLE reg_def( 0, 1) +#define STK_CTRL_TICKINT reg_def( 1, 1) +#define STK_CTRL_CLKSOURCE reg_def( 2, 1) +#define STK_CTRL_reserved reg_def( 3, 13) +#define STK_CTRL_COUNTFLAG reg_def(16, 1) +#define STK_CTRL_reserved2 reg_def(17, 15) + +union STK_LOAD { + struct __attribute__((packed)) { + uint32_t RELOAD:24; + uint32_t reserved1:8; + }; + uint32_t word; +}; + +#define STK_LOAD_RELOAD reg_def( 0, 24) +#define STK_LOAD_reserved1 reg_def(24, 8) + +union STK_VAL { + struct __attribute__((packed)) { + uint32_t CURRENT:24; + uint32_t reserved1:8; + }; + uint32_t word; +}; + +#define STK_VAL_CURRENT reg_def( 0, 24) +#define STK_VAL_reserved1 reg_def(24, 8) + +union STK_CALIB { + struct __attribute__((packed)) { + uint32_t TENMS:24; + uint32_t reserved1:6; + uint32_t SKEW:1; + uint32_t NOREF:1; + }; + uint32_t word; +}; + +#define STK_CALIB_RELOAD reg_def( 0, 24) +#define STK_CALIB_reserved1 reg_def(24, 6) +#define STK_CALIB_SKEW reg_def(30, 1) +#define STK_CALIB_NOREF reg_def(31, 1) + +struct __attribute__((packed)) STK { + union STK_CTRL CTRL; + union STK_LOAD LOAD; + union STK_VAL VAL; + union STK_CALIB CALIB; +}; + + +//--functions------------------------------------------------------------------- + +#endif //_STK_REGS_H_ + From ddd05da6ebae0ef2aef61df964ac7c3d6c98d33d Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 28 Apr 2024 22:04:10 +0200 Subject: [PATCH 03/35] Implement systick module --- drv/stk.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drv/stk.h | 31 ++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 drv/stk.c create mode 100644 drv/stk.h diff --git a/drv/stk.c b/drv/stk.c new file mode 100644 index 0000000..6ac0e5d --- /dev/null +++ b/drv/stk.c @@ -0,0 +1,84 @@ +/** @file stk.c + * Module handling the system timer (systick or STK for short) + * + * The module provides functions to configure and use the system timer embedded + * in the cortex m core + */ + +//--includes-------------------------------------------------------------------- + +#include "stk.h" +#include "stk_regs.h" + +#include "rcc.h" + + +//--local definitions----------------------------------------------------------- + +static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS; + +//--local variables------------------------------------------------------------- + +static StkCallback callback; + + +//--public functions------------------------------------------------------------ + +uint32_t stk_configure(uint32_t period_us, StkCallback cb) +{ + stk_reset(); + + struct RccClocks clocks; + rcc_get_clocks(&clocks); + + uint32_t reload = period_us * (clocks.ahb_freq / 1000000 / 8); + if (reload < 1) { + //period is too small, try using the non-prescaled clock + reload = period_us * (clocks.ahb_freq / 1000000); + if (reload < 1) { + //period is still too small + return 1; + } + reg_set(regs->CTRL, STK_CTRL_CLKSOURCE); + } + reg_write(regs->LOAD, STK_LOAD_RELOAD, reload); + reg_set(regs->CTRL, STK_CTRL_TICKINT); + + callback = cb; + + return 0; +} + +void stk_reset(void) +{ + reg_reset(regs->CTRL, STK_CTRL_ENABLE); + reg_reset(regs->CTRL, STK_CTRL_TICKINT); + reg_reset(regs->CTRL, STK_CTRL_CLKSOURCE); + reg_reset(regs->CTRL, STK_CTRL_COUNTFLAG); + + reg_write(regs->LOAD, STK_LOAD_RELOAD, 0); + reg_write(regs->VAL, STK_VAL_CURRENT, 0); +} + +void stk_start(void) +{ + reg_set(regs->CTRL, STK_CTRL_ENABLE); +} + +void stk_stop(void) +{ + reg_reset(regs->CTRL, STK_CTRL_ENABLE); +} + +uint32_t stk_read(void) +{ + return regs->VAL.word & 0x00FFFFFF; +} + + +//--local functions------------------------------------------------------------- + +void hdr_sys_tick(void) +{ + callback(); +} diff --git a/drv/stk.h b/drv/stk.h new file mode 100644 index 0000000..3099ff1 --- /dev/null +++ b/drv/stk.h @@ -0,0 +1,31 @@ +/** @file stk.h + * Module handling the system timer (systick or STK for short) + * + * The module provides functions to configure and use the system timer embedded + * in the cortex m core + */ + +#ifndef _STK_H_ +#define _STK_H_ + +//--includes-------------------------------------------------------------------- + +#include + + +//--type definitions------------------------------------------------------------ + +typedef void (*StkCallback)(void); + + +//--functions------------------------------------------------------------------- + +uint32_t stk_configure(uint32_t period_us, StkCallback cb); +void stk_reset(void); +void stk_start(void); +void stk_stop(void); +uint32_t stk_read(void); + + +#endif //_STK_H_ + From 7e69bfd89c9c0b3659035871717d81ad9308a9ba Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 28 Apr 2024 22:10:15 +0200 Subject: [PATCH 04/35] Document systick module --- drv/stk.c | 3 +++ drv/stk.h | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drv/stk.c b/drv/stk.c index 6ac0e5d..d865738 100644 --- a/drv/stk.c +++ b/drv/stk.c @@ -17,6 +17,7 @@ static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS; + //--local variables------------------------------------------------------------- static StkCallback callback; @@ -80,5 +81,7 @@ uint32_t stk_read(void) void hdr_sys_tick(void) { + //clearing the pending bit in SCB_ICSR isn't needed, though I don't know why callback(); } + diff --git a/drv/stk.h b/drv/stk.h index 3099ff1..d5c5d1d 100644 --- a/drv/stk.h +++ b/drv/stk.h @@ -20,10 +20,34 @@ typedef void (*StkCallback)(void); //--functions------------------------------------------------------------------- +/** + * Configures the system timer to run at the specified period in µs and call the + * given callback when said period is reached. Due to the limited configuration + * options, 1.8s is the maximum period when running in speed preset (see rcc + * module). The maximum period can be substantially increased by reducing the + * core clock + */ uint32_t stk_configure(uint32_t period_us, StkCallback cb); + +/** + * Resets the system timer configuration, restoring the default configuration + * and stopping it + */ void stk_reset(void); + +/** + * Starts the system timer. The timer will run until stopped + */ void stk_start(void); + +/** + * Stops the system timer + */ void stk_stop(void); + +/** + * Read the current value of the timer's counter + */ uint32_t stk_read(void); From 432310a52dd2945ec70f12979540bf50b25db22b Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 30 Apr 2024 20:15:51 +0200 Subject: [PATCH 05/35] Implement task module For now, most code is temporary to validate that the system can work as envisionned. Optimisations and cleaning will be done shortly --- srv/task.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ srv/task.h | 82 +++++++++++++++++++++++++-------- 2 files changed, 196 insertions(+), 19 deletions(-) diff --git a/srv/task.c b/srv/task.c index 4a2221d..0c40a82 100644 --- a/srv/task.c +++ b/srv/task.c @@ -6,3 +6,136 @@ * see https://dunkels.com/adam/pt/index.html */ +//--includes-------------------------------------------------------------------- + +#include "task.h" +#include "../drv/stk.h" +#include "error.h" + + +//--local definitions----------------------------------------------------------- + +#define MAX_TASK_NB 10 + +struct TaskContext { + Task function; + uint32_t delay_ms; + uint8_t state; + uint8_t priority; +}; + +void task_callback(void); + + +//--local variables------------------------------------------------------------- + +static struct TaskContext task_list[MAX_TASK_NB]; +static uint8_t task_nb; + + +//--public functions------------------------------------------------------------ + +void task_start_scheduler(void) +{ + while (1) { + uint32_t delay = UINT32_MAX; + for (uint8_t priority = 0; priority < UINT8_MAX; ++priority) { + + bool task_runned = false; + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function != nullptr) { + if (task_list[i].priority == priority) { + if (task_list[i].delay_ms == 0) { + task_runned = true; + struct TaskReturn ret + = task_list[i].function(task_list[i].state); + if (ret.state == _TASK_COUNT_EXIT) { + task_list[i].function = nullptr; + } else { + task_list[i].delay_ms = ret.delay_ms; + task_list[i].state = ret.state; + } + } + if (delay > task_list[i].delay_ms) { + delay = task_list[i].delay_ms; + } + } + } + } + + if (task_runned) { + break; + } + } + + if (delay > 0) { + stk_configure(delay * 1000, task_callback); + stk_start(); + __asm("wfi"); + stk_stop(); + uint32_t stk_delay = stk_read(); + if (stk_delay != 0) { + delay = stk_delay; + } + + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function != nullptr) { + task_list[i].delay_ms -= delay; + } + } + } + } + + //never returns +} + +void task_start(Task task, uint8_t priority) +{ + for (uint8_t i = 0; i < MAX_TASK_NB; ++i) { + if (task_list[i].function == nullptr) { + + task_list[i].function = task; + task_list[i].delay_ms = 0; + task_list[i].state = 0; + task_list[i].priority = priority; + + ++task_nb; + return; + } + } + + error_trigger("task list is full"); +} + +void task_stop(Task task) +{ + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function == task) { + task_list[i].function(_TASK_COUNT_CLEANUP); + task_list[i].function = nullptr; + + return; + } + } + + error_trigger("task does not exist"); +} + +bool task_is_running(Task task) +{ + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function == task) { + return true; + } + } + + return false; +} + + + +//--local functions------------------------------------------------------------- + +void task_callback(void) { + stk_stop(); +} diff --git a/srv/task.h b/srv/task.h index f91b782..361da76 100644 --- a/srv/task.h +++ b/srv/task.h @@ -12,41 +12,85 @@ //--includes-------------------------------------------------------------------- #include +#include + + +//--type definitions------------------------------------------------------------ + +struct TaskReturn { + uint32_t delay_ms; + uint8_t state; +}; + +typedef struct TaskReturn(*Task)(uint8_t); //--functions------------------------------------------------------------------- -#define TASK(fct_name) uint8_t fct_name(uint8_t __task_context) +#define TASK(fct_name) struct TaskReturn fct_name(uint8_t __task_state) -#define task_begin() do { \ - _TASK_COUNT_INIT; \ - switch (__task_context) { \ - } while (0) +#define TASK_ENTRY \ + _TASK_COUNT_INIT; \ + switch (__task_state) { -#define task_end() do { \ - } \ - return _TASK_COUNT_STOP; \ - while (0) +#define TASK_CLEANUP \ + case (_TASK_COUNT_CLEANUP): \ + /* fall through */ -#define task_wait_until(cond) _task_wait_until(cond, _TASK_COUNT_INCR) +#define TASK_EXIT \ + } \ + return (struct TaskReturn){0, _TASK_COUNT_EXIT}; + +#define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) +#define TASK_SLEEP(delay_ms) _TASK_SLEEP(delay_ms, _TASK_COUNT_INCR) +#define TASK_WAIT_UNTIL(cond) _TASK_WAIT_UNTIL(cond, _TASK_COUNT_INCR) +#define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) + +void task_start_scheduler(void); + +void task_start(Task task, uint8_t priority); +void task_stop(Task task); +bool task_is_running(Task task); //--internal_functions---------------------------------------------------------- #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) -#define _TASK_COUNT_STOP UINT8_MAX +#define _TASK_COUNT_EXIT UINT8_MAX +#define _TASK_COUNT_CLEANUP (UINT8_MAX - 1) -#define _task(fct_name) +#define _TASK(fct_name) -#define _task_wait_until(cond, count) do { \ - case (count): \ - if (!(cond)) { \ - return count; \ - } \ - /* fall through */ \ - while (0) +#define _TASK_YIELD(count) do { \ + return (struct TaskReturn){0, count}; \ + case (count): \ + /* fall through */ \ + } while (0) +#define _TASK_SLEEP(delay_ms, count) do { \ + return (struct TaskReturn){delay_ms, count}; \ + case (count): \ + /* fall through */ \ + } while (0) + +#define _TASK_WAIT_UNTIL(cond, count) do { \ + case (count): \ + if (!(cond)) { \ + return (struct TaskReturn){0, count}; \ + } \ + /* fall through */ \ + } while (0) + +#define _TASK_EXECUTE(task, count) do { \ + task_start(Task task); \ + return (struct TaskReturn){0, count); \ + case (count): \ + if (task_is_running(task)) { \ + return (struct TaskReturn){0, count}; \ + } \ + /* fall through */ \ + } while (0) #endif //_task_h_ From 34fb4dac769b80ccc338cdacb816bcab4b0ed707 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 30 Apr 2024 20:17:58 +0200 Subject: [PATCH 06/35] Make stk_read function usable This function used to return the raw current value, but that exposes the prescaling used internaly --- drv/stk.c | 11 +++++++---- drv/stk.h | 4 ++-- srv/task.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drv/stk.c b/drv/stk.c index d865738..a86811f 100644 --- a/drv/stk.c +++ b/drv/stk.c @@ -21,6 +21,7 @@ static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS; //--local variables------------------------------------------------------------- static StkCallback callback; +static uint32_t prescaler; //--public functions------------------------------------------------------------ @@ -32,10 +33,12 @@ uint32_t stk_configure(uint32_t period_us, StkCallback cb) struct RccClocks clocks; rcc_get_clocks(&clocks); - uint32_t reload = period_us * (clocks.ahb_freq / 1000000 / 8); + uint32_t prescaler = (clocks.ahb_freq / 1000000 / 8); + uint32_t reload = period_us * prescaler; if (reload < 1) { //period is too small, try using the non-prescaled clock - reload = period_us * (clocks.ahb_freq / 1000000); + prescaler *= 8; + reload = period_us * prescaler; if (reload < 1) { //period is still too small return 1; @@ -71,9 +74,9 @@ void stk_stop(void) reg_reset(regs->CTRL, STK_CTRL_ENABLE); } -uint32_t stk_read(void) +uint32_t stk_read_us(void) { - return regs->VAL.word & 0x00FFFFFF; + return (regs->VAL.word & 0x00FFFFFF) / prescaler; } diff --git a/drv/stk.h b/drv/stk.h index d5c5d1d..9cdd685 100644 --- a/drv/stk.h +++ b/drv/stk.h @@ -46,9 +46,9 @@ void stk_start(void); void stk_stop(void); /** - * Read the current value of the timer's counter + * Read the current value of the timer's counter in µs */ -uint32_t stk_read(void); +uint32_t stk_read_us(void); #endif //_STK_H_ diff --git a/srv/task.c b/srv/task.c index 0c40a82..0baba14 100644 --- a/srv/task.c +++ b/srv/task.c @@ -73,7 +73,7 @@ void task_start_scheduler(void) stk_start(); __asm("wfi"); stk_stop(); - uint32_t stk_delay = stk_read(); + uint32_t stk_delay = stk_read_us(); if (stk_delay != 0) { delay = stk_delay; } From c09d2cda67a9cb4c9ff21c5c1a13162979dcf17c Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 14 May 2024 14:51:50 +0200 Subject: [PATCH 07/35] Remove priority parameter from tasks In the end, priorities are only usefull in preemptive systems. Here, it would only garentee the execution order, which we don't care about most of the time --- srv/task.c | 58 +++++++++++++++++++++++++++++------------------------- srv/task.h | 2 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/srv/task.c b/srv/task.c index 0baba14..72efc46 100644 --- a/srv/task.c +++ b/srv/task.c @@ -11,6 +11,7 @@ #include "task.h" #include "../drv/stk.h" #include "error.h" +#include "debug.h" //--local definitions----------------------------------------------------------- @@ -21,7 +22,6 @@ struct TaskContext { Task function; uint32_t delay_ms; uint8_t state; - uint8_t priority; }; void task_callback(void); @@ -39,36 +39,38 @@ void task_start_scheduler(void) { while (1) { uint32_t delay = UINT32_MAX; - for (uint8_t priority = 0; priority < UINT8_MAX; ++priority) { - bool task_runned = false; - for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function != nullptr) { - if (task_list[i].priority == priority) { - if (task_list[i].delay_ms == 0) { - task_runned = true; - struct TaskReturn ret - = task_list[i].function(task_list[i].state); - if (ret.state == _TASK_COUNT_EXIT) { - task_list[i].function = nullptr; - } else { - task_list[i].delay_ms = ret.delay_ms; - task_list[i].state = ret.state; - } - } - if (delay > task_list[i].delay_ms) { - delay = task_list[i].delay_ms; - } + bool task_runned = false; + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function != nullptr) { + if (task_list[i].delay_ms == 0) { + task_runned = true; + debug_trace("%u", 1); + debug_trace("%u", i + 2); + struct TaskReturn ret + = task_list[i].function(task_list[i].state); + debug_trace("%u", i + 2); + debug_trace("%u", 1); + if (ret.state == _TASK_COUNT_EXIT) { + task_list[i].function = nullptr; + } else { + task_list[i].delay_ms = ret.delay_ms; + task_list[i].state = ret.state; } } - } - - if (task_runned) { - break; + if (delay > task_list[i].delay_ms) { + delay = task_list[i].delay_ms; + } } } + if (task_runned) { + break; + } + if (delay > 0) { + debug_trace("%u", 1); + debug_trace("%u", 0); stk_configure(delay * 1000, task_callback); stk_start(); __asm("wfi"); @@ -83,13 +85,16 @@ void task_start_scheduler(void) task_list[i].delay_ms -= delay; } } + + debug_trace("%u", 0); + debug_trace("%u", 1); } } //never returns } -void task_start(Task task, uint8_t priority) +void task_start(Task task) { for (uint8_t i = 0; i < MAX_TASK_NB; ++i) { if (task_list[i].function == nullptr) { @@ -97,7 +102,6 @@ void task_start(Task task, uint8_t priority) task_list[i].function = task; task_list[i].delay_ms = 0; task_list[i].state = 0; - task_list[i].priority = priority; ++task_nb; return; @@ -133,9 +137,9 @@ bool task_is_running(Task task) } - //--local functions------------------------------------------------------------- void task_callback(void) { stk_stop(); } + diff --git a/srv/task.h b/srv/task.h index 361da76..435cca3 100644 --- a/srv/task.h +++ b/srv/task.h @@ -48,7 +48,7 @@ typedef struct TaskReturn(*Task)(uint8_t); void task_start_scheduler(void); -void task_start(Task task, uint8_t priority); +void task_start(Task task); void task_stop(Task task); bool task_is_running(Task task); From 7cb33f65a501e37ae25d434979615a1fa7d66f59 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 14 May 2024 15:03:18 +0200 Subject: [PATCH 08/35] Create new delay module --- srv/delay.c | 23 +++++++++++++++++++++++ srv/delay.h | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 srv/delay.c create mode 100644 srv/delay.h diff --git a/srv/delay.c b/srv/delay.c new file mode 100644 index 0000000..9ce5bf6 --- /dev/null +++ b/srv/delay.c @@ -0,0 +1,23 @@ +/** @file delay.c + * Module handling delays definitions and operations + * + * The module provides an API to delay the code execution with the most + * accuraccy possible, putting the system in sleep whenever possible. The RTC is + * required when using delays superior to a 1.5s. Accuraccy is only garenteed up + * to the unit being used (to the millisecond when delaying in ms, to the second + * when delaying in seconds) + */ + +//--includes-------------------------------------------------------------------- + +#include "delay.h" + + +//--local definitions----------------------------------------------------------- + +//--local variables------------------------------------------------------------- + +//--public functions------------------------------------------------------------ + +//--local functions------------------------------------------------------------- + diff --git a/srv/delay.h b/srv/delay.h new file mode 100644 index 0000000..7b6d46d --- /dev/null +++ b/srv/delay.h @@ -0,0 +1,23 @@ +/** @file delay.h + * Module handling delays definitions and operations + * + * The module provides an API to delay the code execution with the most + * accuraccy possible, putting the system in sleep whenever possible. The RTC is + * required when using delays superior to a 1.5s. Accuraccy is only garenteed up + * to the unit being used (to the millisecond when delaying in ms, to the second + * when delaying in seconds) + */ + +#ifndef _DELAY_H_ +#define _DELAY_H_ + +//--includes-------------------------------------------------------------------- + +//--type definitions------------------------------------------------------------ + +//--functions------------------------------------------------------------------- + +//--internal_functions---------------------------------------------------------- + +#endif //_DELAY_H_ + From b7951f22118b42eeebebf9506b4adb1fa87bc83d Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 6 Jul 2024 22:43:50 +0200 Subject: [PATCH 09/35] Simplify task module --- srv/task.c | 99 +++++++++++----------------------------------- srv/task.h | 114 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 93 insertions(+), 120 deletions(-) diff --git a/srv/task.c b/srv/task.c index 72efc46..d76b281 100644 --- a/srv/task.c +++ b/srv/task.c @@ -9,99 +9,50 @@ //--includes-------------------------------------------------------------------- #include "task.h" -#include "../drv/stk.h" #include "error.h" -#include "debug.h" //--local definitions----------------------------------------------------------- #define MAX_TASK_NB 10 -struct TaskContext { - Task function; - uint32_t delay_ms; - uint8_t state; -}; - -void task_callback(void); - //--local variables------------------------------------------------------------- -static struct TaskContext task_list[MAX_TASK_NB]; +static struct Task task_list[MAX_TASK_NB]; static uint8_t task_nb; //--public functions------------------------------------------------------------ -void task_start_scheduler(void) +void task_schedule(uint32_t elapsed_ms) { - while (1) { - uint32_t delay = UINT32_MAX; + for (uint8_t i = 0; i < task_nb; ++i) { + if (task_list[i].function != nullptr) { - bool task_runned = false; - for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function != nullptr) { - if (task_list[i].delay_ms == 0) { - task_runned = true; - debug_trace("%u", 1); - debug_trace("%u", i + 2); - struct TaskReturn ret - = task_list[i].function(task_list[i].state); - debug_trace("%u", i + 2); - debug_trace("%u", 1); - if (ret.state == _TASK_COUNT_EXIT) { - task_list[i].function = nullptr; - } else { - task_list[i].delay_ms = ret.delay_ms; - task_list[i].state = ret.state; - } + if (task_list[i].state.is_active + || task_list[i].state.delay <= 0) { + task_list[i].function(&task_list[i].state); + if (task_list[i].state.count == _TASK_COUNT_EXIT) { + task_list[i].function = nullptr; } - if (delay > task_list[i].delay_ms) { - delay = task_list[i].delay_ms; - } - } - } - - if (task_runned) { - break; - } - - if (delay > 0) { - debug_trace("%u", 1); - debug_trace("%u", 0); - stk_configure(delay * 1000, task_callback); - stk_start(); - __asm("wfi"); - stk_stop(); - uint32_t stk_delay = stk_read_us(); - if (stk_delay != 0) { - delay = stk_delay; + } else { + task_list[i].state.delay -= elapsed_ms; } - for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function != nullptr) { - task_list[i].delay_ms -= delay; - } - } - - debug_trace("%u", 0); - debug_trace("%u", 1); } } - - //never returns } -void task_start(Task task) +void task_start(TaskFunction function) { for (uint8_t i = 0; i < MAX_TASK_NB; ++i) { if (task_list[i].function == nullptr) { - task_list[i].function = task; - task_list[i].delay_ms = 0; - task_list[i].state = 0; + task_list[i].function = function; + task_list[i].state.delay = 0; + task_list[i].state.count = 0; + task_list[i].state.is_active = false; ++task_nb; return; @@ -111,11 +62,12 @@ void task_start(Task task) error_trigger("task list is full"); } -void task_stop(Task task) +void task_stop(TaskFunction function) { for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function == task) { - task_list[i].function(_TASK_COUNT_CLEANUP); + if (task_list[i].function == function) { + task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x7F; + task_list[i].function(&task_list[i].state); task_list[i].function = nullptr; return; @@ -125,10 +77,10 @@ void task_stop(Task task) error_trigger("task does not exist"); } -bool task_is_running(Task task) +bool task_is_running(TaskFunction function) { for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function == task) { + if (task_list[i].function == function) { return true; } } @@ -136,10 +88,3 @@ bool task_is_running(Task task) return false; } - -//--local functions------------------------------------------------------------- - -void task_callback(void) { - stk_stop(); -} - diff --git a/srv/task.h b/srv/task.h index 435cca3..4f5e208 100644 --- a/srv/task.h +++ b/srv/task.h @@ -17,79 +17,107 @@ //--type definitions------------------------------------------------------------ -struct TaskReturn { - uint32_t delay_ms; - uint8_t state; +struct TaskState { + int32_t delay; + uint8_t count:7; + uint8_t is_active:1; }; -typedef struct TaskReturn(*Task)(uint8_t); +typedef void(*TaskFunction)(struct TaskState*); + +struct Task { + TaskFunction function; + struct TaskState state; +}; //--functions------------------------------------------------------------------- -#define TASK(fct_name) struct TaskReturn fct_name(uint8_t __task_state) +#define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state) -#define TASK_ENTRY \ - _TASK_COUNT_INIT; \ - switch (__task_state) { +#define TASK_ENTRY \ + _TASK_COUNT_INIT; \ + switch (__task_state->count) { -#define TASK_CLEANUP \ - case (_TASK_COUNT_CLEANUP): \ +#define TASK_CLEANUP \ + case (_TASK_COUNT_CLEANUP): \ /* fall through */ -#define TASK_EXIT \ - } \ - return (struct TaskReturn){0, _TASK_COUNT_EXIT}; +#define TASK_EXIT \ + } \ + __task_state->count = _TASK_COUNT_EXIT; \ + return; + +#define TASK_TIMEOUT #define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) #define TASK_SLEEP(delay_ms) _TASK_SLEEP(delay_ms, _TASK_COUNT_INCR) -#define TASK_WAIT_UNTIL(cond) _TASK_WAIT_UNTIL(cond, _TASK_COUNT_INCR) +#define TASK_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR) +#define TASK_SLEEP_UNTIL(cond, delay_ms) \ + _TASK_SLEEP_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) -void task_start_scheduler(void); +void task_schedule(uint32_t elapsed_ms); -void task_start(Task task); -void task_stop(Task task); -bool task_is_running(Task task); +void task_declare(); + +void task_start(TaskFunction task); +void task_stop(TaskFunction task); +bool task_is_running(TaskFunction task); //--internal_functions---------------------------------------------------------- #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) -#define _TASK_COUNT_EXIT UINT8_MAX +#define _TASK_COUNT_EXIT (UINT8_MAX & 0x7F) #define _TASK_COUNT_CLEANUP (UINT8_MAX - 1) -#define _TASK(fct_name) - -#define _TASK_YIELD(count) do { \ - return (struct TaskReturn){0, count}; \ - case (count): \ - /* fall through */ \ +#define _TASK_YIELD(count_val) do { \ + __task_state->count = count_val; \ + return; \ + case (count_val): \ + /* fall through */ \ } while (0) -#define _TASK_SLEEP(delay_ms, count) do { \ - return (struct TaskReturn){delay_ms, count}; \ - case (count): \ - /* fall through */ \ +#define _TASK_SLEEP(delay_ms, count_val) do { \ + __task_state->count = count_val; \ + __task_state->delay = delay_ms; \ + return; \ + case (count_val): \ + /* fall through */ \ } while (0) -#define _TASK_WAIT_UNTIL(cond, count) do { \ - case (count): \ - if (!(cond)) { \ - return (struct TaskReturn){0, count}; \ - } \ - /* fall through */ \ +#define _TASK_YIELD_UNTIL(cond, count_val) do { \ + __task_state->count = count_val; \ + case (count_val): \ + if (!(cond)) { \ + return; \ + } \ + /* fall through */ \ } while (0) -#define _TASK_EXECUTE(task, count) do { \ - task_start(Task task); \ - return (struct TaskReturn){0, count); \ - case (count): \ - if (task_is_running(task)) { \ - return (struct TaskReturn){0, count}; \ - } \ - /* fall through */ \ +#define _TASK_SLEEP_UNTIL(cond, delay_ms, count_val) do { \ + __task_state->count = count_val; \ + __task_state->delay = delay_ms; \ + __task_state->is_active = true; \ + case (count_val): \ + if (!(cond) && __task_state->delay >= 0) { \ + return; \ + } \ + __task_state->is_active = false; \ + /* fall through */ \ + } while (0) + +#define _TASK_EXECUTE(task, count_val) do { \ + __task_state->count = count_val; \ + task_start(Task task); \ + return; \ + case (count_val): \ + if (task_is_running(task)) { \ + return; \ + } \ + /* fall through */ \ } while (0) #endif //_task_h_ From 173e16eb2e771b4aaee62d8d61b5c176bbdd8f40 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 9 Jul 2024 11:53:05 +0200 Subject: [PATCH 10/35] Add back task features in a simplified way --- srv/task.c | 84 +++++++++++++++++++++++++++++++++++++++++++----------- srv/task.h | 84 +++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 132 insertions(+), 36 deletions(-) diff --git a/srv/task.c b/srv/task.c index d76b281..54989cb 100644 --- a/srv/task.c +++ b/srv/task.c @@ -10,36 +10,50 @@ #include "task.h" #include "error.h" +#include "../drv/stk.h" //--local definitions----------------------------------------------------------- #define MAX_TASK_NB 10 +static bool execute_task(struct Task* restrict task, uint8_t triggers); +static void callback_stk(void); +static void callback_rtc(void); + //--local variables------------------------------------------------------------- static struct Task task_list[MAX_TASK_NB]; static uint8_t task_nb; +static volatile bool stk_irq; +static volatile bool rtc_irq; +static volatile uint32_t timestamp; //--public functions------------------------------------------------------------ -void task_schedule(uint32_t elapsed_ms) +void task_start_scheduler(void) { - for (uint8_t i = 0; i < task_nb; ++i) { - if (task_list[i].function != nullptr) { + stk_configure(1000, callback_stk); + //TODO: configure RTC - if (task_list[i].state.is_active - || task_list[i].state.delay <= 0) { - task_list[i].function(&task_list[i].state); - if (task_list[i].state.count == _TASK_COUNT_EXIT) { - task_list[i].function = nullptr; - } - } else { - task_list[i].state.delay -= elapsed_ms; - } + while (true) { + uint8_t triggers = stk_irq << 0 | rtc_irq << 1; + stk_irq = false; + rtc_irq = false; + bool stk_needed = false; + for (uint8_t i = 0; i < task_nb; ++i) { + stk_needed |= execute_task(&task_list[i], triggers); + } + + if (stk_needed) { + stk_start(); + __asm("wfi"); + } else { + stk_stop(); + //TODO: enter deep sleep } } } @@ -50,9 +64,8 @@ void task_start(TaskFunction function) if (task_list[i].function == nullptr) { task_list[i].function = function; - task_list[i].state.delay = 0; + task_list[i].state.timestamp = 0; task_list[i].state.count = 0; - task_list[i].state.is_active = false; ++task_nb; return; @@ -66,8 +79,8 @@ void task_stop(TaskFunction function) { for (uint8_t i = 0; i < task_nb; ++i) { if (task_list[i].function == function) { - task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x7F; - task_list[i].function(&task_list[i].state); + task_list[i].state.count = _TASK_COUNT_CLEANUP & 0x1F; + task_list[i].function(&task_list[i].state, timestamp); task_list[i].function = nullptr; return; @@ -88,3 +101,42 @@ bool task_is_running(TaskFunction function) return false; } + +//--local functions------------------------------------------------------------- + +static bool execute_task(struct Task* restrict task, uint8_t triggers) +{ + if (task->function != nullptr) { + if (task->state.trigger == TASK_TRIGGER_ANY) { + task->function(&task->state, timestamp); + } else { + if ((task->state.trigger & triggers) != 0) { + + if (task->state.timestamp <= timestamp) { + task->state.timestamp = 0; + } + + if ((task->state.timestamp == 0) || + task->state.timeout_mode) { + task->function(&task->state, + timestamp); + } + } + } + + return (task->state.trigger & TASK_TRIGGER_STK) != 0; + } + + return false; +} + +static void callback_stk(void) +{ + stk_irq = true; + ++timestamp; +} + +static void callback_rtc(void) +{ + rtc_irq = true; +} diff --git a/srv/task.h b/srv/task.h index 4f5e208..ff4f183 100644 --- a/srv/task.h +++ b/srv/task.h @@ -17,13 +17,21 @@ //--type definitions------------------------------------------------------------ -struct TaskState { - int32_t delay; - uint8_t count:7; - uint8_t is_active:1; +enum TaskTrigger { + TASK_TRIGGER_ANY, + TASK_TRIGGER_STK, + TASK_TRIGGER_RTC, + TASK_TRIGGER_BOTH, }; -typedef void(*TaskFunction)(struct TaskState*); +struct TaskState { + uint32_t timestamp; + uint8_t count:5; + enum TaskTrigger trigger:2; + uint8_t timeout_mode:1; +}; + +typedef void(*TaskFunction)(struct TaskState*, uint32_t); struct Task { TaskFunction function; @@ -33,10 +41,12 @@ struct Task { //--functions------------------------------------------------------------------- -#define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state) +#define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state, \ + uint32_t __task_time) #define TASK_ENTRY \ _TASK_COUNT_INIT; \ + (void*) __task_time; \ switch (__task_state->count) { #define TASK_CLEANUP \ @@ -45,19 +55,22 @@ struct Task { #define TASK_EXIT \ } \ - __task_state->count = _TASK_COUNT_EXIT; \ + __task_state->count = _TASK_COUNT_EXIT & 0x1F; \ return; -#define TASK_TIMEOUT +#define TASK_TIMEOUT (__task_state->timeout == 0) #define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) -#define TASK_SLEEP(delay_ms) _TASK_SLEEP(delay_ms, _TASK_COUNT_INCR) +#define TASK_PAUSE(delay_ms) _TASK_PAUSE(delay_ms, _TASK_COUNT_INCR) +#define TASK_SLEEP(delay_s) _TASK_SLEEP(delay_s, _TASK_COUNT_INCR) #define TASK_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR) -#define TASK_SLEEP_UNTIL(cond, delay_ms) \ - _TASK_SLEEP_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) +#define TASK_PAUSE_UNTIL(cond, delay_ms) \ + _TASK_PAUSE_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) +#define TASK_SLEEP_UNTIL(cond, delay_s) \ + _TASK_SLEEP_UNTIL(cond, delay_s, _TASK_COUNT_INCR) #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) -void task_schedule(uint32_t elapsed_ms); +void task_start_scheduler(void); void task_declare(); @@ -70,19 +83,30 @@ bool task_is_running(TaskFunction task); #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) -#define _TASK_COUNT_EXIT (UINT8_MAX & 0x7F) +#define _TASK_COUNT_EXIT (UINT8_MAX & 0x3F) #define _TASK_COUNT_CLEANUP (UINT8_MAX - 1) #define _TASK_YIELD(count_val) do { \ __task_state->count = count_val; \ + __task_state->trigger = TASK_TRIGGER_ANY; \ return; \ case (count_val): \ /* fall through */ \ } while (0) -#define _TASK_SLEEP(delay_ms, count_val) do { \ +#define _TASK_PAUSE(delay_ms, count_val) do { \ __task_state->count = count_val; \ - __task_state->delay = delay_ms; \ + __task_state->timestamp = __task_time + delay_ms; \ + __task_state->trigger = TASK_TRIGGER_STK; \ + return; \ + case (count_val): \ + /* fall through */ \ + } while (0) + +#define _TASK_SLEEP(delay_s, count_val) do { \ + __task_state->count = count_val; \ + __task_state->timestamp = __task_time + delay_s * 1000; \ + __task_state->trigger = TASK_TRIGGER_RTC; \ return; \ case (count_val): \ /* fall through */ \ @@ -90,6 +114,7 @@ bool task_is_running(TaskFunction task); #define _TASK_YIELD_UNTIL(cond, count_val) do { \ __task_state->count = count_val; \ + __task_state->trigger = TASK_TRIGGER_ANY; \ case (count_val): \ if (!(cond)) { \ return; \ @@ -97,20 +122,39 @@ bool task_is_running(TaskFunction task); /* fall through */ \ } while (0) -#define _TASK_SLEEP_UNTIL(cond, delay_ms, count_val) do { \ +#define _TASK_PAUSE_UNTIL(cond, delay_ms, count_val) do { \ __task_state->count = count_val; \ - __task_state->delay = delay_ms; \ - __task_state->is_active = true; \ + __task_state->timestamp = __task_time + delay_ms; \ + __task_state->trigger = TASK_TRIGGER_STK; \ + __task_state->timeout_mode = true; \ + } \ case (count_val): \ - if (!(cond) && __task_state->delay >= 0) { \ + if (!(cond) && __task_state->timestamp != 0) { \ return; \ + } else { \ + __task_state->timeout_mode = false; \ + } \ + /* fall through */ \ + } while (0) + +#define _TASK_SLEEP_UNTIL(cond, delay_s, count_val) do { \ + __task_state->count = count_val; \ + __task_state->timestamp = __taks_time + delay_s * 1000; \ + __task_state->trigger = TASK_TRIGGER_RTC; \ + __task_state->timeout_mode = true; \ + } \ + case (count_val): \ + if (!(cond) && __task_state->timestamp != 0) { \ + return; \ + } else { \ + __task_state->timeout_mode = false; \ } \ - __task_state->is_active = false; \ /* fall through */ \ } while (0) #define _TASK_EXECUTE(task, count_val) do { \ __task_state->count = count_val; \ + __task_state->trigger = TASK_TRIGGER_ANY; \ task_start(Task task); \ return; \ case (count_val): \ From dd1756221d45e6b6d0b83f743b1780552e939552 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 9 Jul 2024 21:46:15 +0200 Subject: [PATCH 11/35] Fix typo in task macros --- srv/task.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/srv/task.h b/srv/task.h index ff4f183..4eb822b 100644 --- a/srv/task.h +++ b/srv/task.h @@ -127,7 +127,6 @@ bool task_is_running(TaskFunction task); __task_state->timestamp = __task_time + delay_ms; \ __task_state->trigger = TASK_TRIGGER_STK; \ __task_state->timeout_mode = true; \ - } \ case (count_val): \ if (!(cond) && __task_state->timestamp != 0) { \ return; \ @@ -142,7 +141,6 @@ bool task_is_running(TaskFunction task); __task_state->timestamp = __taks_time + delay_s * 1000; \ __task_state->trigger = TASK_TRIGGER_RTC; \ __task_state->timeout_mode = true; \ - } \ case (count_val): \ if (!(cond) && __task_state->timestamp != 0) { \ return; \ From 93b383be494d20fca4e60bd1ed7d63acaa7de22a Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 9 Jul 2024 22:07:35 +0200 Subject: [PATCH 12/35] Add API to access task's system time --- srv/task.c | 6 +++++- srv/task.h | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/srv/task.c b/srv/task.c index 54989cb..c58e89e 100644 --- a/srv/task.c +++ b/srv/task.c @@ -58,6 +58,11 @@ void task_start_scheduler(void) } } +uint32_t task_current_time(void) +{ + return timestamp; +} + void task_start(TaskFunction function) { for (uint8_t i = 0; i < MAX_TASK_NB; ++i) { @@ -101,7 +106,6 @@ bool task_is_running(TaskFunction function) return false; } - //--local functions------------------------------------------------------------- static bool execute_task(struct Task* restrict task, uint8_t triggers) diff --git a/srv/task.h b/srv/task.h index 4eb822b..d242b3a 100644 --- a/srv/task.h +++ b/srv/task.h @@ -71,8 +71,7 @@ struct Task { #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) void task_start_scheduler(void); - -void task_declare(); +uint32_t task_current_time(void); void task_start(TaskFunction task); void task_stop(TaskFunction task); From d5c70a3a049e087716b0cb0e9abf39c117f36586 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 10 Jul 2024 21:54:23 +0200 Subject: [PATCH 13/35] Document the task module --- srv/task.c | 17 ++++++- srv/task.h | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 142 insertions(+), 5 deletions(-) diff --git a/srv/task.c b/srv/task.c index c58e89e..818a8b5 100644 --- a/srv/task.c +++ b/srv/task.c @@ -1,9 +1,24 @@ -/** @file task.c +/** @file task.h * Module handling the task creation and management * * The module provides an API to create, run and manage lightweight, stack-less * threads (tasks). This system is based on protothreads, * see https://dunkels.com/adam/pt/index.html + * + * Task can be viewed as a lightweight, somewhat restricted, cooperative OS. + * Tasks are runned on every events. Since the RTC is enabled by the scheduler, + * every task should be run at least once per second. If at least one task is + * currently paused, the systick is enabled and all tasks are updated every + * millisecond + * + * State machine should mainly yield (see TASK_YIELD) while time sensitive + * applications should pause (see TASK_PAUSE) instead. This configuration allows + * state machines to be updated every time something changes in the system while + * allowing the cpu to enter low power mode when possible. When time sensitive + * applications are paused, they cause the systick to start which stops the cpu + * from entering low power but making sure that the task is polled quickly + * enough. Tasks requiring longer delay and less sensitive to timings can sleep + * (see TASK_SLEEP) instead, which relies on the RTC rather than the systick */ //--includes-------------------------------------------------------------------- diff --git a/srv/task.h b/srv/task.h index d242b3a..696a6dd 100644 --- a/srv/task.h +++ b/srv/task.h @@ -4,6 +4,21 @@ * The module provides an API to create, run and manage lightweight, stack-less * threads (tasks). This system is based on protothreads, * see https://dunkels.com/adam/pt/index.html + * + * Task can be viewed as a lightweight, somewhat restricted, cooperative OS. + * Tasks are runned on every events. Since the RTC is enabled by the scheduler, + * every task should be run at least once per second. If at least one task is + * currently paused, the systick is enabled and all tasks are updated every + * millisecond + * + * State machine should mainly yield (see TASK_YIELD) while time sensitive + * applications should pause (see TASK_PAUSE) instead. This configuration allows + * state machines to be updated every time something changes in the system while + * allowing the cpu to enter low power mode when possible. When time sensitive + * applications are paused, they cause the systick to start which stops the cpu + * from entering low power but making sure that the task is polled quickly + * enough. Tasks requiring longer delay and less sensitive to timings can sleep + * (see TASK_SLEEP) instead, which relies on the RTC rather than the systick */ #ifndef _task_h_ @@ -17,6 +32,9 @@ //--type definitions------------------------------------------------------------ +/** + * Available triggers for a task + */ enum TaskTrigger { TASK_TRIGGER_ANY, TASK_TRIGGER_STK, @@ -24,15 +42,26 @@ enum TaskTrigger { TASK_TRIGGER_BOTH, }; +/** + * State of a task at any given time. Every single task is described by such a + * struct + */ struct TaskState { - uint32_t timestamp; - uint8_t count:5; - enum TaskTrigger trigger:2; - uint8_t timeout_mode:1; + uint32_t timestamp; //timestamp at wich to wakeup the task, if any + uint8_t count:5; //task counter: active step of task + enum TaskTrigger trigger:2; //triggers on wich to execute the task + uint8_t timeout_mode:1; //whether the timestamp is a timeout or a delay }; +/** + * Function prototype of tasks + */ typedef void(*TaskFunction)(struct TaskState*, uint32_t); +/** + * Full definition of a task. Contains the function supporting the task as well + * as the state of said task + */ struct Task { TaskFunction function; struct TaskState state; @@ -41,40 +70,133 @@ struct Task { //--functions------------------------------------------------------------------- +/** + * Task declaration macro, to be used to declare and define a task instead of a + * regular function declaration/defintion + */ #define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state, \ uint32_t __task_time) +/** + * Task entry macro, must be present at the begin of every task. Setup code to + * be run indepently of the task state may be put before that (static variables, + * init code, ...) + */ #define TASK_ENTRY \ _TASK_COUNT_INIT; \ (void*) __task_time; \ switch (__task_state->count) { +/** + * Task cleanup macro. Option, can be use right before TASK_EXIT. This step + * will be executed before exiting the task when task_stop() is called. As the + * name suggest, this is mainly usefull to implement cleanup code and allow for + * gracefull shutdowns + */ #define TASK_CLEANUP \ case (_TASK_COUNT_CLEANUP): \ /* fall through */ +/** + * Tasks exit macro, must be present at the end of every task. Any code written + * after that will never be executed + */ #define TASK_EXIT \ } \ __task_state->count = _TASK_COUNT_EXIT & 0x1F; \ return; +/** + * Returns whether the task was timed-out or not. This macro can be used after + * TASK_PAUSE_UNTIL and TASK_SLEEP_UNTIL to know if the task resumed because of + * the condition or because of the timeout. Does not correspond to anything + * when called after any other step + */ #define TASK_TIMEOUT (__task_state->timeout == 0) +/** + * Give up the cpu, allowing the other tasks to run. The task will resume at the + * next event. Between events, the cpu can enter various power saving states + * depending on the other tasks running + */ #define TASK_YIELD() _TASK_YIELD(_TASK_COUNT_INCR) + +/** + * Suspend the task for the specified amount of milliseconds. The systick will + * remain active while the task is suspended to provide milliseconds counting, + * limiting the ability of the cpu to save power + */ #define TASK_PAUSE(delay_ms) _TASK_PAUSE(delay_ms, _TASK_COUNT_INCR) + +/** + * Suspend the task for the specified amount of seconds. The RTC will be used to + * provide seconds counting. If no other tasks requires it, the systick is + * disabled to save more power + */ #define TASK_SLEEP(delay_s) _TASK_SLEEP(delay_s, _TASK_COUNT_INCR) + +/** + * Execute TASK_YIELD until the provided condition is reached. The condition + * will be checked on every event + */ #define TASK_YIELD_UNTIL(cond) _TASK_YIELD_UNTIL(cond, _TASK_COUNT_INCR) + +/** + * Execute TASK_PAUSE until either the condition or the delay is reached. + * TASK_TIMEOUT can be used to know what cause the task to resume. The condition + * will be checked every millisecond + */ #define TASK_PAUSE_UNTIL(cond, delay_ms) \ _TASK_PAUSE_UNTIL(cond, delay_ms, _TASK_COUNT_INCR) + +/** + * Execute TASK_SLEEP until either the condition or the delay is reached. + * TASK_TIMEOUT can be used to know what cause the task to resume. The condition + * will be checked every seconds + */ #define TASK_SLEEP_UNTIL(cond, delay_s) \ _TASK_SLEEP_UNTIL(cond, delay_s, _TASK_COUNT_INCR) + +/** + * Execute the specified task, suspending the current one until the task exits + */ #define TASK_EXECUTE(task) _TASK_EXECUTE(task, _TASK_COUNT_INCR) +/** + * Starts the task scheduler and run it until the system is shutdown. This + * function never returns. + * + * All tasks started using task_start() are run according to their current + * state (see TASK_* macros). Since this system is cooperative, the scheduler + * does not preempt the tasks when running. The RTC is automatically configured + * and started to provide events every seconds. The systick is automatically + * started and stop to provide events every milliseconds when needed + */ void task_start_scheduler(void); + +/** + * Returns the current system time. The epoc is undefined. The time is provided + * in milliseconds, though the millisecond precision is only available while the + * systick is running (at least one task paused) + */ uint32_t task_current_time(void); +/** + * Starts the specified task. The task will only trully be runned after + * task_start_scheduler() is called. + * A task already started will be left as-is + */ void task_start(TaskFunction task); + +/** + * Stops the specified task. The task's cleanup state will be executed before + * it exits + */ void task_stop(TaskFunction task); + +/** + * Returns whether the specified task is currently running or not + */ bool task_is_running(TaskFunction task); From 5e4d87474af2dd478507f5963b6996de57ebd2fc Mon Sep 17 00:00:00 2001 From: Steins7 Date: Wed, 10 Jul 2024 23:16:49 +0200 Subject: [PATCH 14/35] Fix major reg bitfield issue A while back, macros had to be put in place to avoid letting the compiler directly use the bitfields. This was necessary because the compiler used strb instruction which only write bytes. On the AHB bus, byte writes are transformed into word writes by repeating the byte, which caused mayhem in the registers. After a lot of research, turns out the packed attribute stops the compiler from does optimal (word) writes and isn't needed anyway. Removing them fixes the issue --- drv/afio_regs.h | 16 ++-- drv/dma.c | 32 +++---- drv/dma_regs.h | 91 ++------------------ drv/exti.c | 16 ++-- drv/exti_regs.h | 142 ++----------------------------- drv/flash.c | 8 +- drv/flash_regs.h | 26 ++---- drv/gpio_regs.h | 18 ++-- drv/nvic_regs.h | 4 +- drv/rcc.c | 42 +++++----- drv/rcc_regs.h | 213 +++-------------------------------------------- drv/reg.h | 15 ---- drv/stk.c | 22 ++--- drv/stk_regs.h | 30 ++----- drv/usart.c | 38 ++++----- drv/usart_regs.h | 81 ++---------------- 16 files changed, 140 insertions(+), 654 deletions(-) delete mode 100644 drv/reg.h diff --git a/drv/afio_regs.h b/drv/afio_regs.h index aa34561..fcf906e 100644 --- a/drv/afio_regs.h +++ b/drv/afio_regs.h @@ -19,7 +19,7 @@ #define AFIO_BASE_ADDRESS 0x40010000 union EVCR { - struct __attribute__((packed)) { + struct { uint32_t PIN:4; uint32_t PORT:3; uint32_t EVOE:1; @@ -29,7 +29,7 @@ union EVCR { }; union MAPR { - struct __attribute__((packed)) { + struct { uint32_t SPI1_REMAP:1; uint32_t I2C1_REMAP:1; uint32_t USART1_REMAP:1; @@ -54,7 +54,7 @@ union MAPR { }; union EXTICR1 { - struct __attribute__((packed)) { + struct { uint32_t EXTI0:4; uint32_t EXTI1:4; uint32_t EXTI2:4; @@ -65,7 +65,7 @@ union EXTICR1 { }; union EXTICR2 { - struct __attribute__((packed)) { + struct { uint32_t EXTI4:4; uint32_t EXTI5:4; uint32_t EXTI6:4; @@ -76,7 +76,7 @@ union EXTICR2 { }; union EXTICR3 { - struct __attribute__((packed)) { + struct { uint32_t EXTI8:4; uint32_t EXTI9:4; uint32_t EXTI10:4; @@ -87,7 +87,7 @@ union EXTICR3 { }; union EXTICR4 { - struct __attribute__((packed)) { + struct { uint32_t EXTI12:4; uint32_t EXTI13:4; uint32_t EXTI14:4; @@ -98,7 +98,7 @@ union EXTICR4 { }; union MAPR2 { - struct __attribute__((packed)) { + struct { uint32_t reserved1:5; uint32_t TIM9_REMAP:1; uint32_t TIM10_REMAP:1; @@ -111,7 +111,7 @@ union MAPR2 { uint32_t word; }; -struct __attribute__((packed)) AFIO { +struct AFIO { union EVCR EVCR; union MAPR MAPR; union EXTICR1 EXTICR1; diff --git a/drv/dma.c b/drv/dma.c index 7d68b09..e33ab88 100644 --- a/drv/dma.c +++ b/drv/dma.c @@ -121,13 +121,13 @@ void dma_stop(enum DmaPeriph dma, enum DmaChannel channel) { switch (dma) { case DMA_PERIPH_1: - reg_reset(dma1->CHANNELS[channel].CCR, DMA_CCR_EN); + dma1->CHANNELS[channel].CCR.EN = 0; if (dma1_callbacks[channel]) { nvic_disable(NVIC_IRQ_DMA1_CHANNEL1 + channel); } break; case DMA_PERIPH_2: - reg_reset(dma2->CHANNELS[channel].CCR, DMA_CCR_EN); + dma2->CHANNELS[channel].CCR.EN; if (dma2_callbacks[channel]) { nvic_disable(NVIC_IRQ_DMA2_CHANNEL1 + channel); } @@ -207,11 +207,11 @@ static void start_dma(volatile struct DMA* dma, enum DmaChannel channel, volatile struct DMA_CHANNEL* regs = &dma->CHANNELS[channel]; //registers should already be configured, apply transfer config - reg_write(regs->CNDTR, DMA_CNDTR_NDT, size); + regs->CNDTR.NDT = size; regs->CMAR = (uint32_t)mem; //only start transfer when everything is configured - reg_set(regs->CCR, DMA_CCR_EN); + regs->CCR.EN = 1; } //--ISRs------------------------------------------------------------------------ @@ -221,7 +221,7 @@ void hdr_dma1_channel1(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL1); enum DmaIRQSource src = (dma1->IFCR.word >> 1) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF1); + dma1->IFCR.CGIF1 = 1; dma1_callbacks[0](src, dma1_cb_params[0]); } @@ -231,7 +231,7 @@ void hdr_dma1_channel2(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL2); enum DmaIRQSource src = (dma1->IFCR.word >> 5) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF2); + dma1->IFCR.CGIF2 = 1; dma1_callbacks[1](src, dma1_cb_params[1]); } @@ -241,7 +241,7 @@ void hdr_dma1_channel3(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL3); enum DmaIRQSource src = (dma1->IFCR.word >> 9) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF3); + dma1->IFCR.CGIF3 = 1; dma1_callbacks[2](src, dma1_cb_params[2]); } @@ -251,7 +251,7 @@ void hdr_dma1_channel4(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL4); enum DmaIRQSource src = (dma1->IFCR.word >> 13) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF4); + dma1->IFCR.CGIF4 = 1; dma1_callbacks[3](src, dma1_cb_params[3]); } @@ -261,7 +261,7 @@ void hdr_dma1_channel5(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL5); enum DmaIRQSource src = (dma1->IFCR.word >> 17) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF5); + dma1->IFCR.CGIF5 = 1; dma1_callbacks[4](src, dma1_cb_params[4]); } @@ -271,7 +271,7 @@ void hdr_dma1_channel6(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL6); enum DmaIRQSource src = (dma1->IFCR.word >> 21) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF6); + dma1->IFCR.CGIF6 = 1; dma1_callbacks[5](src, dma1_cb_params[5]); } @@ -281,7 +281,7 @@ void hdr_dma1_channel7(void) nvic_clear_pending(NVIC_IRQ_DMA1_CHANNEL7); enum DmaIRQSource src = (dma1->IFCR.word >> 25) & 0x7; - reg_set(dma1->IFCR, DMA_IFCR_CGIF7); + dma1->IFCR.CGIF7 = 1; dma1_callbacks[6](src, dma1_cb_params[6]); } @@ -291,7 +291,7 @@ void hdr_dma2_channel1(void) nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL1); enum DmaIRQSource src = (dma2->IFCR.word >> 1) & 0x7; - reg_set(dma2->IFCR, DMA_IFCR_CGIF1); + dma2->IFCR.CGIF1 = 1; dma2_callbacks[0](src, dma2_cb_params[0]); } @@ -301,7 +301,7 @@ void hdr_dma2_channel2(void) nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL2); enum DmaIRQSource src = (dma2->IFCR.word >> 5) & 0x7; - reg_set(dma2->IFCR, DMA_IFCR_CGIF2); + dma2->IFCR.CGIF2 = 1; dma2_callbacks[1](src, dma2_cb_params[1]); } @@ -311,7 +311,7 @@ void hdr_dma2_channel3(void) nvic_clear_pending(NVIC_IRQ_DMA2_CHANNEL3); enum DmaIRQSource src = (dma2->IFCR.word >> 9) & 0x7; - reg_set(dma2->IFCR, DMA_IFCR_CGIF3); + dma2->IFCR.CGIF3 = 1; dma2_callbacks[2](src, dma2_cb_params[2]); } @@ -322,13 +322,13 @@ void hdr_dma2_channel4_5(void) enum DmaIRQSource src = (dma2->IFCR.word >> 13) & 0x7; if (src != 0) { - reg_set(dma2->IFCR, DMA_IFCR_CGIF4); + dma2->IFCR.CGIF4 = 1; dma1_callbacks[3](src, dma2_cb_params[3]); } src = (dma2->IFCR.word >> 17) & 0x7; if (src != 0) { - reg_set(dma2->IFCR, DMA_IFCR_CGIF5); + dma2->IFCR.CGIF5 = 1; dma1_callbacks[4](src, dma2_cb_params[4]); } } diff --git a/drv/dma_regs.h b/drv/dma_regs.h index bfbb8f9..e343e6f 100644 --- a/drv/dma_regs.h +++ b/drv/dma_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include "stdint.h" @@ -22,7 +20,7 @@ #define DMA2_BASE_ADDRESS 0x40020400 union DMA_ISR { - struct __attribute__((packed)) { + struct { uint32_t GIF1:1; uint32_t TCIF1:1; uint32_t HTIF1:1; @@ -56,38 +54,8 @@ union DMA_ISR { uint32_t word; }; -#define DMA_ISR_GIF1 reg_def( 0, 1) -#define DMA_ISR_TCIF1 reg_def( 1, 1) -#define DMA_ISR_HTIF1 reg_def( 2, 1) -#define DMA_ISR_TEIF1 reg_def( 3, 1) -#define DMA_ISR_GIF2 reg_def( 4, 1) -#define DMA_ISR_TCIF2 reg_def( 5, 1) -#define DMA_ISR_HTIF2 reg_def( 6, 1) -#define DMA_ISR_TEIF2 reg_def( 7, 1) -#define DMA_ISR_GIF3 reg_def( 8, 1) -#define DMA_ISR_TCIF3 reg_def( 9, 1) -#define DMA_ISR_HTIF3 reg_def(10, 1) -#define DMA_ISR_TEIF3 reg_def(11, 1) -#define DMA_ISR_GIF4 reg_def(12, 1) -#define DMA_ISR_TCIF4 reg_def(13, 1) -#define DMA_ISR_HTIF4 reg_def(14, 1) -#define DMA_ISR_TEIF4 reg_def(15, 1) -#define DMA_ISR_GIF5 reg_def(16, 1) -#define DMA_ISR_TCIF5 reg_def(17, 1) -#define DMA_ISR_HTIF5 reg_def(18, 1) -#define DMA_ISR_TEIF5 reg_def(19, 1) -#define DMA_ISR_GIF6 reg_def(20, 1) -#define DMA_ISR_TCIF6 reg_def(21, 1) -#define DMA_ISR_HTIF6 reg_def(22, 1) -#define DMA_ISR_TEIF6 reg_def(23, 1) -#define DMA_ISR_GIF7 reg_def(24, 1) -#define DMA_ISR_TCIF7 reg_def(25, 1) -#define DMA_ISR_HTIF7 reg_def(26, 1) -#define DMA_ISR_TEIF7 reg_def(27, 1) -#define DMA_ISR_reserved1 reg_def(28, 4) - union DMA_IFCR { - struct __attribute__((packed)) { + struct { uint32_t CGIF1:1; uint32_t CTCIF1:1; uint32_t CHTIF1:1; @@ -121,38 +89,8 @@ union DMA_IFCR { uint32_t word; }; -#define DMA_IFCR_CGIF1 reg_def( 0, 1) -#define DMA_IFCR_CTCIF1 reg_def( 1, 1) -#define DMA_IFCR_CHTIF1 reg_def( 2, 1) -#define DMA_IFCR_CTEIF1 reg_def( 3, 1) -#define DMA_IFCR_CGIF2 reg_def( 4, 1) -#define DMA_IFCR_CTCIF2 reg_def( 5, 1) -#define DMA_IFCR_CHTIF2 reg_def( 6, 1) -#define DMA_IFCR_CTEIF2 reg_def( 7, 1) -#define DMA_IFCR_CGIF3 reg_def( 8, 1) -#define DMA_IFCR_CTCIF3 reg_def( 9, 1) -#define DMA_IFCR_CHTIF3 reg_def(10, 1) -#define DMA_IFCR_CTEIF3 reg_def(11, 1) -#define DMA_IFCR_CGIF4 reg_def(12, 1) -#define DMA_IFCR_CTCIF4 reg_def(13, 1) -#define DMA_IFCR_CHTIF4 reg_def(14, 1) -#define DMA_IFCR_CTEIF4 reg_def(15, 1) -#define DMA_IFCR_CGIF5 reg_def(16, 1) -#define DMA_IFCR_CTCIF5 reg_def(17, 1) -#define DMA_IFCR_CHTIF5 reg_def(18, 1) -#define DMA_IFCR_CTEIF5 reg_def(19, 1) -#define DMA_IFCR_CGIF6 reg_def(20, 1) -#define DMA_IFCR_CTCIF6 reg_def(21, 1) -#define DMA_IFCR_CHTIF6 reg_def(22, 1) -#define DMA_IFCR_CTEIF6 reg_def(23, 1) -#define DMA_IFCR_CGIF7 reg_def(24, 1) -#define DMA_IFCR_CTCIF7 reg_def(25, 1) -#define DMA_IFCR_CHTIF7 reg_def(26, 1) -#define DMA_IFCR_CTEIF7 reg_def(27, 1) -#define DMA_IFCR_reserved1 reg_def(28, 4) - union DMA_CCR { - struct __attribute__((packed)) { + struct { uint32_t EN:1; uint32_t TCIE:1; uint32_t HTIE:1; @@ -170,32 +108,15 @@ union DMA_CCR { uint32_t word; }; -#define DMA_CCR_EN reg_def( 0, 1) -#define DMA_CCR_TCIE reg_def( 1, 1) -#define DMA_CCR_HTIE reg_def( 2, 1) -#define DMA_CCR_TEIE reg_def( 3, 1) -#define DMA_CCR_DIR reg_def( 4, 1) -#define DMA_CCR_CIRC reg_def( 5, 1) -#define DMA_CCR_PINC reg_def( 6, 1) -#define DMA_CCR_MINC reg_def( 7, 1) -#define DMA_CCR_PSIZE reg_def( 8, 2) -#define DMA_CCR_MSIZE reg_def(10, 2) -#define DMA_CCR_PL reg_def(12, 2) -#define DMA_CCR_MEM2MEM reg_def(14, 1) -#define DMA_CCR_reserved1 reg_def(15, 17) - union DMA_CNDTR { - struct __attribute__((packed)) { + struct { uint32_t NDT:16; uint32_t reserved1:16; }; uint32_t word; }; -#define DMA_CNDTR_NDT reg_def( 0, 16) -#define DMA_CNDTR_reserved1 reg_def(16, 16) - -struct __attribute__((packed)) DMA_CHANNEL { +struct DMA_CHANNEL { union DMA_CCR CCR; union DMA_CNDTR CNDTR; uint32_t CPAR; @@ -203,7 +124,7 @@ struct __attribute__((packed)) DMA_CHANNEL { uint32_t reserved1; }; -struct __attribute__((packed)) DMA { +struct DMA { union DMA_ISR ISR; union DMA_IFCR IFCR; struct DMA_CHANNEL CHANNELS[7]; diff --git a/drv/exti.c b/drv/exti.c index 686f37f..3db9837 100644 --- a/drv/exti.c +++ b/drv/exti.c @@ -193,35 +193,35 @@ void exti_reset_peripheral(void) void hdr_exti0(void) { nvic_clear_pending(NVIC_IRQ_EXTI0); - reg_set(regs->PR, EXTI_PR_PR0); + regs->PR.PR0 = 1; callbacks[0](); } void hdr_exti1(void) { nvic_clear_pending(NVIC_IRQ_EXTI1); - reg_set(regs->PR, EXTI_PR_PR1); + regs->PR.PR1 = 1; callbacks[1](); } void hdr_exti2(void) { nvic_clear_pending(NVIC_IRQ_EXTI2); - reg_set(regs->PR, EXTI_PR_PR2); + regs->PR.PR2 = 1; callbacks[2](); } void hdr_exti3(void) { nvic_clear_pending(NVIC_IRQ_EXTI3); - reg_set(regs->PR, EXTI_PR_PR3); + regs->PR.PR3 = 1; callbacks[3](); } void hdr_exti4(void) { nvic_clear_pending(NVIC_IRQ_EXTI4); - reg_set(regs->PR, EXTI_PR_PR4); + regs->PR.PR4 = 1; callbacks[4](); } @@ -250,21 +250,21 @@ void hdr_exti15_10(void) void hdr_pvd(void) { nvic_clear_pending(NVIC_IRQ_PVD); - reg_set(regs->PR, EXTI_PR_PR16); + regs->PR.PR16 = 1; callbacks[16](); } void hdr_rtc_alarm(void) { nvic_clear_pending(NVIC_IRQ_RTC_ALARM); - reg_set(regs->PR, EXTI_PR_PR17); + regs->PR.PR17 = 1; callbacks[17](); } void hdr_usb_wakeup(void) { nvic_clear_pending(NVIC_IRQ_USB_WAKEUP); - reg_set(regs->PR, EXTI_PR_PR18); + regs->PR.PR18 = 1; callbacks[18](); } diff --git a/drv/exti_regs.h b/drv/exti_regs.h index 74c0ddd..5b27582 100644 --- a/drv/exti_regs.h +++ b/drv/exti_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include "stdint.h" @@ -21,7 +19,7 @@ #define EXTI_BASE_ADDRESS 0x40010400 union EXTI_IMR { - struct __attribute__((packed)) { + struct { uint32_t MR0:1; uint32_t MR1:1; uint32_t MR2:1; @@ -46,29 +44,8 @@ union EXTI_IMR { uint32_t word; }; -#define EXTI_IMR_MR0 reg_def( 0, 1) -#define EXTI_IMR_MR1 reg_def( 1, 1) -#define EXTI_IMR_MR2 reg_def( 2, 1) -#define EXTI_IMR_MR3 reg_def( 3, 1) -#define EXTI_IMR_MR4 reg_def( 4, 1) -#define EXTI_IMR_MR5 reg_def( 5, 1) -#define EXTI_IMR_MR6 reg_def( 6, 1) -#define EXTI_IMR_MR7 reg_def( 7, 1) -#define EXTI_IMR_MR8 reg_def( 8, 1) -#define EXTI_IMR_MR9 reg_def( 9, 1) -#define EXTI_IMR_MR10 reg_def(10, 1) -#define EXTI_IMR_MR11 reg_def(11, 1) -#define EXTI_IMR_MR12 reg_def(12, 1) -#define EXTI_IMR_MR13 reg_def(13, 1) -#define EXTI_IMR_MR14 reg_def(14, 1) -#define EXTI_IMR_MR15 reg_def(15, 1) -#define EXTI_IMR_MR16 reg_def(16, 1) -#define EXTI_IMR_MR17 reg_def(17, 1) -#define EXTI_IMR_MR18 reg_def(18, 1) -#define EXTI_IMR_reserved1 reg_def(19, 13) - union EXTI_EMR { - struct __attribute__((packed)) { + struct { uint32_t MR0:1; uint32_t MR1:1; uint32_t MR2:1; @@ -93,29 +70,8 @@ union EXTI_EMR { uint32_t word; }; -#define EXTI_EMR_MR0 reg_def( 0, 1) -#define EXTI_EMR_MR1 reg_def( 1, 1) -#define EXTI_EMR_MR2 reg_def( 2, 1) -#define EXTI_EMR_MR3 reg_def( 3, 1) -#define EXTI_EMR_MR4 reg_def( 4, 1) -#define EXTI_EMR_MR5 reg_def( 5, 1) -#define EXTI_EMR_MR6 reg_def( 6, 1) -#define EXTI_EMR_MR7 reg_def( 7, 1) -#define EXTI_EMR_MR8 reg_def( 8, 1) -#define EXTI_EMR_MR9 reg_def( 9, 1) -#define EXTI_EMR_MR10 reg_def(10, 1) -#define EXTI_EMR_MR11 reg_def(11, 1) -#define EXTI_EMR_MR12 reg_def(12, 1) -#define EXTI_EMR_MR13 reg_def(13, 1) -#define EXTI_EMR_MR14 reg_def(14, 1) -#define EXTI_EMR_MR15 reg_def(15, 1) -#define EXTI_EMR_MR16 reg_def(16, 1) -#define EXTI_EMR_MR17 reg_def(17, 1) -#define EXTI_EMR_MR18 reg_def(18, 1) -#define EXTI_EMR_reserved1 reg_def(19, 13) - union EXTI_RTSR { - struct __attribute__((packed)) { + struct { uint32_t TR0:1; uint32_t TR1:1; uint32_t TR2:1; @@ -140,29 +96,8 @@ union EXTI_RTSR { uint32_t word; }; -#define EXTI_RTSR_TR0 reg_def( 0, 1) -#define EXTI_RTSR_TR1 reg_def( 1, 1) -#define EXTI_RTSR_TR2 reg_def( 2, 1) -#define EXTI_RTSR_TR3 reg_def( 3, 1) -#define EXTI_RTSR_TR4 reg_def( 4, 1) -#define EXTI_RTSR_TR5 reg_def( 5, 1) -#define EXTI_RTSR_TR6 reg_def( 6, 1) -#define EXTI_RTSR_TR7 reg_def( 7, 1) -#define EXTI_RTSR_TR8 reg_def( 8, 1) -#define EXTI_RTSR_TR9 reg_def( 9, 1) -#define EXTI_RTSR_TR10 reg_def(10, 1) -#define EXTI_RTSR_TR11 reg_def(11, 1) -#define EXTI_RTSR_TR12 reg_def(12, 1) -#define EXTI_RTSR_TR13 reg_def(13, 1) -#define EXTI_RTSR_TR14 reg_def(14, 1) -#define EXTI_RTSR_TR15 reg_def(15, 1) -#define EXTI_RTSR_TR16 reg_def(16, 1) -#define EXTI_RTSR_TR17 reg_def(17, 1) -#define EXTI_RTSR_TR18 reg_def(18, 1) -#define EXTI_RTSR_reserved1 reg_def(19, 13) - union EXTI_FTSR { - struct __attribute__((packed)) { + struct { uint32_t TR0:1; uint32_t TR1:1; uint32_t TR2:1; @@ -187,29 +122,8 @@ union EXTI_FTSR { uint32_t word; }; -#define EXTI_FTSR_TR0 reg_def( 0, 1) -#define EXTI_FTSR_TR1 reg_def( 1, 1) -#define EXTI_FTSR_TR2 reg_def( 2, 1) -#define EXTI_FTSR_TR3 reg_def( 3, 1) -#define EXTI_FTSR_TR4 reg_def( 4, 1) -#define EXTI_FTSR_TR5 reg_def( 5, 1) -#define EXTI_FTSR_TR6 reg_def( 6, 1) -#define EXTI_FTSR_TR7 reg_def( 7, 1) -#define EXTI_FTSR_TR8 reg_def( 8, 1) -#define EXTI_FTSR_TR9 reg_def( 9, 1) -#define EXTI_FTSR_TR10 reg_def(10, 1) -#define EXTI_FTSR_TR11 reg_def(11, 1) -#define EXTI_FTSR_TR12 reg_def(12, 1) -#define EXTI_FTSR_TR13 reg_def(13, 1) -#define EXTI_FTSR_TR14 reg_def(14, 1) -#define EXTI_FTSR_TR15 reg_def(15, 1) -#define EXTI_FTSR_TR16 reg_def(16, 1) -#define EXTI_FTSR_TR17 reg_def(17, 1) -#define EXTI_FTSR_TR18 reg_def(18, 1) -#define EXTI_FTSR_reserved1 reg_def(19, 13) - union EXTI_SWIER { - struct __attribute__((packed)) { + struct { uint32_t SWIER0:1; uint32_t SWIER1:1; uint32_t SWIER2:1; @@ -234,29 +148,8 @@ union EXTI_SWIER { uint32_t word; }; -#define EXTI_SWIER_SWIER0 reg_def( 0, 1) -#define EXTI_SWIER_SWIER1 reg_def( 1, 1) -#define EXTI_SWIER_SWIER2 reg_def( 2, 1) -#define EXTI_SWIER_SWIER3 reg_def( 3, 1) -#define EXTI_SWIER_SWIER4 reg_def( 4, 1) -#define EXTI_SWIER_SWIER5 reg_def( 5, 1) -#define EXTI_SWIER_SWIER6 reg_def( 6, 1) -#define EXTI_SWIER_SWIER7 reg_def( 7, 1) -#define EXTI_SWIER_SWIER8 reg_def( 8, 1) -#define EXTI_SWIER_SWIER9 reg_def( 9, 1) -#define EXTI_SWIER_SWIER10 reg_def(10, 1) -#define EXTI_SWIER_SWIER11 reg_def(11, 1) -#define EXTI_SWIER_SWIER12 reg_def(12, 1) -#define EXTI_SWIER_SWIER13 reg_def(13, 1) -#define EXTI_SWIER_SWIER14 reg_def(14, 1) -#define EXTI_SWIER_SWIER15 reg_def(15, 1) -#define EXTI_SWIER_SWIER16 reg_def(16, 1) -#define EXTI_SWIER_SWIER17 reg_def(17, 1) -#define EXTI_SWIER_SWIER18 reg_def(18, 1) -#define EXTI_SWIER_reserved1 reg_def(19, 13) - union EXTI_PR { - struct __attribute__((packed)) { + struct { uint32_t PR0:1; uint32_t PR1:1; uint32_t PR2:1; @@ -281,28 +174,7 @@ union EXTI_PR { uint32_t word; }; -#define EXTI_PR_PR0 reg_def( 0, 1) -#define EXTI_PR_PR1 reg_def( 1, 1) -#define EXTI_PR_PR2 reg_def( 2, 1) -#define EXTI_PR_PR3 reg_def( 3, 1) -#define EXTI_PR_PR4 reg_def( 4, 1) -#define EXTI_PR_PR5 reg_def( 5, 1) -#define EXTI_PR_PR6 reg_def( 6, 1) -#define EXTI_PR_PR7 reg_def( 7, 1) -#define EXTI_PR_PR8 reg_def( 8, 1) -#define EXTI_PR_PR9 reg_def( 9, 1) -#define EXTI_PR_PR10 reg_def(10, 1) -#define EXTI_PR_PR11 reg_def(11, 1) -#define EXTI_PR_PR12 reg_def(12, 1) -#define EXTI_PR_PR13 reg_def(13, 1) -#define EXTI_PR_PR14 reg_def(14, 1) -#define EXTI_PR_PR15 reg_def(15, 1) -#define EXTI_PR_PR16 reg_def(16, 1) -#define EXTI_PR_PR17 reg_def(17, 1) -#define EXTI_PR_PR18 reg_def(18, 1) -#define EXTI_PR_reserved1 reg_def(19, 13) - -struct __attribute__((packed)) EXTI { +struct EXTI { union EXTI_IMR IMR; union EXTI_EMR EMR; union EXTI_RTSR RTSR; diff --git a/drv/flash.c b/drv/flash.c index 3378d06..dfa69e2 100644 --- a/drv/flash.c +++ b/drv/flash.c @@ -34,15 +34,13 @@ void flash_configure(enum FlashPreset preset) //apply new configuration switch (preset) { case FLASH_PRESET_LOW_CLOCK_SPEED: - reg_set(regs->ACR, FLASH_ACR_HLFCYA); //half cycle for power saving + regs->ACR.HLFCYA = 1; //half cycle for power saving break; case FLASH_PRESET_MEDIUM_CLOCK_SPEED: - reg_reset(regs->ACR, FLASH_ACR_LATENCY); - reg_write(regs->ACR, FLASH_ACR_LATENCY, 0x1); + regs->ACR.LATENCY = 0x1; break; case FLASH_PRESET_HIGH_CLOCK_SPEED: - reg_reset(regs->ACR, FLASH_ACR_LATENCY); - reg_write(regs->ACR, FLASH_ACR_LATENCY, 0x2); + regs->ACR.LATENCY = 0x2; break; default: break; diff --git a/drv/flash_regs.h b/drv/flash_regs.h index de1068a..aaa945d 100644 --- a/drv/flash_regs.h +++ b/drv/flash_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include "stdint.h" @@ -21,7 +19,7 @@ #define FLASH_BASE_ADDRESS 0x40022000 union FLASH_ACR { - struct __attribute__((packed)) { + struct { uint32_t LATENCY:3; uint32_t HLFCYA:1; uint32_t PRFTBE:1; @@ -31,62 +29,56 @@ union FLASH_ACR { uint32_t word; }; -#define FLASH_ACR_LATENCY reg_def(0, 3) -#define FLASH_ACR_HLFCYA reg_def(3, 1) -#define FLASH_ACR_PRFTBE reg_def(4, 1) -#define FLASH_ACR_PRFTBS reg_def(5, 1) -#define FLASH_ACR_reserved1 reg_def(6, 26) - union FLASH_KEYR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_OPTKEYR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_SR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_CR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_AR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_OBR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; union FLASH_WRPR { - struct __attribute__((packed)) { + struct { uint32_t reserved1; //TODO }; uint32_t word; }; -struct __attribute__((packed)) FLASH { +struct FLASH { union FLASH_ACR ACR; union FLASH_KEYR KEYR; union FLASH_OPTKEYR OPTKEYR; diff --git a/drv/gpio_regs.h b/drv/gpio_regs.h index 5ab539b..222678d 100644 --- a/drv/gpio_regs.h +++ b/drv/gpio_regs.h @@ -19,7 +19,7 @@ #define GPIO_BASE_ADDRESS 0x40010800 union GPIO_CRL { - struct __attribute__((packed)) { + struct { uint32_t MODE0:2; uint32_t CNF0:2; uint32_t MODE1:2; @@ -41,7 +41,7 @@ union GPIO_CRL { }; union GPIO_CRH { - struct __attribute__((packed)) { + struct { uint32_t MODE8:2; uint32_t CNF8:2; uint32_t MODE9:2; @@ -63,7 +63,7 @@ union GPIO_CRH { }; union GPIO_IDR { - struct __attribute__((packed)) { + struct { uint32_t IDR0:1; uint32_t IDR1:1; uint32_t IDR2:1; @@ -86,7 +86,7 @@ union GPIO_IDR { }; union GPIO_ODR { - struct __attribute__((packed)) { + struct { uint32_t ODR0:1; uint32_t ODR1:1; uint32_t ODR2:1; @@ -109,7 +109,7 @@ union GPIO_ODR { }; union GPIO_BSRR { - struct __attribute__((packed)) { + struct { uint32_t BS0:1; uint32_t BS1:1; uint32_t BS2:1; @@ -147,7 +147,7 @@ union GPIO_BSRR { }; union GPIO_BRR { - struct __attribute__((packed)) { + struct { uint32_t BR0:1; uint32_t BR1:1; uint32_t BR2:1; @@ -170,7 +170,7 @@ union GPIO_BRR { }; union GPIO_LCKK { - struct __attribute__((packed)) { + struct { uint32_t LCK0:1; uint32_t LCK1:1; uint32_t LCK2:1; @@ -193,7 +193,7 @@ union GPIO_LCKK { uint32_t word; }; -struct __attribute__((packed)) GPIO_PORT { +struct GPIO_PORT { union GPIO_CRL CRL; union GPIO_CRH CRH; union GPIO_IDR IDR; @@ -204,7 +204,7 @@ struct __attribute__((packed)) GPIO_PORT { uint32_t reserved1[249]; }; -struct __attribute__((packed)) GPIO { +struct GPIO { struct GPIO_PORT PORTS[7]; }; diff --git a/drv/nvic_regs.h b/drv/nvic_regs.h index 7d9d02f..bc12de7 100644 --- a/drv/nvic_regs.h +++ b/drv/nvic_regs.h @@ -19,7 +19,7 @@ #define NVIC1_BASE_ADDRESS 0xE000E100 #define NVIC2_BASE_ADDRESS 0xE000EF00 -struct __attribute__((packed)) NVIC1 { +struct NVIC1 { uint32_t ISERX[3]; uint32_t ICERX[3]; uint32_t ISPRX[3]; @@ -28,7 +28,7 @@ struct __attribute__((packed)) NVIC1 { uint32_t IPRX[20]; }; -struct __attribute__((packed)) NVIC2 { +struct NVIC2 { uint32_t INTID; }; diff --git a/drv/rcc.c b/drv/rcc.c index 20dfcff..73fe49b 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -113,26 +113,26 @@ void rcc_get_clocks(struct RccClocks* clocks) static void apply_default_preset(void) { //ensures HSI is enabled - reg_set(regs->CR, RCC_CR_HSION); + regs->CR.HSION = 1; while (regs->CR.HSIRDY != 0x1); //set HSI as main clock source and disable prescalers regs->CFGR.word &= ~0x077fff3; //disable all options - reg_reset(regs->CR, RCC_CR_HSITRIM); - reg_write(regs->CR, RCC_CR_HSITRIM, 0x10); - reg_reset(regs->CR, RCC_CR_HSEON); - reg_reset(regs->CR, RCC_CR_HSEBYP); - reg_reset(regs->CR, RCC_CR_CCSON); - reg_reset(regs->CR, RCC_CR_PLLON); + regs->CR.HSITRIM = 0; + regs->CR.HSITRIM = 0x10; + regs->CR.HSEON = 0; + regs->CR.HSEBYP = 0; + regs->CR.CCSON = 0; + regs->CR.PLLON = 0; //disable all interrupts - reg_reset(regs->CIR, RCC_CIR_LSIRDYIE); - reg_reset(regs->CIR, RCC_CIR_LSERDYIE); - reg_reset(regs->CIR, RCC_CIR_HSIRDYIE); - reg_reset(regs->CIR, RCC_CIR_HSERDYIE); - reg_reset(regs->CIR, RCC_CIR_PLLRDYIE); + regs->CIR.LSIRDYIE = 0; + regs->CIR.LSERDYIE = 0; + regs->CIR.HSIRDYIE = 0; + regs->CIR.HSERDYIE = 0; + regs->CIR.PLLRDYIE = 0; //reconfigure flash flash_configure(FLASH_PRESET_LOW_CLOCK_SPEED); @@ -149,35 +149,35 @@ static void apply_speed_preset(void) apply_default_preset(); //try enabling HSE, fallback to HSI if HSE fails - reg_set(regs->CR, RCC_CR_HSEON); + regs->CR.HSEON = 1; for (uint32_t i=0; i<1000; ++i) { __asm__("nop"); } if (regs->CR.HSERDY == 0x1) { - reg_set(regs->CFGR, RCC_CFGR_PLLSCR); + regs->CFGR.PLLSCR = 1; } else { - reg_reset(regs->CR, RCC_CR_HSEON); + regs->CR.HSEON = 0; } //configure PLL, fallback to HSI if PLL fails - reg_write(regs->CFGR, RCC_CFGR_PLLMUL, 0x7); //PLL x9 - reg_set(regs->CR, RCC_CR_PLLON); + regs->CFGR.PLLMUL = 0x7; //PLL x9 + regs->CR.PLLON = 1; for (uint32_t i=0; i<1000; ++i) { __asm__("nop"); } if (regs->CR.PLLRDY != 0x1) { - reg_reset(regs->CR, RCC_CR_PLLON); + regs->CR.PLLON = 0; return; //clock low enough, no need for prescalers } //configure prescalers - reg_write(regs->CFGR, RCC_CFGR_PPRE1, 0x4); // /2 - reg_write(regs->CFGR, RCC_CFGR_ADCPRE, 0x2); // /6 + regs->CFGR.PPRE1 = 0x4; // /2 + regs->CFGR.ADCPRE = 0x2; // /6 //reconfigure flash flash_configure(FLASH_PRESET_HIGH_CLOCK_SPEED); //switch to PLL output - reg_write(regs->CFGR, RCC_CFGR_SW, 0x2); + regs->CFGR.SW = 0x2; } diff --git a/drv/rcc_regs.h b/drv/rcc_regs.h index 44f7eff..47a9612 100644 --- a/drv/rcc_regs.h +++ b/drv/rcc_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include "stdint.h" @@ -21,7 +19,7 @@ #define RCC_BASE_ADDRESS 0x40021000 union RCC_CR { - struct __attribute__((packed)) { + struct { uint32_t HSION:1; uint32_t HSIRDY:1; uint32_t reserved1:1; @@ -39,22 +37,8 @@ union RCC_CR { uint32_t word; }; -#define RCC_CR_HSION reg_def( 0, 1) -#define RCC_CR_HSIRDY reg_def( 1, 1) -#define RCC_CR_reserved1 reg_def( 2, 1) -#define RCC_CR_HSITRIM reg_def( 3, 5) -#define RCC_CR_HSICAL reg_def( 8, 8) -#define RCC_CR_HSEON reg_def(16, 1) -#define RCC_CR_HSERDY reg_def(17, 1) -#define RCC_CR_HSEBYP reg_def(18, 1) -#define RCC_CR_CCSON reg_def(19, 1) -#define RCC_CR_reserved2 reg_def(20, 4) -#define RCC_CR_PLLON reg_def(24, 1) -#define RCC_CR_PLLRDY reg_def(25, 1) -#define RCC_CR_reserved3 reg_def(26, 6) - union RCC_CFGR { - struct __attribute__((packed)) { + struct { uint32_t SW:2; uint32_t SWS:2; uint32_t HPRE:4; @@ -72,22 +56,8 @@ union RCC_CFGR { uint32_t word; }; -#define RCC_CFGR_SW reg_def( 0, 2) -#define RCC_CFGR_SWS reg_def( 2, 2) -#define RCC_CFGR_HPRE reg_def( 4, 4) -#define RCC_CFGR_PPRE1 reg_def( 8, 3) -#define RCC_CFGR_PPRE2 reg_def(11, 3) -#define RCC_CFGR_ADCPRE reg_def(14, 2) -#define RCC_CFGR_PLLSCR reg_def(16, 1) -#define RCC_CFGR_PLLXTPRE reg_def(17, 1) -#define RCC_CFGR_PLLMUL reg_def(18, 4) -#define RCC_CFGR_USBPRE reg_def(22, 1) -#define RCC_CFGR_reserved1 reg_def(23, 1) -#define RCC_CFGR_MCO reg_def(24, 3) -#define RCC_CFGR_reserved2 reg_def(27, 5) - union RCC_CIR { - struct __attribute__((packed)) { + struct { uint32_t LSIRDYF:1; uint32_t LSERDYF:1; uint32_t HSIRDYF:1; @@ -113,30 +83,8 @@ union RCC_CIR { uint32_t word; }; -#define RCC_CIR_LSIRDYF reg_def( 0, 1) -#define RCC_CIR_LSERDYF reg_def( 1, 1) -#define RCC_CIR_HSIRDYF reg_def( 2, 1) -#define RCC_CIR_HSERDYF reg_def( 3, 1) -#define RCC_CIR_PLLRDYF reg_def( 4, 1) -#define RCC_CIR_reserved1 reg_def( 5, 2) -#define RCC_CIR_CSSF reg_def( 7, 1) -#define RCC_CIR_LSIRDYIE reg_def( 8, 1) -#define RCC_CIR_LSERDYIE reg_def( 9, 1) -#define RCC_CIR_HSIRDYIE reg_def(10, 1) -#define RCC_CIR_HSERDYIE reg_def(11, 1) -#define RCC_CIR_PLLRDYIE reg_def(12, 1) -#define RCC_CIR_RSE2 reg_def(13, 3) -#define RCC_CIR_LSIRDYC reg_def(16, 1) -#define RCC_CIR_LSERDYC reg_def(17, 1) -#define RCC_CIR_HSIRDYC reg_def(18, 1) -#define RCC_CIR_HSERDYC reg_def(19, 1) -#define RCC_CIR_PLLRDYC reg_def(20, 1) -#define RCC_CIR_reserved3 reg_def(21, 2) -#define RCC_CIR_CSSC reg_def(23, 1) -#define RCC_CIR_reserved4 reg_def(24, 8) - union RCC_APB2RSTR { - struct __attribute__((packed)) { + struct { uint32_t AFIORST:1; uint32_t reserved1:1; uint32_t IOPARST:1; @@ -162,30 +110,8 @@ union RCC_APB2RSTR { uint32_t word; }; -#define RCC_APB2RSTR_AFIORST reg_def( 0, 1) -#define RCC_APB2RSTR_reserved1 reg_def( 1, 1) -#define RCC_APB2RSTR_IOPARST reg_def( 2, 1) -#define RCC_APB2RSTR_IOPBRST reg_def( 3, 1) -#define RCC_APB2RSTR_IOPCRST reg_def( 4, 1) -#define RCC_APB2RSTR_IOPDRST reg_def( 5, 1) -#define RCC_APB2RSTR_IOPERST reg_def( 6, 1) -#define RCC_APB2RSTR_IOPFRST reg_def( 7, 1) -#define RCC_APB2RSTR_IOPGRST reg_def( 8, 1) -#define RCC_APB2RSTR_ADC1RST reg_def( 9, 1) -#define RCC_APB2RSTR_ACD2RST reg_def(10, 1) -#define RCC_APB2RSTR_TIM1RST reg_def(11, 1) -#define RCC_APB2RSTR_SPI1RST reg_def(12, 1) -#define RCC_APB2RSTR_TIM8RST reg_def(13, 1) -#define RCC_APB2RSTR_USART1RST reg_def(14, 1) -#define RCC_APB2RSTR_ADC3RST reg_def(15, 1) -#define RCC_APB2RSTR_reserved2 reg_def(16, 3) -#define RCC_APB2RSTR_TIM9RST reg_def(19, 1) -#define RCC_APB2RSTR_TIM10RST reg_def(20, 1) -#define RCC_APB2RSTR_TIM11RST reg_def(21, 1) -#define RCC_APB2RSTR_reserved3 reg_def(22, 10) - union RCC_APB1RSTR { - struct __attribute__((packed)) { + struct { uint32_t TIM2RST:1; uint32_t TIM3RST:1; uint32_t TIM4RST:1; @@ -219,38 +145,8 @@ union RCC_APB1RSTR { uint32_t word; }; -#define RCC_APB1RSTR_TIM2RST reg_def( 0, 1) -#define RCC_APB1RSTR_TIM3RST reg_def( 1, 1) -#define RCC_APB1RSTR_TIM4RST reg_def( 2, 1) -#define RCC_APB1RSTR_TIM5RST reg_def( 3, 1) -#define RCC_APB1RSTR_TIM6RST reg_def( 4, 1) -#define RCC_APB1RSTR_TIM7RST reg_def( 5, 1) -#define RCC_APB1RSTR_TIM12RST reg_def( 6, 1) -#define RCC_APB1RSTR_TIM13RST reg_def( 7, 1) -#define RCC_APB1RSTR_TIM14RST reg_def( 8, 1) -#define RCC_APB1RSTR_reserved1 reg_def( 9, 2) -#define RCC_APB1RSTR_WWDGRST reg_def(11, 1) -#define RCC_APB1RSTR_reserved2 reg_def(12, 2) -#define RCC_APB1RSTR_SPI2RST reg_def(14, 1) -#define RCC_APB1RSTR_SPI3RST reg_def(15, 1) -#define RCC_APB1RSTR_reserved3 reg_def(16, 1) -#define RCC_APB1RSTR_USART2RST reg_def(17, 1) -#define RCC_APB1RSTR_USART3RST reg_def(18, 1) -#define RCC_APB1RSTR_UART4RST reg_def(19, 1) -#define RCC_APB1RSTR_UART5RST reg_def(20, 1) -#define RCC_APB1RSTR_I2C12RST reg_def(21, 1) -#define RCC_APB1RSTR_I2C2RST reg_def(22, 1) -#define RCC_APB1RSTR_USB2RST reg_def(23, 1) -#define RCC_APB1RSTR_reserved4 reg_def(24, 1) -#define RCC_APB1RSTR_CANRST reg_def(25, 1) -#define RCC_APB1RSTR_reserved5 reg_def(26, 1) -#define RCC_APB1RSTR_BKPRST reg_def(27, 1) -#define RCC_APB1RSTR_PWRRST reg_def(28, 1) -#define RCC_APB1RSTR_DACRST reg_def(29, 1) -#define RCC_APB1RSTR_reserved6 reg_def(30, 2) - union RCC_AHBENR { - struct __attribute__((packed)) { + struct { uint32_t DMA1EN:1; uint32_t DMA2EN:1; uint32_t SRAMEN:1; @@ -267,21 +163,8 @@ union RCC_AHBENR { uint32_t word; }; -#define RCC_AHBENR_DMA1EN reg_def( 0, 1) -#define RCC_AHBENR_DMA2EN reg_def( 1, 1) -#define RCC_AHBENR_SRAMEN reg_def( 2, 1) -#define RCC_AHBENR_reserved1 reg_def( 3, 1) -#define RCC_AHBENR_FLITFEN reg_def( 4, 1) -#define RCC_AHBENR_reserved2 reg_def( 5, 1) -#define RCC_AHBENR_CRCEN reg_def( 6, 1) -#define RCC_AHBENR_reserved3 reg_def( 7, 1) -#define RCC_AHBENR_FSMCEN reg_def( 8, 1) -#define RCC_AHBENR_reserved4 reg_def( 9, 1) -#define RCC_AHBENR_SDIOEN reg_def(10, 1) -#define RCC_AHBENR_reserved5 reg_def(11, 21) - union RCC_APB2ENR { - struct __attribute__((packed)) { + struct { uint32_t AFIOEN:1; uint32_t reserved1:1; uint32_t IOPAEN:1; @@ -307,30 +190,8 @@ union RCC_APB2ENR { uint32_t word; }; -#define RCC_APB2ENR_AFIOEN reg_def( 0, 1) -#define RCC_APB2ENR_reserved1 reg_def( 1, 1) -#define RCC_APB2ENR_IOPAEN reg_def( 2, 1) -#define RCC_APB2ENR_IOPBEN reg_def( 3, 1) -#define RCC_APB2ENR_IOPCEN reg_def( 4, 1) -#define RCC_APB2ENR_IOPDEN reg_def( 5, 1) -#define RCC_APB2ENR_IOPEEN reg_def( 6, 1) -#define RCC_APB2ENR_IOPFEN reg_def( 7, 1) -#define RCC_APB2ENR_IOPGEN reg_def( 8, 1) -#define RCC_APB2ENR_ADC1EN reg_def( 9, 1) -#define RCC_APB2ENR_ACD2EN reg_def(10, 1) -#define RCC_APB2ENR_TIM1EN reg_def(11, 1) -#define RCC_APB2ENR_SPI1EN reg_def(12, 1) -#define RCC_APB2ENR_TIM8EN reg_def(13, 1) -#define RCC_APB2ENR_USART1EN reg_def(14, 1) -#define RCC_APB2ENR_ADC3EN reg_def(15, 1) -#define RCC_APB2ENR_reserved2 reg_def(16, 3) -#define RCC_APB2ENR_TIM9EN reg_def(19, 1) -#define RCC_APB2ENR_TIM10EN reg_def(20, 1) -#define RCC_APB2ENR_TIM11EN reg_def(21, 1) -#define RCC_APB2ENR_reserved3 reg_def(22, 10) - union RCC_APB1ENR { - struct __attribute__((packed)) { + struct { uint32_t TIM2EN:1; uint32_t TIM3EN:1; uint32_t TIM4EN:1; @@ -364,38 +225,8 @@ union RCC_APB1ENR { uint32_t word; }; -#define RCC_APB1ENR_TIM2EN reg_def( 0, 1) -#define RCC_APB1ENR_TIM3EN reg_def( 1, 1) -#define RCC_APB1ENR_TIM4EN reg_def( 2, 1) -#define RCC_APB1ENR_TIM5EN reg_def( 3, 1) -#define RCC_APB1ENR_TIM6EN reg_def( 4, 1) -#define RCC_APB1ENR_TIM7EN reg_def( 5, 1) -#define RCC_APB1ENR_TIM12EN reg_def( 6, 1) -#define RCC_APB1ENR_TIM13EN reg_def( 7, 1) -#define RCC_APB1ENR_TIM14EN reg_def( 8, 1) -#define RCC_APB1ENR_reserved1 reg_def( 9, 2) -#define RCC_APB1ENR_WWDGEN reg_def(11, 1) -#define RCC_APB1ENR_reserved reg_def(12, 2) -#define RCC_APB1ENR_SPI2EN reg_def(14, 1) -#define RCC_APB1ENR_SPI3EN reg_def(15, 1) -#define RCC_APB1ENR_reserved2 reg_def(16, 1) -#define RCC_APB1ENR_USART2EN reg_def(17, 1) -#define RCC_APB1ENR_USART3EN reg_def(18, 1) -#define RCC_APB1ENR_UART4EN reg_def(19, 1) -#define RCC_APB1ENR_UART5EN reg_def(20, 1) -#define RCC_APB1ENR_I2C12EN reg_def(21, 1) -#define RCC_APB1ENR_I2C2EN reg_def(22, 1) -#define RCC_APB1ENR_USB2EN reg_def(23, 1) -#define RCC_APB1ENR_reserved3 reg_def(24, 1) -#define RCC_APB1ENR_CANEN reg_def(25, 1) -#define RCC_APB1ENR_reserved4 reg_def(26, 1) -#define RCC_APB1ENR_BKPEN reg_def(27, 1) -#define RCC_APB1ENR_PWREN reg_def(28, 1) -#define RCC_APB1ENR_DACEN reg_def(29, 1) -#define RCC_APB1ENR_reserved5 reg_def(30, 2) - union RCC_BDCR { - struct __attribute__((packed)) { + struct { uint32_t LSEON:1; uint32_t LSERDY:1; uint32_t LSEBYP:1; @@ -409,18 +240,8 @@ union RCC_BDCR { uint32_t word; }; -#define RCC_BDCR_LSEON reg_def( 0, 1) -#define RCC_BDCR_LSERDY reg_def( 1, 1) -#define RCC_BDCR_LSEBYP reg_def( 2, 1) -#define RCC_BDCR_reserved1 reg_def( 3, 5) -#define RCC_BDCR_RTCSEL reg_def( 8, 2) -#define RCC_BDCR_reserved2 reg_def(10, 5) -#define RCC_BDCR_RTCEN reg_def(15, 1) -#define RCC_BDCR_BDRST reg_def(16, 1) -#define RCC_BDCR_reserved3 reg_def(17, 15) - union RCC_CSR { - struct __attribute__((packed)) { + struct { uint32_t LSION:1; uint32_t LSIRDY:1; uint32_t reserved1:22; @@ -436,19 +257,7 @@ union RCC_CSR { uint32_t word; }; -#define RCC_CSR_LSION reg_def( 0, 1) -#define RCC_CSR_LSIRDY reg_def( 1, 1) -#define RCC_CSR_reserved1 reg_def( 2, 22) -#define RCC_CSR_RMVF reg_def(24, 1) -#define RCC_CSR_reserved2 reg_def(25, 1) -#define RCC_CSR_PINRSTF reg_def(26, 1) -#define RCC_CSR_PORRSTF reg_def(27, 1) -#define RCC_CSR_SFTRSTF reg_def(28, 1) -#define RCC_CSR_IWDGRSTF reg_def(29, 1) -#define RCC_CSR_WWDGRSTF reg_def(30, 1) -#define RCC_CSR_LPWRSTF reg_def(31, 1) - -struct __attribute__((packed)) RCC { +struct RCC { union RCC_CR CR; union RCC_CFGR CFGR; union RCC_CIR CIR; diff --git a/drv/reg.h b/drv/reg.h deleted file mode 100644 index 5334e18..0000000 --- a/drv/reg.h +++ /dev/null @@ -1,15 +0,0 @@ - -#define reg_def(pos, size) pos, (((0x1 << size) - 1) << pos) - -#define reg_set(reg, field) _reg_set(reg, field) -#define _reg_set(reg, pos, mask) do { reg.word |= mask; } while (false) - -#define reg_reset(reg, field) _reg_reset(reg, field) -#define _reg_reset(reg, pos, mask) do { reg.word &= ~mask; } while (false) - -#define reg_write(reg, field, value) _reg_write(reg, field, (value)) -#define _reg_write(reg, pos, mask, value) \ -do { \ - reg.word |= value << pos; \ -} while (false) \ - diff --git a/drv/stk.c b/drv/stk.c index a86811f..3e9ce61 100644 --- a/drv/stk.c +++ b/drv/stk.c @@ -43,10 +43,10 @@ uint32_t stk_configure(uint32_t period_us, StkCallback cb) //period is still too small return 1; } - reg_set(regs->CTRL, STK_CTRL_CLKSOURCE); + regs->CTRL.CLKSOURCE = 1; } - reg_write(regs->LOAD, STK_LOAD_RELOAD, reload); - reg_set(regs->CTRL, STK_CTRL_TICKINT); + regs->LOAD.RELOAD = reload; + regs->CTRL.TICKINT = 1; callback = cb; @@ -55,23 +55,23 @@ uint32_t stk_configure(uint32_t period_us, StkCallback cb) void stk_reset(void) { - reg_reset(regs->CTRL, STK_CTRL_ENABLE); - reg_reset(regs->CTRL, STK_CTRL_TICKINT); - reg_reset(regs->CTRL, STK_CTRL_CLKSOURCE); - reg_reset(regs->CTRL, STK_CTRL_COUNTFLAG); + regs->CTRL.ENABLE = 0; + regs->CTRL.TICKINT = 0; + regs->CTRL.CLKSOURCE = 0; + regs->CTRL.COUNTFLAG = 0; - reg_write(regs->LOAD, STK_LOAD_RELOAD, 0); - reg_write(regs->VAL, STK_VAL_CURRENT, 0); + regs->LOAD.RELOAD = 0; + regs->VAL.CURRENT = 0; } void stk_start(void) { - reg_set(regs->CTRL, STK_CTRL_ENABLE); + regs->CTRL.ENABLE = 1; } void stk_stop(void) { - reg_reset(regs->CTRL, STK_CTRL_ENABLE); + regs->CTRL.ENABLE = 0; } uint32_t stk_read_us(void) diff --git a/drv/stk_regs.h b/drv/stk_regs.h index 5739f0d..fe5e0c6 100644 --- a/drv/stk_regs.h +++ b/drv/stk_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include @@ -21,7 +19,7 @@ #define STK_BASE_ADDRESS 0xE000E010 union STK_CTRL { - struct __attribute__((packed)) { + struct { uint32_t ENABLE:1; uint32_t TICKINT:1; uint32_t CLKSOURCE:1; @@ -32,37 +30,24 @@ union STK_CTRL { uint32_t word; }; -#define STK_CTRL_ENABLE reg_def( 0, 1) -#define STK_CTRL_TICKINT reg_def( 1, 1) -#define STK_CTRL_CLKSOURCE reg_def( 2, 1) -#define STK_CTRL_reserved reg_def( 3, 13) -#define STK_CTRL_COUNTFLAG reg_def(16, 1) -#define STK_CTRL_reserved2 reg_def(17, 15) - union STK_LOAD { - struct __attribute__((packed)) { + struct { uint32_t RELOAD:24; uint32_t reserved1:8; }; uint32_t word; }; -#define STK_LOAD_RELOAD reg_def( 0, 24) -#define STK_LOAD_reserved1 reg_def(24, 8) - union STK_VAL { - struct __attribute__((packed)) { + struct { uint32_t CURRENT:24; uint32_t reserved1:8; }; uint32_t word; }; -#define STK_VAL_CURRENT reg_def( 0, 24) -#define STK_VAL_reserved1 reg_def(24, 8) - union STK_CALIB { - struct __attribute__((packed)) { + struct { uint32_t TENMS:24; uint32_t reserved1:6; uint32_t SKEW:1; @@ -71,12 +56,7 @@ union STK_CALIB { uint32_t word; }; -#define STK_CALIB_RELOAD reg_def( 0, 24) -#define STK_CALIB_reserved1 reg_def(24, 6) -#define STK_CALIB_SKEW reg_def(30, 1) -#define STK_CALIB_NOREF reg_def(31, 1) - -struct __attribute__((packed)) STK { +struct STK { union STK_CTRL CTRL; union STK_LOAD LOAD; union STK_VAL VAL; diff --git a/drv/usart.c b/drv/usart.c index 25167a2..36eaebb 100644 --- a/drv/usart.c +++ b/drv/usart.c @@ -9,7 +9,6 @@ #include "usart.h" #include "usart_regs.h" -#include "reg.h" #include "rcc.h" #include "dma.h" @@ -132,7 +131,7 @@ uint32_t usart_write_byte(enum UsartPeriph periph, uint8_t byte) //only write data if the tx register it empty, give up otherwise if (usarts[periph]->SR.TXE) { - reg_write(usarts[periph]->DR, USART_DR_DR, byte); + usarts[periph]->DR.DR = byte; return 0; } else { return 1; @@ -145,7 +144,7 @@ const struct DmaParam* usart_configure_rx_dma(enum UsartPeriph periph) return nullptr; } - reg_set(usarts[periph]->CR3, USART_CR3_DMAR); + usarts[periph]->CR3.DMAR = 1; return &usarts_rx_param[periph]; } @@ -155,7 +154,7 @@ const struct DmaParam* usart_configure_tx_dma(enum UsartPeriph periph) return nullptr; } - reg_set(usarts[periph]->CR3, USART_CR3_DMAT); + usarts[periph]->CR3.DMAT = 1; return &usarts_tx_param[periph]; } @@ -176,19 +175,19 @@ static void configure_usart(volatile struct USART* regs, case USART_CONFIG_8E1: case USART_CONFIG_7E2: case USART_CONFIG_8E2: - reg_set(regs->CR1, USART_CR1_PCE); - reg_reset(regs->CR1, USART_CR1_PS); + regs->CR1.PCE = 1; + regs->CR1.PS = 0; break; case USART_CONFIG_7O1: case USART_CONFIG_7O2: case USART_CONFIG_8O1: case USART_CONFIG_8O2: - reg_set(regs->CR1, USART_CR1_PCE); - reg_set(regs->CR1, USART_CR1_PS); + regs->CR1.PCE = 1; + regs->CR1.PS = 1; break; case USART_CONFIG_8N1: case USART_CONFIG_8N2: - reg_reset(regs->CR1, USART_CR1_PCE); + regs->CR1.PCE = 0; break; default: break; @@ -203,13 +202,13 @@ static void configure_usart(volatile struct USART* regs, case USART_CONFIG_7O2: case USART_CONFIG_8N1: case USART_CONFIG_8N2: - reg_reset(regs->CR1, USART_CR1_M); + regs->CR1.M = 0; break; case USART_CONFIG_8E2: case USART_CONFIG_8E1: case USART_CONFIG_8O1: case USART_CONFIG_8O2: - reg_set(regs->CR1, USART_CR1_M); + regs->CR1.M = 1; break; default: break; @@ -223,24 +222,23 @@ static void configure_usart(volatile struct USART* regs, case USART_CONFIG_8N1: case USART_CONFIG_8E1: case USART_CONFIG_8O1: - reg_reset(regs->CR2, USART_CR2_STOP); + regs->CR2.STOP = 0; break; case USART_CONFIG_7E2: case USART_CONFIG_7O2: case USART_CONFIG_8N2: case USART_CONFIG_8E2: case USART_CONFIG_8O2: - reg_reset(regs->CR2, USART_CR2_STOP); - reg_write(regs->CR2, USART_CR2_STOP, 2); + regs->CR2.STOP = 2; break; default: break; } //enable Rx/Tx - reg_set(regs->CR1, USART_CR1_TE); - reg_set(regs->CR1, USART_CR1_RE); - reg_set(regs->CR1, USART_CR1_UE); + regs->CR1.TE = 1; + regs->CR1.RE = 1; + regs->CR1.UE = 1; } /** @@ -255,9 +253,7 @@ static void configure_baudrate(volatile struct USART* regs, uint32_t clock, uint32_t factor = clock / baudrate; volatile uint32_t divider = factor - (mantissa * 16); - reg_reset(regs->BRR, USART_BRR_DIV_Mantissa); - reg_write(regs->BRR, USART_BRR_DIV_Mantissa, mantissa & 0xFFF); - reg_reset(regs->BRR, USART_BRR_DIV_Fraction); - reg_write(regs->BRR, USART_BRR_DIV_Fraction, divider & 0xF); + regs->BRR.DIV_Mantissa = mantissa & 0xFFF; + regs->BRR.DIV_Fraction = divider & 0xF; } diff --git a/drv/usart_regs.h b/drv/usart_regs.h index 2c84cc3..54c86a9 100644 --- a/drv/usart_regs.h +++ b/drv/usart_regs.h @@ -11,8 +11,6 @@ //--includes-------------------------------------------------------------------- -#include "reg.h" - #include "stdint.h" @@ -23,7 +21,7 @@ #define USART3_BASE_ADDRESS 0x40004800 union USART_SR { - struct __attribute__((packed)) { + struct { uint32_t PE:1; uint32_t FE:1; uint32_t NE:1; @@ -39,31 +37,16 @@ union USART_SR { uint32_t word; }; -#define USART_SR_PE reg_def( 0, 1) -#define USART_SR_FE reg_def( 1, 1) -#define USART_SR_NE reg_def( 2, 1) -#define USART_SR_ORE reg_def( 3, 1) -#define USART_SR_IDLE reg_def( 4, 1) -#define USART_SR_RXNE reg_def( 5, 1) -#define USART_SR_TC reg_def( 6, 1) -#define USART_SR_TXE reg_def( 7, 1) -#define USART_SR_LBD reg_def( 8, 1) -#define USART_SR_CTS reg_def( 9, 1) -#define USART_SR_reserved1 reg_def(10, 22) - union USART_DR { - struct __attribute__((packed)) { + struct { uint32_t DR:9; uint32_t reserved1:23; }; uint32_t word; }; -#define USART_DR_DR reg_def( 0, 9) -#define USART_DR_reserved1 reg_def( 9, 23) - union USART_BRR { - struct __attribute__((packed)) { + struct { uint32_t DIV_Fraction:4; uint32_t DIV_Mantissa:12; uint32_t reserved1:16; @@ -71,12 +54,8 @@ union USART_BRR { uint32_t word; }; -#define USART_BRR_DIV_Fraction reg_def( 0, 4) -#define USART_BRR_DIV_Mantissa reg_def( 4, 12) -#define USART_BRR_reserved1 reg_def(16, 16) - union USART_CR1 { - struct __attribute__((packed)) { + struct { uint32_t SBK:1; uint32_t RWU:1; uint32_t RE:1; @@ -96,24 +75,8 @@ union USART_CR1 { uint32_t word; }; -#define USART_CR1_SBK reg_def( 0, 1) -#define USART_CR1_RWU reg_def( 1, 1) -#define USART_CR1_RE reg_def( 2, 1) -#define USART_CR1_TE reg_def( 3, 1) -#define USART_CR1_IDLEIE reg_def( 4, 1) -#define USART_CR1_RXNEIE reg_def( 5, 1) -#define USART_CR1_TCIE reg_def( 6, 1) -#define USART_CR1_TXEIE reg_def( 7, 1) -#define USART_CR1_PEI reg_def( 8, 1) -#define USART_CR1_PS reg_def( 9, 1) -#define USART_CR1_PCE reg_def(10, 1) -#define USART_CR1_WAKE reg_def(11, 1) -#define USART_CR1_M reg_def(12, 1) -#define USART_CR1_UE reg_def(13, 1) -#define USART_CR1_reserved1 reg_def(14, 18) - union USART_CR2 { - struct __attribute__((packed)) { + struct { uint32_t ADD:4; uint32_t reserved1:1; uint32_t LBDL:1; @@ -130,21 +93,8 @@ union USART_CR2 { uint32_t word; }; -#define USART_CR2_ADD reg_def( 0, 4) -#define USART_CR2_reserved1 reg_def( 4, 1) -#define USART_CR2_LBDL reg_def( 5, 1) -#define USART_CR2_LBDIE reg_def( 6, 1) -#define USART_CR2_reserved2 reg_def( 7, 1) -#define USART_CR2_LBCL reg_def( 8, 1) -#define USART_CR2_CPHA reg_def( 9, 1) -#define USART_CR2_CPOL reg_def(10, 1) -#define USART_CR2_CLKEN reg_def(11, 1) -#define USART_CR2_STOP reg_def(12, 2) -#define USART_CR2_LINEN reg_def(14, 1) -#define USART_CR2_reserved3 reg_def(15, 17) - union USART_CR3 { - struct __attribute__((packed)) { + struct { uint32_t EIE:1; uint32_t IREN:1; uint32_t IRLP:1; @@ -161,21 +111,8 @@ union USART_CR3 { uint32_t word; }; -#define USART_CR3_EIE reg_def( 0, 1) -#define USART_CR3_IREN reg_def( 1, 1) -#define USART_CR3_IRLP reg_def( 2, 1) -#define USART_CR3_HDSEL reg_def( 3, 1) -#define USART_CR3_NACK reg_def( 4, 1) -#define USART_CR3_SCEN reg_def( 5, 1) -#define USART_CR3_DMAR reg_def( 6, 1) -#define USART_CR3_DMAT reg_def( 7, 1) -#define USART_CR3_RTSE reg_def( 8, 1) -#define USART_CR3_CTSE reg_def( 9, 1) -#define USART_CR3_CTSIE reg_def(10, 1) -#define USART_CR3_reserved3 reg_def(11, 21) - union USART_GTPR { - struct __attribute__((packed)) { + struct { uint32_t PSC:8; uint32_t GT:8; uint32_t reserved1:16; @@ -183,10 +120,6 @@ union USART_GTPR { uint32_t word; }; -#define USART_GTPR_PSC reg_def( 0, 8) -#define USART_GTPR_GT reg_def( 8, 8) -#define USART_GTPR_reserved1 reg_def(16, 16) - struct USART { union USART_SR SR; union USART_DR DR; From 968175516877714bec5adf5b5381c1254dad0deb Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 13 Jul 2024 13:19:17 +0200 Subject: [PATCH 15/35] Define PWR module's registers --- drv/pwr_regs.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 drv/pwr_regs.h diff --git a/drv/pwr_regs.h b/drv/pwr_regs.h new file mode 100644 index 0000000..d84f4ac --- /dev/null +++ b/drv/pwr_regs.h @@ -0,0 +1,56 @@ +/** @file pwr_regs.h + * Module defining Power control (PWR) registers. + * + * Mainly made to be used by the pwr module. It is recommanded to go through + * the functions provided by that module instead of directly using the registers + * defined here. + */ + +#ifndef _PWR_REGS_H_ +#define _PWR_REGS_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +#define PWR_BASE_ADDRESS 0x40007000 + +union PWR_CR { + struct { + uint32_t LPDS:1; + uint32_t LDDS:1; + uint32_t CWUF:1; + uint32_t CSBF:1; + uint32_t PVDE:1; + uint32_t PLS:3; + uint32_t DBP:1; + uint32_t reserved1:23; + }; + uint32_t word; +}; + +union PWR_CSR { + struct { + uint32_t WUF:1; + uint32_t SBF:1; + uint32_t PVDO:1; + uint32_t reserved1:5; + uint32_t EWUP:1; + uint32_t reserved2:23; + }; + uint32_t word; +}; + +struct PWR { + union PWR_CR CR; + union PWR_CSR CSR; +}; + + +//--functions------------------------------------------------------------------- + +#endif //_PWR_REGS_H_ + From 97dad5362128896bb0846752c967a14b6bf83e38 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 13 Jul 2024 21:14:44 +0200 Subject: [PATCH 16/35] Define SCB module's registers --- drv/scb_regs.h | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 drv/scb_regs.h diff --git a/drv/scb_regs.h b/drv/scb_regs.h new file mode 100644 index 0000000..90622e4 --- /dev/null +++ b/drv/scb_regs.h @@ -0,0 +1,192 @@ +/** @file scb_regs.h + * Module defining System Control Block (SCB) registers. + * + * Mainly made to be used by the scb module. It is recommanded to go through + * the functions provided by that module instead of directly using the registers + * defined here. + */ + +#ifndef _SCB_REGS_H_ +#define _SCB_REGS_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +#define SCB_BASE_ADDRESS 0xE000ED00 + +union SCB_CPUID { + struct { + uint32_t revision:4; + uint32_t part_no:12; + uint32_t constant:4; + uint32_t variant:4; + uint32_t implementer:8; + }; + uint32_t word; +}; + +union SCB_ICSR { + struct { + uint32_t VECTACTIVE:9; + uint32_t reserved1:2; + uint32_t RETOBASE:1; + uint32_t VECTPENDING:10; + uint32_t ISRPENDING:1; + uint32_t reserved2:2; + uint32_t PENDSTCLR:1; + uint32_t PENDSTSET:1; + uint32_t PENDSVCRL:1; + uint32_t PENDSVSET:1; + uint32_t reserved3:2; + uint32_t NMIPENDSET:1; + }; + uint32_t word; +}; + +union SCB_VTOR { + struct { + uint32_t reserved1:9; + uint32_t TABLEOFF:21; + uint32_t reserved2:2; + }; + uint32_t word; +}; + +union SCB_AIRCR { + struct { + uint32_t VECTRESET:1; + uint32_t VECTCRLACTIVE:1; + uint32_t SYSRESETREQ:1; + uint32_t reserved1:5; + uint32_t PRIGROUP:3; + uint32_t reserved2:4; + uint32_t ENDIANESS:1; + uint32_t VECTKEY:16; + }; + uint32_t word; +}; + +union SCB_SCR { + struct { + uint32_t reserved1:1; + uint32_t SLEEPONEXIT:1; + uint32_t SLEEPDEEP:1; + uint32_t reserved2:1; + uint32_t SEVONPEND:1; + uint32_t reserved3:27; + }; + uint32_t word; +}; + +union SCB_CCR { + struct { + uint32_t NONBASETHRDEN:1; + uint32_t USERSETMPEND:1; + uint32_t reserved1:1; + uint32_t UNALIGN_TRP:1; + uint32_t DIV_0_TRP:1; + uint32_t reserved2:3; + uint32_t BFHFNIGN:1; + uint32_t STKALIGN:1; + uint32_t reserved3:22; + }; + uint32_t word; +}; + +union SCB_SHPR1 { + struct { + uint32_t PRI4:8; + uint32_t PRI5:8; + uint32_t PRI6:8; + uint32_t reserved1:8; + }; + uint32_t word; +}; + +union SCB_SHPR2 { + struct { + uint32_t reserved1:24; + uint32_t PRI11:8; + }; + uint32_t word; +}; + +union SCB_SHPR3 { + struct { + uint32_t reserved1:16; + uint32_t PRI14:8; + uint32_t PRI15:8; + }; + uint32_t word; +}; + +union SCB_SHCRS { + struct { + uint32_t MEMFAULTACT:1; + uint32_t BUSFAULTACT:1; + uint32_t reserved1:1; + uint32_t USGFAULTACT:1; + uint32_t reserved2:3; + uint32_t SVCALLACT:1; + uint32_t MONITORACT:1; + uint32_t reserved3:1; + uint32_t PENDSVACT:1; + uint32_t SYSTICKACT:1; + uint32_t USGFAULTPENDED:1; + uint32_t MEMFAULTPENDED:1; + uint32_t BUSFAULTPENDED:1; + uint32_t SVCALLPENDED:1; + uint32_t MEMFAULTENA:1; + uint32_t BUSFAULTENA:1; + uint32_t USGFAULTENA:1; + uint32_t reserved4:13; + }; + uint32_t word; +}; + +union SCB_CFSR { + struct { + uint32_t MMFSR:8; + uint32_t BFSR:8; + uint32_t UFSR:16; + }; + uint32_t word; +}; + +union SCB_HFSR { + struct { + uint32_t reserved1:1; + uint32_t VECTTBL:1; + uint32_t reserved2:28; + uint32_t FORCED:1; + uint32_t DEBUG_VT:1; + }; + uint32_t word; +}; + +struct SCB { + union SCB_CPUID CPUID; + union SCB_ICSR ICSR; + union SCB_VTOR VTOR; + union SCB_AIRCR AIRCR; + union SCB_SCR SCR; + union SCB_CCR CCR; + union SCB_SHPR1 SHPR1; + union SCB_SHPR2 SHPR2; + union SCB_SHPR3 SHPR3; + union SCB_SHCRS SHCRS; + union SCB_CFSR CFSR; + union SCB_HFSR HFSR; + uint32_t MMAR; + uint32_t BFAR; +}; + + +//--functions------------------------------------------------------------------- + +#endif //_PWR_REGS_H_ + From 1741d47546f57eef2ceb053bb20618edd19b567f Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 13 Jul 2024 21:35:22 +0200 Subject: [PATCH 17/35] Implement SCB module --- drv/scb.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drv/scb.h | 32 ++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 drv/scb.c create mode 100644 drv/scb.h diff --git a/drv/scb.c b/drv/scb.c new file mode 100644 index 0000000..ba0fb96 --- /dev/null +++ b/drv/scb.c @@ -0,0 +1,64 @@ +/** @file scb.c + * Module handling the System Control Block + * + * The module provides functions to configure miscelaneous options of the cortex + * m3, including sleep behavior, event handler priorities, resets and fault + * handlers + */ + +//--includes-------------------------------------------------------------------- + +#include "scb.h" +#include "scb_regs.h" + + +//--local definitions----------------------------------------------------------- + +//--local variables------------------------------------------------------------- + +static volatile struct SCB* regs = (struct SCB*)SCB_BASE_ADDRESS; + + +//--public functions------------------------------------------------------------ + +uint16_t scb_pending_exception(void) +{ + return regs->ICSR.VECTPENDING; +} + +uint16_t scb_active_exception(void) +{ + return regs->ICSR.VECTACTIVE; +} + +void scb_configure_vector_table(uint32_t offset) +{ + //TODO check that last LSB is 0 (alignement restrictions) + regs->VTOR.TABLEOFF = offset & 0x1FFFFF; +} + +void scb_reset_system(void) +{ + regs->AIRCR.SYSRESETREQ = 1; +} + +void scb_configure_deepsleep(bool enable) +{ + regs->SCR.SLEEPDEEP = enable; +} + +void scb_configure_div0_fault(bool enable) +{ + regs->CCR.DIV_0_TRP = enable; +} + +void scb_configure_unalign_fault(bool enable) +{ + regs->CCR.UNALIGN_TRP = enable; +} + + +//--local functions------------------------------------------------------------- + +//--ISRs------------------------------------------------------------------------ + diff --git a/drv/scb.h b/drv/scb.h new file mode 100644 index 0000000..c814cde --- /dev/null +++ b/drv/scb.h @@ -0,0 +1,32 @@ +/** @file scb.h + * Module handling the System Control Block + * + * The module provides functions to configure miscelaneous options of the cortex + * m3, including sleep behavior, event handler priorities, resets and fault + * handlers + */ + +#ifndef _SCB_H_ +#define _SCB_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +//--functions------------------------------------------------------------------- + +uint16_t scb_pending_exception(void); +uint16_t scb_active_exception(void); + +void scb_configure_vector_table(uint32_t offset); +void scb_reset_system(void); +void scb_configure_deepsleep(bool enable); +void scb_configure_div0_fault(bool enable); +void scb_configure_unalign_fault(bool enable); + + +#endif //_SCB_H_ + From 5c89df432477416d0155b0c2d8fa2a8321ea9dc7 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 13 Jul 2024 21:35:42 +0200 Subject: [PATCH 18/35] Fix typo in PWR registers --- drv/pwr_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drv/pwr_regs.h b/drv/pwr_regs.h index d84f4ac..c9da4cf 100644 --- a/drv/pwr_regs.h +++ b/drv/pwr_regs.h @@ -21,7 +21,7 @@ union PWR_CR { struct { uint32_t LPDS:1; - uint32_t LDDS:1; + uint32_t PDDS:1; uint32_t CWUF:1; uint32_t CSBF:1; uint32_t PVDE:1; From 3e97d4fe7e13aeebae0ada1d323023028c338e25 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 14 Jul 2024 19:17:20 +0200 Subject: [PATCH 19/35] Implement sleep modes --- drv/pwr.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ drv/pwr.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 drv/pwr.c create mode 100644 drv/pwr.h diff --git a/drv/pwr.c b/drv/pwr.c new file mode 100644 index 0000000..223a660 --- /dev/null +++ b/drv/pwr.c @@ -0,0 +1,51 @@ +/** @file pwr.c + * Module handling the power management's control + * + * The module provides functions to enter the different sleep states, control + * and filter wakeup events (WKUP and RTC) and configure power voltage + * detection + */ + +//--includes-------------------------------------------------------------------- + +#include "pwr.h" +#include "pwr_regs.h" +#include "scb.h" + + +//--local definitions----------------------------------------------------------- + +//--local variables------------------------------------------------------------- + +static volatile struct PWR* regs = (struct PWR*)PWR_BASE_ADDRESS; + + +//--public functions------------------------------------------------------------ + +void pwr_sleep(void) +{ + scb_configure_deepsleep(false); + __asm("wfi"); +} + +void pwr_stop(enum PwrWakeupSpeed speed) +{ + scb_configure_deepsleep(true); + regs->CR.PDDS = 0; + regs->CR.LPDS = speed; + __asm("wfi"); +} + +void pwr_standby(void) +{ + scb_configure_deepsleep(true); + regs->CR.PDDS = 1; + __asm("wfi"); +} + + +//--local functions------------------------------------------------------------- + +//--ISRs------------------------------------------------------------------------ + + diff --git a/drv/pwr.h b/drv/pwr.h new file mode 100644 index 0000000..f20ad9a --- /dev/null +++ b/drv/pwr.h @@ -0,0 +1,51 @@ +/** @file pwr.h + * Module handling the power management's control + * + * The module provides functions to enter the different sleep states, control + * and filter wakeup events (WKUP and RTC) and configure power voltage + * detection + */ + +#ifndef _PWR_H_ +#define _PWR_H_ + +//--includes-------------------------------------------------------------------- + +//--type definitions------------------------------------------------------------ + +enum PwrWakeupSpeed { + PWR_WAKEUP_SPEED_FAST, //faster wakeup, higher consumption in stop mode + PWR_WAKEUP_SPEED_SLOW, //slower wakeup, lower consumption in stop mode +}; + +enum PwrPvdThreshold { + PWR_PVD_THRESHOLD_2_2V, + PWR_PVD_THRESHOLD_2_3V, + PWR_PVD_THRESHOLD_2_4V, + PWR_PVD_THRESHOLD_2_5V, + PWR_PVD_THRESHOLD_2_6V, + PWR_PVD_THRESHOLD_2_7V, + PWR_PVD_THRESHOLD_2_8V, + PWR_PVD_THRESHOLD_2_9V, + +}; + +typedef void (*PwrPvdCallback)(void); + + +//--functions------------------------------------------------------------------- + +void pwr_sleep(void); +void pwr_stop(enum PwrWakeupSpeed speed); +void pwr_standby(void); + +bool pwr_wakeup_event(void); +bool pwr_standby_exit(void); + +void pwr_configure_bkp_write(bool enable); +void pwr_configure_wakeup_pin(bool enable); +void pwr_configure_pvd(enum PwrPvdThreshold treshold); + + +#endif //_PWR_H_ + From 699569ec99e6921cacf390964e7b62ef96ff1307 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 16 Jul 2024 21:50:01 +0200 Subject: [PATCH 20/35] Add LSI configuration function to RCC --- drv/rcc.c | 10 ++++++++++ drv/rcc.h | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/drv/rcc.c b/drv/rcc.c index 73fe49b..56adbbc 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -60,6 +60,16 @@ void rcc_configure(enum RccPreset preset) regs->APB2ENR = apb2_enr; } +void rcc_configure_lsi(bool enable) +{ + regs->CSR.LSION = enable; + + //ensure LSI is enabled + if (enable) { + while (regs->CSR.LSIRDY != 0x1); + } +} + void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask, enum RccApb2 apb2_mask) { diff --git a/drv/rcc.h b/drv/rcc.h index 770b7a0..f26ba01 100644 --- a/drv/rcc.h +++ b/drv/rcc.h @@ -112,6 +112,12 @@ struct RccClocks { */ void rcc_configure(enum RccPreset preset); +/** + * Configures the Low Speed Internal (LSI) oscillator for low power + * applications. + */ +void rcc_configure_lsi(bool enable); + /** * Enables peripherals on the different buses. The enums values can used as * masks to enable multiple peripherals at the same time. Invalid values will be From a02bcecaec7048173b47d56edd8d96fea597ac15 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Tue, 16 Jul 2024 22:21:05 +0200 Subject: [PATCH 21/35] Implement RTC module's registers --- drv/rtc_regs.h | 125 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 drv/rtc_regs.h diff --git a/drv/rtc_regs.h b/drv/rtc_regs.h new file mode 100644 index 0000000..de83d87 --- /dev/null +++ b/drv/rtc_regs.h @@ -0,0 +1,125 @@ +/** @file rtc_regs.h + * Module defining the Real-Time Clock (RTC) registers. + * + * Mainly made to be used by the rtc module. It is recommanded to go through + * the functions provided by that module instead of directly using the registers + * defined here. + */ + +#ifndef _RTC_REGS_H_ +#define _RTC_REGS_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +#define RTC_BASE_ADDRESS 0x40002800 + +union RTC_CRH { + struct { + uint32_t SECIE:1; + uint32_t ALRIE:1; + uint32_t OWIE:1; + uint32_t reserved1:29; + }; + uint32_t word; +}; + +union RTC_CRL { + struct { + uint32_t SECF:1; + uint32_t ALRF:1; + uint32_t OWF:1; + uint32_t RSF:1; + uint32_t CNF:1; + uint32_t RTOFF:1; + uint32_t reserved1:26; + }; + uint32_t word; +}; + +union RTC_PRLH { + struct { + uint32_t PRL:4; + uint32_t reserved1:28; + }; + uint32_t word; +}; + +union RTC_PRLL { + struct { + uint32_t PRL:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union RTC_DIVH { + struct { + uint32_t RTC_DIV:4; + uint32_t reserved1:28; + }; + uint32_t word; +}; + +union RTC_DIVL { + struct { + uint32_t RTC_DIV:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union RTC_CNTH { + struct { + uint32_t RTC_CNT:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union RTC_CNTL { + struct { + uint32_t RTC_CNT:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union RTC_ALRH { + struct { + uint32_t RTC_ALR:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union RTC_ALRL { + struct { + uint32_t RTC_ALR:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +struct RTC { + union RTC_CRH CRH; + union RTC_CRL CRL; + union RTC_PRLH PRLH; + union RTC_PRLL PRLL; + union RTC_DIVH DIVH; + union RTC_DIVL DIVL; + union RTC_CNTH CNTH; + union RTC_CNTL CNTL; + union RTC_ALRH ALRH; + union RTC_ALRL ALRL; +}; + + +//--functions------------------------------------------------------------------- + +#endif //_RTC_REGS_H_ + From 0b483c535bd68404b4269188d550ab188a314b6e Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 14:15:31 +0200 Subject: [PATCH 22/35] Ensure PWR is enabled before configuration --- drv/pwr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drv/pwr.c b/drv/pwr.c index 223a660..19f17f7 100644 --- a/drv/pwr.c +++ b/drv/pwr.c @@ -11,6 +11,7 @@ #include "pwr.h" #include "pwr_regs.h" #include "scb.h" +#include "rcc.h" //--local definitions----------------------------------------------------------- @@ -30,19 +31,28 @@ void pwr_sleep(void) void pwr_stop(enum PwrWakeupSpeed speed) { + rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE); scb_configure_deepsleep(true); regs->CR.PDDS = 0; regs->CR.LPDS = speed; __asm("wfi"); + rcc_configure(RCC_PRESET_SPEED); } void pwr_standby(void) { + rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE); scb_configure_deepsleep(true); regs->CR.PDDS = 1; __asm("wfi"); + rcc_configure(RCC_PRESET_SPEED); } +void pwr_configure_bkp_write(bool enable) +{ + rcc_enable(RCC_AHB_NONE, RCC_APB1_PWR, RCC_APB2_NONE); + regs->CR.DBP = enable; +} //--local functions------------------------------------------------------------- From b37eb1dd6eb53f94f25ad2a201903ac5e24bf01c Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 14:17:58 +0200 Subject: [PATCH 23/35] Add RTC configuration to RCC module --- drv/rcc.c | 8 +++++++- drv/rcc.h | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drv/rcc.c b/drv/rcc.c index 56adbbc..c229c45 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -66,10 +66,16 @@ void rcc_configure_lsi(bool enable) //ensure LSI is enabled if (enable) { - while (regs->CSR.LSIRDY != 0x1); + while (regs->CSR.LSIRDY != 0x1) {} } } +void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src) +{ + regs->BDCR.RTCSEL = clock_src; + regs->BDCR.RTCEN = enable; +} + void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask, enum RccApb2 apb2_mask) { diff --git a/drv/rcc.h b/drv/rcc.h index f26ba01..b437ecb 100644 --- a/drv/rcc.h +++ b/drv/rcc.h @@ -95,6 +95,13 @@ enum RccApb2 { RCC_APB2_TIM11 = (0x1 << 21), }; +enum RccRtcClockSrc { + RCC_RTC_CLOCK_SRC_NONE = 0x0, + RCC_RTC_CLOCK_SRC_LSE = 0x1, + RCC_RTC_CLOCK_SRC_LSI = 0x2, + RCC_RTC_CLOCK_SRC_HSE = 0x3, +}; + struct RccClocks { uint32_t ahb_freq; uint32_t apb1_freq; @@ -118,6 +125,8 @@ void rcc_configure(enum RccPreset preset); */ void rcc_configure_lsi(bool enable); +void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src); + /** * Enables peripherals on the different buses. The enums values can used as * masks to enable multiple peripherals at the same time. Invalid values will be From 3e3d4d2bff8b8418c54d81598fb44300f4a3568f Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 16:39:49 +0200 Subject: [PATCH 24/35] Implement RTC module's basic functionnalities FUnctions need a cleanup and some details need be ironned, like the clock management since the whole backup domain must be reset to configure them --- drv/rtc.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ drv/rtc.h | 43 +++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 drv/rtc.c create mode 100644 drv/rtc.h diff --git a/drv/rtc.c b/drv/rtc.c new file mode 100644 index 0000000..fe5ddd1 --- /dev/null +++ b/drv/rtc.c @@ -0,0 +1,139 @@ +//--includes-------------------------------------------------------------------- + +#include "rtc.h" +#include "rtc_regs.h" +#include "rcc.h" +#include "pwr.h" +#include "nvic.h" + + +//--local definitions----------------------------------------------------------- + +//--local variables------------------------------------------------------------- + +static volatile struct RTC* regs = (struct RTC*)RTC_BASE_ADDRESS; +static RtcCallback rtc_callback; + + +//--public functions------------------------------------------------------------ + +void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, + enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback) +{ + pwr_configure_bkp_write(true); + //start RTC + rcc_configure_rtc(true, clock_src + 1); + + //rtc_reset(); + rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + //rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); + + //compute prescaler + uint32_t prescaler = 0; + switch (clock_src) { + case RTC_CLOCK_SRC_LSE: + prescaler = 32768000; //32.768kHz + break; + case RTC_CLOCK_SRC_LSI: + prescaler = 40000000; //40khz + break; + case RTC_CLOCK_SRC_HSE: + prescaler = 62500000; //8Mhz / 128 + break; + default: + return; + } + prescaler /= period_ms; + + //wait for registers to synchronize + regs->CRL.RSF = 0; + while (regs->CRL.RSF != 1) {} + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + //enable core configuration + regs->CRL.CNF = 1; + + //configure core registers + regs->PRLH.PRL = prescaler >> 16; + regs->PRLL.PRL = prescaler; + regs->ALRH.RTC_ALR = alarm_tick >> 16; + regs->ALRL.RTC_ALR = alarm_tick; + + //apply irq config + regs->CRH.word |= irq_mask & 0x7; + + //disable/apply core configuration + regs->CRL.CNF = 0; + + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + pwr_configure_bkp_write(false); + + if (callback) { + rtc_callback = callback; + nvic_enable(NVIC_IRQ_RTC); + } +} + +void rtc_reset(void) +{ + nvic_disable(NVIC_IRQ_RTC); + pwr_configure_bkp_write(true); + rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + + //wait for registers to synchronize + regs->CRL.RSF = 0; + //while (regs->CRL.RSF != 1) {} + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + //clear config registers + regs->CRH.word &= ~0x7; + regs->CRL.word &= ~0xf; + + //enable core configuration + regs->CRL.CNF = 1; + + //reset core registers. DIV register can be ignore since it is reset on any + //changes of the other 2 + regs->PRLH.PRL = 0x0; + regs->PRLL.PRL = 0x8000; + regs->CNTH.RTC_CNT = 0x0; + regs->CNTL.RTC_CNT = 0x0; + + //disable/apply core configuration + regs->CRL.CNF = 0; + + //wait for last operation to finish + while (regs->CRL.RTOFF != 1) {} + + rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); + rcc_disable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + pwr_configure_bkp_write(false); +} + +uint32_t stk_read_s(void) +{ + //wait for core registers to be synchronized, immediate most of the time + while (regs->CRL.RSF != 1) {} + + uint32_t time = regs->CNTH.RTC_CNT << 16; + time |= regs->CNTL.RTC_CNT << 0; + + return time; +} + + +//--local functions------------------------------------------------------------- + +void hdr_rtc(void) +{ + nvic_clear_pending(NVIC_IRQ_RTC); + + //copy and clear and pass along src flags + enum RtcIrq src = regs->CRL.word & 0x7; + regs->CRL.word &= ~(0x7); + rtc_callback(src); +} diff --git a/drv/rtc.h b/drv/rtc.h new file mode 100644 index 0000000..ff161f4 --- /dev/null +++ b/drv/rtc.h @@ -0,0 +1,43 @@ +/** @file rtc.h + * Module handling the Real-Time Clock (RTC). + * + */ + +#ifndef _RTC_H_ +#define _RTC_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +enum RtcClockSrc { + RTC_CLOCK_SRC_LSE = 0x0, + RTC_CLOCK_SRC_LSI = 0x1, + RTC_CLOCK_SRC_HSE = 0x2, +}; + +enum RtcIrq { + RTC_IRQ_NONE = 0, + RTC_IRQ_SECOND = 0x1 << 0, + RTC_IRQ_ALARM = 0x1 << 1, + RTC_IRQ_OVERFLOW = 0x1 << 2, +}; + +typedef void (*RtcCallback)(enum RtcIrq src); + + +//--functions------------------------------------------------------------------- + +void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, + enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback); + +void rtc_reset(void); + +uint32_t stk_read_s(void); + + +#endif //_RTC_H_ + From 507f1e68635f702eb79f825e5c09c542bea4f760 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 20:07:36 +0200 Subject: [PATCH 25/35] Move rtc control to new BKP module RCC's BCDR register has been moved to the BKP module since it is part of the backup circuit and thus also aboeys some restrictions access-wise --- drv/bkp.c | 125 +++++++++++++++++++++++++++++ drv/bkp.h | 47 +++++++++++ drv/{rtc_regs.h => bkp_regs.h} | 83 ++++++++++++++++++-- drv/rcc.c | 6 -- drv/rcc.h | 2 - drv/rcc_regs.h | 17 +--- drv/rtc.c | 139 --------------------------------- drv/rtc.h | 43 ---------- 8 files changed, 250 insertions(+), 212 deletions(-) create mode 100644 drv/bkp.c create mode 100644 drv/bkp.h rename drv/{rtc_regs.h => bkp_regs.h} (59%) delete mode 100644 drv/rtc.c delete mode 100644 drv/rtc.h diff --git a/drv/bkp.c b/drv/bkp.c new file mode 100644 index 0000000..5c2f4ec --- /dev/null +++ b/drv/bkp.c @@ -0,0 +1,125 @@ +/** @file bkp.c + * Module handling the Backup (BKP) domain functionalities. + * + */ + +//--includes-------------------------------------------------------------------- + +#include "bkp.h" +#include "bkp_regs.h" +#include "rcc.h" +#include "nvic.h" + + +//--local definitions----------------------------------------------------------- + +uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src); + + +//--local variables------------------------------------------------------------- + +static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS; +static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS; +static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS; + +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) +{ + rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); + + //start RTC + rcc_regs->BDCR.RTCSEL = clock_src + 1; + rcc_regs->BDCR.RTCEN = 1; + + //compute prescaler + uint32_t prescaler = compute_prescaler(period_ms, clock_src); + + //wait for registers to synchronize + rtc_regs->CRL.RSF = 0; + while (rtc_regs->CRL.RSF != 1) {} + //wait for last operation to finish + while (rtc_regs->CRL.RTOFF != 1) {} + + //enable core configuration + rtc_regs->CRL.CNF = 1; + + //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; + + //disable/apply core configuration + rtc_regs->CRL.CNF = 0; + + //wait for last operation to finish + while (rtc_regs->CRL.RTOFF != 1) {} + + if (callback) { + rtc_callback = callback; + nvic_enable(NVIC_IRQ_RTC); + } +} + +uint32_t bkp_read_rtc(void) +{ + //wait for core registers to be synchronized, immediate most of the time + while (rtc_regs->CRL.RSF != 1) {} + + uint32_t time = rtc_regs->CNTH.RTC_CNT << 16; + time |= rtc_regs->CNTL.RTC_CNT << 0; + + return time; +} + +void bkp_reset(void) +{ + rcc_regs->BDCR.BDRST = 1; + rcc_regs->BDCR.BDRST = 0; +} + + +//--local functions------------------------------------------------------------- + +uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src) +{ + uint32_t prescaler; + + switch (clock_src) { + case BKP_RTC_CLOCK_SRC_LSE: + prescaler = 32768000; //32.768kHz + break; + case BKP_RTC_CLOCK_SRC_LSI: + prescaler = 40000000; //40khz + break; + case BKP_RTC_CLOCK_SRC_HSE: + prescaler = 62500000; //8Mhz / 128 + break; + default: + return 0; + } + + return prescaler / period_ms; +} + + +//--ISRs------------------------------------------------------------------------ + +void hdr_rtc(void) +{ + nvic_clear_pending(NVIC_IRQ_RTC); + + //copy and clear and pass along src flags + enum BkpRtcIrq src = rtc_regs->CRL.word & 0x7; + rtc_regs->CRL.word &= ~(0x7); + rtc_callback(src); +} + diff --git a/drv/bkp.h b/drv/bkp.h new file mode 100644 index 0000000..f7e9c0f --- /dev/null +++ b/drv/bkp.h @@ -0,0 +1,47 @@ +/** @file bkp.h + * Module handling the Backup (BKP) domain functionalities. + * + */ + +#ifndef _BKP_H_ +#define _BKP_H_ + +//--includes-------------------------------------------------------------------- + +#include "stdint.h" + + +//--type definitions------------------------------------------------------------ + +enum BkpRtcClockSrc { + BKP_RTC_CLOCK_SRC_LSE = 0x0, + BKP_RTC_CLOCK_SRC_LSI = 0x1, + BKP_RTC_CLOCK_SRC_HSE = 0x2, +}; + +enum BkpRtcIrq { + BKP_RTC_IRQ_NONE = 0, + BKP_RTC_IRQ_SECOND = 0x1 << 0, + BKP_RTC_IRQ_ALARM = 0x1 << 1, + BKP_RTC_IRQ_OVERFLOW = 0x1 << 2, +}; + +typedef void (*BkpRtcCallback)(enum BkpRtcIrq src); + + +//--functions------------------------------------------------------------------- + +void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src, + enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback); +uint32_t bkp_read_rtc(void); + +void bkp_reset(void); + +//unimplemented functions +void bkp_configure_tamper(); +void bkp_calibrate_lsi(void); +void bkp_configure_lse(bool enable); + + +#endif //_BKP_H_ + diff --git a/drv/rtc_regs.h b/drv/bkp_regs.h similarity index 59% rename from drv/rtc_regs.h rename to drv/bkp_regs.h index de83d87..8a3b6c7 100644 --- a/drv/rtc_regs.h +++ b/drv/bkp_regs.h @@ -1,13 +1,13 @@ -/** @file rtc_regs.h - * Module defining the Real-Time Clock (RTC) registers. +/** @file bkp_regs.h + * Module defining the Backup (bkp) domain registers. * - * Mainly made to be used by the rtc module. It is recommanded to go through + * Mainly made to be used by the bkp module. It is recommanded to go through * the functions provided by that module instead of directly using the registers * defined here. */ -#ifndef _RTC_REGS_H_ -#define _RTC_REGS_H_ +#ifndef _BKP_REGS_H_ +#define _BKP_REGS_H_ //--includes-------------------------------------------------------------------- @@ -16,8 +16,79 @@ //--type definitions------------------------------------------------------------ +#define BKP_BASE_ADDRESS 0x40006C00 +#define RCC_BASE_ADDRESS 0x40021020 #define RTC_BASE_ADDRESS 0x40002800 +union BKP_DR { + struct { + uint32_t D:16; + uint32_t reserved1:16; + }; + uint32_t word; +}; + +union BKP_RTCCR { + struct { + uint32_t CAL:7; + uint32_t CCO:1; + uint32_t ASOE:1; + uint32_t ASOS:1; + uint32_t reserved1:22; + }; + uint32_t word; +}; + +union BKP_CR { + struct { + uint32_t TPE:1; + uint32_t TPAL:1; + uint32_t reserved1:30; + }; + uint32_t word; +}; + +union BKP_CSR { + struct { + uint32_t CTE:1; + uint32_t CTI:1; + uint32_t TPIE:1; + uint32_t reserved1:5; + uint32_t TEF:1; + uint32_t TIF:1; + uint32_t reserved2:22; + }; + uint32_t word; +}; + +struct BKP { + union BKP_DR DR[20]; + union BKP_RTCCR RTCCR; + union BKP_CR CR; + union BKP_CSR CSR; +}; + + +union RCC_BDCR { + struct { + uint32_t LSEON:1; + uint32_t LSERDY:1; + uint32_t LSEBYP:1; + uint32_t reserved1:5; + uint32_t RTCSEL:2; + uint32_t reserved2:5; + uint32_t RTCEN:1; + uint32_t BDRST:1; + uint32_t reserved3:15; + }; + uint32_t word; +}; + +struct RCC { + union RCC_BDCR BDCR; +}; + + union RTC_CRH { struct { uint32_t SECIE:1; @@ -121,5 +192,5 @@ struct RTC { //--functions------------------------------------------------------------------- -#endif //_RTC_REGS_H_ +#endif //_BKP_REGS_H_ diff --git a/drv/rcc.c b/drv/rcc.c index c229c45..4369a79 100644 --- a/drv/rcc.c +++ b/drv/rcc.c @@ -70,12 +70,6 @@ void rcc_configure_lsi(bool enable) } } -void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src) -{ - regs->BDCR.RTCSEL = clock_src; - regs->BDCR.RTCEN = enable; -} - void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask, enum RccApb2 apb2_mask) { diff --git a/drv/rcc.h b/drv/rcc.h index b437ecb..9d1e9d4 100644 --- a/drv/rcc.h +++ b/drv/rcc.h @@ -125,8 +125,6 @@ void rcc_configure(enum RccPreset preset); */ void rcc_configure_lsi(bool enable); -void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src); - /** * Enables peripherals on the different buses. The enums values can used as * masks to enable multiple peripherals at the same time. Invalid values will be diff --git a/drv/rcc_regs.h b/drv/rcc_regs.h index 47a9612..7e36f7a 100644 --- a/drv/rcc_regs.h +++ b/drv/rcc_regs.h @@ -225,21 +225,6 @@ union RCC_APB1ENR { uint32_t word; }; -union RCC_BDCR { - struct { - uint32_t LSEON:1; - uint32_t LSERDY:1; - uint32_t LSEBYP:1; - uint32_t reserved1:5; - uint32_t RTCSEL:2; - uint32_t reserved2:5; - uint32_t RTCEN:1; - uint32_t BDRST:1; - uint32_t reserved3:15; - }; - uint32_t word; -}; - union RCC_CSR { struct { uint32_t LSION:1; @@ -266,7 +251,7 @@ struct RCC { union RCC_AHBENR AHBENR; union RCC_APB2ENR APB2ENR; union RCC_APB1ENR APB1ENR; - union RCC_BDCR BDCR; + uint32_t reserved1; union RCC_CSR CSR; }; diff --git a/drv/rtc.c b/drv/rtc.c deleted file mode 100644 index fe5ddd1..0000000 --- a/drv/rtc.c +++ /dev/null @@ -1,139 +0,0 @@ -//--includes-------------------------------------------------------------------- - -#include "rtc.h" -#include "rtc_regs.h" -#include "rcc.h" -#include "pwr.h" -#include "nvic.h" - - -//--local definitions----------------------------------------------------------- - -//--local variables------------------------------------------------------------- - -static volatile struct RTC* regs = (struct RTC*)RTC_BASE_ADDRESS; -static RtcCallback rtc_callback; - - -//--public functions------------------------------------------------------------ - -void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, - enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback) -{ - pwr_configure_bkp_write(true); - //start RTC - rcc_configure_rtc(true, clock_src + 1); - - //rtc_reset(); - rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); - //rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); - - //compute prescaler - uint32_t prescaler = 0; - switch (clock_src) { - case RTC_CLOCK_SRC_LSE: - prescaler = 32768000; //32.768kHz - break; - case RTC_CLOCK_SRC_LSI: - prescaler = 40000000; //40khz - break; - case RTC_CLOCK_SRC_HSE: - prescaler = 62500000; //8Mhz / 128 - break; - default: - return; - } - prescaler /= period_ms; - - //wait for registers to synchronize - regs->CRL.RSF = 0; - while (regs->CRL.RSF != 1) {} - //wait for last operation to finish - while (regs->CRL.RTOFF != 1) {} - - //enable core configuration - regs->CRL.CNF = 1; - - //configure core registers - regs->PRLH.PRL = prescaler >> 16; - regs->PRLL.PRL = prescaler; - regs->ALRH.RTC_ALR = alarm_tick >> 16; - regs->ALRL.RTC_ALR = alarm_tick; - - //apply irq config - regs->CRH.word |= irq_mask & 0x7; - - //disable/apply core configuration - regs->CRL.CNF = 0; - - //wait for last operation to finish - while (regs->CRL.RTOFF != 1) {} - - pwr_configure_bkp_write(false); - - if (callback) { - rtc_callback = callback; - nvic_enable(NVIC_IRQ_RTC); - } -} - -void rtc_reset(void) -{ - nvic_disable(NVIC_IRQ_RTC); - pwr_configure_bkp_write(true); - rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); - - //wait for registers to synchronize - regs->CRL.RSF = 0; - //while (regs->CRL.RSF != 1) {} - //wait for last operation to finish - while (regs->CRL.RTOFF != 1) {} - - //clear config registers - regs->CRH.word &= ~0x7; - regs->CRL.word &= ~0xf; - - //enable core configuration - regs->CRL.CNF = 1; - - //reset core registers. DIV register can be ignore since it is reset on any - //changes of the other 2 - regs->PRLH.PRL = 0x0; - regs->PRLL.PRL = 0x8000; - regs->CNTH.RTC_CNT = 0x0; - regs->CNTL.RTC_CNT = 0x0; - - //disable/apply core configuration - regs->CRL.CNF = 0; - - //wait for last operation to finish - while (regs->CRL.RTOFF != 1) {} - - rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE); - rcc_disable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE); - pwr_configure_bkp_write(false); -} - -uint32_t stk_read_s(void) -{ - //wait for core registers to be synchronized, immediate most of the time - while (regs->CRL.RSF != 1) {} - - uint32_t time = regs->CNTH.RTC_CNT << 16; - time |= regs->CNTL.RTC_CNT << 0; - - return time; -} - - -//--local functions------------------------------------------------------------- - -void hdr_rtc(void) -{ - nvic_clear_pending(NVIC_IRQ_RTC); - - //copy and clear and pass along src flags - enum RtcIrq src = regs->CRL.word & 0x7; - regs->CRL.word &= ~(0x7); - rtc_callback(src); -} diff --git a/drv/rtc.h b/drv/rtc.h deleted file mode 100644 index ff161f4..0000000 --- a/drv/rtc.h +++ /dev/null @@ -1,43 +0,0 @@ -/** @file rtc.h - * Module handling the Real-Time Clock (RTC). - * - */ - -#ifndef _RTC_H_ -#define _RTC_H_ - -//--includes-------------------------------------------------------------------- - -#include "stdint.h" - - -//--type definitions------------------------------------------------------------ - -enum RtcClockSrc { - RTC_CLOCK_SRC_LSE = 0x0, - RTC_CLOCK_SRC_LSI = 0x1, - RTC_CLOCK_SRC_HSE = 0x2, -}; - -enum RtcIrq { - RTC_IRQ_NONE = 0, - RTC_IRQ_SECOND = 0x1 << 0, - RTC_IRQ_ALARM = 0x1 << 1, - RTC_IRQ_OVERFLOW = 0x1 << 2, -}; - -typedef void (*RtcCallback)(enum RtcIrq src); - - -//--functions------------------------------------------------------------------- - -void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src, - enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback); - -void rtc_reset(void); - -uint32_t stk_read_s(void); - - -#endif //_RTC_H_ - From b1d25561b4467548422fbf7b94a050777532e08f Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 21:57:53 +0200 Subject: [PATCH 26/35] Temporarily fix warning --- drv/bkp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drv/bkp.c b/drv/bkp.c index 5c2f4ec..f57aab9 100644 --- a/drv/bkp.c +++ b/drv/bkp.c @@ -18,7 +18,7 @@ uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src); //--local variables------------------------------------------------------------- -static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS; +//static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS; static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS; static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS; From 80c027370b4102f876ae0a07cdcd8d2cb1a0dee4 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 22:13:46 +0200 Subject: [PATCH 27/35] Document BKP module --- drv/bkp.c | 5 ++++- drv/bkp.h | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drv/bkp.c b/drv/bkp.c index f57aab9..457fa74 100644 --- a/drv/bkp.c +++ b/drv/bkp.c @@ -36,7 +36,6 @@ void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src, rcc_regs->BDCR.RTCSEL = clock_src + 1; rcc_regs->BDCR.RTCEN = 1; - //compute prescaler uint32_t prescaler = compute_prescaler(period_ms, clock_src); //wait for registers to synchronize @@ -89,6 +88,10 @@ void bkp_reset(void) //--local functions------------------------------------------------------------- +/** + * Computes the prescaler value based on the clock source and the required + * period + */ uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src) { uint32_t prescaler; diff --git a/drv/bkp.h b/drv/bkp.h index f7e9c0f..c921897 100644 --- a/drv/bkp.h +++ b/drv/bkp.h @@ -13,12 +13,20 @@ //--type definitions------------------------------------------------------------ +/** + * Available clock sources for the RTC. See bkp_configure_rtc() for more + * information + */ enum BkpRtcClockSrc { BKP_RTC_CLOCK_SRC_LSE = 0x0, BKP_RTC_CLOCK_SRC_LSI = 0x1, BKP_RTC_CLOCK_SRC_HSE = 0x2, }; +/** + * Available IRQ sources. This enum is passed to the RTC callback to allow + * differentiating IRQ sources + */ enum BkpRtcIrq { BKP_RTC_IRQ_NONE = 0, BKP_RTC_IRQ_SECOND = 0x1 << 0, @@ -26,15 +34,45 @@ enum BkpRtcIrq { BKP_RTC_IRQ_OVERFLOW = 0x1 << 2, }; +/** + * Prototype of the IRQ callbacks that the applicative code can provide + */ typedef void (*BkpRtcCallback)(enum BkpRtcIrq src); //--functions------------------------------------------------------------------- +/** + * Configures the RTC, starting it immediately. Configuration is saved between + * boots as long as VBAT is present + * + * The RTC can run on a period of up to 1s and using one of 3 clocks. Clock + * choice is a question of compromise : + * - LSE consumes the less energy and continues to run in standby mode, but + * requires an extra oscillator circuit + * - LSI consumes little but isn't very accurate and requires extra calibration + * (see bkp_callibrate_lsi) + * - HSE consumes the most. + * WARNING : once configured, the clock source can only changed by reseting the + * whole backup domain via bkp_reset() + * 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. + */ void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src, enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback); + +/** + * Returns the current counter value of the RTC + */ uint32_t bkp_read_rtc(void); +/** + * Resets the entire backup domain, composed of everything configured through + * this module + */ void bkp_reset(void); //unimplemented functions From 947df53ecb260372af20d3303ed3f13cf866f7c5 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sat, 27 Jul 2024 22:19:29 +0200 Subject: [PATCH 28/35] Add missing file documentation --- drv/bkp.c | 5 +++++ drv/bkp.h | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/drv/bkp.c b/drv/bkp.c index 457fa74..c6b93a4 100644 --- a/drv/bkp.c +++ b/drv/bkp.c @@ -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-------------------------------------------------------------------- diff --git a/drv/bkp.h b/drv/bkp.h index c921897..b78994e 100644 --- a/drv/bkp.h +++ b/drv/bkp.h @@ -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_ @@ -60,6 +65,9 @@ typedef void (*BkpRtcCallback)(enum BkpRtcIrq src); * 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. + * + * 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); From ba9bc57a4976c0541954d18d8c225ec32acc192d Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 15:52:24 +0200 Subject: [PATCH 29/35] 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 --- openocd.cfg | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 openocd.cfg diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..5598416 --- /dev/null +++ b/openocd.cfg @@ -0,0 +1,22 @@ + +# 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 +} + +# 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 + From 7ab6622908df5cc4795f8949d465edca3f4eef8d Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 19:38:24 +0200 Subject: [PATCH 30/35] 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 --- drv/exti.c | 71 ++++++++++-------------------------------------------- drv/exti.h | 63 +++++++++++++++--------------------------------- 2 files changed, 33 insertions(+), 101 deletions(-) diff --git a/drv/exti.c b/drv/exti.c index 3db9837..c1d56af 100644 --- a/drv/exti.c +++ b/drv/exti.c @@ -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------------------------------------------------------------- diff --git a/drv/exti.h b/drv/exti.h index 3349aca..dc8a337 100644 --- a/drv/exti.h +++ b/drv/exti.h @@ -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 */ From 24e412446dc0cc2e95037a6afd5db6df9715fac8 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 20:04:09 +0200 Subject: [PATCH 31/35] 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 --- drv/bkp.c | 25 ++++++++++++++++++++++--- drv/bkp.h | 15 ++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/drv/bkp.c b/drv/bkp.c index c6b93a4..69630b9 100644 --- a/drv/bkp.c +++ b/drv/bkp.c @@ -33,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); @@ -55,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; @@ -73,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 diff --git a/drv/bkp.h b/drv/bkp.h index b78994e..28da3f8 100644 --- a/drv/bkp.h +++ b/drv/bkp.h @@ -63,14 +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 From 89c81b8c42dc4df3568a4c21d57775a79d0d40bc Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 20:13:18 +0200 Subject: [PATCH 32/35] Integrate the RTC to the task module --- srv/task.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/srv/task.c b/srv/task.c index 818a8b5..047fca1 100644 --- a/srv/task.c +++ b/srv/task.c @@ -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; } From a4ca0d30c3cfc1668943adbebdf947d95de99848 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 20:14:34 +0200 Subject: [PATCH 33/35] 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 --- openocd.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openocd.cfg b/openocd.cfg index 5598416..06dd5e9 100644 --- a/openocd.cfg +++ b/openocd.cfg @@ -14,6 +14,9 @@ $CHIPNAME.cpu configure -event examine-end { 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 From bc4bab47049acd04a402d17be7dfa2f37af175b4 Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 20:17:52 +0200 Subject: [PATCH 34/35] Fix include issue in afio module --- drv/afio.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drv/afio.h b/drv/afio.h index f1a06de..f32253a 100644 --- a/drv/afio.h +++ b/drv/afio.h @@ -9,10 +9,8 @@ //--includes-------------------------------------------------------------------- -#include "stdint.h" -#include "stdbool.h" - #include "exti.h" +#include "gpio.h" //--type definitions------------------------------------------------------------ From ebc7ad42352d45f2f8d4e9432bc973034667ae4f Mon Sep 17 00:00:00 2001 From: Steins7 Date: Sun, 4 Aug 2024 20:18:45 +0200 Subject: [PATCH 35/35] Fix compilation warning in task module --- srv/task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srv/task.h b/srv/task.h index 696a6dd..00e0d32 100644 --- a/srv/task.h +++ b/srv/task.h @@ -84,7 +84,7 @@ struct Task { */ #define TASK_ENTRY \ _TASK_COUNT_INIT; \ - (void*) __task_time; \ + (void) __task_time; \ switch (__task_state->count) { /**