-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
tzhu
committed
Mar 16, 2024
1 parent
31c7a94
commit 298fe50
Showing
6 changed files
with
311 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef _OS_TIMER_PORT_H_ | ||
#define _OS_TIMER_PORT_H_ | ||
|
||
#include "hal/timer/mtime.h" | ||
#include "hal/timer/riscv_mtime_csr.h" | ||
|
||
#define portTimerInit(cb) \ | ||
do \ | ||
{ \ | ||
MtimeSetPeriod(0); \ | ||
MtimeRegister(cb); \ | ||
} while (0) | ||
|
||
#define portTimerStop() __mtime_set_compare(~0ULL) | ||
|
||
#define portTimerTicksPerUs() ((MtimeGetPeriod() + 1) * 1000) | ||
|
||
#define portTimerGetTick() __mtime_get_count() | ||
|
||
#define portTimerComputeEndTick(tick) (portTimerGetTick() + (tick)) | ||
|
||
#define portTimerStart(end) __mtime_set_compare(end) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#include "os_timer.h" | ||
#include "pt-os.h" | ||
#include "os_timer_port.h" | ||
|
||
constexpr int kMaxTimerItem = 16; | ||
|
||
typedef struct | ||
{ | ||
OsTimerCallback_t callback; | ||
void *param; | ||
uint64_t period_tick; | ||
uint64_t end_tick; | ||
int id; | ||
bool repeatable; | ||
} OsTimer_t; | ||
|
||
volatile int kOsTimerTrigged_ = 0; | ||
int kOsTimerHandled_ = 0; | ||
int kOsTimerIdSeed_ = 0; | ||
uint64_t kOsTimerTicksPerUs_ = 0; | ||
|
||
struct tick_cmp | ||
{ | ||
bool operator()(const OsTimer_t &a, const OsTimer_t &b) const { return a.end_tick < b.end_tick; } | ||
}; | ||
etl::set<OsTimer_t, kMaxTimerItem, tick_cmp> gOsTimerObj_; | ||
|
||
static void OsTimerIsrHandler_() | ||
{ | ||
kOsTimerTrigged_ += 1; | ||
portTimerStop(); | ||
} | ||
|
||
TASK_DECLARE(OsTimerTask_(OsTaskId taskId, void *)) | ||
{ | ||
TASK_BEGIN(taskId); | ||
while (1) | ||
{ | ||
TASK_WAIT_UNTIL(taskId, kOsTimerTrigged_ > kOsTimerHandled_); | ||
kOsTimerHandled_++; | ||
// find the first timer. Which happened most recently. | ||
auto tim = gOsTimerObj_.begin(); | ||
OS_ASSERT(tim != gOsTimerObj_.end()); // Shouldn't be empty. | ||
if (tim->callback) tim->callback(tim->id, tim->param); | ||
// update the repeatable timer. | ||
if (tim->repeatable) | ||
{ | ||
gOsTimerObj_.insert( | ||
{tim->callback, tim->param, tim->period_tick, tim->end_tick + tim->period_tick, tim->id, true}); | ||
} | ||
// remove the current timer. | ||
gOsTimerObj_.erase(tim); | ||
// if has one or more timer enable it. | ||
if (gOsTimerObj_.size()) | ||
{ | ||
tim = gOsTimerObj_.begin(); | ||
portTimerStart(tim->end_tick); | ||
} | ||
} | ||
TASK_END(taskId); | ||
} | ||
|
||
void OsTimerInit() | ||
{ | ||
portTimerInit(OsTimerIsrHandler_); | ||
portTimerStop(); | ||
kOsTimerTicksPerUs_ = portTimerTicksPerUs(); | ||
RegisterTask("thrTmr", OsTimerTask_, nullptr); | ||
} | ||
|
||
int OsTimerRegister(OsTimerCallback_t callback, void *param, uint64_t period_us, bool repeatable, int *id) | ||
{ | ||
if (gOsTimerObj_.full()) return kLtMallocFail; | ||
portTimerStop(); | ||
gOsTimerObj_.insert({callback, param, period_us * kOsTimerTicksPerUs_, | ||
portTimerComputeEndTick(period_us * kOsTimerTicksPerUs_), ++kOsTimerIdSeed_, repeatable}); | ||
portTimerStart(gOsTimerObj_.begin()->end_tick); | ||
if (id) *id = kOsTimerIdSeed_; | ||
return TASK_OP_SUCCESS; | ||
} | ||
|
||
int OsTimerCount() { return gOsTimerObj_.size(); } | ||
|
||
int OsTimerKill(int id) | ||
{ | ||
for (auto it = gOsTimerObj_.begin(); it != gOsTimerObj_.end(); it++) | ||
{ | ||
if (it->id == id) | ||
{ | ||
gOsTimerObj_.erase(it); | ||
return TASK_OP_SUCCESS; | ||
} | ||
} | ||
} | ||
|
||
static void timerDelayCallback_(int id, void *param) | ||
{ | ||
bool *triggerred = (bool *)param; | ||
// HAL_UartPrint("[TIM]: to %llu\n", portTimerGetTick()); | ||
*triggerred = true; | ||
} | ||
|
||
int OsTimerDelayUs(uint64_t delay_us) | ||
{ | ||
bool timerTriggered = false; | ||
// HAL_UartPrint("[TIM]: from %llu - %lluUs\n", portTimerGetTick(), delay_us); | ||
int rc = OsTimerRegister(timerDelayCallback_, &timerTriggered, delay_us, false, 0); | ||
if (rc != TASK_OP_SUCCESS) return rc; | ||
while (timerTriggered == false) TaskYield(); | ||
return TASK_OP_SUCCESS; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#ifndef _OS_TIMER_H_ | ||
#define _OS_TIMER_H_ | ||
|
||
#ifdef __cplusplus | ||
extern "C" | ||
{ | ||
#endif | ||
typedef void (*OsTimerCallback_t)(int id, void *param); | ||
/*****************************************************************************\ | ||
* @description : Initialize the OsTimer module. | ||
* @return {*} | ||
\*****************************************************************************/ | ||
void OsTimerInit(); | ||
|
||
/*****************************************************************************\ | ||
* @description : Register a timer | ||
* ------------ | ||
* @callback [I]: timer triggered callback function. | ||
* @param [I]: input parameter for callback function. | ||
* @period_us [I]: micro second delay to trigger the timer. | ||
* @repeatable [I]: true=auto reload period_us. | ||
* @id [O]: output the timer id for Kill. (Will be auto killed after | ||
* triggered, if not repeatable timer) | ||
* @return error or success | ||
\*****************************************************************************/ | ||
int OsTimerRegister(OsTimerCallback_t callback, void *param, uint64_t period_us, bool repeatable, int *id); | ||
|
||
/*****************************************************************************\ | ||
* @description : return number of active timer | ||
* @return number of active timer | ||
\*****************************************************************************/ | ||
int OsTimerCount(); | ||
|
||
/*****************************************************************************\ | ||
* @description : Kill a timer | ||
* @id [I]: timer id, which given by OsTimerRegister(...,&id) | ||
* @return error or success | ||
\*****************************************************************************/ | ||
int OsTimerKill(int id); | ||
|
||
int OsTimerDelayUs(uint64_t delay_us); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
#include <os.h> | ||
#include <os-timer-port.h> | ||
|
||
constexpr int kMaxTestNum_ = 10; | ||
volatile int testCount = 0; | ||
uint64_t tickStart; | ||
static long testTimerParam[kMaxTestNum_]; | ||
constexpr long testTimerGolden[kMaxTestNum_] = {11, 33, 50, 51, 33, 99, 33, 33, 33, 33}; | ||
static uint64_t testTickCounter[kMaxTestNum_]; | ||
constexpr uint64_t testTickGolden[kMaxTestNum_] = {100, 300, 500, 500, 600, 900, 900, 1200, 1500, 1800}; | ||
|
||
void testTimerCallback_(int id, void *param) | ||
{ | ||
testTickCounter[testCount] = portTimerGetTick() / 1000 - tickStart; | ||
testTimerParam[testCount] = (long)param; | ||
OS_TRACE("Timer%d: %lld happened at %llu\n", id, testTimerParam[testCount], testTickCounter[testCount]); | ||
testCount++; | ||
} | ||
|
||
constexpr long kTimerTaskSeconds_ = 3; | ||
long tCount1Ms = 0; | ||
long tCount100Us = 0; | ||
long tCountIdle = 0; | ||
|
||
static void timerDelayCallback_(int id, void *param) | ||
{ | ||
bool *triggerred = (bool *)param; | ||
// OS_TRACE("[TIM]: to %llu\n", portTimerGetTick()); | ||
*triggerred = true; | ||
} | ||
|
||
PT_THREAD(testTimerThread1Ms_(OsTaskId taskId, void *param)) | ||
{ | ||
static bool timerTriggered; | ||
TASK_BEGIN(taskId); | ||
while (1) | ||
{ | ||
OsTimerDelayUs(1000); | ||
TASK_YIELD(taskId); // force Yield | ||
tCount1Ms++; | ||
// OS_TRACE("1Ms hit %ld, idleYield %ld\n", tCount1Ms, tCountIdle); | ||
} | ||
TASK_END(taskId); | ||
} | ||
|
||
PT_THREAD(testTimerThread100Us_(OsTaskId taskId, void *param)) | ||
{ | ||
static bool timerTriggered; | ||
TASK_BEGIN(taskId); | ||
while (1) | ||
{ | ||
OsTimerDelayUs(100); | ||
TASK_YIELD(taskId); // force Yield | ||
tCount100Us++; | ||
// OS_TRACE("100Us hit %ld, idleYield %ld\n", tCount100Us, tCountIdle); | ||
} | ||
TASK_END(taskId); | ||
} | ||
|
||
PT_THREAD(testIdleThread_(OsTaskId taskId, void *param)) | ||
{ | ||
TASK_BEGIN(taskId); | ||
while (1) | ||
{ | ||
tCountIdle++; | ||
TASK_YIELD(taskId); // force Yield | ||
} | ||
TASK_END(taskId); | ||
} | ||
|
||
int TestTimer() | ||
{ | ||
int repeat_timer_id; | ||
OsInit(); | ||
OsTimerInit(); | ||
|
||
tickStart = portTimerGetTick() / 1000; | ||
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(11), 100, false, nullptr)); | ||
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(50), 500, false, nullptr)); | ||
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(99), 900, false, nullptr)); | ||
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(33), 300, true, &repeat_timer_id)); | ||
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(51), 500, false, nullptr)); | ||
|
||
while (testCount < kMaxTestNum_) TaskYield(); | ||
for (int i = 0; i < kMaxTestNum_; i++) | ||
{ | ||
if (testTimerParam[i] != testTimerGolden[i] || testTickCounter[i] / 10 != testTickGolden[i] / 10) | ||
{ | ||
OS_TRACE("Test%d Failed\n", i); | ||
OS_TRACE("Timer [%lld : %lld]. Tick [%llu : %llu]\n", testTimerParam[i], testTimerGolden[i], | ||
testTickCounter[i], testTickGolden[i]); | ||
return 1; | ||
} | ||
} | ||
if (OsTimerCount() != 1) | ||
{ | ||
OS_TRACE("Timer count error 1 - %d\n", OsTimerCount()); | ||
return 2; | ||
} | ||
LT_ASSERT(OsTimerKill(repeat_timer_id) == kLtSc); | ||
if (OsTimerCount() != 0) | ||
{ | ||
OS_TRACE("Timer count error 0 - %d\n", OsTimerCount()); | ||
return 3; | ||
} | ||
|
||
OS_TRACE("Test Timer in task\n"); | ||
RegisterTask("thr1Ms", &testTimerThread1Ms_, nullptr); | ||
RegisterTask("thr100Us", &testTimerThread100Us_, nullptr); | ||
RegisterTask("thrIdle", &testIdleThread_, nullptr); | ||
OS_TRACE("Test Timer start\n"); | ||
while (tCount1Ms < kTimerTaskSeconds_) | ||
{ | ||
TaskYield(); | ||
} | ||
if ((tCount1Ms * 10 - tCount100Us) <= 2) | ||
{ | ||
OS_TRACE("Timer task error %ld - %ld\n", tCount1Ms, tCount100Us); | ||
return 4; | ||
} | ||
OS_TRACE("Idle task yield %ld\n", tCountIdle); | ||
|
||
OS_TRACE("Test Passed\n"); | ||
return 0; | ||
} |