STM32 firmware for a remotely-controlled stepper motor demo with a mobile interface.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
3.5 KiB

#pragma once
/**
* To use the Timebase functionality,
* set up SysTick to 1 kHz and call
* timebase_ms_cb() in the IRQ.
*
* If you plan to use pendable future tasks,
* also make sure you call run_pending_tasks()
* in your main loop.
*
* This is not needed for non-pendable tasks.
*/
#include "main.h"
/** Task PID. */
typedef uint32_t task_pid_t;
/** Time value in ms */
typedef uint32_t ms_time_t;
// PID value that can be used to indicate no task
#define PID_NONE 0
/** Loop until timeout - use in place of while() or for(). break and continue work too! */
#define until_timeout(to_ms) for(uint32_t _utmeo = ms_now(); ms_elapsed(_utmeo) < (to_ms);)
/** Retry a call until a timeout. Variable 'suc' is set to the return value. Must be defined. */
#define retry_TO(to_ms, call) \
until_timeout(to_ms) { \
suc = call; \
if (suc) break; \
}
/** Init timebase, allocate slots for tasks. */
void timebase_init(size_t periodic_count, size_t future_count);
/** Must be called every 1 ms */
void timebase_ms_cb(void);
// --- Periodic -----------------------------------------------
/**
* @brief Add a periodic task with an arg.
* @param callback : task callback
* @param arg : callback argument
* @param interval : task interval (ms)
* @param enqueue : put on the task queue when due
* @return task PID
*/
task_pid_t add_periodic_task(void (*callback)(void *), void *arg, ms_time_t interval, bool enqueue);
/** Destroy a periodic task. */
bool remove_periodic_task(task_pid_t pid);
/** Enable or disable a periodic task. Returns true on success. */
bool enable_periodic_task(task_pid_t pid, FunctionalState cmd);
/** Check if a periodic task exists and is enabled. */
bool is_periodic_task_enabled(task_pid_t pid);
/** Reset timer for a task */
bool reset_periodic_task(task_pid_t pid);
// --- Future -------------------------------------------------
/**
* @brief Schedule a future task, with uint32_t argument.
* @param callback : task callback
* @param arg : callback argument
* @param delay : task delay (ms)
* @param enqueue : put on the task queue when due
* @return task PID
*/
task_pid_t schedule_task(void (*callback_arg)(void *), void *arg, ms_time_t delay, bool enqueue);
/** Abort a scheduled task. */
bool abort_scheduled_task(task_pid_t pid);
// --- Waiting functions --------------------------------------
/** Get milliseconds elapsed since start timestamp */
ms_time_t ms_elapsed(ms_time_t start);
/** Get current timestamp. */
ms_time_t ms_now(void);
/** Delay using SysTick */
void delay_ms(ms_time_t ms);
/** Delay N seconds */
void delay_s(uint32_t s);
inline __attribute__((always_inline))
void delay_cycles(uint32_t n)
{
uint32_t l = n >> 2;
__asm volatile(
"0: mov r0,r0;"
"subs %[count], #1;"
"bne 0b;"
: [count] "+r"(l)
);
}
inline __attribute__((always_inline))
void delay_ns(uint32_t ns)
{
delay_cycles(ns / 24);
}
/**
* @brief Microsecond delay.
* @param us
*/
inline __attribute__((always_inline))
void delay_us(uint32_t us)
{
delay_ns(us * 1150);
}
/**
* @brief Check if time since `start` elapsed.
*
* If so, sets the *start variable to the current time.
*
* Example:
*
* ms_time_t s = ms_now();
*
* while(1) {
* if (ms_loop_elapsed(&s, 100)) {
* // this is called every 100 ms
* }
* // ... rest of the loop ...
* }
*
* @param start start time variable
* @param duration delay length
* @return delay elapsed; start was updated.
*/
bool ms_loop_elapsed(ms_time_t *start, ms_time_t duration);