2 Star 3 Fork 0

huohongpeng/software-timer

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
soft_timer.c 9.19 KB
一键复制 编辑 原始数据 按行查看 历史
huohongpeng 提交于 2020-11-23 17:22 . fix sw_timer_stop bug
/*
* Copyright (C) 2020, 2020 huohongpeng
* Author: huohongpeng <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Change logs:
* Date Author Notes
* 2020-09-18 huohongpeng First add
* 2020-09-23 huohongpeng 1.Modify software timer base on timer update interrupt
* 2.Modify software use TIME5(basic timer)
* 2020-11-23 huohongpeng fix sw_timer_stop() bug
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "soft_timer.h"
#include <string.h>
#include <platform_usart.h>
/*
* Software timer max number
* User to configurate [1-65535]
*/
#define SW_TIMER_MAX_NUMBER 32
/*
* Hardware timer max count value
* Note : depend on hardware platform, user to overwrite
*/
#define __HW_TIME_MAX_COUNT (0xffff)
/*
* Hardware timer how many count value equal 1ms
* Note : depend on hardware platform, user to overwrite
*/
#define __HW_TIME_COUNT_PER_MS 10
#include <gd32f30x.h>
void TIMER5_IRQHandler(void)
{
if (timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP) == SET) {
timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
sw_timer_timeout_irq();
}
}
/*
* Disable mcu global interrupt use for atomic operation
* Note : depend on hardware platform, user to overwrite
*/
void __hw_disable_mcu_irq(void)
{
__disable_irq();
}
/*
* Enable mcu global interrupt use for atomic operation
* Note : depend on hardware platform, user to overwrite
*/
static void __hw_enable_mcu_irq(void)
{
__enable_irq();
}
/*
* Initialized hardware timer
* Requirement :
* Counter mode - single, don't repeat
* Counter unit - (1 / __HW_TIME_COUNT_PER_MS) ms. For example :
* __HW_TIME_COUNT_PER_MS = 10, Counter unit equal 0.1ms
* Timeout - trigger interrupt and stop count
* Note : depend on hardware platform, user to overwrite
*/
static void __hw_timer_init(void)
{
nvic_irq_enable(TIMER5_IRQn, 1, 0);
rcu_periph_clock_enable(RCU_TIMER5);
timer_deinit(TIMER5);
timer_parameter_struct timer_initpara;
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 120*100-1;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 0xffff;
timer_init(TIMER5, &timer_initpara);
timer_counter_value_config(TIMER5, 0);
timer_update_source_config(TIMER5, TIMER_UPDATE_SRC_REGULAR);
timer_auto_reload_shadow_disable(TIMER5);
timer_single_pulse_mode_config(TIMER5, TIMER_SP_MODE_SINGLE);
}
/*
* Stop hardware timer
* Note : depend on hardware platform, user to overwrite
*/
static void __hw_timer_stop(void)
{
timer_interrupt_disable(TIMER5, TIMER_INT_UP);
timer_disable(TIMER5);
}
/*
* Configurate hardware timer timeout, enable hardware timer
* interrupt and start hardware timer count
* Note : depend on hardware platform, user to overwrite
*/
static void __hw_timer_start(uint32_t count)
{
timer_counter_value_config(TIMER5, 0);
timer_autoreload_value_config(TIMER5, count);
timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
timer_interrupt_enable(TIMER5, TIMER_INT_UP);
timer_enable(TIMER5);
}
/*
* Get hardware timer counter value
* Note : depend on hardware platform, user to overwrite
*/
static uint32_t __hw_timer_get_count(void)
{
return timer_counter_read(TIMER5);
}
/*
* Set hardware timer counter value
* Note : depend on hardware platform, user to overwrite
*/
static void __hw_timer_set_count(uint32_t count)
{
timer_counter_value_config(TIMER5, count);
}
struct sw_timer {
sw_func_cb_t func;
void *cb_data;
uint32_t timeout_ms;
uint32_t remain_ms;
uint32_t is_running : 1;
uint32_t is_repeat : 1;
uint32_t is_used : 1;
uint32_t reserve : 29;
};
struct sw_timer_context_t {
struct sw_timer timer[SW_TIMER_MAX_NUMBER];
uint32_t count;
uint8_t is_init;
};
static struct sw_timer_context_t sw_timer_context;
static void update_remain(uint32_t count_ms)
{
uint16_t i;
struct sw_timer *sw_timer;
for(i = 0; i < SW_TIMER_MAX_NUMBER; i++) {
sw_timer = &sw_timer_context.timer[i];
if(sw_timer->is_used && sw_timer->is_running) {
if(sw_timer->remain_ms > count_ms) {
sw_timer->remain_ms = sw_timer->remain_ms - count_ms;
} else {
sw_timer->remain_ms = 0;
}
}
}
}
static uint32_t get_run_timer_min_remain(void)
{
uint16_t i;
struct sw_timer *sw_timer;
uint32_t min_remain = 0xffffffff;
for(i = 0; i < SW_TIMER_MAX_NUMBER; i++) {
sw_timer = &sw_timer_context.timer[i];
if(sw_timer->is_running) {
if(sw_timer->remain_ms < min_remain) {
min_remain = sw_timer->remain_ms;
}
}
}
return min_remain;
}
/*
* Call by hardware timer interrupt server
*/
void sw_timer_timeout_irq(void)
{
uint16_t i;
struct sw_timer *sw_timer;
__hw_disable_mcu_irq();
uint32_t count_ms = sw_timer_context.count / __HW_TIME_COUNT_PER_MS;
__hw_timer_set_count(0);
__hw_timer_stop();
update_remain(count_ms);
__hw_enable_mcu_irq();
for(i = 0; i < SW_TIMER_MAX_NUMBER; i++) {
__hw_disable_mcu_irq();
sw_timer = &sw_timer_context.timer[i];
if(sw_timer->is_used && sw_timer->is_running &&
sw_timer->remain_ms == 0) {
if(sw_timer->is_repeat) {
sw_timer->remain_ms = sw_timer->timeout_ms;
} else {
sw_timer->is_running = 0;
}
__hw_enable_mcu_irq();
if(sw_timer->func) {
sw_timer->func(sw_timer->cb_data);
}
}
__hw_enable_mcu_irq();
}
__hw_disable_mcu_irq();
uint32_t hw_timeout_ms = get_run_timer_min_remain();
/*
* None Software timer need run if hw_timeout_ms equal 0xffffffff.
*/
if(hw_timeout_ms == 0xffffffff) {
__hw_enable_mcu_irq();
return;
}
if(hw_timeout_ms > __HW_TIME_MAX_COUNT /__HW_TIME_COUNT_PER_MS) {
hw_timeout_ms = __HW_TIME_MAX_COUNT / __HW_TIME_COUNT_PER_MS;
}
sw_timer_context.count = hw_timeout_ms * __HW_TIME_COUNT_PER_MS;
__hw_timer_start(sw_timer_context.count);
__hw_enable_mcu_irq();
}
int sw_timer_alloc(uint32_t *handle)
{
uint16_t i;
struct sw_timer *sw_timer;
for(i = 0; i < SW_TIMER_MAX_NUMBER; i++) {
__hw_disable_mcu_irq();
sw_timer = &sw_timer_context.timer[i];
if(!sw_timer->is_used) {
memset(sw_timer, 0x00, sizeof(struct sw_timer));
sw_timer->is_used = 1;
*handle = SW_TIMER_HANDLE_MAGIC | i;
__hw_enable_mcu_irq();
return 0;
}
__hw_enable_mcu_irq();
}
return -1;
}
int sw_timer_free(uint32_t handle)
{
uint16_t timer_index = handle ^ SW_TIMER_HANDLE_MAGIC;
if((handle & SW_TIMER_HANDLE_MAGIC) != SW_TIMER_HANDLE_MAGIC ||
timer_index >= SW_TIMER_MAX_NUMBER) {
return -1;
}
__hw_disable_mcu_irq();
struct sw_timer *sw_timer = &sw_timer_context.timer[timer_index];
sw_timer->is_used = 0;
sw_timer->is_running = 0;
sw_timer->is_repeat = 0;
__hw_enable_mcu_irq();
return 0;
}
int sw_timer_start(uint32_t handle, uint32_t timeout_ms, sw_func_cb_t func, void *cb_data, uint8_t repeat)
{
uint16_t timer_index = handle ^ SW_TIMER_HANDLE_MAGIC;
if((handle & SW_TIMER_HANDLE_MAGIC) != SW_TIMER_HANDLE_MAGIC ||
timer_index >= SW_TIMER_MAX_NUMBER) {
return -1;
}
if(timeout_ms == 0xffffffff || timeout_ms == 0) {
return -1;
}
__hw_disable_mcu_irq();
struct sw_timer *sw_timer = &sw_timer_context.timer[timer_index];
if(!sw_timer->is_used || sw_timer->is_running) {
__hw_enable_mcu_irq();
return -1;
}
if(!sw_timer_context.is_init) {
sw_timer_context.is_init = 1;
__hw_timer_init();
}
__hw_timer_stop();
uint32_t count_ms = __hw_timer_get_count() / __HW_TIME_COUNT_PER_MS;
__hw_timer_set_count(0);
update_remain(count_ms);
sw_timer->timeout_ms = timeout_ms;
sw_timer->func = func;
sw_timer->cb_data = cb_data;
sw_timer->is_repeat = repeat;
sw_timer->is_running = 1;
sw_timer->remain_ms = timeout_ms;
uint32_t hw_timeout_ms = get_run_timer_min_remain();
if(hw_timeout_ms > __HW_TIME_MAX_COUNT /__HW_TIME_COUNT_PER_MS) {
hw_timeout_ms = __HW_TIME_MAX_COUNT / __HW_TIME_COUNT_PER_MS;
}
if(hw_timeout_ms == 0) {
/*
* Exist timer expire, write 1ms to trigger interrupt quickly.
*/
sw_timer_context.count = __HW_TIME_COUNT_PER_MS;
__hw_timer_start(__HW_TIME_COUNT_PER_MS);
} else {
sw_timer_context.count = hw_timeout_ms * __HW_TIME_COUNT_PER_MS;
__hw_timer_start(hw_timeout_ms * __HW_TIME_COUNT_PER_MS);
}
__hw_enable_mcu_irq();
return 0;
}
int sw_timer_stop(uint32_t handle)
{
uint16_t timer_index = handle ^ SW_TIMER_HANDLE_MAGIC;
if((handle & SW_TIMER_HANDLE_MAGIC) != SW_TIMER_HANDLE_MAGIC ||
timer_index >= SW_TIMER_MAX_NUMBER) {
return -1;
}
__hw_disable_mcu_irq();
struct sw_timer *sw_timer = &sw_timer_context.timer[timer_index];
if(!sw_timer->is_used || !sw_timer->is_running) {
__hw_enable_mcu_irq();
return -1;
}
sw_timer->is_running = 0;
__hw_enable_mcu_irq();
return 0;
}
#define SW_TIMER_TEST
#ifdef SW_TIMER_TEST
static uint32_t time[SW_TIMER_MAX_NUMBER];
static void sw_func_cb_test(void *cb_data)
{
uint32_t handle = *(unsigned int *)cb_data;
if((handle & 0xffff) == 2) {
u_tm_log("soft timer = %x\r\n", handle);
}
}
void sw_timer_test(void)
{
uint16_t i;
for(i = 0; i < SW_TIMER_MAX_NUMBER; i++) {
sw_timer_alloc(&time[i]);
sw_timer_start(time[i], 1000+(i*100), sw_func_cb_test, &time[i], 1);
}
}
#endif
#ifdef __cplusplus
}
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/huohongpeng/software-timer.git
[email protected]:huohongpeng/software-timer.git
huohongpeng
software-timer
software-timer
master

搜索帮助