rusefi-1/firmware/hw_layer/microsecond_timer.cpp

167 lines
4.5 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file microsecond_timer.cpp
*
* Here we have a 1MHz timer dedicated to event scheduling. We are using one of the 32-bit timers here,
* so this timer can schedule events up to 4B/100M ~ 4000 seconds ~ 1 hour from current time.
*
* GPT5 timer clock: 84000000Hz
* If only it was a better multiplier of 2 (84000000 = 328125 * 256)
*
* @date Apr 14, 2014
2018-01-20 17:55:31 -08:00
* @author Andrey Belomutskiy, (c) 2012-2018
2015-07-10 06:01:56 -07:00
*/
2018-09-16 19:26:57 -07:00
#include "global.h"
2015-07-10 06:01:56 -07:00
#include "microsecond_timer.h"
#include "scheduler.h"
#include "rfiutil.h"
// https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fInterrupt%20on%20CEN%20bit%20setting%20in%20TIM7&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=474
#if (EFI_PROD_CODE && HAL_USE_GPT) || defined(__DOXYGEN__)
#include "efilib2.h"
2017-05-21 07:25:35 -07:00
/**
* Maximum duration of complete timer callback, all pending events together
* See also 'maxEventCallbackDuration' for maximum duration of one event
*/
uint32_t maxPrecisionCallbackDuration = 0;
2015-07-10 06:01:56 -07:00
2017-05-21 07:25:35 -07:00
// must be one of 32 bit times
2015-07-10 06:01:56 -07:00
#define GPTDEVICE GPTD5
static volatile efitick_t lastSetTimerTimeNt;
static int lastSetTimerValue;
static volatile bool isTimerPending = FALSE;
static volatile int timerCallbackCounter = 0;
static volatile int timerRestartCounter = 0;
schfunc_t globalTimerCallback;
static THD_WORKING_AREA(mwThreadStack, UTILITY_THREAD_STACK_SIZE);
static const char * msg;
static char buff[32];
2016-01-30 19:03:36 -08:00
static int timerFreezeCounter = 0;
2016-01-18 16:01:48 -08:00
extern bool hasFirmwareErrorFlag;
2015-07-10 06:01:56 -07:00
/**
* sets the alarm to the specified number of microseconds from now.
* This function should be invoked under kernel lock which would disable interrupts.
*/
void setHardwareUsTimer(int32_t timeUs) {
2016-01-30 19:03:36 -08:00
/**
* #259 BUG error: not positive timeUs
* Once in a while we night get an interrupt where we do not expect it
*/
if (timeUs <= 0) {
timerFreezeCounter++;
2017-03-08 22:10:33 -08:00
warning(CUSTOM_OBD_LOCAL_FREEZE, "local freeze cnt=%d", timerFreezeCounter);
2016-01-30 19:03:36 -08:00
}
if (timeUs < 2)
2015-07-10 06:01:56 -07:00
timeUs = 2; // for some reason '1' does not really work
2018-07-25 20:03:04 -07:00
efiAssertVoid(CUSTOM_ERR_6681, timeUs > 0, "not positive timeUs");
2017-01-21 15:02:13 -08:00
if (timeUs >= 10 * US_PER_SECOND) {
2017-03-08 22:10:33 -08:00
firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareUsTimer() too long: %d", timeUs);
2017-01-21 15:02:13 -08:00
return;
}
2015-07-10 06:01:56 -07:00
2018-05-30 21:32:55 -07:00
if (GPTDEVICE.state == GPT_ONESHOT) {
2015-07-10 06:01:56 -07:00
gptStopTimerI(&GPTDEVICE);
2018-05-30 21:32:55 -07:00
}
2018-05-20 10:36:15 -07:00
if (GPTDEVICE.state != GPT_READY) {
2018-09-10 19:00:13 -07:00
firmwareError(CUSTOM_HW_TIMER, "HW timer state %d", GPTDEVICE.state);
2018-05-20 10:36:15 -07:00
return;
}
2016-01-18 16:01:48 -08:00
if (hasFirmwareError())
return;
2015-07-10 06:01:56 -07:00
gptStartOneShotI(&GPTDEVICE, timeUs);
lastSetTimerTimeNt = getTimeNowNt();
lastSetTimerValue = timeUs;
isTimerPending = TRUE;
timerRestartCounter++;
}
static void callback(GPTDriver *gptp) {
(void)gptp;
timerCallbackCounter++;
if (globalTimerCallback == NULL) {
firmwareError(CUSTOM_ERR_NULL_TIMER_CALLBACK, "NULL globalTimerCallback");
2015-07-10 06:01:56 -07:00
return;
}
isTimerPending = false;
// // test code
// setOutputPinValue(LED_CRANKING, timerCallbackCounter % 2);
// int mod = timerCallbackCounter % 400;
// chSysLockFromISR()
2015-07-10 06:01:56 -07:00
// ;
// setHardwareUsTimer(400 - mod);
// chSysUnlockFromISR()
2015-07-10 06:01:56 -07:00
// ;
uint32_t before = GET_TIMESTAMP();
2015-07-10 06:01:56 -07:00
globalTimerCallback(NULL);
uint32_t precisionCallbackDuration = GET_TIMESTAMP() - before;
2017-05-21 07:25:35 -07:00
if (precisionCallbackDuration > maxPrecisionCallbackDuration) {
maxPrecisionCallbackDuration = precisionCallbackDuration;
}
2015-07-10 06:01:56 -07:00
}
static void usTimerWatchDog(void) {
if (getTimeNowNt() >= lastSetTimerTimeNt + 2 * CORE_CLOCK) {
strcpy(buff, "no_event");
itoa10(&buff[8], lastSetTimerValue);
firmwareError(CUSTOM_ERR_SCHEDULING_ERROR, buff);
2015-07-10 06:01:56 -07:00
return;
}
msg = isTimerPending ? "No_cb too long" : "Timer not awhile";
// 2 seconds of inactivity would not look right
2018-07-25 20:03:04 -07:00
efiAssertVoid(CUSTOM_ERR_6682, getTimeNowNt() < lastSetTimerTimeNt + 2 * CORE_CLOCK, msg);
2015-07-10 06:01:56 -07:00
}
static msg_t mwThread(int param) {
(void)param;
chRegSetThreadName("timer watchdog");
while (true) {
chThdSleepMilliseconds(1000); // once a second is enough
usTimerWatchDog();
}
#if defined __GNUC__
return -1;
#endif
}
//static const GPTConfig gpt5cfg;
static const GPTConfig gpt5cfg = { 1000000, /* 1 MHz timer clock.*/
callback, /* Timer callback.*/
2017-03-22 16:46:05 -07:00
0, 0 };
2015-07-10 06:01:56 -07:00
void initMicrosecondTimer(void) {
gptStart(&GPTDEVICE, &gpt5cfg);
lastSetTimerTimeNt = getTimeNowNt();
#if EFI_EMULATE_POSITION_SENSORS
2018-12-27 06:40:40 -08:00
chThdCreateStatic(mwThreadStack, sizeof(mwThreadStack), NORMALPRIO, (tfunc_t)(void*) mwThread, NULL);
2015-07-10 06:01:56 -07:00
#endif /* EFI_ENGINE_EMULATOR */
// // test code
// chSysLock()
// ;
// setHardwareUsTimer(300);
// chSysUnlock()
// ;
}
#endif /* EFI_PROD_CODE */