#c #chrono #cortex-m #newlib
#c #c -chrono #cortex-m #новая библиотека
Вопрос:
Я использую набор инструментов arm-none-eabi с newlib для нацеливания на пользовательскую плату с ARM Cortex-M0 (в частности, на версию набора инструментов MCU-on-eclipse). Я компилирую / связываю с -nostartfiles
и --specs=nano.specs
и перенастроил stdout и stderr на USB и последовательный порт соответственно. Я создал реализации для большинства системных вызовов C.
Я использую библиотеку chrono с двумя пользовательскими часами, функции now () получают время RTC или мой системный таймер. Похоже, что это отражает назначение стандартных steady_clock и system_clock, и поэтому я подумал, что мог бы попробовать их использовать.
для этого мне пришлось реализовать системный вызов gettimeofday, что я и сделал
// returning a set time of one second just for testing
int _gettimeofday(struct timeval* tv, void* tz) {
tv->tv_sec = 1;
tv->tv_usec = 255;
return 0;
}
мой основной код выглядит следующим образом:
int main(void)
{
HWInit();
static std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
static std::chrono::system_clock::time_point t2 = std::chrono::system_clock::now();
int64_t count1 = t1.time_since_epoch().count();
int64_t count2 = t2.time_since_epoch().count();
printf("Time 1: %lldn Time 2: %lldn", count1, count2);
for(;;){}
return 0;
}
используя отладчик, я вижу, что оба, steady_clock::now()
и sysytem_clock::now()
, вызывают мою функцию _gettimeofday(), и оба заканчиваются с точно таким же временным моментом.
конечно, если я попытаюсь сделать следующее, я получу множество ошибок определения:
using SysClock = std::chrono::system_clock;
SysClock::time_point SysClock::now() noexcept {
return SysClock::time_point( SysClock::duration(1983) );
}
Итак, могу ли я каким-либо образом перегрузить функции now () стандартных часов chrono? или, может быть, вся реализация clock с моими собственными параметрами типа duration и rep, которые лучше соответствуют аппаратному обеспечению? Я могу перегрузить new и delete для своей встроенной системы (и должен), поэтому сделать это для chrono также было бы неплохо.
Ответ №1:
system_clock::now()
используетgettimeofday(amp;tv, 0);
илиclock_gettime(CLOCK_REALTIME, amp;tp);
или системный вызов. Еслиgettimeofday
у вас работает, это означает, что он его использует.steady_clock::now()
используетclock_gettime(CLOCK_MONOTONIC, amp;tp);
. Таким образом, вы должны перегрузитьclock_gettime
и обработатьCLOCK_MONOTONIC
аргумент.- В newlib нет такой
_clock_gettime_r
функции, как в_gettimeofday_t
, которая передает newlibstruct reent
по кругу. Если вы хотите обрабатывать многопоточность внутри newlib, неплохо написать свою собственную аналогичную оболочку, которая обрабатывает_reent->errno
значение. Но ставка была бы на перегрузку_gettimeofday_r
функции, поскольку вы нацелены только на newlib.
Комментарии:
1. похоже, что работает только gettimeofday, что означает, что моя копия была скомпилирована с
_GLIBCXX_USE_GETTIMEOFDAY
вместо_GLIBCXX_USE_CLOCK_REALTIME
. В структуре возврата нет никаких указаний на тип запрашиваемых часов, поэтому мне, вероятно, пришлось бы перекомпилировать libstdc , чтобы заставить clock_gettime () работать. спасибо за ссылки на код.2.
_GLIBCXX_USE_GETTIMEOFDAY
влияетsystem_clock::now()
. Посколькуlibstdc
forarm-none-eabi-gcc
компилируется без_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL
необходимости предоставления определенияextern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp);
.clk_id
Точно используется для указания часов…
Ответ №2:
Вместо того, чтобы пытаться изменить поведение system_clock
и steady_clock
, я рекомендую просто написать свои собственные часы и использовать их. Таким образом, вы сможете лучше адаптировать их к своему оборудованию и потребностям. Если у вас есть какой-либо способ получить текущее время, создать пользовательские chrono
часы для переноса этой функции очень просто.
class SysClock
{
public:
// 500MHz, or whatever you need
using period = std::ratio<1, 500'000'000>;
using rep = long long;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<SysClcok>;
static constexpr bool is_steady = true;
static time_point now() noexcept
{
return time_point{duration{
/*turn SysTick_getValue() into the number of ticks since epoch*/}};
}
};
Теперь используйте SysClock::now()
в своем коде вместо system_clock::now()
. Это дает вам SysClock::time_point
и chrono::durations
результат вычитания двух SysClock::time_point
секунд.
Если вы можете превратить ваше низкоуровневое «сейчас» в количество тактов по отношению к некоторой эпохе, и вы можете описать эти такты как доли секунды во время компиляции с помощью period
, тогда все в порядке.
Комментарии:
1. Это то, что я делаю сейчас, с моими пользовательскими часами в заголовке
sealChrono.h
(это фреймворк на основе ластоногих), который затем включает chrono и date.h (кстати, потрясающая библиотека!). Я просто надеялся / экспериментировал с тем, чтобы сделать фреймворк более прозрачным для пользователя. Однако перекомпиляция стандартной библиотеки немного выходит за рамки, поэтому я, вероятно, буду придерживаться этого решения.