1 Commits
Author SHA1 Message Date
raduetandCursor 1f06c3c363 Clock RTC from LSI instead of LSE (v1.0.34).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 16:03:29 +02:00
14 changed files with 8823 additions and 10122 deletions
+9 -27
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include "charger_config.h"
typedef enum{ typedef enum{
RELAY_AUX0 = 0, RELAY_AUX0 = 0,
@@ -41,39 +40,22 @@ typedef enum{
uint8_t IN_ReadInput(inputNum_t input_n); uint8_t IN_ReadInput(inputNum_t input_n);
// ConfigBlock: new bootloader at 0x08007800, legacy at 0x080001E4 // Версия устройства
#define VERSION_OFFSET (0x08007800u) #define VERSION_OFFSET (0x1E4)
#define VERSION_OFFSET_LEGACY (0x080001E4u)
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
uint32_t serialNumber; // Байты 0-3 uint32_t serialNumber; // Байты 0-3
uint8_t stationType; // Байт 4 uint8_t stationType; // Байт 4
uint8_t boardVersion; // Байт 5 uint8_t boardVersion; // Байт 5
uint8_t addrEdcan; // Байт 6 uint8_t addrEdcan; // Байт 6
uint8_t contactorConfig; // Байт 7 uint8_t maxPower; // Байт 7
uint8_t connectorConfig; // Байт 8 uint8_t pad[7]; // bytes 8-14, see edcan.h
uint8_t maxPower; // Байт 9, 5 кВт/bit
uint8_t psuType; // Байт 10
uint8_t meterType; // Байт 11
uint8_t balancerType; // Байт 12
uint8_t autostartMode; // Байт 13
uint8_t motorEnable; // Байт 14
uint16_t connector1CurrentLimitA; // Байты 15-16, A; 0 = legacy PSU_MAX_CURRENT uint16_t connector1CurrentLimitA; // Байты 15-16, A; 0 = legacy PSU_MAX_CURRENT
uint16_t connector2CurrentLimitA; // Байты 17-18 uint8_t reserved[45]; // Байты 17-63
uint16_t connector3CurrentLimitA; // Байты 19-20
uint8_t reserved[43]; // Байты 21-63
} InfoBlock_t; } InfoBlock_t;
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
_Static_assert(sizeof(InfoBlock_t) == 64, "InfoBlock_t must be 64 bytes");
#endif
extern InfoBlock_t *InfoBlock; extern InfoBlock_t *InfoBlock;
void Board_SelectInfoBlockAddress(void);
void Board_LoadInfoBlockLimits(void); void Board_LoadInfoBlockLimits(void);
uint16_t Board_GetConnectorCurrentLimit_0p1A(void); uint16_t Board_GetConnectorCurrentLimit_0p1A(void);
uint16_t Board_ClampCurrent_0p1A(uint16_t current_0p1A); uint16_t Board_ClampCurrent_0p1A(uint16_t current_0p1A);
PsuType_t Board_GetPsuType(void);
uint16_t Board_GetPsuMaxCurrentA(void);
uint32_t Board_GetPsuMaxPowerW(void);
+1 -17
View File
@@ -7,21 +7,8 @@
#define PSU_MIN_CURRENT 1 //1A/bit #define PSU_MIN_CURRENT 1 //1A/bit
#define PSU_MAX_POWER 40000 //1W/bit #define PSU_MAX_POWER 40000 //1W/bit
#define PSU_BLOCK_POWER_30KW 30000u
#define PSU_BLOCK_POWER_40KW 40000u
#define PSU_BLOCK_CURRENT_30KW 100u
#define PSU_BLOCK_CURRENT_40KW 133u
#define PSU_NUM 1 #define PSU_NUM 1
/* Values match bootloader-flasher firmwares.json psuTypes[].value (InfoBlock byte 10). */
typedef enum {
PSU_TYPE_NONE = 0,
PSU_TYPE_NIUERA_30KW = 1,
PSU_TYPE_NIUERA_40KW = 2,
PSU_TYPE_TONHE_30KW = 3
} PsuType_t;
/* Dynamic LV clamp (CS60 hv_limit): active only on overload at low bus voltage. */ /* Dynamic LV clamp (CS60 hv_limit): active only on overload at low bus voltage. */
#define PSU_LV_CLAMP_V 499u #define PSU_LV_CLAMP_V 499u
#define PSU_HV_LIMIT_ON_THRESHOLD 480u #define PSU_HV_LIMIT_ON_THRESHOLD 480u
@@ -30,10 +17,7 @@ typedef enum {
#define PSU_HV_LOAD_CURRENT 300u /* 30.0 A, MeasuredCurrent is 0.1 A/bit */ #define PSU_HV_LOAD_CURRENT 300u /* 30.0 A, MeasuredCurrent is 0.1 A/bit */
#define PSU_HV_LIMIT_MAX_COUNT 3u #define PSU_HV_LIMIT_MAX_COUNT 3u
/* TonHe group start: ≤500 V = LV, >500 V = HV. LV→HV while ON dies; HV→LV stays ON. */ /* Fast discharge: PSU off/on cycle on step-down setpoint (unloaded bus). */
#define TONHE_HV_THRESHOLD_V 500u
/* Fast discharge: Niuera off/on cycle on step-down (unloaded bus). TonHe skips this. */
#define PSD_ENABLE 1u #define PSD_ENABLE 1u
#define PSD_MAX_CMD_CURRENT_0P1A 20u /* 2.0 A */ #define PSD_MAX_CMD_CURRENT_0P1A 20u /* 2.0 A */
#define PSD_MAX_MEASURED_CURRENT_0P1A 30u /* 3.0 A */ #define PSD_MAX_MEASURED_CURRENT_0P1A 30u /* 3.0 A */
+1 -1
View File
@@ -27,7 +27,7 @@ extern "C" {
/* USER CODE BEGIN EC */ /* USER CODE BEGIN EC */
#define FW_VERSION_MAJOR 1 #define FW_VERSION_MAJOR 1
#define FW_VERSION_MINOR 0 #define FW_VERSION_MINOR 0
#define FW_VERSION_PATCH 37 #define FW_VERSION_PATCH 34
/* USER CODE END EC */ /* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/
-1
View File
@@ -7,7 +7,6 @@ void PSU_Init();
void PSU_Enable(uint8_t addr, uint8_t enable); void PSU_Enable(uint8_t addr, uint8_t enable);
void PSU_SetVoltageCurrent(uint8_t addr, uint16_t voltage, uint16_t current); void PSU_SetVoltageCurrent(uint8_t addr, uint16_t voltage, uint16_t current);
void PSU_ReadWrite(void); void PSU_ReadWrite(void);
PsuType_t PSU_GetType(void);
// --- Состояние силового модуля (DC30, один PSU) --- // --- Состояние силового модуля (DC30, один PSU) ---
+2 -50
View File
@@ -10,64 +10,16 @@ InfoBlock_t *InfoBlock = (InfoBlock_t *)(VERSION_OFFSET);
static uint16_t s_connector_max_current_0p1A = (uint16_t)PSU_MAX_CURRENT * 10u; static uint16_t s_connector_max_current_0p1A = (uint16_t)PSU_MAX_CURRENT * 10u;
void Board_SelectInfoBlockAddress(void)
{
const volatile uint32_t *new_base = (const volatile uint32_t *)VERSION_OFFSET;
if (*new_base == 0xFFFFFFFFu) {
InfoBlock = (InfoBlock_t *)VERSION_OFFSET_LEGACY;
} else {
InfoBlock = (InfoBlock_t *)VERSION_OFFSET;
}
}
PsuType_t Board_GetPsuType(void)
{
/* Legacy ConfigBlock has no psuType field; keep Niuera path. */
if (InfoBlock == (InfoBlock_t *)VERSION_OFFSET_LEGACY) {
return PSU_TYPE_NONE;
}
return (PsuType_t)InfoBlock->psuType;
}
uint16_t Board_GetPsuMaxCurrentA(void)
{
switch (Board_GetPsuType()) {
case PSU_TYPE_TONHE_30KW:
case PSU_TYPE_NIUERA_30KW:
return (uint16_t)PSU_BLOCK_CURRENT_30KW;
case PSU_TYPE_NIUERA_40KW:
return (uint16_t)PSU_BLOCK_CURRENT_40KW;
case PSU_TYPE_NONE:
default:
return (uint16_t)PSU_MAX_CURRENT;
}
}
uint32_t Board_GetPsuMaxPowerW(void)
{
switch (Board_GetPsuType()) {
case PSU_TYPE_TONHE_30KW:
case PSU_TYPE_NIUERA_30KW:
return PSU_BLOCK_POWER_30KW;
case PSU_TYPE_NIUERA_40KW:
return PSU_BLOCK_POWER_40KW;
case PSU_TYPE_NONE:
default:
return (uint32_t)PSU_MAX_POWER;
}
}
static uint16_t Board_ResolveConnectorCurrentLimitA(uint16_t raw_limit_a) static uint16_t Board_ResolveConnectorCurrentLimitA(uint16_t raw_limit_a)
{ {
return (raw_limit_a == 0u) ? Board_GetPsuMaxCurrentA() : raw_limit_a; return (raw_limit_a == 0u) ? (uint16_t)PSU_MAX_CURRENT : raw_limit_a;
} }
void Board_LoadInfoBlockLimits(void) void Board_LoadInfoBlockLimits(void)
{ {
const uint16_t limit_a = Board_ResolveConnectorCurrentLimitA(InfoBlock->connector1CurrentLimitA); const uint16_t limit_a = Board_ResolveConnectorCurrentLimitA(InfoBlock->connector1CurrentLimitA);
uint32_t limit_0p1a = (uint32_t)limit_a * 10u; uint32_t limit_0p1a = (uint32_t)limit_a * 10u;
const uint32_t hw_max_0p1a = (uint32_t)Board_GetPsuMaxCurrentA() * 10u; const uint32_t hw_max_0p1a = (uint32_t)PSU_MAX_CURRENT * 10u;
if (limit_0p1a > hw_max_0p1a) { if (limit_0p1a > hw_max_0p1a) {
limit_0p1a = hw_max_0p1a; limit_0p1a = hw_max_0p1a;
-4
View File
@@ -220,10 +220,6 @@ int main(void)
log_printf(LOG_INFO, "Connector current limit: %u.%u A\n", log_printf(LOG_INFO, "Connector current limit: %u.%u A\n",
(unsigned)(Board_GetConnectorCurrentLimit_0p1A() / 10u), (unsigned)(Board_GetConnectorCurrentLimit_0p1A() / 10u),
(unsigned)(Board_GetConnectorCurrentLimit_0p1A() % 10u)); (unsigned)(Board_GetConnectorCurrentLimit_0p1A() % 10u));
log_printf(LOG_INFO, "PSU type: %u (%u W / %u A)\n",
(unsigned)Board_GetPsuType(),
(unsigned)Board_GetPsuMaxPowerW(),
(unsigned)Board_GetPsuMaxCurrentA());
log_printf(LOG_INFO, "FW version: %d.%d.%d\n", infoPacket.fw_version_major, infoPacket.fw_version_minor, infoPacket.fw_version_patch); log_printf(LOG_INFO, "FW version: %d.%d.%d\n", infoPacket.fw_version_major, infoPacket.fw_version_minor, infoPacket.fw_version_patch);
CAN1_MinimalReInit(); CAN1_MinimalReInit();
PSU_Init(); PSU_Init();
+1 -3
View File
@@ -145,9 +145,7 @@ PowerSetpointTryResult_t PowerSetpoint_TryApply(void)
ctx = build_context(); ctx = build_context();
action = PowerSetpoint_Decide(&applied, &pending, &ctx); action = PowerSetpoint_Decide(&applied, &pending, &ctx);
/* TonHe dumps HV→LV itself; LV→HV is a group stop/start in psu_control. */ if (action == POWER_SETPOINT_FAST_DISCHARGE) {
if ((action == POWER_SETPOINT_FAST_DISCHARGE) &&
(PSU_GetType() != PSU_TYPE_TONHE_30KW)) {
fd_target = pending; fd_target = pending;
fd_active = 1u; fd_active = 1u;
setpoint_dirty = 0u; setpoint_dirty = 0u;
+27 -645
View File
@@ -24,95 +24,24 @@ PSU_t PSU0;
#define CAN_DELAY 20 #define CAN_DELAY 20
#define PSU_VOLTAGE_THRESHOLD 20 // Порог напряжения для определения состояния (В) #define PSU_VOLTAGE_THRESHOLD 20 // Порог напряжения для определения состояния (В)
#define PSU_ONLINE_TIMEOUT 500 // Таймаут Niuera (мс) #define PSU_ONLINE_TIMEOUT 500 // Таймаут для определения состояния (мс)
#define PSU_TONHE_ONLINE_TIMEOUT 3000u /* PF=01 ~0.5–1 с по документу/записи */
#define PSU_STARTUP_DELAY 4000 // Задержка 2 секунды перед включением #define PSU_STARTUP_DELAY 4000 // Задержка 2 секунды перед включением
#define PSU_DIAG_LOG_MS 2000u #define PSU_DIAG_LOG_MS 2000u
#define PSU_SUDDEN_OFF_DEBOUNCE_MS 200u #define PSU_SUDDEN_OFF_DEBOUNCE_MS 200u
/* TonHe V1.2/V1.3: 125 kbit/s already on CAN2, extended 29-bit PDU1.
* Start/stop is group PF=04 then PF=03 with a member bit, not addressed PF=06.
* TONHE_MODULE_ADDR: live SA for the bitmask (4 on the bench). 0 = first SA that answers A0. */
#define TONHE_SA_CTRL 0xA0u
#define TONHE_DA_BROADCAST 0xFFu
#define TONHE_MODULE_ADDR 4u
#define TONHE_PF_STATUS 0x01u
#define TONHE_PF_AC 0x0Bu
#define TONHE_PF_EXT 0x91u
#define TONHE_PF_GROUP_CMD 0x03u
#define TONHE_PF_UI_MASK 0x04u
#define TONHE_PF_HEARTBEAT 0x05u
#define TONHE_P_GROUP_CMD 2u
#define TONHE_P_UI_MASK 4u
#define TONHE_P_HEARTBEAT 6u
#define TONHE_CMD_START 0xAAu
#define TONHE_CMD_STOP 0x55u
#define TONHE_HEARTBEAT_MS 4000u
#define TONHE_CMD_MIN_MS 200u
#define TONHE_STATE_OFF 0x00u
#define TONHE_STATE_ON 0x01u
#define TONHE_STATE_FAULT_OFF 0x11u
#define TONHE_RESTART_RETRY_MS 500u
#define TONHE_RESTART_OFF_MS 10000u
#define TONHE_RESTART_ON_MS 10000u
typedef enum {
TONHE_RESTART_IDLE = 0,
TONHE_RESTART_STOP,
TONHE_RESTART_WAIT_OFF,
TONHE_RESTART_START,
TONHE_RESTART_WAIT_ON
} TonHeRestart_t;
uint32_t can_lastpacket; uint32_t can_lastpacket;
extern CAN_HandleTypeDef hcan2; extern CAN_HandleTypeDef hcan2;
static uint16_t psu_last_can_v; static uint16_t psu_last_can_v;
static uint16_t psu_last_can_i_0p1A; static uint16_t psu_last_can_i_0p1A;
static uint16_t psu_cmd_v = PSU_MIN_VOLTAGE;
static uint16_t psu_cmd_i_0p1A;
static uint8_t psu_last_good_s0; static uint8_t psu_last_good_s0;
static uint8_t psu_last_good_s1; static uint8_t psu_last_good_s1;
static uint8_t psu_last_good_s2; static uint8_t psu_last_good_s2;
static PsuType_t psu_type;
static uint16_t psu_max_current_a = PSU_MAX_CURRENT;
static uint8_t psu_output_cmd_on;
static uint8_t tonhe_state;
static uint8_t tonhe_sa;
static uint32_t tonhe_last_cmd_ms;
static uint8_t tonhe_last_sent_start = 0xFFu;
static uint16_t tonhe_last_sent_v;
static uint16_t tonhe_last_sent_i;
static uint16_t tonhe_faults;
static uint8_t tonhe_pfc;
static uint16_t tonhe_ext_x;
static uint8_t tonhe_ext_valid;
static uint32_t tonhe_hb_tick;
static TonHeRestart_t tonhe_restart;
static uint32_t tonhe_restart_tick;
static uint32_t tonhe_restart_cmd_ms;
static uint16_t tonhe_run_v;
static uint8_t tonhe_run_valid;
static void PSU_SendCmd(uint8_t source, uint8_t destination, uint8_t cmd, void *data); static void PSU_SendCmd(uint8_t source, uint8_t destination, uint8_t cmd, void *data);
static void PSU_SwitchState(PSU_State_t state);
static void PSU_LogActiveStatusFlags(LogLevel_t level); static void PSU_LogActiveStatusFlags(LogLevel_t level);
static void PSU_MonitorStatusAndUnexpectedOff(void); static void PSU_MonitorStatusAndUnexpectedOff(void);
static uint8_t PSU_IsTonHe(void);
static void PSU_TonHeSend(uint8_t priority, uint8_t pf, uint8_t da, const uint8_t *data);
static void PSU_TonHeHeartbeat(void);
static void PSU_TonHeSendGroupUi(uint16_t voltage_v, uint16_t current_0p1A, uint8_t force);
static void PSU_TonHeSendGroupOnOff(uint8_t start, uint8_t force);
static void PSU_TonHeRefreshFlags(void);
static void PSU_TonHeRx(uint32_t ext_id, uint32_t dlc, const uint8_t *rx);
static uint8_t PSU_TonHeIsHv(uint16_t voltage_v);
static uint8_t PSU_TonHeNearTarget(uint16_t target_v);
static uint8_t PSU_TonHeLvEstablished(void);
static uint8_t PSU_TonHeCanLvHvRestart(uint16_t target_v);
static void PSU_TonHeRestartReset(void);
static void PSU_TonHeRestartBegin(void);
static void PSU_TonHeRestartTask(void);
static const char *PSU_StateName(PSU_State_t state) static const char *PSU_StateName(PSU_State_t state)
{ {
@@ -136,460 +65,6 @@ static const char *PSU_StateName(PSU_State_t state)
} }
} }
static uint8_t PSU_IsTonHe(void)
{
return (psu_type == PSU_TYPE_TONHE_30KW) ? 1u : 0u;
}
PsuType_t PSU_GetType(void)
{
return psu_type;
}
static uint8_t PSU_TonHeIsHv(uint16_t voltage_v)
{
return (voltage_v > TONHE_HV_THRESHOLD_V) ? 1u : 0u;
}
/* Same window as Niuera PSD_ON_WAIT: measured U near the commanded setpoint. */
static uint8_t PSU_TonHeNearTarget(uint16_t target_v)
{
uint16_t v_low;
v_low = (target_v > PSD_PRECHARGE_TOLERANCE_V) ?
(uint16_t)(target_v - PSD_PRECHARGE_TOLERANCE_V) : 0u;
return (CONN.MeasuredVoltage >= v_low) ? 1u : 0u;
}
static uint8_t PSU_TonHeLvEstablished(void)
{
if ((tonhe_run_valid == 0u) || PSU_TonHeIsHv(tonhe_run_v) ||
PSU_TonHeIsHv(CONN.MeasuredVoltage)) {
return 0u;
}
return PSU_TonHeNearTarget(tonhe_run_v);
}
static uint8_t PSU_TonHeCanLvHvRestart(uint16_t target_v)
{
if ((tonhe_restart != TONHE_RESTART_IDLE) ||
(PSU0.state != PSU_CONNECTED) ||
(psu_output_cmd_on == 0u) ||
(PSU0.PSU_enabled == 0u) ||
(tonhe_run_valid == 0u) ||
PSU_TonHeIsHv(tonhe_run_v) ||
(PSU_TonHeIsHv(target_v) == 0u)) {
return 0u;
}
return PSU_TonHeLvEstablished();
}
static void PSU_TonHeRestartReset(void)
{
tonhe_restart = TONHE_RESTART_IDLE;
tonhe_run_valid = 0u;
}
static void PSU_TonHeRestartBegin(void)
{
if (tonhe_restart != TONHE_RESTART_IDLE) {
return;
}
log_printf(LOG_INFO, "TonHe LV->HV restart %u->%u\n",
(unsigned)tonhe_run_v, (unsigned)psu_cmd_v);
tonhe_restart = TONHE_RESTART_STOP;
tonhe_restart_tick = HAL_GetTick();
}
static void PSU_TonHeRestartTask(void)
{
uint32_t now;
if (!PSU_IsTonHe() || (tonhe_restart == TONHE_RESTART_IDLE)) {
return;
}
if (!CONN.EnableOutput || !PSU0.ready || PSU0.cont_fault || PSU0.psu_fault) {
log_printf(LOG_WARN, "TonHe LV->HV restart abort\n");
tonhe_restart = TONHE_RESTART_IDLE;
return;
}
now = HAL_GetTick();
switch (tonhe_restart) {
case TONHE_RESTART_STOP:
PSU_TonHeSendGroupOnOff(0u, 1u);
tonhe_restart = TONHE_RESTART_WAIT_OFF;
tonhe_restart_tick = now;
break;
case TONHE_RESTART_WAIT_OFF:
if (PSU0.PSU_enabled == 0u) {
tonhe_restart = TONHE_RESTART_START;
tonhe_restart_tick = now;
} else if ((now - tonhe_restart_tick) > TONHE_RESTART_OFF_MS) {
log_printf(LOG_WARN, "TonHe LV->HV restart off timeout V=%u\n",
(unsigned)CONN.MeasuredVoltage);
PSU0.psu_fault = 1;
CONN.chargingError = CONN_ERR_PSU_FAULT;
tonhe_restart = TONHE_RESTART_IDLE;
PSU_SwitchState(PSU_CURRENT_DROP);
}
break;
case TONHE_RESTART_START:
PSU_TonHeSendGroupUi(psu_cmd_v, psu_cmd_i_0p1A, 1u);
ED_Delay(CAN_DELAY);
PSU_TonHeSendGroupOnOff(1u, 1u);
psu_output_cmd_on = 1u;
tonhe_restart_cmd_ms = now;
tonhe_restart = TONHE_RESTART_WAIT_ON;
tonhe_restart_tick = now;
break;
case TONHE_RESTART_WAIT_ON:
if ((PSU0.PSU_enabled != 0u) && PSU_TonHeNearTarget(psu_cmd_v)) {
tonhe_run_v = psu_cmd_v;
tonhe_run_valid = 1u;
tonhe_restart = TONHE_RESTART_IDLE;
log_printf(LOG_INFO, "TonHe LV->HV restart done V=%u\n",
(unsigned)CONN.MeasuredVoltage);
} else {
if ((now - tonhe_restart_cmd_ms) >= TONHE_RESTART_RETRY_MS) {
PSU_TonHeSendGroupUi(psu_cmd_v, psu_cmd_i_0p1A, 1u);
ED_Delay(CAN_DELAY);
PSU_TonHeSendGroupOnOff(1u, 1u);
tonhe_restart_cmd_ms = now;
}
if ((now - tonhe_restart_tick) > TONHE_RESTART_ON_MS) {
log_printf(LOG_ERR, "TonHe LV->HV restart on timeout V=%u target=%u\n",
(unsigned)CONN.MeasuredVoltage, (unsigned)psu_cmd_v);
PSU0.psu_fault = 1;
CONN.chargingError = CONN_ERR_PSU_FAULT;
tonhe_restart = TONHE_RESTART_IDLE;
PSU_SwitchState(PSU_UNREADY);
}
}
break;
default:
tonhe_restart = TONHE_RESTART_IDLE;
break;
}
}
static uint32_t PSU_TonHeMakeId(uint8_t priority, uint8_t pf, uint8_t da, uint8_t sa)
{
return ((uint32_t)(priority & 7u) << 26) |
((uint32_t)pf << 16) |
((uint32_t)da << 8) |
(uint32_t)sa;
}
static uint16_t PSU_TonHeU16le(const uint8_t *data, uint8_t offset)
{
return (uint16_t)data[offset] | ((uint16_t)data[offset + 1u] << 8);
}
static void PSU_TonHePutU16le(uint8_t *data, uint8_t offset, uint16_t value)
{
data[offset] = (uint8_t)(value & 0xFFu);
data[offset + 1u] = (uint8_t)((value >> 8) & 0xFFu);
}
static void PSU_ApplyOutputTelemetry(uint16_t voltage_v, int16_t current_0p1A, uint8_t temperature)
{
PSU0.outputVoltage = voltage_v;
PSU0.outputCurrent = current_0p1A;
PSU0.temperature = temperature;
if (PSU0.state >= PSU_READY) {
CONN.MeasuredVoltage = PSU0.outputVoltage;
CONN.MeasuredCurrent = (uint16_t)PSU0.outputCurrent;
CONN.Power = CONN.MeasuredCurrent * CONN.MeasuredVoltage / 10u;
CONN.outputEnabled = PSU0.PSU_enabled;
}
}
static void PSU_TonHeRefreshFlags(void)
{
PSU_Status0_t s0;
PSU_Status1_t s1;
PSU_Status2_t s2;
memset(&s0, 0, sizeof(s0));
memset(&s1, 0, sizeof(s1));
memset(&s2, 0, sizeof(s2));
s0.shortCircuitFault = (tonhe_faults & 0x8000u) ? 1u : 0u;
s0.internalCommunicationFault = (tonhe_faults & 0x0200u) ? 1u : 0u;
s0.inputBusLineFault = (tonhe_faults & 0x0100u) ? 1u : 0u;
s0.dischargeFault = (tonhe_faults & 0x0400u) ? 1u : 0u;
s1.dcSideOffStatus = (tonhe_state != TONHE_STATE_ON) ? 1u : 0u;
s1.moduleFaultAlarm = ((tonhe_faults & 0x0080u) || (tonhe_state == TONHE_STATE_FAULT_OFF)) ? 1u : 0u;
s1.fanFaultAlarm = (tonhe_faults & 0x0040u) ? 1u : 0u;
s1.overTempAlarm = (tonhe_faults & 0x0020u) ? 1u : 0u;
s1.outputOverVoltageAlarm = (tonhe_faults & 0x0008u) ? 1u : 0u;
s1.outputOverCurrentAlarm = (tonhe_faults & 0x0010u) ? 1u : 0u;
s2.powerLimitStatus = (tonhe_faults & 0x4000u) ? 1u : 0u;
s2.moduleAddressDuplicate = (tonhe_pfc & 0x10u) ? 1u : 0u;
s2.threePhaseInputPhaseLossAlarm = (tonhe_faults & 0x0002u) ? 1u : 0u;
s2.threePhaseInputUnbalanceAlarm = (tonhe_pfc & 0x04u) ? 1u : 0u;
s2.inputUnderVoltageAlarm = (tonhe_faults & 0x0001u) ? 1u : 0u;
s2.inputOverVoltageAlarm = (tonhe_faults & 0x0004u) ? 1u : 0u;
s2.pfcSideOffStatus = (tonhe_faults & 0x0800u) ? 1u : 0u;
/* PF=91 is optional; missing it must not look like a zero mask. */
if (tonhe_ext_valid) {
if (tonhe_ext_x & 0x0004u) {
s1.canCommunicationInterruptAlarm = 1u;
}
if (tonhe_ext_x & 0x0300u) {
s2.powerLimitStatus = 1u;
}
if (tonhe_ext_x & 0x2000u) {
s1.moduleFaultAlarm = 1u;
}
}
PSU0.status0.bits = s0;
PSU0.status1.bits = s1;
PSU0.status2.bits = s2;
psu_last_good_s0 = PSU0.status0.raw;
psu_last_good_s1 = PSU0.status1.raw;
psu_last_good_s2 = PSU0.status2.raw;
}
static void PSU_TonHeSend(uint8_t priority, uint8_t pf, uint8_t da, const uint8_t *data)
{
int8_t retry_counter = 10;
CAN_TxHeaderTypeDef tx_header;
uint32_t tx_mailbox;
HAL_StatusTypeDef can_result;
uint8_t payload[8];
memcpy(payload, data, 8);
tx_header.ExtId = PSU_TonHeMakeId(priority, pf, da, TONHE_SA_CTRL);
tx_header.RTR = CAN_RTR_DATA;
tx_header.IDE = CAN_ID_EXT;
tx_header.DLC = 8;
while (retry_counter > 0) {
if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan2) > 0) {
can_result = HAL_CAN_AddTxMessage(&hcan2, &tx_header, payload, &tx_mailbox);
if (can_result == HAL_OK) {
return;
}
}
ED_Delay(1);
retry_counter--;
}
}
static void PSU_TonHeHeartbeat(void)
{
uint8_t zeros[8];
uint32_t now = HAL_GetTick();
if ((tonhe_hb_tick != 0u) && ((now - tonhe_hb_tick) < TONHE_HEARTBEAT_MS)) {
return;
}
tonhe_hb_tick = now;
memset(zeros, 0, sizeof(zeros));
PSU_TonHeSend(TONHE_P_HEARTBEAT, TONHE_PF_HEARTBEAT, TONHE_DA_BROADCAST, zeros);
}
static void PSU_TonHeEncodeUi(uint8_t *data, uint8_t u_off, uint8_t i_off,
uint16_t voltage_v, uint16_t current_0p1A)
{
uint32_t u_raw = (uint32_t)voltage_v * 10u;
uint32_t i_raw = (uint32_t)current_0p1A * 10u;
if (u_raw > 10000u) {
u_raw = 10000u;
}
if (i_raw > 50000u) {
i_raw = 50000u;
}
PSU_TonHePutU16le(data, u_off, (uint16_t)u_raw);
PSU_TonHePutU16le(data, i_off, (uint16_t)i_raw);
}
static uint8_t PSU_TonHeLiveSa(void)
{
if (TONHE_MODULE_ADDR != 0u) {
return (uint8_t)TONHE_MODULE_ADDR;
}
return tonhe_sa;
}
static uint8_t PSU_TonHeAcceptSa(uint8_t sa)
{
if ((sa == 0u) || (sa == TONHE_SA_CTRL)) {
return 0u;
}
if (TONHE_MODULE_ADDR != 0u) {
return (sa == (uint8_t)TONHE_MODULE_ADDR) ? 1u : 0u;
}
if (tonhe_sa == 0u) {
tonhe_sa = sa;
}
return (sa == tonhe_sa) ? 1u : 0u;
}
/* PDF group mask: bit (SA-1)%24, bank (SA-1)/24. SA=4 → 08 00 00, bank 0. */
static uint8_t PSU_TonHeFillMask(uint8_t *bytes, uint8_t sa)
{
uint8_t idx;
uint8_t bit;
uint32_t k;
if (sa < 1u) {
sa = 1u;
}
idx = (uint8_t)(sa - 1u);
bit = (uint8_t)(idx % 24u);
k = (1uL << bit);
bytes[0] = (uint8_t)(k & 0xFFu);
bytes[1] = (uint8_t)((k >> 8) & 0xFFu);
bytes[2] = (uint8_t)((k >> 16) & 0xFFu);
return (uint8_t)((idx / 24u) & 0x0Fu);
}
static void PSU_TonHeClampUi(uint16_t *voltage_v, uint16_t *current_0p1A)
{
uint16_t min_i = (uint16_t)PSU_MIN_CURRENT * 10u;
if (*voltage_v < PSU_MIN_VOLTAGE) {
*voltage_v = PSU_MIN_VOLTAGE;
}
if (*current_0p1A < min_i) {
*current_0p1A = min_i;
}
}
static void PSU_TonHeSendGroupUi(uint16_t voltage_v, uint16_t current_0p1A, uint8_t force)
{
uint8_t data[8];
uint8_t sa = PSU_TonHeLiveSa();
uint32_t now;
if (sa == 0u) {
return;
}
PSU_TonHeClampUi(&voltage_v, &current_0p1A);
now = HAL_GetTick();
if (!force &&
(tonhe_last_sent_v == voltage_v) &&
(tonhe_last_sent_i == current_0p1A) &&
((now - tonhe_last_cmd_ms) < TONHE_CMD_MIN_MS)) {
return;
}
memset(data, 0, sizeof(data));
data[3] = PSU_TonHeFillMask(data, sa);
PSU_TonHeEncodeUi(data, 4, 6, voltage_v, current_0p1A);
PSU_TonHeSend(TONHE_P_UI_MASK, TONHE_PF_UI_MASK, TONHE_DA_BROADCAST, data);
if (force || (tonhe_last_sent_v != voltage_v) || (tonhe_last_sent_i != current_0p1A)) {
log_printf(LOG_INFO, "TonHe PF04 U=%u I=%u.%uA sa=%u mask=%02X\n",
(unsigned)voltage_v,
(unsigned)(current_0p1A / 10u),
(unsigned)(current_0p1A % 10u),
(unsigned)sa,
(unsigned)data[0]);
}
tonhe_last_cmd_ms = now;
tonhe_last_sent_v = voltage_v;
tonhe_last_sent_i = current_0p1A;
}
static void PSU_TonHeSendGroupOnOff(uint8_t start, uint8_t force)
{
uint8_t data[8];
uint8_t sa = PSU_TonHeLiveSa();
uint32_t now;
if (sa == 0u) {
return;
}
now = HAL_GetTick();
if (!force &&
(tonhe_last_sent_start == start) &&
((now - tonhe_last_cmd_ms) < TONHE_CMD_MIN_MS)) {
return;
}
memset(data, 0, sizeof(data));
data[4] = PSU_TonHeFillMask(data, sa);
data[3] = start ? TONHE_CMD_START : TONHE_CMD_STOP;
PSU_TonHeSend(TONHE_P_GROUP_CMD, TONHE_PF_GROUP_CMD, TONHE_DA_BROADCAST, data);
if (force || (tonhe_last_sent_start != start)) {
log_printf(LOG_INFO, "TonHe PF03 %s sa=%u mask=%02X\n",
start ? "AA" : "55",
(unsigned)sa,
(unsigned)data[0]);
}
tonhe_last_cmd_ms = now;
tonhe_last_sent_start = start;
}
ISR_FAST static void PSU_TonHeRx(uint32_t ext_id, uint32_t dlc, const uint8_t *rx)
{
uint8_t pf;
uint8_t da;
uint8_t sa;
if (dlc < 8u) {
return;
}
pf = (uint8_t)((ext_id >> 16) & 0xFFu);
da = (uint8_t)((ext_id >> 8) & 0xFFu);
sa = (uint8_t)(ext_id & 0xFFu);
/* Group path still reports from the module SA to controller A0. */
if ((da != TONHE_SA_CTRL) || (PSU_TonHeAcceptSa(sa) == 0u)) {
return;
}
if (pf == TONHE_PF_STATUS) {
uint16_t v_raw = PSU_TonHeU16le(rx, 1);
uint16_t i_raw = PSU_TonHeU16le(rx, 3);
uint16_t v = (uint16_t)(v_raw / 10u);
int16_t i = (int16_t)(i_raw / 10u);
tonhe_state = rx[0];
tonhe_faults = PSU_TonHeU16le(rx, 5);
tonhe_pfc = rx[7];
PSU_TonHeRefreshFlags();
PSU0.online = 1u;
/* Niuera-style: enabled = bus up, not the ON command bit. */
PSU0.PSU_enabled = (v >= PSU_VOLTAGE_THRESHOLD) ? 1u : 0u;
can_lastpacket = HAL_GetTick();
/* Measured only — do not overwrite commanded U/I. */
psu_last_can_v = v;
psu_last_can_i_0p1A = (uint16_t)i;
PSU_ApplyOutputTelemetry(v, i, PSU0.temperature);
} else if (pf == TONHE_PF_AC) {
PSU_06.VAB = PSU_TonHeU16le(rx, 0);
PSU_06.VBC = PSU_TonHeU16le(rx, 2);
PSU_06.VCA = PSU_TonHeU16le(rx, 4);
PSU0.tempAmbient = PSU_TonHeU16le(rx, 6);
PSU0.temperature = (uint8_t)PSU0.tempAmbient;
can_lastpacket = HAL_GetTick();
PSU0.online = 1u;
} else if (pf == TONHE_PF_EXT) {
tonhe_ext_x = PSU_TonHeU16le(rx, 2);
tonhe_ext_valid = 1u;
PSU_TonHeRefreshFlags();
can_lastpacket = HAL_GetTick();
PSU0.online = 1u;
}
}
static void PSU_LogPeriodicDiag(void) static void PSU_LogPeriodicDiag(void)
{ {
static uint32_t last_log_ms; static uint32_t last_log_ms;
@@ -717,8 +192,7 @@ static void PSU_MonitorStatusAndUnexpectedOff(void)
(PSU0.state == PSU_CONT_WAIT_ACK_ON)); (PSU0.state == PSU_CONT_WAIT_ACK_ON));
expect_on = in_charging && (CONN.EnableOutput != 0) && (PSU0.state == PSU_CONNECTED) && expect_on = in_charging && (CONN.EnableOutput != 0) && (PSU0.state == PSU_CONNECTED) &&
!host_export_off && !host_export_off;
(!PSU_IsTonHe() || (tonhe_restart == TONHE_RESTART_IDLE));
if (!inited) { if (!inited) {
prev_s0 = PSU0.status0.raw; prev_s0 = PSU0.status0.raw;
@@ -933,11 +407,6 @@ ISR_FAST void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan){
if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &RxHeader, RxData) == HAL_OK) if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &RxHeader, RxData) == HAL_OK)
{ {
if (PSU_IsTonHe()) {
PSU_TonHeRx(RxHeader.ExtId, RxHeader.DLC, RxData);
return;
}
memcpy(&CanId, &RxHeader.ExtId, sizeof(CanId_t)); memcpy(&CanId, &RxHeader.ExtId, sizeof(CanId_t));
/* Для DC30 поддерживается только один силовой модуль (source == 0) */ /* Для DC30 поддерживается только один силовой модуль (source == 0) */
@@ -987,9 +456,21 @@ ISR_FAST void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan){
uint16_t v = PSU_09.moduleNVoltage / 1000; uint16_t v = PSU_09.moduleNVoltage / 1000;
int16_t i = PSU_09.moduleNCurrent / 100; int16_t i = PSU_09.moduleNCurrent / 100;
PSU0.PSU_enabled = (v >= PSU_VOLTAGE_THRESHOLD); // Обновляем модель PSU0 по телеметрии
PSU0.online = 1; PSU0.outputVoltage = v;
PSU_ApplyOutputTelemetry(v, i, PSU_04.moduleTemperature); PSU0.outputCurrent = i;
PSU0.PSU_enabled = (v >= PSU_VOLTAGE_THRESHOLD);
PSU0.online = 1;
PSU0.temperature = PSU_04.moduleTemperature;
// Экспортируем значения из PSU0 в CONN только,
// когда модуль хотя бы в состоянии READY и выше
if(PSU0.state >= PSU_READY){
CONN.MeasuredVoltage = PSU0.outputVoltage;
CONN.MeasuredCurrent = PSU0.outputCurrent;
CONN.Power = CONN.MeasuredCurrent * CONN.MeasuredVoltage / 10;
CONN.outputEnabled = PSU0.PSU_enabled;
}
} }
} }
} }
@@ -1029,27 +510,7 @@ void PSU_Init(){
PSU0.state = PSU_UNREADY; PSU0.state = PSU_UNREADY;
PSU0.statetick = HAL_GetTick(); PSU0.statetick = HAL_GetTick();
psu_type = Board_GetPsuType(); PSU0.power_limit = PSU_MAX_POWER; // kW
psu_max_current_a = Board_GetPsuMaxCurrentA();
PSU0.power_limit = Board_GetPsuMaxPowerW();
psu_output_cmd_on = 0u;
psu_cmd_v = PSU_MIN_VOLTAGE;
psu_cmd_i_0p1A = (uint16_t)PSU_MIN_CURRENT * 10u;
psu_last_can_v = 0u;
psu_last_can_i_0p1A = 0u;
tonhe_sa = (TONHE_MODULE_ADDR != 0u) ? (uint8_t)TONHE_MODULE_ADDR : 0u;
tonhe_last_sent_start = 0xFFu;
tonhe_ext_valid = 0u;
tonhe_hb_tick = 0u;
PSU_TonHeRestartReset();
tonhe_run_v = PSU_MIN_VOLTAGE;
if (PSU_IsTonHe()) {
log_printf(LOG_INFO, "PSU proto: TonHe 30kW group SA=%u (0=discover)\n",
(unsigned)TONHE_MODULE_ADDR);
} else {
log_printf(LOG_INFO, "PSU proto: Niuera type=%u\n", (unsigned)psu_type);
}
PSU_Enable(0, 0); PSU_Enable(0, 0);
PowerSetpoint_Init(); PowerSetpoint_Init();
@@ -1062,21 +523,6 @@ void PSU_Enable(uint8_t addr, uint8_t enable){
if(addr != 0) return; if(addr != 0) return;
if(PSU0.online == 0) return; if(PSU0.online == 0) return;
psu_output_cmd_on = enable ? 1u : 0u;
if (PSU_IsTonHe()) {
if (enable) {
PSU_TonHeSendGroupUi(psu_cmd_v, psu_cmd_i_0p1A, 1u);
ED_Delay(CAN_DELAY);
PSU_TonHeSendGroupOnOff(1u, 1u);
} else {
tonhe_restart = TONHE_RESTART_IDLE;
tonhe_run_valid = 0u;
PSU_TonHeSendGroupOnOff(0u, 1u);
}
ED_Delay(CAN_DELAY);
return;
}
data.enable = !enable; data.enable = !enable;
PSU_SendCmd(0xF0, addr, 0x1A, &data); PSU_SendCmd(0xF0, addr, 0x1A, &data);
ED_Delay(CAN_DELAY); ED_Delay(CAN_DELAY);
@@ -1084,11 +530,6 @@ void PSU_Enable(uint8_t addr, uint8_t enable){
void PSU_SetHVMode(uint8_t addr, uint8_t enable){ void PSU_SetHVMode(uint8_t addr, uint8_t enable){
PSU_1D_t data; PSU_1D_t data;
if (PSU_IsTonHe()) {
(void)addr;
(void)enable;
return;
}
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.enable = !enable; data.enable = !enable;
if(addr != 0) return; if(addr != 0) return;
@@ -1106,34 +547,6 @@ void PSU_SetVoltageCurrent(uint8_t addr, uint16_t voltage, uint16_t current){
voltage = PSU_LV_CLAMP_V; voltage = PSU_LV_CLAMP_V;
} }
psu_cmd_v = voltage;
psu_cmd_i_0p1A = current;
if (PSU_IsTonHe()) {
if (tonhe_restart != TONHE_RESTART_IDLE) {
return;
}
if (psu_output_cmd_on && tonhe_run_valid &&
(PSU_TonHeIsHv(tonhe_run_v) == 0u) && PSU_TonHeIsHv(voltage)) {
if (PSU_TonHeCanLvHvRestart(voltage)) {
PSU_TonHeRestartBegin();
}
/* Keep the LV PF=04 until measured LV is real. */
return;
}
if (psu_output_cmd_on) {
PSU_TonHeSendGroupUi(voltage, current, 0u);
if (PSU0.PSU_enabled) {
tonhe_run_v = voltage;
tonhe_run_valid = 1u;
}
}
return;
}
psu_last_can_v = voltage;
psu_last_can_i_0p1A = current;
uint32_t current_ma = current * 100; uint32_t current_ma = current * 100;
uint32_t voltage_mv = voltage * 1000; uint32_t voltage_mv = voltage * 1000;
@@ -1147,6 +560,8 @@ void PSU_SetVoltageCurrent(uint8_t addr, uint16_t voltage, uint16_t current){
data.moduleVoltage[2] = (voltage_mv >> 8) & 0xFF; data.moduleVoltage[2] = (voltage_mv >> 8) & 0xFF;
data.moduleVoltage[3] = (voltage_mv >> 0) & 0xFF; data.moduleVoltage[3] = (voltage_mv >> 0) & 0xFF;
psu_last_can_v = voltage;
psu_last_can_i_0p1A = current;
PSU_SendCmd(0xF0, addr, 0x1C, &data); PSU_SendCmd(0xF0, addr, 0x1C, &data);
} }
@@ -1190,14 +605,10 @@ void PSU_ReadWrite(){
uint8_t zero_data[8] = {0,0,0,0,0,0,0,0}; uint8_t zero_data[8] = {0,0,0,0,0,0,0,0};
if (PSU_IsTonHe()) { PSU_SendCmd(0xF0, 0, 0x04, zero_data);ED_Delay(CAN_DELAY);
PSU_TonHeHeartbeat(); PSU_SendCmd(0xF0, 0, 0x06, zero_data);ED_Delay(CAN_DELAY);
} else { // PSU_SendCmd(0xF0, 0, 0x08, zero_data);ED_Delay(CAN_DELAY);
PSU_SendCmd(0xF0, 0, 0x04, zero_data);ED_Delay(CAN_DELAY); PSU_SendCmd(0xF0, 0, 0x09, zero_data);ED_Delay(CAN_DELAY);
PSU_SendCmd(0xF0, 0, 0x06, zero_data);ED_Delay(CAN_DELAY);
// PSU_SendCmd(0xF0, 0, 0x08, zero_data);ED_Delay(CAN_DELAY);
PSU_SendCmd(0xF0, 0, 0x09, zero_data);ED_Delay(CAN_DELAY);
}
// Power Limit // Power Limit
if ((CONN.WantedCurrent/10) * CONN.MeasuredVoltage > PSU0.power_limit){ if ((CONN.WantedCurrent/10) * CONN.MeasuredVoltage > PSU0.power_limit){
@@ -1206,8 +617,8 @@ void PSU_ReadWrite(){
CONN.RequestedCurrent = CONN.WantedCurrent; CONN.RequestedCurrent = CONN.WantedCurrent;
} }
if(CONN.RequestedCurrent > (psu_max_current_a * 10u)){ if(CONN.RequestedCurrent > (PSU_MAX_CURRENT*10)){
CONN.RequestedCurrent = psu_max_current_a * 10u; CONN.RequestedCurrent = PSU_MAX_CURRENT*10;
} }
CONN.RequestedPower = CONN.RequestedCurrent * CONN.RequestedVoltage / 10; CONN.RequestedPower = CONN.RequestedCurrent * CONN.RequestedVoltage / 10;
@@ -1237,7 +648,6 @@ void PSU_Task(void){
static uint32_t psu_on_tick = 0; static uint32_t psu_on_tick = 0;
static uint32_t cont_ok_tick = 0; static uint32_t cont_ok_tick = 0;
static uint32_t fd_on_last_cmd_ms = 0; static uint32_t fd_on_last_cmd_ms = 0;
static uint32_t tonhe_on_retry_ms = 0;
PowerSetpointTryResult_t psd_result; PowerSetpointTryResult_t psd_result;
#if PSD_ENABLE #if PSD_ENABLE
@@ -1251,15 +661,13 @@ void PSU_Task(void){
#endif #endif
// Обновляем ONLINE/READY по таймауту // Обновляем ONLINE/READY по таймауту
if((HAL_GetTick() - can_lastpacket) > (PSU_IsTonHe() ? PSU_TONHE_ONLINE_TIMEOUT : PSU_ONLINE_TIMEOUT)){ if((HAL_GetTick() - can_lastpacket) > PSU_ONLINE_TIMEOUT){
if (PSU0.online) { if (PSU0.online) {
log_printf(LOG_WARN, "PSU CAN timeout age=%lums -> offline\n", log_printf(LOG_WARN, "PSU CAN timeout age=%lums -> offline\n",
(unsigned long)(HAL_GetTick() - can_lastpacket)); (unsigned long)(HAL_GetTick() - can_lastpacket));
} }
PSU0.online = 0; PSU0.online = 0;
PSU0.PSU_enabled = 0; PSU0.PSU_enabled = 0;
tonhe_restart = TONHE_RESTART_IDLE;
tonhe_run_valid = 0u;
PSU_04.moduleTemperature = 0; PSU_04.moduleTemperature = 0;
PSU_04.modularForm0 = 0; PSU_04.modularForm0 = 0;
PSU_04.modularForm1 = 0; PSU_04.modularForm1 = 0;
@@ -1306,9 +714,6 @@ void PSU_Task(void){
PSU0.enableOutput = 0; PSU0.enableOutput = 0;
RELAY_Write(RELAY_DC, 0); RELAY_Write(RELAY_DC, 0);
if(PSU0.online && PSU0.enableAC && !PSU0.cont_fault){ if(PSU0.online && PSU0.enableAC && !PSU0.cont_fault){
if (PSU_IsTonHe()) {
PSU_Enable(0, 0);
}
PSU_SwitchState(PSU_INITIALIZING); PSU_SwitchState(PSU_INITIALIZING);
} }
break; break;
@@ -1333,7 +738,6 @@ void PSU_Task(void){
} }
if(CONN.EnableOutput){ if(CONN.EnableOutput){
PSU_Enable(0, 1); PSU_Enable(0, 1);
tonhe_on_retry_ms = HAL_GetTick();
PSU_SwitchState(PSU_WAIT_ACK_ON); PSU_SwitchState(PSU_WAIT_ACK_ON);
} }
break; break;
@@ -1341,24 +745,12 @@ void PSU_Task(void){
case PSU_WAIT_ACK_ON: case PSU_WAIT_ACK_ON:
if(PSU0.PSU_enabled && PSU0.ready){ if(PSU0.PSU_enabled && PSU0.ready){
if (PSU_IsTonHe()) {
tonhe_run_v = tonhe_last_sent_v;
tonhe_run_valid = 1u;
}
PSU_SwitchState(PSU_CONT_WAIT_ACK_ON); PSU_SwitchState(PSU_CONT_WAIT_ACK_ON);
}else if(PSU_StateTime() > 10000){ }else if(PSU_StateTime() > 10000){
PSU0.psu_fault = 1; PSU0.psu_fault = 1;
CONN.chargingError = CONN_ERR_PSU_FAULT; CONN.chargingError = CONN_ERR_PSU_FAULT;
PSU_SwitchState(PSU_UNREADY); PSU_SwitchState(PSU_UNREADY);
log_printf(LOG_ERR, "PSU on timeout\n"); log_printf(LOG_ERR, "PSU on timeout\n");
}else if (PSU_IsTonHe() &&
((HAL_GetTick() - tonhe_on_retry_ms) >= TONHE_RESTART_RETRY_MS)) {
/* Retry the LV/HV start already sent — do not jump to a later HV cmd. */
PSU_TonHeSendGroupUi(tonhe_last_sent_v, tonhe_last_sent_i, 1u);
ED_Delay(CAN_DELAY);
PSU_TonHeSendGroupOnOff(1u, 1u);
psu_output_cmd_on = 1u;
tonhe_on_retry_ms = HAL_GetTick();
} }
break; break;
@@ -1382,19 +774,9 @@ void PSU_Task(void){
case PSU_CONNECTED: case PSU_CONNECTED:
// Основное рабочее состояние // Основное рабочее состояние
if(!CONN.EnableOutput || !PSU0.ready){ if(!CONN.EnableOutput || !PSU0.ready){
tonhe_restart = TONHE_RESTART_IDLE;
tonhe_run_valid = 0u;
PSU_SwitchState(PSU_CURRENT_DROP); PSU_SwitchState(PSU_CURRENT_DROP);
break; break;
} }
if (PSU_IsTonHe() && (tonhe_restart == TONHE_RESTART_IDLE) &&
PSU_TonHeCanLvHvRestart(psu_cmd_v)) {
PSU_TonHeRestartBegin();
}
PSU_TonHeRestartTask();
if (PSU0.state != PSU_CONNECTED) {
break;
}
// контроль контактора: 1 c таймаут // контроль контактора: 1 c таймаут
if (IN_ReadInput(IN_CONT_FB_DC) != RELAY_Read(RELAY_DC)){ if (IN_ReadInput(IN_CONT_FB_DC) != RELAY_Read(RELAY_DC)){
if((HAL_GetTick() - cont_ok_tick) > 1000){ if((HAL_GetTick() - cont_ok_tick) > 1000){
-1
View File
@@ -394,7 +394,6 @@ void CCS_Init(void){
void CCS_UpdateMaxLoadFromInfoBlock(void) void CCS_UpdateMaxLoadFromInfoBlock(void)
{ {
CCS_MaxLoad.maxCurrent = Board_GetConnectorCurrentLimit_0p1A(); CCS_MaxLoad.maxCurrent = Board_GetConnectorCurrentLimit_0p1A();
CCS_MaxLoad.maxPower = Board_GetPsuMaxPowerW();
} }
ISR_FAST static uint16_t crc16_ibm(const uint8_t* data, uint16_t length) { ISR_FAST static uint16_t crc16_ibm(const uint8_t* data, uint16_t length) {
-1
View File
@@ -70,7 +70,6 @@ InfoPacket_t infoPacket = {
}; };
void ReadVersion(){ void ReadVersion(){
Board_SelectInfoBlockAddress();
infoPacket.serialNumber = InfoBlock->serialNumber; infoPacket.serialNumber = InfoBlock->serialNumber;
infoPacket.boardVersion = InfoBlock->boardVersion; infoPacket.boardVersion = InfoBlock->boardVersion;
infoPacket.stationType = InfoBlock->stationType; infoPacket.stationType = InfoBlock->stationType;
Binary file not shown.
Binary file not shown.
+4391 -4686
View File
File diff suppressed because it is too large Load Diff
+4391 -4686
View File
File diff suppressed because it is too large Load Diff