diff --git a/firmware/config/stm32f4ems/mcuconf.h b/firmware/config/stm32f4ems/mcuconf.h index a55efcdd9f..08e4233535 100644 --- a/firmware/config/stm32f4ems/mcuconf.h +++ b/firmware/config/stm32f4ems/mcuconf.h @@ -179,7 +179,7 @@ #define STM32_GPT_USE_TIM2 FALSE #define STM32_GPT_USE_TIM3 FALSE #define STM32_GPT_USE_TIM4 FALSE -#define STM32_GPT_USE_TIM5 TRUE +#define STM32_GPT_USE_TIM5 FALSE #define STM32_GPT_USE_TIM6 TRUE #define STM32_GPT_USE_TIM7 FALSE #define STM32_GPT_USE_TIM8 FALSE @@ -191,7 +191,7 @@ #define STM32_GPT_TIM2_IRQ_PRIORITY 7 #define STM32_GPT_TIM3_IRQ_PRIORITY 7 #define STM32_GPT_TIM4_IRQ_PRIORITY 7 -#define STM32_GPT_TIM5_IRQ_PRIORITY PRECISE_SCHEDULING_TIMER_PRIORITY +#define STM32_GPT_TIM5_IRQ_PRIORITY 7 #define STM32_GPT_TIM6_IRQ_PRIORITY 7 #define STM32_GPT_TIM7_IRQ_PRIORITY 7 #define STM32_GPT_TIM8_IRQ_PRIORITY 7 @@ -273,14 +273,14 @@ #define STM32_PWM_USE_TIM2 FALSE #define STM32_PWM_USE_TIM3 FALSE #define STM32_PWM_USE_TIM4 TRUE -#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM5 TRUE #define STM32_PWM_USE_TIM8 TRUE #define STM32_PWM_USE_TIM9 FALSE #define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7 #define STM32_PWM_TIM3_IRQ_PRIORITY 7 #define STM32_PWM_TIM4_IRQ_PRIORITY 7 -#define STM32_PWM_TIM5_IRQ_PRIORITY 7 +#define STM32_PWM_TIM5_IRQ_PRIORITY PRECISE_SCHEDULING_TIMER_PRIORITY #define STM32_PWM_TIM8_IRQ_PRIORITY 7 #define STM32_PWM_TIM9_IRQ_PRIORITY 7 diff --git a/firmware/config/stm32f7ems/mcuconf.h b/firmware/config/stm32f7ems/mcuconf.h index fe85ebf0de..12ffad6271 100644 --- a/firmware/config/stm32f7ems/mcuconf.h +++ b/firmware/config/stm32f7ems/mcuconf.h @@ -200,7 +200,7 @@ #define STM32_GPT_USE_TIM2 FALSE #define STM32_GPT_USE_TIM3 FALSE #define STM32_GPT_USE_TIM4 FALSE -#define STM32_GPT_USE_TIM5 TRUE +#define STM32_GPT_USE_TIM5 FALSE #define STM32_GPT_USE_TIM6 TRUE #define STM32_GPT_USE_TIM7 FALSE #define STM32_GPT_USE_TIM8 FALSE @@ -212,7 +212,7 @@ #define STM32_GPT_TIM2_IRQ_PRIORITY 7 #define STM32_GPT_TIM3_IRQ_PRIORITY 7 #define STM32_GPT_TIM4_IRQ_PRIORITY 7 -#define STM32_GPT_TIM5_IRQ_PRIORITY PRECISE_SCHEDULING_TIMER_PRIORITY +#define STM32_GPT_TIM5_IRQ_PRIORITY 7 #define STM32_GPT_TIM6_IRQ_PRIORITY 7 #define STM32_GPT_TIM7_IRQ_PRIORITY 7 #define STM32_GPT_TIM8_IRQ_PRIORITY 7 @@ -284,14 +284,14 @@ #define STM32_PWM_USE_TIM2 FALSE #define STM32_PWM_USE_TIM3 FALSE #define STM32_PWM_USE_TIM4 TRUE -#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM5 TRUE #define STM32_PWM_USE_TIM8 TRUE #define STM32_PWM_USE_TIM9 FALSE #define STM32_PWM_TIM1_IRQ_PRIORITY 7 #define STM32_PWM_TIM2_IRQ_PRIORITY 7 #define STM32_PWM_TIM3_IRQ_PRIORITY 7 #define STM32_PWM_TIM4_IRQ_PRIORITY 7 -#define STM32_PWM_TIM5_IRQ_PRIORITY 7 +#define STM32_PWM_TIM5_IRQ_PRIORITY PRECISE_SCHEDULING_TIMER_PRIORITY #define STM32_PWM_TIM8_IRQ_PRIORITY 7 #define STM32_PWM_TIM9_IRQ_PRIORITY 7 diff --git a/firmware/hw_layer/ports/stm32/microsecond_timer_stm32.cpp b/firmware/hw_layer/ports/stm32/microsecond_timer_stm32.cpp new file mode 100644 index 0000000000..dcea8be757 --- /dev/null +++ b/firmware/hw_layer/ports/stm32/microsecond_timer_stm32.cpp @@ -0,0 +1,65 @@ +/** + * @file microsecond_timer_stm32.cpp + * + * A single upcounting timer (currently TIM5) is used as a single timebase both for time + * measurement and event scheduling. This helps reduce jitter by not making another time + * measurement at the time of scheduling. + * + * This implementation only works on stm32 because it sets hardware registers directly. + * ChibiOS doesn't support using timers in output compare mode, only PMW, so we have to + * manually configure the timer in outupt compare mode. + * + * @date Dec 1, 2020 + * @author Matthew Kennedy, (c) 2012-2020 + */ + +#include "global.h" + +#if EFI_PROD_CODE && HAL_USE_PWM + +#include "port_microsecond_timer.h" + +void portSetHardwareSchedulerTimer(efitick_t nowNt, efitick_t setTimeNt) { + // This implementation doesn't need the current time, only the target time + UNUSED(nowNt); + + pwm_lld_enable_channel(&SCHEDULER_PWM_DEVICE, 0, setTimeNt); + pwmEnableChannelNotificationI(&SCHEDULER_PWM_DEVICE, 0); +} + +static void hwTimerCallback(PWMDriver*) { + pwmDisableChannelNotificationI(&SCHEDULER_PWM_DEVICE, 0); + portMicrosecondTimerCallback(); +} + +static constexpr PWMConfig timerConfig = { + SCHEDULER_TIMER_FREQ, + UINT32_MAX, // timer period = 2^32 counts + nullptr, // No update callback + { + {PWM_OUTPUT_DISABLED, hwTimerCallback}, // Channel 0 = timer callback, others unused + {PWM_OUTPUT_DISABLED, nullptr}, + {PWM_OUTPUT_DISABLED, nullptr}, + {PWM_OUTPUT_DISABLED, nullptr} + }, + 0, // CR1 + 0 // CR2 +}; + +void portInitMicrosecondTimer() { + pwmStart(&SCHEDULER_PWM_DEVICE, &timerConfig); + + // ChibiOS doesn't let you configure timers in output compare mode, only PWM mode. + // We want to be able to set the compare register without waiting for an update event + // (which would take 358 seconds at 12mhz timer speed), so we have to use normal upcounting + // output compare mode instead. + SCHEDULER_TIMER_DEVICE->CCMR1 = STM32_TIM_CCMR1_OC1M(1); +} + +uint32_t getTimeNowLowerNt() { + // Using the same timer for measurement and scheduling improves + // precision and reduces jitter. + return SCHEDULER_TIMER_DEVICE->CNT; +} + +#endif // EFI_PROD_CODE diff --git a/firmware/hw_layer/ports/stm32/port_mpu_util.h b/firmware/hw_layer/ports/stm32/port_mpu_util.h index 4ad414ea40..50b8e21d5e 100644 --- a/firmware/hw_layer/ports/stm32/port_mpu_util.h +++ b/firmware/hw_layer/ports/stm32/port_mpu_util.h @@ -10,11 +10,14 @@ #include "device_mpu_util.h" -// 168 ticks in microsecond in case of 168MHz 407 -#define US_TO_NT_MULTIPLIER (CORE_CLOCK / 1000000) +// 12mhz was chosen because it's the GCD of (168, 180, 216), the three speeds of STM32 currently supported +// https://www.wolframalpha.com/input/?i=common+factors+of+168+180+216 +#define US_TO_NT_MULTIPLIER (12) -// Scheduler queue GPT device - use TIM5 -#define GPTDEVICE GPTD5 +// Scheduler queue timer - use TIM5 +#define SCHEDULER_PWM_DEVICE PWMD5 +#define SCHEDULER_TIMER_DEVICE TIM5 +#define SCHEDULER_TIMER_FREQ (US_TO_NT_MULTIPLIER * 1'000'000) typedef enum { BOR_Level_None = OB_BOR_OFF, // 0x0C=12 Supply voltage ranges from 1.62 to 2.10 V diff --git a/firmware/hw_layer/ports/stm32/stm32_common.mk b/firmware/hw_layer/ports/stm32/stm32_common.mk index 47b3274408..e6b5e47b46 100644 --- a/firmware/hw_layer/ports/stm32/stm32_common.mk +++ b/firmware/hw_layer/ports/stm32/stm32_common.mk @@ -6,7 +6,7 @@ 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/microsecond_timer/microsecond_timer_gpt.cpp \ + $(PROJECT_DIR)/hw_layer/ports/stm32/microsecond_timer_stm32.cpp \ RUSEFIASM = $(PROJECT_DIR)/hw_layer/ports/stm32/rusEfiStartup.S diff --git a/simulator/simulator/framework.cpp b/simulator/simulator/framework.cpp index c57cdc696e..c033563f12 100644 --- a/simulator/simulator/framework.cpp +++ b/simulator/simulator/framework.cpp @@ -7,11 +7,16 @@ #include "global.h" #include "framework.h" +#include "efitime.h" efitick_t getTimeNowNt(void) { return getTimeNowUs() * US_TO_NT_MULTIPLIER; } +uint32_t getTimeNowLowerNt(void) { + return getTimeNowNt(); +} + efitimeus_t getTimeNowUs(void) { return chVTGetSystemTimeX() * (1000000 / CH_CFG_ST_FREQUENCY); }