diff --git a/Core/Inc/AMS_CAN.h b/Core/Inc/AMS_CAN.h index 4e42aaf..5a20b43 100644 --- a/Core/Inc/AMS_CAN.h +++ b/Core/Inc/AMS_CAN.h @@ -17,6 +17,7 @@ #include #define CAN_ID_SLAVE_ERROR 0x001 +#define CAN_ID_TIME_SYNC 0x002 #define CAN_ID_AMS_SLAVE_HEARTBEAT_BASE 0x600 #define CAN_HEARTBEAT_TX_TIMEOUT 10 /* ms */ diff --git a/Core/Inc/TimeSync.h b/Core/Inc/TimeSync.h new file mode 100644 index 0000000..842c7ee --- /dev/null +++ b/Core/Inc/TimeSync.h @@ -0,0 +1,13 @@ +#ifndef INC_TIME_SYNC_H_ +#define INC_TIME_SYNC_H_ + +#define TARGET_FREQ 16000000 // Hz +#define TRIM_FREQ 48000 // Hz +#define TIME_SYNC_INTERVAL 1000 // ms +#define RCC_CR_HSITRIM_MAX 31 + +#define STARTUP_TIME_SYNC_TIME 5000 // ms + +void time_sync_handle_frame(); + +#endif // INC_TIME_SYNC_H_ diff --git a/Core/Src/AMS_CAN.c b/Core/Src/AMS_CAN.c index 1b94e20..c17d693 100644 --- a/Core/Src/AMS_CAN.c +++ b/Core/Src/AMS_CAN.c @@ -9,6 +9,7 @@ #include "BQ_Abstraction_Layer.h" #include "TMP144.h" +#include "TimeSync.h" #include "common_defs.h" #include "main.h" @@ -32,6 +33,30 @@ void ams_can_init(CAN_HandleTypeDef* ams_handle, } } + // Config filter + CAN_FilterTypeDef can_filter; + can_filter.FilterActivation = CAN_FILTER_ENABLE; + can_filter.FilterBank = 0; + can_filter.FilterFIFOAssignment = CAN_FILTER_FIFO0; + /* Message ID is in the MSBs of the FilterId register */ + can_filter.FilterIdHigh = CAN_ID_TIME_SYNC << (16 - 11); + can_filter.FilterIdLow = 0; + /* Filter the 11 MSBs (i.e. a StdId) */ + can_filter.FilterMaskIdHigh = 0xFFE0; + can_filter.FilterMaskIdLow = 0; + can_filter.FilterMode = CAN_FILTERMODE_IDMASK; + can_filter.FilterScale = CAN_FILTERSCALE_32BIT; + // If we use CAN1, the slave filter should start after our filter bank. If we + // use CAN2, it should start at our filter bank. + if (handle_ams == ams_handle) { + can_filter.SlaveStartFilterBank = 1; + } else { + can_filter.SlaveStartFilterBank = 0; + } + if (HAL_CAN_ConfigFilter(handle_ams, &can_filter) != HAL_OK) { + Error_Handler(); + } + // Activate RX notifications if (HAL_CAN_ActivateNotification(handle_ams, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) { @@ -57,7 +82,17 @@ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* handle) { } } -void ams_can_handle_ams_msg(CAN_RxHeaderTypeDef* header, uint8_t* data) {} +void ams_can_handle_ams_msg(CAN_RxHeaderTypeDef* header, uint8_t* data) { + if (header->IDE != CAN_ID_STD) { + return; + } + + switch (header->StdId) { + case CAN_ID_TIME_SYNC: + time_sync_handle_frame(); + break; + } +} void ams_can_send_heartbeat() { static CAN_TxHeaderTypeDef header; diff --git a/Core/Src/TimeSync.c b/Core/Src/TimeSync.c new file mode 100644 index 0000000..dd79ee9 --- /dev/null +++ b/Core/Src/TimeSync.c @@ -0,0 +1,53 @@ +#include "TimeSync.h" + +#include "stm32f412rx.h" +#include "stm32f4xx_hal.h" + +#include + +void time_sync_handle_frame() { + static uint32_t last_time_sync_frame = 0; + static uint32_t f_pre_trim = TARGET_FREQ; + static uint8_t trimmed_last_frame = 0; + static int32_t last_trim_delta = TRIM_FREQ; + + uint32_t now = HAL_GetTick(); + if (last_time_sync_frame != 0) { + uint32_t n_measured = now - last_time_sync_frame; + uint32_t f_real = n_measured * (TARGET_FREQ / TIME_SYNC_INTERVAL); + if (trimmed_last_frame) { + last_trim_delta = (f_pre_trim - f_real) / trimmed_last_frame; + if (last_trim_delta < 0) { + last_trim_delta = -last_trim_delta; + } + trimmed_last_frame = 0; + } + + int32_t delta_f = TARGET_FREQ - f_real; + int32_t delta_quants = delta_f / last_trim_delta; + if (delta_quants != 0) { + uint32_t trim_delta = (now < STARTUP_TIME_SYNC_TIME) ? 2 : 1; + uint32_t rcc_cr = RCC->CR; + // Determine current trim + int32_t trim = (rcc_cr & RCC_CR_HSITRIM_Msk) >> RCC_CR_HSITRIM_Pos; + if (delta_quants > 0) { + trim += trim_delta; + if (trim > RCC_CR_HSITRIM_MAX) { + trim = RCC_CR_HSITRIM_MAX; + } + } else if (delta_quants < 0) { + trim -= trim_delta; + if (trim < 0) { + trim = 0; + } + } + // Clear current trim and overwrite with new trim + rcc_cr = (rcc_cr & ~RCC_CR_HSITRIM_Msk) | + ((trim << RCC_CR_HSITRIM_Pos) & RCC_CR_HSITRIM_Msk); + RCC->CR = rcc_cr; + f_pre_trim = f_real; + trimmed_last_frame = trim_delta; + } + } + last_time_sync_frame = now; +} diff --git a/Core/Src/main.c b/Core/Src/main.c index c980e20..8b7fc19 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -26,6 +26,7 @@ #include "EEPROM.h" #include "FanControl.h" #include "TMP144.h" +#include "TimeSync.h" #include "common_defs.h" #include "stm32f4xx_hal.h" @@ -214,7 +215,10 @@ int main(void) { check_error_conditions(); } fan_ctrl_update(); - ams_can_send_heartbeat(); + // Only start sending CAN frames once the clock is somewhat synchronized + if (HAL_GetTick() > STARTUP_TIME_SYNC_TIME) { + ams_can_send_heartbeat(); + } delay_period(); } /* USER CODE END 3 */ @@ -236,8 +240,9 @@ void SystemClock_Config(void) { /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); @@ -247,7 +252,7 @@ void SystemClock_Config(void) { */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; @@ -255,10 +260,6 @@ void SystemClock_Config(void) { if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } - - /** Enables the Clock Security System - */ - HAL_RCC_EnableCSS(); } /** @@ -551,7 +552,6 @@ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); diff --git a/Core/Src/stm32f4xx_it.c b/Core/Src/stm32f4xx_it.c index f531eec..e7b7766 100644 --- a/Core/Src/stm32f4xx_it.c +++ b/Core/Src/stm32f4xx_it.c @@ -77,7 +77,6 @@ void NMI_Handler(void) /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ - HAL_RCC_NMI_IRQHandler(); /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ while (1) { } diff --git a/Makefile b/Makefile index 209c29f..36e0329 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ ########################################################################################################################## -# File automatically-generated by tool: [projectgenerator] version: [3.17.1] date: [Sat Jul 30 20:03:51 CEST 2022] +# File automatically-generated by tool: [projectgenerator] version: [3.17.1] date: [Sat Jul 30 20:29:35 CEST 2022] ########################################################################################################################## # ------------------------------------------------ diff --git a/STM32Make.make b/STM32Make.make index 5d6bcb7..fb2c1ed 100644 --- a/STM32Make.make +++ b/STM32Make.make @@ -44,6 +44,7 @@ Core/Src/EEPROM.c \ Core/Src/FanControl.c \ Core/Src/SoftI2C.c \ Core/Src/TMP144.c \ +Core/Src/TimeSync.c \ Core/Src/main.c \ Core/Src/stm32f4xx_hal_msp.c \ Core/Src/stm32f4xx_it.c \ diff --git a/ams-slave.ioc b/ams-slave.ioc index 8291d56..738465f 100644 --- a/ams-slave.ioc +++ b/ams-slave.ioc @@ -58,35 +58,33 @@ Mcu.IP9=USART2 Mcu.IPNb=12 Mcu.Name=STM32F412R(E-G)Tx Mcu.Package=LQFP64 -Mcu.Pin0=PH0 - OSC_IN -Mcu.Pin1=PH1 - OSC_OUT -Mcu.Pin10=PB2 -Mcu.Pin11=PB10 -Mcu.Pin12=PB13 -Mcu.Pin13=PC6 -Mcu.Pin14=PC7 -Mcu.Pin15=PC9 -Mcu.Pin16=PA10 -Mcu.Pin17=PA11 -Mcu.Pin18=PA12 -Mcu.Pin19=PA13 -Mcu.Pin2=PC0 -Mcu.Pin20=PA14 -Mcu.Pin21=PA15 -Mcu.Pin22=PB3 -Mcu.Pin23=PB4 -Mcu.Pin24=PB5 -Mcu.Pin25=PB6 -Mcu.Pin26=PB7 -Mcu.Pin27=VP_SYS_VS_Systick -Mcu.Pin3=PC1 -Mcu.Pin4=PC2 -Mcu.Pin5=PC3 -Mcu.Pin6=PA2 -Mcu.Pin7=PA3 -Mcu.Pin8=PC5 -Mcu.Pin9=PB0 -Mcu.PinsNb=28 +Mcu.Pin0=PC0 +Mcu.Pin1=PC1 +Mcu.Pin10=PB13 +Mcu.Pin11=PC6 +Mcu.Pin12=PC7 +Mcu.Pin13=PC9 +Mcu.Pin14=PA10 +Mcu.Pin15=PA11 +Mcu.Pin16=PA12 +Mcu.Pin17=PA13 +Mcu.Pin18=PA14 +Mcu.Pin19=PA15 +Mcu.Pin2=PC2 +Mcu.Pin20=PB3 +Mcu.Pin21=PB4 +Mcu.Pin22=PB5 +Mcu.Pin23=PB6 +Mcu.Pin24=PB7 +Mcu.Pin25=VP_SYS_VS_Systick +Mcu.Pin3=PC3 +Mcu.Pin4=PA2 +Mcu.Pin5=PA3 +Mcu.Pin6=PC5 +Mcu.Pin7=PB0 +Mcu.Pin8=PB2 +Mcu.Pin9=PB10 +Mcu.PinsNb=26 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F412RETx @@ -105,7 +103,7 @@ NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.I2C1_EV_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false @@ -184,10 +182,6 @@ PC9.GPIOParameters=GPIO_Label PC9.GPIO_Label=FAN_PWM PC9.Locked=true PC9.Signal=S_TIM3_CH4 -PH0\ -\ OSC_IN.Mode=HSE-External-Oscillator -PH0\ -\ OSC_IN.Signal=RCC_OSC_IN -PH1\ -\ OSC_OUT.Mode=HSE-External-Oscillator -PH1\ -\ OSC_OUT.Signal=RCC_OSC_OUT PinOutPanel.RotationAngle=0 ProjectManager.AskForMigrate=true ProjectManager.BackupPrevious=false @@ -219,10 +213,9 @@ 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_CAN1_Init-CAN1-false-HAL-true,5-MX_CAN2_Init-CAN2-false-HAL-true,6-MX_I2C1_Init-I2C1-false-HAL-true,7-MX_TIM3_Init-TIM3-false-HAL-true,8-MX_USART1_UART_Init-USART1-false-HAL-true,9-MX_USART2_UART_Init-USART2-false-HAL-true,10-MX_USART3_UART_Init-USART3-false-HAL-true,11-MX_USART6_UART_Init-USART6-false-HAL-true RCC.CortexFreq_Value=16000000 RCC.DFSDMFreq_Value=16000000 -RCC.EnbaleCSS=true RCC.FamilyName=M RCC.HSE_VALUE=16000000 -RCC.IPParameters=CortexFreq_Value,DFSDMFreq_Value,EnbaleCSS,FamilyName,HSE_VALUE,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLM,PLLN,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLRoutputFreq_Value,PLLSourceVirtual,RNGFreq_Value,SDIOFreq_Value,SYSCLKSource,USBFreq_Value,VCOI2SInputFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value +RCC.IPParameters=CortexFreq_Value,DFSDMFreq_Value,FamilyName,HSE_VALUE,PLLCLKFreq_Value,PLLI2SPCLKFreq_Value,PLLI2SQCLKFreq_Value,PLLI2SRCLKFreq_Value,PLLM,PLLN,PLLQCLKFreq_Value,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PLLRoutputFreq_Value,RNGFreq_Value,SDIOFreq_Value,USBFreq_Value,VCOI2SInputFreq_Value,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value RCC.PLLCLKFreq_Value=50000000 RCC.PLLI2SPCLKFreq_Value=96000000 RCC.PLLI2SQCLKFreq_Value=96000000 @@ -233,10 +226,8 @@ RCC.PLLQCLKFreq_Value=50000000 RCC.PLLQoutputFreq_Value=50000000 RCC.PLLRCLKFreq_Value=50000000 RCC.PLLRoutputFreq_Value=50000000 -RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE RCC.RNGFreq_Value=50000000 RCC.SDIOFreq_Value=50000000 -RCC.SYSCLKSource=RCC_SYSCLKSOURCE_HSE RCC.USBFreq_Value=50000000 RCC.VCOI2SInputFreq_Value=1000000 RCC.VCOI2SOutputFreq_Value=192000000