forked from achamaikin/CCSModuleSW30Web
Update version to 1.0.3. Everest timeout changed to 2000ms. CP Line improved, added hysteresis, debounce and EMA filtering
This commit is contained in:
125
Core/Src/cp.c
125
Core/Src/cp.c
@@ -2,13 +2,50 @@
|
||||
#include "adc.h"
|
||||
#include "board.h"
|
||||
#include "tim.h"
|
||||
#include "debug.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_DUTY 450
|
||||
#define CP_EMA_ALPHA_Q8 38
|
||||
#define CP_DEBOUNCE_MS_DEFAULT 10
|
||||
#define CP_DEBOUNCE_MS_F 60
|
||||
#define CP_DEBOUNCE_MS_F_LOW_DUTY 100
|
||||
#define CP_LOW_DUTY_THRESHOLD_PERCENT 10
|
||||
|
||||
#define CP_A_ENTER_MV 11000
|
||||
#define CP_A_EXIT_MV 10000
|
||||
|
||||
#define CP_B_ENTER_LOW_MV 8000
|
||||
#define CP_B_ENTER_HIGH_MV 10000
|
||||
#define CP_B_EXIT_LOW_MV 7500
|
||||
#define CP_B_EXIT_HIGH_MV 10500
|
||||
|
||||
#define CP_C_ENTER_LOW_MV 5000
|
||||
#define CP_C_ENTER_HIGH_MV 7000
|
||||
#define CP_C_EXIT_LOW_MV 4500
|
||||
#define CP_C_EXIT_HIGH_MV 7500
|
||||
|
||||
#define CP_D_ENTER_LOW_MV 2000
|
||||
#define CP_D_ENTER_HIGH_MV 4000
|
||||
#define CP_D_EXIT_LOW_MV 1500
|
||||
#define CP_D_EXIT_HIGH_MV 4500
|
||||
|
||||
#define CP_E_ENTER_LOW_MV -1000
|
||||
#define CP_E_ENTER_HIGH_MV 2000
|
||||
#define CP_E_EXIT_LOW_MV -1500
|
||||
#define CP_E_EXIT_HIGH_MV 2500
|
||||
|
||||
#define CP_F_ENTER_MV -11500
|
||||
#define CP_F_EXIT_MV -10500
|
||||
|
||||
static int32_t cp_voltage_mv = 0;
|
||||
static int32_t cp_voltage_filt_mv = 0;
|
||||
static uint8_t cp_filter_initialized = 0;
|
||||
static uint8_t cp_duty = 0;
|
||||
CP_State_t fake_cp_state = EV_STATE_ACQUIRING;
|
||||
static CP_State_t cp_stable_state = EV_STATE_ACQUIRING;
|
||||
static CP_State_t cp_candidate_state = EV_STATE_ACQUIRING;
|
||||
static uint32_t cp_candidate_since_ms = 0;
|
||||
|
||||
static uint32_t CP_ReadAdcChannel(uint32_t ch) {
|
||||
uint32_t adc = 0;
|
||||
@@ -23,6 +60,64 @@ static uint32_t CP_ReadAdcChannel(uint32_t ch) {
|
||||
}
|
||||
#define VREFINT_CAL_ADDR ((uint16_t*)0x1FFFF7BA) // для STM32F1!
|
||||
|
||||
static uint8_t CP_IsInRange(int32_t v, int32_t lo, int32_t hi) {
|
||||
return (v >= lo && v <= hi) ? 1u : 0u;
|
||||
}
|
||||
|
||||
static int32_t CP_ApplyEma(int32_t raw_mv) {
|
||||
if (!cp_filter_initialized) {
|
||||
cp_voltage_filt_mv = raw_mv;
|
||||
cp_filter_initialized = 1;
|
||||
return cp_voltage_filt_mv;
|
||||
}
|
||||
|
||||
cp_voltage_filt_mv += ((raw_mv - cp_voltage_filt_mv) * CP_EMA_ALPHA_Q8) / 256;
|
||||
return cp_voltage_filt_mv;
|
||||
}
|
||||
|
||||
static CP_State_t CP_ClassifyWithHysteresis(int32_t v, CP_State_t prev) {
|
||||
switch (prev) {
|
||||
case EV_STATE_A_IDLE:
|
||||
if (v >= CP_A_EXIT_MV) return EV_STATE_A_IDLE;
|
||||
break;
|
||||
case EV_STATE_B_CONN_PREP:
|
||||
if (CP_IsInRange(v, CP_B_EXIT_LOW_MV, CP_B_EXIT_HIGH_MV)) return EV_STATE_B_CONN_PREP;
|
||||
break;
|
||||
case EV_STATE_C_CONN_ACTIVE:
|
||||
if (CP_IsInRange(v, CP_C_EXIT_LOW_MV, CP_C_EXIT_HIGH_MV)) return EV_STATE_C_CONN_ACTIVE;
|
||||
break;
|
||||
case EV_STATE_D_CONN_ACT_VENT:
|
||||
if (CP_IsInRange(v, CP_D_EXIT_LOW_MV, CP_D_EXIT_HIGH_MV)) return EV_STATE_D_CONN_ACT_VENT;
|
||||
break;
|
||||
case EV_STATE_E_NO_POWER:
|
||||
if (CP_IsInRange(v, CP_E_EXIT_LOW_MV, CP_E_EXIT_HIGH_MV)) return EV_STATE_E_NO_POWER;
|
||||
break;
|
||||
case EV_STATE_F_ERROR:
|
||||
if (v <= CP_F_EXIT_MV) return EV_STATE_F_ERROR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (v >= CP_A_ENTER_MV) return EV_STATE_A_IDLE;
|
||||
if (CP_IsInRange(v, CP_B_ENTER_LOW_MV, CP_B_ENTER_HIGH_MV)) return EV_STATE_B_CONN_PREP;
|
||||
if (CP_IsInRange(v, CP_C_ENTER_LOW_MV, CP_C_ENTER_HIGH_MV)) return EV_STATE_C_CONN_ACTIVE;
|
||||
if (CP_IsInRange(v, CP_D_ENTER_LOW_MV, CP_D_ENTER_HIGH_MV)) return EV_STATE_D_CONN_ACT_VENT;
|
||||
if (CP_IsInRange(v, CP_E_ENTER_LOW_MV, CP_E_ENTER_HIGH_MV)) return EV_STATE_E_NO_POWER;
|
||||
if (v <= CP_F_ENTER_MV) return EV_STATE_F_ERROR;
|
||||
return EV_STATE_ACQUIRING;
|
||||
}
|
||||
|
||||
static uint32_t CP_GetDebounceMs(CP_State_t next_state) {
|
||||
if (next_state == EV_STATE_F_ERROR) {
|
||||
if (cp_duty <= CP_LOW_DUTY_THRESHOLD_PERCENT) {
|
||||
return CP_DEBOUNCE_MS_F_LOW_DUTY;
|
||||
}
|
||||
return CP_DEBOUNCE_MS_F;
|
||||
}
|
||||
return CP_DEBOUNCE_MS_DEFAULT;
|
||||
}
|
||||
|
||||
static int32_t CP_ReadVoltageMv(void)
|
||||
{
|
||||
uint32_t adc = 0;
|
||||
@@ -75,27 +170,28 @@ int32_t CP_GetVoltage(void) {
|
||||
}
|
||||
|
||||
CP_State_t CP_GetState(void) {
|
||||
int32_t voltage_real = cp_voltage_mv;
|
||||
int32_t voltage_real = cp_voltage_filt_mv;
|
||||
uint32_t now = HAL_GetTick();
|
||||
|
||||
if(fake_cp_state != EV_STATE_ACQUIRING) {
|
||||
return fake_cp_state;
|
||||
}
|
||||
|
||||
if (voltage_real >= (12000-1000)) {
|
||||
return EV_STATE_A_IDLE;
|
||||
} else if (voltage_real >= (9000-1000) && voltage_real <= (9000+1000)) {
|
||||
return EV_STATE_B_CONN_PREP;
|
||||
} else if (voltage_real >= (6000-1000) && voltage_real <= (6000+1000)) {
|
||||
return EV_STATE_C_CONN_ACTIVE;
|
||||
} else if (voltage_real >= (3000-1000) && voltage_real <= (3000 + 1000)) {
|
||||
return EV_STATE_D_CONN_ACT_VENT;
|
||||
} else if (voltage_real >= (0-1000) && voltage_real <= (0+2000)){
|
||||
return EV_STATE_E_NO_POWER;
|
||||
} else if (voltage_real <= (-12000+1000)) {
|
||||
return EV_STATE_F_ERROR;
|
||||
CP_State_t instant_state = CP_ClassifyWithHysteresis(voltage_real, cp_stable_state);
|
||||
|
||||
if (instant_state == cp_stable_state) {
|
||||
cp_candidate_state = cp_stable_state;
|
||||
cp_candidate_since_ms = now;
|
||||
} else {
|
||||
return EV_STATE_ACQUIRING;
|
||||
if (cp_candidate_state != instant_state) {
|
||||
cp_candidate_state = instant_state;
|
||||
cp_candidate_since_ms = now;
|
||||
} else if ((now - cp_candidate_since_ms) >= CP_GetDebounceMs(cp_candidate_state)) {
|
||||
cp_stable_state = cp_candidate_state;
|
||||
}
|
||||
}
|
||||
|
||||
return cp_stable_state;
|
||||
}
|
||||
|
||||
void CP_Loop(void) {
|
||||
@@ -109,6 +205,7 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
return;
|
||||
}
|
||||
cp_voltage_mv = CP_ReadVoltageMv();
|
||||
(void)CP_ApplyEma(cp_voltage_mv);
|
||||
ADC_Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ uint8_t ev_enable_output = 0;
|
||||
#define CMD_INTERVAL 10
|
||||
#define MAX_TX_BUFFER_SIZE 256
|
||||
#define MAX_RX_BUFFER_SIZE 256
|
||||
#define EVEREST_TIMEOUT_MS 2000
|
||||
|
||||
static uint8_t rx_buffer[MAX_RX_BUFFER_SIZE];
|
||||
static uint8_t tx_buffer[MAX_TX_BUFFER_SIZE];
|
||||
@@ -178,11 +179,11 @@ void CCS_SerialLoop(void) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (last_host_seen > 0 && (HAL_GetTick() - last_host_seen) > 500) {
|
||||
if (last_host_seen > 0 && (HAL_GetTick() - last_host_seen) > EVEREST_TIMEOUT_MS) {
|
||||
log_printf(LOG_ERR, "Everest timeout\n");
|
||||
CONN.EnableOutput = 0;
|
||||
CCS_EvseState = Unknown;
|
||||
CP_SetDuty(100);
|
||||
log_printf(LOG_ERR, "Everest timeout\n");
|
||||
} else {
|
||||
if (last_cmd == CMD_STOP) {
|
||||
CONN.EnableOutput = 0;
|
||||
|
||||
@@ -61,10 +61,6 @@ void MX_TIM3_Init(void)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
|
||||
@@ -79,12 +75,6 @@ void MX_TIM3_Init(void)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigOC.OCMode = TIM_OCMODE_TIMING;
|
||||
sConfigOC.Pulse = 1;
|
||||
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM3_Init 2 */
|
||||
|
||||
/* USER CODE END TIM3_Init 2 */
|
||||
|
||||
Reference in New Issue
Block a user