switch stm32 scheduling to use PWM driver (#1983)

* move to folder

* extract hardware part of microsecond_timer

* dead ST forum link

* de-volatile

* simulator build

* guard

* switch stm32 to pwm timer

* comments

* f7 mcuconf

* simulator

* guard

* warning

* header, cleanup

* constant

* less magic

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-12-10 21:44:40 -08:00 committed by GitHub
parent 64fdfba435
commit 8ad2080df7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}