Compare commits

..

5 Commits

Author SHA1 Message Date
b7951f2211 Simplify task module 2024-07-06 22:43:50 +02:00
7cb33f65a5 Create new delay module 2024-05-14 15:03:18 +02:00
c09d2cda67 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
2024-05-14 14:53:51 +02:00
34fb4dac76 Make stk_read function usable
This function used to return the raw current value, but that exposes the
prescaling used internaly
2024-04-30 20:17:58 +02:00
432310a52d 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
2024-04-30 20:15:58 +02:00
6 changed files with 228 additions and 25 deletions

View File

@ -21,6 +21,7 @@ static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS;
//--local variables------------------------------------------------------------- //--local variables-------------------------------------------------------------
static StkCallback callback; static StkCallback callback;
static uint32_t prescaler;
//--public functions------------------------------------------------------------ //--public functions------------------------------------------------------------
@ -32,10 +33,12 @@ uint32_t stk_configure(uint32_t period_us, StkCallback cb)
struct RccClocks clocks; struct RccClocks clocks;
rcc_get_clocks(&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) { if (reload < 1) {
//period is too small, try using the non-prescaled clock //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) { if (reload < 1) {
//period is still too small //period is still too small
return 1; return 1;
@ -71,9 +74,9 @@ void stk_stop(void)
reg_reset(regs->CTRL, STK_CTRL_ENABLE); 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;
} }

View File

@ -46,9 +46,9 @@ void stk_start(void);
void stk_stop(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_ #endif //_STK_H_

23
srv/delay.c Normal file
View File

@ -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-------------------------------------------------------------

23
srv/delay.h Normal file
View File

@ -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_

View File

@ -6,3 +6,85 @@
* see https://dunkels.com/adam/pt/index.html * see https://dunkels.com/adam/pt/index.html
*/ */
//--includes--------------------------------------------------------------------
#include "task.h"
#include "error.h"
//--local definitions-----------------------------------------------------------
#define MAX_TASK_NB 10
//--local variables-------------------------------------------------------------
static struct Task task_list[MAX_TASK_NB];
static uint8_t task_nb;
//--public functions------------------------------------------------------------
void task_schedule(uint32_t elapsed_ms)
{
for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function != nullptr) {
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;
}
}
}
}
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 = function;
task_list[i].state.delay = 0;
task_list[i].state.count = 0;
task_list[i].state.is_active = false;
++task_nb;
return;
}
}
error_trigger("task list is full");
}
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].function = nullptr;
return;
}
}
error_trigger("task does not exist");
}
bool task_is_running(TaskFunction function)
{
for (uint8_t i = 0; i < task_nb; ++i) {
if (task_list[i].function == function) {
return true;
}
}
return false;
}

View File

@ -12,41 +12,113 @@
//--includes-------------------------------------------------------------------- //--includes--------------------------------------------------------------------
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
//--type definitions------------------------------------------------------------
struct TaskState {
int32_t delay;
uint8_t count:7;
uint8_t is_active:1;
};
typedef void(*TaskFunction)(struct TaskState*);
struct Task {
TaskFunction function;
struct TaskState state;
};
//--functions------------------------------------------------------------------- //--functions-------------------------------------------------------------------
#define TASK(fct_name) uint8_t fct_name(uint8_t __task_context) #define TASK(fct_name) void fct_name(struct TaskState* restrict __task_state)
#define task_begin() do { \ #define TASK_ENTRY \
_TASK_COUNT_INIT; \ _TASK_COUNT_INIT; \
switch (__task_context) { \ switch (__task_state->count) {
} while (0)
#define task_end() do { \ #define TASK_CLEANUP \
case (_TASK_COUNT_CLEANUP): \
/* fall through */
#define TASK_EXIT \
} \ } \
return _TASK_COUNT_STOP; \ __task_state->count = _TASK_COUNT_EXIT; \
while (0) return;
#define task_wait_until(cond) _task_wait_until(cond, _TASK_COUNT_INCR) #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_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_schedule(uint32_t elapsed_ms);
void task_declare();
void task_start(TaskFunction task);
void task_stop(TaskFunction task);
bool task_is_running(TaskFunction task);
//--internal_functions---------------------------------------------------------- //--internal_functions----------------------------------------------------------
#define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ } #define _TASK_COUNT_INIT enum { TASK_COUNTER_BASE = __COUNTER__ }
#define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1) #define _TASK_COUNT_INCR (uint8_t)(__COUNTER__ - TASK_COUNTER_BASE - 1)
#define _TASK_COUNT_STOP UINT8_MAX #define _TASK_COUNT_EXIT (UINT8_MAX & 0x7F)
#define _TASK_COUNT_CLEANUP (UINT8_MAX - 1)
#define _task(fct_name) #define _TASK_YIELD(count_val) do { \
__task_state->count = count_val; \
return; \
case (count_val): \
/* fall through */ \
} while (0)
#define _task_wait_until(cond, count) do { \ #define _TASK_SLEEP(delay_ms, count_val) do { \
case (count): \ __task_state->count = count_val; \
__task_state->delay = delay_ms; \
return; \
case (count_val): \
/* fall through */ \
} while (0)
#define _TASK_YIELD_UNTIL(cond, count_val) do { \
__task_state->count = count_val; \
case (count_val): \
if (!(cond)) { \ if (!(cond)) { \
return count; \ return; \
} \ } \
/* fall through */ \ /* fall through */ \
while (0) } while (0)
#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_ #endif //_task_h_