Skip to content

Bugfix: micros() returns smaller number when timer wraps #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 8, 2023
Merged
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ cores/arduino/mydebug.cpp
libraries/Storage/.development
cores/arduino/mydebug.cpp.donotuse
.DS_Store
.DS_Store?
.DS_Store?
/.vs
/.gitignore
34 changes: 21 additions & 13 deletions cores/arduino/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
#include "IRQManager.h"
#include "FspTimer.h"

// this file implements the following public funcions: delay, delayMicroseconds, yield, millis, micros
// The millis and micros implementation uses timer AGT0 (24 HMz, 16-bits, count-down mode, 1 ms period)

volatile unsigned long agt_time_ms = 0;
uint32_t _freq_hz = 0;

__attribute__((weak)) void delay(uint32_t ms) {
R_BSP_SoftwareDelay(ms, BSP_DELAY_UNITS_MILLISECONDS);
Expand All @@ -17,20 +19,25 @@ __attribute__((weak)) void yield() {
}

static FspTimer main_timer;

static uint32_t _top_counter;
// specifying these details as constants makes micros() faster !
#define _timer_type AGT_TIMER
#define _timer_index 0
#define _timer_underflow_bit R_AGT0->AGTCR_b.TUNDF
#define _timer_clock_divider TIMER_SOURCE_DIV_8 // dividers 1, 2, 4 and 8 work because _timer_period is < 16-bit. bug in R4 1.0.2: divider 4 acts as 1 !?
#define _timer_clock_freq 24000000UL
#define _timer_ticks_per_us (_timer_clock_freq / ((1 << _timer_clock_divider) * 1000000UL))
#define _timer_period (_timer_ticks_per_us * 1000UL)
#define TIMER_PRIORITY 8

static void timer_micros_callback(timer_callback_args_t __attribute((unused)) *p_args) {
agt_time_ms += 1; //1ms
agt_time_ms += 1;
}

void startAgt() {
main_timer.begin(TIMER_MODE_PERIODIC, AGT_TIMER, 0, 2000.0f, 0.5f, timer_micros_callback);
IRQManager::getInstance().addPeripheral(IRQ_AGT,(void*)main_timer.get_cfg());
main_timer.begin(TIMER_MODE_PERIODIC, _timer_type, _timer_index, _timer_period, 1, _timer_clock_divider, timer_micros_callback);;
main_timer.setup_overflow_irq(TIMER_PRIORITY);
main_timer.open();
_top_counter = main_timer.get_counter();
main_timer.start();
_freq_hz = main_timer.get_freq_hz();
main_timer.start(); // bug in R4 1.0.2: calling start() is not necessary: open() starts the counter already !?
}

unsigned long millis()
Expand All @@ -43,10 +50,11 @@ unsigned long millis()
}

unsigned long micros() {

// Convert time to us
// Return time in us
NVIC_DisableIRQ(main_timer.get_cfg()->cycle_end_irq);
uint32_t time_us = ((main_timer.get_period_raw() - main_timer.get_counter()) * 1000 / main_timer.get_period_raw()) + (agt_time_ms * 1000);
uint32_t ms = agt_time_ms;
uint32_t cnt = main_timer.get_counter();
if (_timer_underflow_bit && (cnt > (_timer_period / 2))) ++ms; // the counter wrapped arround just before it was read
NVIC_EnableIRQ(main_timer.get_cfg()->cycle_end_irq);
return time_us;
return ms * 1000 + (((_timer_period - 1) - cnt) / _timer_ticks_per_us);
}