I was thinking something like the following (NOTE: does not necessarily even build) - there is a low-priority thread that updates a double-buffered structure with a 64-bit representation of the system time. When millis() or micros() are called, the 64-bit representation of system time is converted to millis or micros and then truncated to 32 bits.
Any suggestions on how to avoid the 64-bit arithmetic, while retaining the guarantee that the values will increase monotonically?
Code: Select all
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <common/timing.h>
#include <ch.h>
static thread_t* worker_thread;
static THD_WORKING_AREA(waTimingThread, 128);
static THD_FUNCTION(TimingThread, arg);
static {
uint64_t time_ticks;
systime_t update_systime;
} timing_state[2];
static volatile uint8_t timing_state_idx;
void timing_init(void)
{
if (!worker_thread) {
worker_thread = chThdCreateStatic(waTimingThread, sizeof(waTimingThread), LOWPRIO, TimingThread, NULL);
}
}
uint32_t millis(void) {
uint8_t idx = timing_state_idx;
return (uint32_t)ST2MS(timing_state[idx].time_ticks + chVTTimeElapsedSinceX(timing_state[idx].update_systime));
}
uint32_t micros(void) {
uint8_t idx = timing_state_idx;
return (uint32_t)ST2US(timing_state[idx].time_ticks + chVTTimeElapsedSinceX(timing_state[idx].update_systime));
}
void usleep(uint32_t delay) {
uint32_t tbegin = micros();
while (micros()-tbegin < delay);
}
static THD_FUNCTION(TimingThread, arg)
{
(void)arg;
while (true) {
uint8_t next_timing_state_idx = (timing_state_idx+1) % 2;
systime_t systime_now = chVTGetSystemTime();
uint32_t dt_ticks = systime_now-timing_state[timing_state_idx].update_systime;
timing_state[next_timing_state_idx].update_systime = systime_now;
timing_state[next_timing_state_idx].time_ticks = timing_state[timing_state_idx].time_ticks + dt_ticks;
timing_state_idx = next_timing_state_idx;
chThdSleepMilliseconds(1000);
}
}