Skip to content

Commit 14783dc

Browse files
authored
Merge pull request arduino#52 from Kees-van-der-Oord/main
Bugfix: `micros()` returns smaller number when timer wraps
2 parents e989e72 + 70ef6c7 commit 14783dc

File tree

2 files changed

+39
-20
lines changed

2 files changed

+39
-20
lines changed

Diff for: .gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ cores/arduino/mydebug.cpp
33
libraries/Storage/.development
44
cores/arduino/mydebug.cpp.donotuse
55
.DS_Store
6-
.DS_Store?
6+
.DS_Store?
7+
/.vs
8+
/.gitignore

Diff for: cores/arduino/time.cpp

+36-19
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
#include "IRQManager.h"
33
#include "FspTimer.h"
44

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

87
__attribute__((weak)) void delay(uint32_t ms) {
98
R_BSP_SoftwareDelay(ms, BSP_DELAY_UNITS_MILLISECONDS);
@@ -16,21 +15,31 @@ void delayMicroseconds(unsigned int us) {
1615
__attribute__((weak)) void yield() {
1716
}
1817

19-
static FspTimer main_timer;
18+
static FspTimer agt_timer;
19+
volatile uint32_t agt_time_ms = 0;
2020

21-
static uint32_t _top_counter;
22-
23-
static void timer_micros_callback(timer_callback_args_t __attribute((unused)) *p_args) {
24-
agt_time_ms += 1; //1ms
21+
static void timer_micros_callback(timer_callback_args_t __attribute((unused))* p_args) {
22+
agt_time_ms += 1;
2523
}
2624

2725
void startAgt() {
28-
main_timer.begin(TIMER_MODE_PERIODIC, AGT_TIMER, 0, 2000.0f, 0.5f, timer_micros_callback);
29-
IRQManager::getInstance().addPeripheral(IRQ_AGT,(void*)main_timer.get_cfg());
30-
main_timer.open();
31-
_top_counter = main_timer.get_counter();
32-
main_timer.start();
33-
_freq_hz = main_timer.get_freq_hz();
26+
// configure AGT timer 0 to generate an underflow interrupt every 1 ms
27+
// a clock divider 8 works for both the Uno R4 and Portenta C33 because number of clock ticks
28+
// in 1 ms (period) is an integer number and below the 16-bit counter limit
29+
// on the Uno R4 the AGT clock is 24 MHz / 8 -> 3000 ticks per ms
30+
// on the Portenta C33 the AGT clock is 50 Mhz / 8 -> 6250 ticks per ms
31+
const uint32_t clock_freq_Hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKB);
32+
const uint32_t period = clock_freq_Hz / ((1 << TIMER_SOURCE_DIV_8) * 1000UL);
33+
agt_timer.begin(/* mode */ TIMER_MODE_PERIODIC,
34+
/* type */ AGT_TIMER,
35+
/* channel */ 0,
36+
period,
37+
/* pulse */ 1,
38+
TIMER_SOURCE_DIV_8,
39+
timer_micros_callback);;
40+
agt_timer.setup_overflow_irq(8);
41+
agt_timer.open();
42+
agt_timer.start(); // bug in R4 1.0.2: calling start() is not necessary: open() starts the counter already !?
3443
}
3544

3645
unsigned long millis()
@@ -43,10 +52,18 @@ unsigned long millis()
4352
}
4453

4554
unsigned long micros() {
46-
47-
// Convert time to us
48-
NVIC_DisableIRQ(main_timer.get_cfg()->cycle_end_irq);
49-
uint32_t time_us = ((main_timer.get_period_raw() - main_timer.get_counter()) * 1000 / main_timer.get_period_raw()) + (agt_time_ms * 1000);
50-
NVIC_EnableIRQ(main_timer.get_cfg()->cycle_end_irq);
51-
return time_us;
55+
// Return time in us
56+
const timer_cfg_t* cfg = agt_timer.get_cfg();
57+
NVIC_DisableIRQ(cfg->cycle_end_irq);
58+
uint32_t ms = agt_time_ms;
59+
// read from the R_AGT0 registers directly for performance reasons
60+
uint32_t const down_counts = R_AGT0->AGT; // get the counter value
61+
if (R_AGT0->AGTCR_b.TUNDF && (down_counts > (cfg->period_counts / 2))) {
62+
// if the TUNDF (underflow) bit is set, the counter wrapped around
63+
// just before down_counts was read and agt_time_ms was not yet updated
64+
++ms;
65+
}
66+
NVIC_EnableIRQ(cfg->cycle_end_irq);
67+
uint32_t const up_counts = (cfg->period_counts - 1) - down_counts;
68+
return (ms * 1000) + ((up_counts * 1000) / cfg->period_counts);
5269
}

0 commit comments

Comments
 (0)