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.
135 lines
3.4 KiB
135 lines
3.4 KiB
//
|
|
// Created by MightyPork on 2018/01/27.
|
|
//
|
|
|
|
#include "platform.h"
|
|
#include "timebase.h"
|
|
|
|
// ---------------------------- HAL TIMEBASE -----------------------------
|
|
|
|
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
|
|
{
|
|
// EDIT - used 17 instead because 14 was needed for fcap
|
|
|
|
// TIM14 is a simple 16-bit timer timer with no special features.
|
|
// This makes it a good choice for the timebase generation. We set it to generate
|
|
// an interrupt every 1 ms
|
|
|
|
assert_param(TickPriority == 0); // any other setting can lead to crashes
|
|
|
|
// - TIM14 is always up-counting
|
|
// - using APB1 clock
|
|
__HAL_RCC_TIM17_CLK_ENABLE();
|
|
NVIC_SetPriority(TIM17_IRQn, TickPriority); // highest possible priority
|
|
NVIC_EnableIRQ(TIM17_IRQn);
|
|
|
|
/* Compute TIM1 clock */
|
|
uint32_t uwTimclock = HAL_RCC_GetPCLK1Freq();
|
|
/* Get a 1 MHz clock for the timer */
|
|
uint16_t uhPrescalerValue = (uint16_t) ((uwTimclock / 1000000) - 1);
|
|
/* Get 1 kHz interrupt */
|
|
uint16_t uhPeriod = (1000000 / 1000) - 1;
|
|
|
|
LL_TIM_SetPrescaler(TIMEBASE_TIMER, uhPrescalerValue);
|
|
LL_TIM_SetAutoReload(TIMEBASE_TIMER, uhPeriod);
|
|
LL_TIM_EnableARRPreload(TIMEBASE_TIMER);
|
|
LL_TIM_EnableIT_UPDATE(TIMEBASE_TIMER);
|
|
LL_TIM_GenerateEvent_UPDATE(TIMEBASE_TIMER);
|
|
|
|
LL_TIM_EnableCounter(TIMEBASE_TIMER);
|
|
|
|
/* Return function status */
|
|
return HAL_OK;
|
|
}
|
|
|
|
static volatile uint32_t uwUptimeMs = 0;
|
|
|
|
/* TIMEBASE TIMER ISR */
|
|
void TIM17_IRQHandler(void)
|
|
{
|
|
uwUptimeMs++;
|
|
LL_TIM_ClearFlag_UPDATE(TIMEBASE_TIMER);
|
|
}
|
|
|
|
void HAL_IncTick(void)
|
|
{
|
|
uwUptimeMs++;
|
|
}
|
|
|
|
uint32_t HAL_GetTick(void)
|
|
{
|
|
return uwUptimeMs;
|
|
}
|
|
|
|
void HAL_SuspendTick(void)
|
|
{
|
|
LL_TIM_DisableIT_UPDATE(TIMEBASE_TIMER);
|
|
}
|
|
|
|
void HAL_ResumeTick(void)
|
|
{
|
|
LL_TIM_EnableIT_UPDATE(TIMEBASE_TIMER);
|
|
}
|
|
|
|
|
|
// -------------------------- DELAY FUNCTIONS AND TS -----------------------------
|
|
|
|
/*
|
|
* I wanted to freeze time. I wanted to savor that moment, to live in that moment
|
|
* for a week. But I couldn't stop it, only slow it. And before I knew it, she was gone.
|
|
* -- Ben Willis, "Cashback"
|
|
*/
|
|
uint64_t PTIM_GetMicrotime(void)
|
|
{
|
|
uint32_t uwMicros;
|
|
uint32_t uwMillis;
|
|
|
|
vPortEnterCritical();
|
|
{
|
|
uwMicros = TIMEBASE_TIMER->CNT;
|
|
uwMillis = uwUptimeMs;
|
|
|
|
if (LL_TIM_IsActiveFlag_UPDATE(TIMEBASE_TIMER)) {
|
|
// This means the timer has overflown after we disabled IRQ
|
|
// Use the last CNT value before the overflow
|
|
uwMicros = TIMEBASE_TIMER->ARR; // this is 999us
|
|
}
|
|
}
|
|
vPortExitCritical();
|
|
|
|
return (uint64_t) uwMillis * 1000 + uwMicros;
|
|
}
|
|
|
|
|
|
/** microsecond delay */
|
|
void PTIM_MicroDelayAligned(uint32_t usec, register const uint32_t start)
|
|
{
|
|
assert_param(usec < 1000);
|
|
|
|
register const uint32_t remain = (1000 - start);
|
|
|
|
if (remain > usec) {
|
|
// timer still has enough space going forward to pass the required wait time
|
|
register const uint32_t end = start + usec;
|
|
while (TIMEBASE_TIMER->CNT < end) {
|
|
__NOP();
|
|
__NOP();
|
|
__NOP();
|
|
}
|
|
return;
|
|
}
|
|
else {
|
|
// timer is too close to the end
|
|
usec -= remain;
|
|
while (1) {
|
|
register const uint32_t t = TIMEBASE_TIMER->CNT;
|
|
if (t < start && t >= usec) return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** microsecond delay */
|
|
void PTIM_MicroDelay(const uint32_t usec)
|
|
{
|
|
PTIM_MicroDelayAligned(usec, TIMEBASE_TIMER->CNT);
|
|
}
|
|
|