This commit is contained in:
David Rice
2026-01-20 16:51:04 +00:00
parent 17b1b7b762
commit 7990f118dd
14 changed files with 15386 additions and 12720 deletions

View File

@@ -49,6 +49,8 @@ extern "C" {
/* USER CODE END EM */
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
@@ -65,8 +67,6 @@ void Error_Handler(void);
#define VIN_GPIO_Port GPIOA
#define VOUT_Pin GPIO_PIN_7
#define VOUT_GPIO_Port GPIOA
#define POWER_SWITCH_Pin GPIO_PIN_12
#define POWER_SWITCH_GPIO_Port GPIOA
#define T_SWDIO_Pin GPIO_PIN_13
#define T_SWDIO_GPIO_Port GPIOA
#define T_SWCLK_Pin GPIO_PIN_14

View File

@@ -21,12 +21,18 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32g4xx_hal.h"
#include <stdio.h>
#define FILTER_SIZE 128 /* Must be a power of 2 for optimal bit-shifting (e.g., 8, 16, 32, 64) */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct
{
uint16_t buffer[FILTER_SIZE]; /* Circular buffer to hold N samples */
uint32_t sum; /* Running sum of all samples */
uint8_t index; /* Current position in the buffer */
} MovingAverageFilter;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
@@ -46,6 +52,7 @@ ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim16;
UART_HandleTypeDef huart2;
@@ -70,13 +77,19 @@ uint8_t command = 0x00;
uint8_t adc_task_flag = 0x00;
uint16_t vin_adc_val = 0x0000;
uint16_t vout_adc_val = 0x0000;
uint16_t vout_adc_val_av = 0x0000;
uint32_t vdd_ref = 0x00000000;
uint32_t vin_val = 0x00000000;
uint32_t vout_val = 0x00000000;
uint32_t v_target = 0x00000000;
uint8_t vset_task_flag = 0x00;
uint8_t serial_number_flag = 0x00;
uint8_t serial_number[19] = "ARRIVE-POWERSIM-001";
/* Initialise MA filter */
MovingAverageFilter movavFilter;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
@@ -86,13 +99,17 @@ static void MX_USART2_UART_Init(void);
static void MX_ADC2_Init(void);
static void MX_TIM2_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM16_Init(void);
/* USER CODE BEGIN PFP */
void power_switch (uint8_t state);
void adc_task(void);
uint32_t get_actual_vdda(ADC_HandleTypeDef *hadc);
void voltage_conversion_task(void);
void voltage_conversion_task_no_tx(void);
uint32_t get_divider_input_mv(uint32_t raw_adc_value, uint32_t vdda_mv);
void serial_number_task (void);
void MA_Init(MovingAverageFilter *filter);
uint16_t MA_Update(MovingAverageFilter *filter, uint16_t new_sample);
/* USER CODE END PFP */
@@ -134,11 +151,11 @@ int main(void)
MX_ADC2_Init();
MX_TIM2_Init();
MX_ADC1_Init();
MX_TIM16_Init();
/* USER CODE BEGIN 2 */
/*Configure GPIO pin output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(POWER_SWITCH_GPIO_Port, POWER_SWITCH_Pin, GPIO_PIN_RESET);
/* Run ADC calibration */
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
@@ -156,14 +173,10 @@ int main(void)
/* Get real VDDA value */
vdd_ref = get_actual_vdda(&hadc1);
tx_buffer[0] = (uint8_t)((vdd_ref >> 24) & 0xFF);
tx_buffer[1] = (uint8_t)((vdd_ref >> 16) & 0xFF);
tx_buffer[2] = (uint8_t)((vdd_ref >> 8) & 0xFF);
tx_buffer[3] = (uint8_t)(vdd_ref & 0xFF);
tx_len = 0x04;
HAL_UART_Transmit(&huart2, tx_buffer, tx_len, 100);
/* Start output PWM at zero */
__HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, 0);
HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1);
/* USER CODE END 2 */
@@ -174,7 +187,13 @@ int main(void)
if (adc_task_flag == 0xff)
{
adc_task_flag = 0x00;
adc_task();
if (vset_task_flag != 0xff)
{
adc_task();
vout_adc_val_av = MA_Update (&movavFilter, vout_adc_val);
}
voltage_conversion_task();
}
@@ -184,6 +203,14 @@ int main(void)
serial_number_task ();
}
if (vset_task_flag == 0xff)
{
__HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, 300);
adc_task();
vout_adc_val_av = MA_Update (&movavFilter, vout_adc_val);
voltage_conversion_task_no_tx();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
@@ -419,6 +446,69 @@ static void MX_TIM2_Init(void)
}
/**
* @brief TIM16 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM16_Init(void)
{
/* USER CODE BEGIN TIM16_Init 0 */
/* USER CODE END TIM16_Init 0 */
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM16_Init 1 */
/* USER CODE END TIM16_Init 1 */
htim16.Instance = TIM16;
htim16.Init.Prescaler = 1;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
htim16.Init.Period = 63999;
htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim16.Init.RepetitionCounter = 0;
htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim16) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim16, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim16, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM16_Init 2 */
/* USER CODE END TIM16_Init 2 */
HAL_TIM_MspPostInit(&htim16);
}
/**
* @brief USART2 Initialization Function
* @param None
@@ -483,19 +573,9 @@ static void MX_GPIO_Init(void)
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(POWER_SWITCH_GPIO_Port, POWER_SWITCH_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : POWER_SWITCH_Pin */
GPIO_InitStruct.Pin = POWER_SWITCH_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(POWER_SWITCH_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
@@ -509,6 +589,68 @@ static void MX_GPIO_Init(void)
}
/* USER CODE BEGIN 4 */
void Control_Loop_Update(uint32_t )
{
// 1. Get filtered ADC raw and convert to mV
uint16_t raw_adc = HAL_ADC_GetValue(&hadc1);
uint16_t filtered_raw = MA_Update(filter, raw_adc);
// Conversion (Example: 12-bit ADC on 3.3V Vref)
uint16_t measured_mv = (uint16_t)(((uint32_t)filtered_raw * 3300) / 4095);
// 2. Calculate Bidirectional Error
// Positive error = need more power
// Negative error = need less power
int32_t error = (int32_t)SETPOINT_MV - (int32_t)measured_mv;
// 3. Proportional Calculation
float p_term = KP * (float)error;
// 4. Adjust the Duty Cycle
static float current_duty = 500.0f; // Start at 50%
current_duty += p_term;
// 5. Anti-Windup / Saturation (Crucial for bidirectional)
// Prevents the PWM from trying to go to -50% or 200%
if (current_duty > MAX_PWM) current_duty = (float)MAX_PWM;
if (current_duty < 0.0f) current_duty = 0.0f;
// 6. Update STM32 Hardware
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint32_t)current_duty);
}
void MA_Init(MovingAverageFilter *filter)
{
for (int i = 0; i < FILTER_SIZE; i++)
{
filter->buffer[i] = 0;
}
filter->sum = 0;
filter->index = 0;
}
uint16_t MA_Update(MovingAverageFilter *filter, uint16_t new_sample)
{
/* Subtract the oldest value from the running sum */
filter->sum -= filter->buffer[filter->index];
/* Add the new value to the running sum */
filter->sum += new_sample;
/* Store the new value in the buffer, overwriting the oldest one */
filter->buffer[filter->index] = new_sample;
/* Move the index to the next position (circular buffer wrap-around) */
filter->index++;
filter->index &= (FILTER_SIZE - 1); /* Equivalent to: if (filter->index >= FILTER_SIZE) filter->index = 0; */
/* Calculate the average using bit-shifting (faster than division by power of 2) */
/* For FILTER_SIZE = 16, this is a right shift by 4 bits (sum / 16) */
/* If used 32, it would be sum >> 5 */
return (uint16_t)(filter->sum >> 7);
}
uint32_t get_actual_vdda(ADC_HandleTypeDef *hadc)
{
uint32_t vrefint_raw = 0;
@@ -551,7 +693,7 @@ void voltage_conversion_task(void)
vin_val = get_divider_input_mv(vin_adc_val, vdd_ref);
/* Get Vout voltage */
vout_val = get_divider_input_mv(vout_adc_val, vdd_ref);
vout_val = get_divider_input_mv(vout_adc_val_av, vdd_ref);
tx_len = 0x08;
@@ -583,6 +725,13 @@ void voltage_conversion_task(void)
HAL_UART_Transmit(&huart2, tx_buffer, tx_len, 100);
}
/* Voltage Conversion Task with No UART Tx */
void voltage_conversion_task_no_tx(void)
{
/* Get Vout voltage */
vout_val = get_divider_input_mv(vout_adc_val_av, vdd_ref);
}
void serial_number_task (void)
{
tx_len = 0x13;
@@ -639,13 +788,14 @@ void power_switch (uint8_t state)
{
if (state == 1)
{
HAL_GPIO_WritePin(POWER_SWITCH_GPIO_Port, POWER_SWITCH_Pin, GPIO_PIN_SET);
vset_task_flag = 0xFF;
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(POWER_SWITCH_GPIO_Port, POWER_SWITCH_Pin, GPIO_PIN_RESET);
vset_task_flag = 0x00;
__HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, 0);
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
}
}
@@ -765,6 +915,8 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
/* 'S' - Set power output state */
case 0x53:
power_state_value = rx_buffer[1];
v_target = ((uint32_t)rx_buffer[2] << 24) | ((uint32_t)rx_buffer[3] << 16) | ((uint32_t)rx_buffer[4] << 8) | ((uint32_t)rx_buffer[5]);
MA_Init(&movavFilter);
power_switch(power_state_value);
break;

View File

@@ -57,7 +57,9 @@
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
@@ -222,11 +224,47 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
/* USER CODE BEGIN TIM2_MspInit 1 */
/* USER CODE END TIM2_MspInit 1 */
}
else if(htim_base->Instance==TIM16)
{
/* USER CODE BEGIN TIM16_MspInit 0 */
/* USER CODE END TIM16_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM16_CLK_ENABLE();
/* USER CODE BEGIN TIM16_MspInit 1 */
/* USER CODE END TIM16_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM16)
{
/* USER CODE BEGIN TIM16_MspPostInit 0 */
/* USER CODE END TIM16_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM16 GPIO Configuration
PA12 ------> TIM16_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM16;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM16_MspPostInit 1 */
/* USER CODE END TIM16_MspPostInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
@@ -249,6 +287,17 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
/* USER CODE END TIM2_MspDeInit 1 */
}
else if(htim_base->Instance==TIM16)
{
/* USER CODE BEGIN TIM16_MspDeInit 0 */
/* USER CODE END TIM16_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM16_CLK_DISABLE();
/* USER CODE BEGIN TIM16_MspDeInit 1 */
/* USER CODE END TIM16_MspDeInit 1 */
}
}