diff --git a/firmware/c_board/app/src/app.cpp b/firmware/c_board/app/src/app.cpp index 9418f82..21c8e6e 100644 --- a/firmware/c_board/app/src/app.cpp +++ b/firmware/c_board/app/src/app.cpp @@ -15,6 +15,7 @@ #include "firmware/c_board/app/src/spi/bmi088/accel.hpp" #include "firmware/c_board/app/src/spi/bmi088/gyro.hpp" #include "firmware/c_board/app/src/spi/spi.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" #include "firmware/c_board/app/src/uart/uart.hpp" #include "firmware/c_board/app/src/usb/vendor.hpp" #include "firmware/c_board/app/src/utility/boot_mailbox.hpp" @@ -34,9 +35,10 @@ App::App() { SystemClock_Config(); utility::boot_mailbox.clear(); - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + // TIM9 must be initialized before TIM2. + MX_TIM9_Init(); + MX_TIM2_Init(); + timer::timer.init(); MX_GPIO_Init(); MX_DMA_Init(); diff --git a/firmware/c_board/app/src/spi/bmi088/accel.hpp b/firmware/c_board/app/src/spi/bmi088/accel.hpp index 8f23295..e7fed92 100644 --- a/firmware/c_board/app/src/spi/bmi088/accel.hpp +++ b/firmware/c_board/app/src/spi/bmi088/accel.hpp @@ -10,7 +10,7 @@ #include "core/src/utility/assert.hpp" #include "firmware/c_board/app/src/spi/bmi088/base.hpp" #include "firmware/c_board/app/src/spi/spi.hpp" -#include "firmware/c_board/app/src/timer/delay.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" #include "firmware/c_board/app/src/usb/vendor.hpp" #include "firmware/c_board/app/src/utility/lazy.hpp" @@ -75,11 +75,11 @@ class Accelerometer final // Dummy read to switch accelerometer to SPI mode. read_register(RegisterAddress::kAccChipId); - timer::delay(1ms); + timer::timer->spin_wait(1ms); // Reset all registers to reset value. write_register(RegisterAddress::kAccSoftReset, 0xB6); - timer::delay(1ms); + timer::timer->spin_wait(1ms); // "Who am I" check. core::utility::assert_always(read_and_confirm(RegisterAddress::kAccChipId, 0x1E)); @@ -100,7 +100,7 @@ class Accelerometer final core::utility::assert_always(write_and_confirm(RegisterAddress::kAccPwrConf, 0x00)); // Turn on the accelerometer. core::utility::assert_always(write_and_confirm(RegisterAddress::kAccPwrCtrl, 0x04)); - timer::delay(1ms); // Datasheet: wait >=450us after entering normal mode + timer::timer->spin_wait(1ms); // Datasheet: wait >=450us after entering normal mode spi_.unlock(); } diff --git a/firmware/c_board/app/src/spi/bmi088/base.hpp b/firmware/c_board/app/src/spi/bmi088/base.hpp index a066f01..d10ff4b 100644 --- a/firmware/c_board/app/src/spi/bmi088/base.hpp +++ b/firmware/c_board/app/src/spi/bmi088/base.hpp @@ -11,7 +11,7 @@ #include "core/src/utility/assert.hpp" #include "firmware/c_board/app/src/spi/spi.hpp" -#include "firmware/c_board/app/src/timer/delay.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" namespace librmcs::firmware::spi::bmi088 { @@ -53,7 +53,7 @@ class Bmi088Base : private SpiModule { for (int i = kMaxRetries; i-- > 0;) { if (read_register(addr) == expected) return true; - timer::delay(1ms); + timer::timer->spin_wait(1ms); } return false; } @@ -63,7 +63,7 @@ class Bmi088Base : private SpiModule { for (int i = kMaxRetries; i-- > 0;) { write_register(addr, val); - timer::delay(1ms); + timer::timer->spin_wait(1ms); if (read_register(addr) == val) return true; } diff --git a/firmware/c_board/app/src/spi/bmi088/gyro.hpp b/firmware/c_board/app/src/spi/bmi088/gyro.hpp index a398e01..0b78243 100644 --- a/firmware/c_board/app/src/spi/bmi088/gyro.hpp +++ b/firmware/c_board/app/src/spi/bmi088/gyro.hpp @@ -10,7 +10,7 @@ #include "core/src/utility/assert.hpp" #include "firmware/c_board/app/src/spi/bmi088/base.hpp" #include "firmware/c_board/app/src/spi/spi.hpp" -#include "firmware/c_board/app/src/timer/delay.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" #include "firmware/c_board/app/src/usb/vendor.hpp" #include "firmware/c_board/app/src/utility/lazy.hpp" @@ -74,7 +74,7 @@ class Gyroscope final // Reset all registers to reset value. write_register(RegisterAddress::kGyroSoftReset, 0xB6); - timer::delay(30ms); + timer::timer->spin_wait(30ms); // "Who am I" check. core::utility::assert_always(read_and_confirm(RegisterAddress::kGyroChipId, 0x0F)); diff --git a/firmware/c_board/app/src/timer/delay.cpp b/firmware/c_board/app/src/timer/delay.cpp index 8bfc418..352499d 100644 --- a/firmware/c_board/app/src/timer/delay.cpp +++ b/firmware/c_board/app/src/timer/delay.cpp @@ -1,17 +1,18 @@ -#include "firmware/c_board/app/src/timer/delay.hpp" - #include #include #include #include "firmware/c_board/app/src/led/led.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" namespace librmcs::firmware::timer { -// The STM32 DWT (Data Watchpoint and Trace) unit is used to rewrite the Hal_Delay function to -// ensure that it works when interrupts are disabled, while significantly improving accuracy. -extern "C" void HAL_Delay(uint32_t delay) { timer::delay(std::chrono::milliseconds(delay)); } +// Rewrite the Hal_Delay function to ensure that it works when interrupts are disabled, +// while significantly improving accuracy. +extern "C" void HAL_Delay(uint32_t delay) { + timer::timer->spin_wait(timer::Timer::to_duration48_checked(std::chrono::milliseconds(delay))); +} // Hack this useless function to perform regular low-priority tasks, eliminating the need for a // dedicated timer peripheral. diff --git a/firmware/c_board/app/src/timer/delay.hpp b/firmware/c_board/app/src/timer/delay.hpp deleted file mode 100644 index f90b805..0000000 --- a/firmware/c_board/app/src/timer/delay.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -namespace librmcs::firmware::timer { - -constexpr uint32_t kSystemFrequency = 168'000'000; -using SysFreqDuration = std::chrono::duration>; - -inline void delay_basic(SysFreqDuration delay) { - if (!delay.count()) [[unlikely]] - return; - - const uint32_t start = DWT->CYCCNT; - const uint32_t end = start + delay.count(); - - if (end < start) { // Overflow - while (DWT->CYCCNT >= start) - ; - } - - while (DWT->CYCCNT < end) - ; -} - -template -inline void delay(std::chrono::duration delay) { - if constexpr (std::is_signed_v) { - if (delay.count() < 0) [[unlikely]] - return; - } - - if constexpr (sizeof(Rep) > sizeof(uint32_t)) { - assert(delay.count() <= std::numeric_limits::max()); - } - - using DurationT = std::chrono::duration; - auto casted_delay = DurationT{delay.count()}; - constexpr auto max = std::chrono::floor(SysFreqDuration::max()); - static_assert(max.count() > 0, "The unit is too large, please choose a smaller unit"); - - while (casted_delay > max) { - casted_delay -= max; - delay_basic(SysFreqDuration::max()); - } - delay_basic(std::chrono::round(casted_delay)); -} - -} // namespace librmcs::firmware::timer diff --git a/firmware/c_board/app/src/timer/timer.hpp b/firmware/c_board/app/src/timer/timer.hpp new file mode 100644 index 0000000..cb43447 --- /dev/null +++ b/firmware/c_board/app/src/timer/timer.hpp @@ -0,0 +1,146 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "core/src/utility/assert.hpp" +#include "firmware/c_board/app/src/utility/lazy.hpp" + +namespace librmcs::firmware::timer { + +class Timer { +public: + using Lazy = utility::Lazy; + + static constexpr uint32_t kClockFrequency = 168'000'000 / 2 / 21; + using TickPeriod = std::ratio<1, kClockFrequency>; + + // 1/4 us + using Duration = std::chrono::duration; + using Duration48 = std::chrono::duration; + + using TimePoint = std::chrono::time_point; + using TimePoint48 = std::chrono::time_point; + + // Keep the true-window at least half-cycle for stateless expiration checks. + static constexpr uint64_t kMaxDurationTicks = uint64_t{1} << 31; + static constexpr uint64_t kMaxDuration48Ticks = uint64_t{1} << 47; + + static constexpr uint64_t kCounter48Mask = 0xFFFFFFFFFFFFULL; + + static constexpr TIM_HandleTypeDef* kTimerLow = &htim2; + static constexpr TIM_HandleTypeDef* kTimerHigh = &htim9; + + Timer() + : timer_counter_high_(kTimerHigh->Instance->CNT) + , timer_counter_low_(kTimerLow->Instance->CNT) { + core::utility::assert_always( + HAL_TIM_Base_Start(kTimerHigh) == HAL_OK && HAL_TIM_Base_Start(kTimerLow) == HAL_OK); + } + + TimePoint timepoint() const { return TimePoint{Duration{timer_counter_low_}}; } + + TimePoint48 timepoint48() const { + uint32_t hi1, hi2, lo; + do { + hi1 = timer_counter_high_; + lo = timer_counter_low_; + hi2 = timer_counter_high_; + } while (hi1 != hi2); + + return TimePoint48{Duration48{(uint64_t{hi2} << 32) | lo}}; + } + + [[nodiscard]] bool check_expired(TimePoint start_point, Duration delay) const { + core::utility::assert_debug(delay.count() <= kMaxDurationTicks); + + const uint32_t start_ticks = start_point.time_since_epoch().count(); + const uint32_t now_ticks = timepoint().time_since_epoch().count(); + const Duration elapsed_duration{static_cast(now_ticks - start_ticks)}; + return elapsed_duration >= delay; + } + + [[nodiscard]] bool check_expired(TimePoint48 start_point, Duration48 delay) const { + core::utility::assert_debug(delay.count() <= kMaxDuration48Ticks); + + const uint64_t start_ticks = start_point.time_since_epoch().count() & kCounter48Mask; + const uint64_t now_ticks = timepoint48().time_since_epoch().count() & kCounter48Mask; + const Duration48 elapsed_duration{(now_ticks - start_ticks) & kCounter48Mask}; + return elapsed_duration >= delay; + } + + void spin_wait(Duration48 delay) const { + core::utility::assert_debug(delay.count() <= kMaxDuration48Ticks); + + const TimePoint48 start = timepoint48(); + while (!check_expired(start, delay)) + ; + } + + template + [[nodiscard]] static constexpr Duration + to_duration_checked(std::chrono::duration duration) { + static_assert(Period::num > 0 && Period::den > 0); + + const uint64_t count = count_to_u64_checked(duration.count()); + using InputDuration = std::chrono::duration; + const InputDuration duration_u64{count}; + + constexpr Duration max_duration{static_cast(kMaxDurationTicks)}; + const InputDuration max_input_duration = + std::chrono::duration_cast(max_duration); + + core::utility::assert_debug(duration_u64 <= max_input_duration); + const Duration delay_duration = std::chrono::ceil(duration_u64); + + core::utility::assert_debug(delay_duration.count() <= kMaxDurationTicks); + return delay_duration; + } + + template + [[nodiscard]] static constexpr Duration48 + to_duration48_checked(std::chrono::duration duration) { + static_assert(Period::num > 0 && Period::den > 0); + + const uint64_t count = count_to_u64_checked(duration.count()); + using InputDuration = std::chrono::duration; + const InputDuration duration_u64{count}; + + constexpr Duration48 max_duration{kMaxDuration48Ticks}; + const InputDuration max_input_duration = + std::chrono::duration_cast(max_duration); + + core::utility::assert_debug(duration_u64 <= max_input_duration); + const Duration48 delay_duration = std::chrono::ceil(duration_u64); + + core::utility::assert_debug(delay_duration.count() <= kMaxDuration48Ticks); + return delay_duration; + } + +private: + template + [[nodiscard]] static uint64_t count_to_u64_checked(Rep count) { + if constexpr (std::is_signed_v) + core::utility::assert_debug(count >= 0); + + if constexpr (sizeof(Rep) > sizeof(uint64_t)) { + core::utility::assert_debug( + count <= static_cast(std::numeric_limits::max())); + } + return static_cast(count); + } + + const volatile uint32_t& timer_counter_high_; + const volatile uint32_t& timer_counter_low_; +}; + +inline constinit Timer::Lazy timer; + +} // namespace librmcs::firmware::timer diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/tim.h b/firmware/c_board/bsp/cubemx/Core/Inc/tim.h index 9b55dce..7ccb3fa 100644 --- a/firmware/c_board/bsp/cubemx/Core/Inc/tim.h +++ b/firmware/c_board/bsp/cubemx/Core/Inc/tim.h @@ -32,13 +32,19 @@ extern "C" { #include "stm32f4xx_hal_tim.h" // IWYU pragma: export /* USER CODE END Includes */ +extern TIM_HandleTypeDef htim2; + extern TIM_HandleTypeDef htim5; +extern TIM_HandleTypeDef htim9; + /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ +void MX_TIM2_Init(void); void MX_TIM5_Init(void); +void MX_TIM9_Init(void); void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); diff --git a/firmware/c_board/bsp/cubemx/Core/Src/tim.c b/firmware/c_board/bsp/cubemx/Core/Src/tim.c index dd3b371..deee6ca 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/tim.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/tim.c @@ -24,8 +24,50 @@ /* USER CODE END 0 */ +TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim5; +TIM_HandleTypeDef htim9; +/* TIM2 init function */ +void MX_TIM2_Init(void) +{ + + /* USER CODE BEGIN TIM2_Init 0 */ + + /* USER CODE END TIM2_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + /* USER CODE BEGIN TIM2_Init 1 */ + + /* USER CODE END TIM2_Init 1 */ + htim2.Instance = TIM2; + htim2.Init.Prescaler = 21 - 1; + htim2.Init.CounterMode = TIM_COUNTERMODE_UP; + htim2.Init.Period = 4294967295; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM2_Init 2 */ + + /* USER CODE END TIM2_Init 2 */ + +} /* TIM5 init function */ void MX_TIM5_Init(void) { @@ -87,12 +129,57 @@ void MX_TIM5_Init(void) /* USER CODE END TIM5_Init 2 */ HAL_TIM_MspPostInit(&htim5); +} +/* TIM9 init function */ +void MX_TIM9_Init(void) +{ + + /* USER CODE BEGIN TIM9_Init 0 */ + + /* USER CODE END TIM9_Init 0 */ + + TIM_SlaveConfigTypeDef sSlaveConfig = {0}; + + /* USER CODE BEGIN TIM9_Init 1 */ + + /* USER CODE END TIM9_Init 1 */ + htim9.Instance = TIM9; + htim9.Init.Prescaler = 0; + htim9.Init.CounterMode = TIM_COUNTERMODE_UP; + htim9.Init.Period = 65535; + htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim9.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim9) != HAL_OK) + { + Error_Handler(); + } + sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; + sSlaveConfig.InputTrigger = TIM_TS_ITR0; + if (HAL_TIM_SlaveConfigSynchro(&htim9, &sSlaveConfig) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM9_Init 2 */ + + /* USER CODE END TIM9_Init 2 */ + } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { - if(tim_baseHandle->Instance==TIM5) + if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspInit 0 */ + + /* USER CODE END TIM2_MspInit 0 */ + /* TIM2 clock enable */ + __HAL_RCC_TIM2_CLK_ENABLE(); + /* USER CODE BEGIN TIM2_MspInit 1 */ + + /* USER CODE END TIM2_MspInit 1 */ + } + else if(tim_baseHandle->Instance==TIM5) { /* USER CODE BEGIN TIM5_MspInit 0 */ @@ -103,6 +190,17 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM5_MspInit 1 */ } + else if(tim_baseHandle->Instance==TIM9) + { + /* USER CODE BEGIN TIM9_MspInit 0 */ + + /* USER CODE END TIM9_MspInit 0 */ + /* TIM9 clock enable */ + __HAL_RCC_TIM9_CLK_ENABLE(); + /* USER CODE BEGIN TIM9_MspInit 1 */ + + /* USER CODE END TIM9_MspInit 1 */ + } } void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) { @@ -137,7 +235,18 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) { - if(tim_baseHandle->Instance==TIM5) + if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspDeInit 0 */ + + /* USER CODE END TIM2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM2_CLK_DISABLE(); + /* USER CODE BEGIN TIM2_MspDeInit 1 */ + + /* USER CODE END TIM2_MspDeInit 1 */ + } + else if(tim_baseHandle->Instance==TIM5) { /* USER CODE BEGIN TIM5_MspDeInit 0 */ @@ -148,6 +257,17 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM5_MspDeInit 1 */ } + else if(tim_baseHandle->Instance==TIM9) + { + /* USER CODE BEGIN TIM9_MspDeInit 0 */ + + /* USER CODE END TIM9_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM9_CLK_DISABLE(); + /* USER CODE BEGIN TIM9_MspDeInit 1 */ + + /* USER CODE END TIM9_MspDeInit 1 */ + } } /* USER CODE BEGIN 1 */ diff --git a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc index a9709d4..9734cb6 100644 --- a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc +++ b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc @@ -48,17 +48,19 @@ Mcu.CPN=STM32F407IGH6 Mcu.Family=STM32F4 Mcu.IP0=CAN1 Mcu.IP1=CAN2 -Mcu.IP10=USART6 -Mcu.IP11=USB_OTG_FS +Mcu.IP10=USART1 +Mcu.IP11=USART3 +Mcu.IP12=USART6 +Mcu.IP13=USB_OTG_FS Mcu.IP2=DMA Mcu.IP3=NVIC Mcu.IP4=RCC Mcu.IP5=SPI1 Mcu.IP6=SYS -Mcu.IP7=TIM5 -Mcu.IP8=USART1 -Mcu.IP9=USART3 -Mcu.IPNb=12 +Mcu.IP7=TIM2 +Mcu.IP8=TIM5 +Mcu.IP9=TIM9 +Mcu.IPNb=14 Mcu.Name=STM32F407I(E-G)Hx Mcu.Package=UFBGA176 Mcu.Pin0=PB5 @@ -81,15 +83,18 @@ Mcu.Pin23=PC5 Mcu.Pin24=PA7 Mcu.Pin25=PB0 Mcu.Pin26=VP_SYS_VS_Systick -Mcu.Pin27=VP_TIM5_VS_ClockSourceINT +Mcu.Pin27=VP_TIM2_VS_ClockSourceINT +Mcu.Pin28=VP_TIM5_VS_ClockSourceINT +Mcu.Pin29=VP_TIM9_VS_ControllerModeClock Mcu.Pin3=PB3 +Mcu.Pin30=VP_TIM9_VS_ClockSourceITR Mcu.Pin4=PA14 Mcu.Pin5=PA13 Mcu.Pin6=PB7 Mcu.Pin7=PB6 Mcu.Pin8=PD0 Mcu.Pin9=PC11 -Mcu.PinsNb=28 +Mcu.PinsNb=31 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F407IGHx @@ -257,7 +262,7 @@ ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SPI1_Init-SPI1-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_CAN2_Init-CAN2-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USART6_UART_Init-USART6-false-HAL-true,10-MX_TIM5_Init-TIM5-false-HAL-true,11-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SPI1_Init-SPI1-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_CAN2_Init-CAN2-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USART6_UART_Init-USART6-false-HAL-true,10-MX_TIM5_Init-TIM5-false-HAL-true,11-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_TIM9_Init-TIM9-false-HAL-true RCC.48MHZClocksFreq_Value=48000000 RCC.AHBFreq_Value=168000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -309,12 +314,18 @@ SPI1.Direction=SPI_DIRECTION_2LINES SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPhase,CLKPolarity SPI1.Mode=SPI_MODE_MASTER SPI1.VirtualType=VM_MASTER +TIM2.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger,Prescaler +TIM2.Prescaler=21 - 1 +TIM2.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE +TIM2.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE TIM5.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 TIM5.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 TIM5.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 TIM5.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Period,Prescaler,Channel-PWM Generation3 CH3 TIM5.Period=256-1 TIM5.Prescaler=84-1 +TIM9.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE +TIM9.IPParameters=AutoReloadPreload USART1.IPParameters=VirtualMode USART1.VirtualMode=VM_ASYNC USART3.BaudRate=100000 @@ -329,6 +340,12 @@ USB_OTG_FS.IPParameters=VirtualMode USB_OTG_FS.VirtualMode=Device_Only VP_SYS_VS_Systick.Mode=SysTick VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM2_VS_ClockSourceINT.Mode=Internal +VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT VP_TIM5_VS_ClockSourceINT.Mode=Internal VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT +VP_TIM9_VS_ClockSourceITR.Mode=TriggerSource_ITR0 +VP_TIM9_VS_ClockSourceITR.Signal=TIM9_VS_ClockSourceITR +VP_TIM9_VS_ControllerModeClock.Mode=Clock Mode +VP_TIM9_VS_ControllerModeClock.Signal=TIM9_VS_ControllerModeClock board=custom