From 6334e5011f3d7986b8aca99a73ebc84db2cd90cf Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 22 Nov 2020 17:39:32 -0800 Subject: [PATCH] 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 --- firmware/hw_layer/hw_layer.mk | 5 +- .../microsecond_timer.cpp} | 68 +++++++------------ .../microsecond_timer.h | 0 .../microsecond_timer_gpt.cpp | 45 ++++++++++++ .../port_microsecond_timer.h | 13 ++++ firmware/hw_layer/ports/cypress/hw_ports.mk | 3 +- firmware/hw_layer/ports/cypress/mpu_util.cpp | 5 -- firmware/hw_layer/ports/kinetis/hw_ports.mk | 3 +- firmware/hw_layer/ports/kinetis/mpu_util.cpp | 5 -- .../hw_layer/ports/stm32/stm32_common.cpp | 4 -- firmware/hw_layer/ports/stm32/stm32_common.mk | 3 +- 11 files changed, 90 insertions(+), 64 deletions(-) rename firmware/hw_layer/{microsecond_timer_gpt.cpp => microsecond_timer/microsecond_timer.cpp} (72%) rename firmware/hw_layer/{ => microsecond_timer}/microsecond_timer.h (100%) create mode 100644 firmware/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp create mode 100644 firmware/hw_layer/microsecond_timer/port_microsecond_timer.h diff --git a/firmware/hw_layer/hw_layer.mk b/firmware/hw_layer/hw_layer.mk index 325f7b2ecf..bf103e7c8f 100644 --- a/firmware/hw_layer/hw_layer.mk +++ b/firmware/hw_layer/hw_layer.mk @@ -1,7 +1,8 @@ HW_LAYER_INC= $(PROJECT_DIR)/hw_layer $(PROJECT_DIR)/hw_layer/adc \ $(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) \ $(PROJECT_DIR)/hw_layer/ports @@ -15,7 +16,7 @@ HW_LAYER_EMS = $(HW_LAYER_EGT) \ HW_LAYER_EMS_CPP = $(HW_LAYER_EGT_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_icu.cpp \ $(PROJECT_DIR)/hw_layer/digital_input/digital_input_exti.cpp \ diff --git a/firmware/hw_layer/microsecond_timer_gpt.cpp b/firmware/hw_layer/microsecond_timer/microsecond_timer.cpp similarity index 72% rename from firmware/hw_layer/microsecond_timer_gpt.cpp rename to firmware/hw_layer/microsecond_timer/microsecond_timer.cpp index a5774e9a93..20afd06616 100644 --- a/firmware/hw_layer/microsecond_timer_gpt.cpp +++ b/firmware/hw_layer/microsecond_timer/microsecond_timer.cpp @@ -12,14 +12,10 @@ */ #include "global.h" -#include "os_access.h" #include "microsecond_timer.h" -#include "scheduler.h" -#include "os_util.h" +#include "port_microsecond_timer.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 && HAL_USE_GPT +#if EFI_PROD_CODE #include "periodic_task.h" #include "engine.h" @@ -39,20 +35,19 @@ EXTERN_ENGINE; */ uint32_t maxPrecisionCallbackDuration = 0; -static volatile efitick_t lastSetTimerTimeNt; -static int lastSetTimerValue; -static volatile bool isTimerPending = false; +static efitick_t lastSetTimerTimeNt; +static bool isTimerPending = false; -static volatile int timerCallbackCounter = 0; -static volatile int timerRestartCounter = 0; +static int timerCallbackCounter = 0; +static int timerRestartCounter = 0; static const char * msg; static char buff[32]; static int timerFreezeCounter = 0; -static volatile int setHwTimerCounter = 0; -static volatile bool hwStarted = false; +static int setHwTimerCounter = 0; +static bool hwStarted = false; /** * 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) { 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++; /** - * #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 */ - if (deltaTimeUs <= 0) { + if (timeDeltaNt <= 0) { 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 - if (deltaTimeUs < 2) { - deltaTimeUs = 2; + if (timeDeltaNt < US2NT(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 - firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareSchedulerTimer() too far: %d", deltaTimeUs); - 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); + firmwareError(CUSTOM_ERR_TIMER_OVERFLOW, "setHardwareSchedulerTimer() too far: %d", timeDeltaNt); return; } + // Skip scheduling if there's a firmware error active if (hasFirmwareError()) { return; } - // Start the timer - gptStartOneShotI(&GPTDEVICE, deltaTimeUs); + // Do the actual hardware-specific timer set operation + portSetHardwareSchedulerTimer(nowNt, setTimeNt); lastSetTimerTimeNt = getTimeNowNt(); - lastSetTimerValue = deltaTimeUs; isTimerPending = true; timerRestartCounter++; } void globalTimerCallback(); -static void hwTimerCallback(GPTDriver*) { +void portMicrosecondTimerCallback() { timerCallbackCounter++; isTimerPending = false; @@ -127,7 +113,7 @@ class MicrosecondTimerWatchdogController : public PeriodicTimerController { efitick_t nowNt = getTimeNowNt(); if (nowNt >= lastSetTimerTimeNt + 2 * CORE_CLOCK) { strcpy(buff, "no_event"); - itoa10(&buff[8], lastSetTimerValue); + itoa10(&buff[8], lastSetTimerTimeNt); firmwareError(CUSTOM_ERR_SCHEDULING_ERROR, buff); return; } @@ -144,14 +130,6 @@ class MicrosecondTimerWatchdogController : public PeriodicTimerController { 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 void watchDogBuddyCallback(void*) { @@ -195,8 +173,8 @@ static void validateHardwareTimer() { } void initMicrosecondTimer() { - gptStart(&GPTDEVICE, &gpt5cfg); - efiAssertVoid(CUSTOM_ERR_TIMER_STATE, GPTDEVICE.state == GPT_READY, "hw state"); + portInitMicrosecondTimer(); + hwStarted = true; lastSetTimerTimeNt = getTimeNowNt(); diff --git a/firmware/hw_layer/microsecond_timer.h b/firmware/hw_layer/microsecond_timer/microsecond_timer.h similarity index 100% rename from firmware/hw_layer/microsecond_timer.h rename to firmware/hw_layer/microsecond_timer/microsecond_timer.h diff --git a/firmware/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp b/firmware/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp new file mode 100644 index 0000000000..ddbfbc08d7 --- /dev/null +++ b/firmware/hw_layer/microsecond_timer/microsecond_timer_gpt.cpp @@ -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(); +} diff --git a/firmware/hw_layer/microsecond_timer/port_microsecond_timer.h b/firmware/hw_layer/microsecond_timer/port_microsecond_timer.h new file mode 100644 index 0000000000..b688200ceb --- /dev/null +++ b/firmware/hw_layer/microsecond_timer/port_microsecond_timer.h @@ -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(); diff --git a/firmware/hw_layer/ports/cypress/hw_ports.mk b/firmware/hw_layer/ports/cypress/hw_ports.mk index f50cd0c279..24d65ef3e4 100644 --- a/firmware/hw_layer/ports/cypress/hw_ports.mk +++ b/firmware/hw_layer/ports/cypress/hw_ports.mk @@ -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_common.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 diff --git a/firmware/hw_layer/ports/cypress/mpu_util.cpp b/firmware/hw_layer/ports/cypress/mpu_util.cpp index 0cffea7a78..030eb1dcf3 100644 --- a/firmware/hw_layer/ports/cypress/mpu_util.cpp +++ b/firmware/hw_layer/ports/cypress/mpu_util.cpp @@ -257,9 +257,4 @@ uintptr_t getFlashAddrSecondCopy() { return FLASH_ADDR_SECOND_COPY; } -uint32_t getTimeNowLowerNt() { - return port_rt_get_counter_value(); -} - #endif /* EFI_PROD_CODE */ - diff --git a/firmware/hw_layer/ports/kinetis/hw_ports.mk b/firmware/hw_layer/ports/kinetis/hw_ports.mk index 2ada42203e..1c8a672eab 100644 --- a/firmware/hw_layer/ports/kinetis/hw_ports.mk +++ b/firmware/hw_layer/ports/kinetis/hw_ports.mk @@ -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/backup_ram.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 \ diff --git a/firmware/hw_layer/ports/kinetis/mpu_util.cpp b/firmware/hw_layer/ports/kinetis/mpu_util.cpp index ab4b7403ca..c078074443 100644 --- a/firmware/hw_layer/ports/kinetis/mpu_util.cpp +++ b/firmware/hw_layer/ports/kinetis/mpu_util.cpp @@ -262,9 +262,4 @@ uintptr_t getFlashAddrSecondCopy() { return nullptr; } -uint32_t getTimeNowLowerNt() { - return port_rt_get_counter_value(); -} - #endif /* EFI_PROD_CODE */ - diff --git a/firmware/hw_layer/ports/stm32/stm32_common.cpp b/firmware/hw_layer/ports/stm32/stm32_common.cpp index 611913be14..11d5623ba9 100644 --- a/firmware/hw_layer/ports/stm32/stm32_common.cpp +++ b/firmware/hw_layer/ports/stm32/stm32_common.cpp @@ -326,7 +326,3 @@ bool isValidSerialRxPin(brain_pin_e pin) { } #endif /*EFI_AUX_SERIAL*/ - -uint32_t getTimeNowLowerNt() { - return port_rt_get_counter_value(); -} diff --git a/firmware/hw_layer/ports/stm32/stm32_common.mk b/firmware/hw_layer/ports/stm32/stm32_common.mk index 7cea70241b..47b3274408 100644 --- a/firmware/hw_layer/ports/stm32/stm32_common.mk +++ b/firmware/hw_layer/ports/stm32/stm32_common.mk @@ -5,7 +5,8 @@ HW_LAYER_EMS += $(PROJECT_DIR)/hw_layer/ports/stm32/serial_over_usb/usbcfg.c \ HW_LAYER_EMS_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/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