Port-ify microsecond_timer hardware implementation (#1964)
* move to folder * extract hardware part of microsecond_timer * dead ST forum link * de-volatile * simulator build * guard
This commit is contained in:
parent
4f7ff102f2
commit
6334e5011f
|
@ -1,7 +1,8 @@
|
||||||
|
|
||||||
HW_LAYER_INC= $(PROJECT_DIR)/hw_layer $(PROJECT_DIR)/hw_layer/adc \
|
HW_LAYER_INC= $(PROJECT_DIR)/hw_layer $(PROJECT_DIR)/hw_layer/adc \
|
||||||
$(PROJECT_DIR)/hw_layer/digital_input \
|
$(PROJECT_DIR)/hw_layer/digital_input \
|
||||||
$(PROJECT_DIR)/hw_layer/digital_input/trigger
|
$(PROJECT_DIR)/hw_layer/digital_input/trigger \
|
||||||
|
$(PROJECT_DIR)/hw_layer/microsecond_timer \
|
||||||
|
|
||||||
HW_INC = hw_layer/$(CPU_HWLAYER) \
|
HW_INC = hw_layer/$(CPU_HWLAYER) \
|
||||||
$(PROJECT_DIR)/hw_layer/ports
|
$(PROJECT_DIR)/hw_layer/ports
|
||||||
|
@ -15,7 +16,7 @@ HW_LAYER_EMS = $(HW_LAYER_EGT) \
|
||||||
|
|
||||||
HW_LAYER_EMS_CPP = $(HW_LAYER_EGT_CPP) \
|
HW_LAYER_EMS_CPP = $(HW_LAYER_EGT_CPP) \
|
||||||
$(PROJECT_DIR)/hw_layer/pin_repository.cpp \
|
$(PROJECT_DIR)/hw_layer/pin_repository.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/microsecond_timer_gpt.cpp \
|
$(PROJECT_DIR)/hw_layer/microsecond_timer/microsecond_timer.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/digital_input/digital_input.cpp \
|
$(PROJECT_DIR)/hw_layer/digital_input/digital_input.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/digital_input/digital_input_icu.cpp \
|
$(PROJECT_DIR)/hw_layer/digital_input/digital_input_icu.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/digital_input/digital_input_exti.cpp \
|
$(PROJECT_DIR)/hw_layer/digital_input/digital_input_exti.cpp \
|
||||||
|
|
|
@ -12,14 +12,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "os_access.h"
|
|
||||||
#include "microsecond_timer.h"
|
#include "microsecond_timer.h"
|
||||||
#include "scheduler.h"
|
#include "port_microsecond_timer.h"
|
||||||
#include "os_util.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¤tviews=474
|
#if EFI_PROD_CODE
|
||||||
|
|
||||||
#if EFI_PROD_CODE && HAL_USE_GPT
|
|
||||||
|
|
||||||
#include "periodic_task.h"
|
#include "periodic_task.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
@ -39,20 +35,19 @@ EXTERN_ENGINE;
|
||||||
*/
|
*/
|
||||||
uint32_t maxPrecisionCallbackDuration = 0;
|
uint32_t maxPrecisionCallbackDuration = 0;
|
||||||
|
|
||||||
static volatile efitick_t lastSetTimerTimeNt;
|
static efitick_t lastSetTimerTimeNt;
|
||||||
static int lastSetTimerValue;
|
static bool isTimerPending = false;
|
||||||
static volatile bool isTimerPending = false;
|
|
||||||
|
|
||||||
static volatile int timerCallbackCounter = 0;
|
static int timerCallbackCounter = 0;
|
||||||
static volatile int timerRestartCounter = 0;
|
static int timerRestartCounter = 0;
|
||||||
|
|
||||||
static const char * msg;
|
static const char * msg;
|
||||||
|
|
||||||
static char buff[32];
|
static char buff[32];
|
||||||
|
|
||||||
static int timerFreezeCounter = 0;
|
static int timerFreezeCounter = 0;
|
||||||
static volatile int setHwTimerCounter = 0;
|
static int setHwTimerCounter = 0;
|
||||||
static volatile bool hwStarted = false;
|
static bool hwStarted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the alarm to the specified number of microseconds from now.
|
* sets the alarm to the specified number of microseconds from now.
|
||||||
|
@ -61,56 +56,47 @@ static volatile bool hwStarted = false;
|
||||||
void setHardwareSchedulerTimer(efitick_t nowNt, efitick_t setTimeNt) {
|
void setHardwareSchedulerTimer(efitick_t nowNt, efitick_t setTimeNt) {
|
||||||
efiAssertVoid(OBD_PCM_Processor_Fault, hwStarted, "HW.started");
|
efiAssertVoid(OBD_PCM_Processor_Fault, hwStarted, "HW.started");
|
||||||
|
|
||||||
int32_t deltaTimeUs = NT2US((int32_t)setTimeNt - (int32_t)nowNt);
|
// How many ticks in the future is this event?
|
||||||
|
auto timeDeltaNt = setTimeNt - nowNt;
|
||||||
|
|
||||||
setHwTimerCounter++;
|
setHwTimerCounter++;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #259 BUG error: not positive deltaTimeUs
|
* #259 BUG error: not positive deltaTimeNt
|
||||||
* Once in a while we night get an interrupt where we do not expect it
|
* Once in a while we night get an interrupt where we do not expect it
|
||||||
*/
|
*/
|
||||||
if (deltaTimeUs <= 0) {
|
if (timeDeltaNt <= 0) {
|
||||||
timerFreezeCounter++;
|
timerFreezeCounter++;
|
||||||
warning(CUSTOM_OBD_LOCAL_FREEZE, "local freeze cnt=%d", timerFreezeCounter);
|
warning(CUSTOM_OBD_LOCAL_FREEZE, "local freeze cnt=%d", timerFreezeCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need the timer to fire after we return - 1 doesn't work as it may actually schedule in the past
|
// We need the timer to fire after we return - 1 doesn't work as it may actually schedule in the past
|
||||||
if (deltaTimeUs < 2) {
|
if (timeDeltaNt < US2NT(2)) {
|
||||||
deltaTimeUs = 2;
|
timeDeltaNt = US2NT(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deltaTimeUs >= TOO_FAR_INTO_FUTURE_US) {
|
if (timeDeltaNt >= TOO_FAR_INTO_FUTURE_NT) {
|
||||||
// we are trying to set callback for too far into the future. This does not look right at all
|
// we are trying to set callback for too far into the future. This does not look right at all
|
||||||
firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareSchedulerTimer() too far: %d", deltaTimeUs);
|
firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareSchedulerTimer() too far: %d", timeDeltaNt);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If already set, reset the timer
|
|
||||||
if (GPTDEVICE.state == GPT_ONESHOT) {
|
|
||||||
gptStopTimerI(&GPTDEVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GPTDEVICE.state != GPT_READY) {
|
|
||||||
firmwareError(CUSTOM_HW_TIMER, "HW timer state %d/%d", GPTDEVICE.state, setHwTimerCounter);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip scheduling if there's a firmware error active
|
||||||
if (hasFirmwareError()) {
|
if (hasFirmwareError()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the timer
|
// Do the actual hardware-specific timer set operation
|
||||||
gptStartOneShotI(&GPTDEVICE, deltaTimeUs);
|
portSetHardwareSchedulerTimer(nowNt, setTimeNt);
|
||||||
|
|
||||||
lastSetTimerTimeNt = getTimeNowNt();
|
lastSetTimerTimeNt = getTimeNowNt();
|
||||||
lastSetTimerValue = deltaTimeUs;
|
|
||||||
isTimerPending = true;
|
isTimerPending = true;
|
||||||
timerRestartCounter++;
|
timerRestartCounter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void globalTimerCallback();
|
void globalTimerCallback();
|
||||||
|
|
||||||
static void hwTimerCallback(GPTDriver*) {
|
void portMicrosecondTimerCallback() {
|
||||||
timerCallbackCounter++;
|
timerCallbackCounter++;
|
||||||
isTimerPending = false;
|
isTimerPending = false;
|
||||||
|
|
||||||
|
@ -127,7 +113,7 @@ class MicrosecondTimerWatchdogController : public PeriodicTimerController {
|
||||||
efitick_t nowNt = getTimeNowNt();
|
efitick_t nowNt = getTimeNowNt();
|
||||||
if (nowNt >= lastSetTimerTimeNt + 2 * CORE_CLOCK) {
|
if (nowNt >= lastSetTimerTimeNt + 2 * CORE_CLOCK) {
|
||||||
strcpy(buff, "no_event");
|
strcpy(buff, "no_event");
|
||||||
itoa10(&buff[8], lastSetTimerValue);
|
itoa10(&buff[8], lastSetTimerTimeNt);
|
||||||
firmwareError(CUSTOM_ERR_SCHEDULING_ERROR, buff);
|
firmwareError(CUSTOM_ERR_SCHEDULING_ERROR, buff);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -144,14 +130,6 @@ class MicrosecondTimerWatchdogController : public PeriodicTimerController {
|
||||||
|
|
||||||
static MicrosecondTimerWatchdogController watchdogControllerInstance;
|
static MicrosecondTimerWatchdogController watchdogControllerInstance;
|
||||||
|
|
||||||
/*
|
|
||||||
* The specific 1MHz frequency is important here since 'setHardwareUsTimer' method takes microsecond parameter
|
|
||||||
* For any arbitrary frequency to work we would need an additional layer of conversion.
|
|
||||||
*/
|
|
||||||
static constexpr GPTConfig gpt5cfg = { 1000000, /* 1 MHz timer clock.*/
|
|
||||||
hwTimerCallback, /* Timer callback.*/
|
|
||||||
0, 0 };
|
|
||||||
|
|
||||||
static scheduling_s watchDogBuddy;
|
static scheduling_s watchDogBuddy;
|
||||||
|
|
||||||
static void watchDogBuddyCallback(void*) {
|
static void watchDogBuddyCallback(void*) {
|
||||||
|
@ -195,8 +173,8 @@ static void validateHardwareTimer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void initMicrosecondTimer() {
|
void initMicrosecondTimer() {
|
||||||
gptStart(&GPTDEVICE, &gpt5cfg);
|
portInitMicrosecondTimer();
|
||||||
efiAssertVoid(CUSTOM_ERR_TIMER_STATE, GPTDEVICE.state == GPT_READY, "hw state");
|
|
||||||
hwStarted = true;
|
hwStarted = true;
|
||||||
|
|
||||||
lastSetTimerTimeNt = getTimeNowNt();
|
lastSetTimerTimeNt = getTimeNowNt();
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "port_microsecond_timer.h"
|
||||||
|
|
||||||
|
#if EFI_PROD_CODE && HAL_USE_GPT
|
||||||
|
|
||||||
|
void portSetHardwareSchedulerTimer(efitick_t nowNt, efitick_t setTimeNt) {
|
||||||
|
int32_t deltaTimeUs = NT2US((int32_t)setTimeNt - (int32_t)nowNt);
|
||||||
|
|
||||||
|
// If already set, reset the timer
|
||||||
|
if (GPTDEVICE.state == GPT_ONESHOT) {
|
||||||
|
gptStopTimerI(&GPTDEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GPTDEVICE.state != GPT_READY) {
|
||||||
|
firmwareError(CUSTOM_HW_TIMER, "HW timer state %d", GPTDEVICE.state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the timer
|
||||||
|
gptStartOneShotI(&GPTDEVICE, deltaTimeUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hwTimerCallback(GPTDriver*) {
|
||||||
|
portMicrosecondTimerCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The specific 1MHz frequency is important here since 'setHardwareUsTimer' method takes microsecond parameter
|
||||||
|
* For any arbitrary frequency to work we would need an additional layer of conversion.
|
||||||
|
*/
|
||||||
|
static constexpr GPTConfig gpt5cfg = { 1000000, /* 1 MHz timer clock.*/
|
||||||
|
hwTimerCallback, /* Timer callback.*/
|
||||||
|
0, 0 };
|
||||||
|
|
||||||
|
void portInitMicrosecondTimer() {
|
||||||
|
gptStart(&GPTDEVICE, &gpt5cfg);
|
||||||
|
efiAssertVoid(CUSTOM_ERR_TIMER_STATE, GPTDEVICE.state == GPT_READY, "hw state");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EFI_PROD_CODE
|
||||||
|
|
||||||
|
// This implementation just uses the generic port counter - this usually returns a count of CPU cycles since start
|
||||||
|
uint32_t getTimeNowLowerNt() {
|
||||||
|
return port_rt_get_counter_value();
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* This file defines the API for the microsecond timer that a port needs to implement
|
||||||
|
*
|
||||||
|
* Do not call these functions directly, they should only be called by microsecond_timer.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void portInitMicrosecondTimer();
|
||||||
|
void portSetHardwareSchedulerTimer(efitick_t nowNt, efitick_t setTimeNt);
|
||||||
|
|
||||||
|
// The port should call this callback when the timer expires
|
||||||
|
void portMicrosecondTimerCallback();
|
|
@ -11,6 +11,7 @@ HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/cypress/mpu_util.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/cypress/cypress_pins.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/cypress/cypress_pins.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/cypress/cypress_common.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/cypress/cypress_common.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/cypress/backup_ram.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/cypress/backup_ram.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/trigger_input_adc.cpp
|
$(PROJECT_DIR)/hw_layer/trigger_input_adc.cpp \
|
||||||
|
$(PROJECT_DIR)/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp \
|
||||||
|
|
||||||
HW_INC += $(PROJECT_DIR)/hw_layer/ports/cypress/serial_over_usb
|
HW_INC += $(PROJECT_DIR)/hw_layer/ports/cypress/serial_over_usb
|
||||||
|
|
|
@ -257,9 +257,4 @@ uintptr_t getFlashAddrSecondCopy() {
|
||||||
return FLASH_ADDR_SECOND_COPY;
|
return FLASH_ADDR_SECOND_COPY;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getTimeNowLowerNt() {
|
|
||||||
return port_rt_get_counter_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* EFI_PROD_CODE */
|
#endif /* EFI_PROD_CODE */
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,5 @@ HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/kinetis/mpu_util.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_pins.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_pins.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/kinetis/backup_ram.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/kinetis/backup_ram.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_common.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/kinetis/kinetis_common.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/trigger_input_comp.cpp
|
$(PROJECT_DIR)/hw_layer/trigger_input_comp.cpp \
|
||||||
|
$(PROJECT_DIR)/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp \
|
||||||
|
|
|
@ -262,9 +262,4 @@ uintptr_t getFlashAddrSecondCopy() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getTimeNowLowerNt() {
|
|
||||||
return port_rt_get_counter_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* EFI_PROD_CODE */
|
#endif /* EFI_PROD_CODE */
|
||||||
|
|
||||||
|
|
|
@ -326,7 +326,3 @@ bool isValidSerialRxPin(brain_pin_e pin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*EFI_AUX_SERIAL*/
|
#endif /*EFI_AUX_SERIAL*/
|
||||||
|
|
||||||
uint32_t getTimeNowLowerNt() {
|
|
||||||
return port_rt_get_counter_value();
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ HW_LAYER_EMS += $(PROJECT_DIR)/hw_layer/ports/stm32/serial_over_usb/usbcfg.c \
|
||||||
HW_LAYER_EMS_CPP += \
|
HW_LAYER_EMS_CPP += \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/stm32/stm32_pins.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/stm32/stm32_pins.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/stm32/stm32_common.cpp \
|
$(PROJECT_DIR)/hw_layer/ports/stm32/stm32_common.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/ports/stm32/backup_ram.cpp
|
$(PROJECT_DIR)/hw_layer/ports/stm32/backup_ram.cpp \
|
||||||
|
$(PROJECT_DIR)/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp \
|
||||||
|
|
||||||
RUSEFIASM = $(PROJECT_DIR)/hw_layer/ports/stm32/rusEfiStartup.S
|
RUSEFIASM = $(PROJECT_DIR)/hw_layer/ports/stm32/rusEfiStartup.S
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue