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
55 changes: 36 additions & 19 deletions cores/arduino/time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
#include "IRQManager.h"
#include "FspTimer.h"

volatile unsigned long agt_time_ms = 0;
uint32_t _freq_hz = 0;
// this file implements the following public funcions: delay, delayMicroseconds, yield, millis, micros

__attribute__((weak)) void delay(uint32_t ms) {
R_BSP_SoftwareDelay(ms, BSP_DELAY_UNITS_MILLISECONDS);
Expand All @@ -16,21 +15,31 @@ void delayMicroseconds(unsigned int us) {
__attribute__((weak)) void yield() {
}

static FspTimer main_timer;
static FspTimer agt_timer;
volatile uint32_t agt_time_ms = 0;

static uint32_t _top_counter;

static void timer_micros_callback(timer_callback_args_t __attribute((unused)) *p_args) {
agt_time_ms += 1; //1ms
static void timer_micros_callback(timer_callback_args_t __attribute((unused))* p_args) {
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.open();
_top_counter = main_timer.get_counter();
main_timer.start();
_freq_hz = main_timer.get_freq_hz();
// configure AGT timer 0 to generate an underflow interrupt every 1 ms
// a clock divider 8 works for both the Uno R4 and Portenta C33 because number of clock ticks
// in 1 ms (period) is an integer number and below the 16-bit counter limit
// on the Uno R4 the AGT clock is 24 MHz / 8 -> 3000 ticks per ms
// on the Portenta C33 the AGT clock is 50 Mhz / 8 -> 6250 ticks per ms
const uint32_t clock_freq_Hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKB);
const uint32_t period = clock_freq_Hz / ((1 << TIMER_SOURCE_DIV_8) * 1000UL);
agt_timer.begin(/* mode */ TIMER_MODE_PERIODIC,
/* type */ AGT_TIMER,
/* channel */ 0,
period,
/* pulse */ 1,
TIMER_SOURCE_DIV_8,
timer_micros_callback);;
agt_timer.setup_overflow_irq(8);
agt_timer.open();
agt_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 +52,18 @@ unsigned long millis()
}

unsigned long micros() {

// Convert time to 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);
NVIC_EnableIRQ(main_timer.get_cfg()->cycle_end_irq);
return time_us;
// Return time in us
const timer_cfg_t* cfg = agt_timer.get_cfg();
NVIC_DisableIRQ(cfg->cycle_end_irq);
uint32_t ms = agt_time_ms;
// read from the R_AGT0 registers directly for performance reasons
uint32_t const down_counts = R_AGT0->AGT; // get the counter value
if (R_AGT0->AGTCR_b.TUNDF && (down_counts > (cfg->period_counts / 2))) {
// if the TUNDF (underflow) bit is set, the counter wrapped around
// just before down_counts was read and agt_time_ms was not yet updated
++ms;
}
NVIC_EnableIRQ(cfg->cycle_end_irq);
uint32_t const up_counts = (cfg->period_counts - 1) - down_counts;
return (ms * 1000) + ((up_counts * 1000) / cfg->period_counts);
}