Skip to content

Commit 252d264

Browse files
committed
RMS info
1 parent 1ac8974 commit 252d264

13 files changed

Lines changed: 301 additions & 62 deletions

File tree

DASH/Core/User/Src/FEB_CAN_PCU.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,13 @@ static void rx_callback_torque(FEB_CAN_Instance_t instance, uint32_t can_id, FEB
6565
static void rx_callback_brake_position(FEB_CAN_Instance_t instance, uint32_t can_id, FEB_CAN_ID_Type_t id_type,
6666
const uint8_t *data, uint8_t length, void *user_data)
6767
{
68-
uint16_t position;
69-
memcpy(&position, &data[0], sizeof(uint16_t));
70-
brake_state.brake_position = position;
71-
__DMB();
72-
brake_state.last_rx_tick = HAL_GetTick();
68+
struct feb_can_brake_t msg;
69+
if (feb_can_brake_unpack(&msg, data, length) == 0)
70+
{
71+
brake_state.brake_position = msg.brake_position; /* centi-percent; endianness handled by codegen */
72+
__DMB();
73+
brake_state.last_rx_tick = HAL_GetTick();
74+
}
7375
}
7476

7577
/* ============================================================================

DASH/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.1
1+
1.7.2

LVPDB/Core/User/Inc/FEB_CAN_BRAKE.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
typedef struct
1616
{
17-
volatile uint8_t brake_percent;
17+
volatile uint16_t brake_position; /* centi-percent (0-10000) */
1818
volatile uint32_t last_rx_tick;
1919
} BRAKE_State_t;
2020

LVPDB/Core/User/Src/FEB_CAN_BRAKE.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static void rx_callback(FEB_CAN_Instance_t instance, uint32_t can_id, FEB_CAN_ID
2424
struct feb_can_brake_t msg;
2525
if (feb_can_brake_unpack(&msg, data, length) == 0)
2626
{
27-
brake_state.brake_percent = msg.brake_percent;
27+
brake_state.brake_position = msg.brake_position;
2828

2929
__DMB();
3030
brake_state.last_rx_tick = HAL_GetTick();
@@ -52,7 +52,8 @@ void FEB_CAN_BRAKE_Init(void)
5252

5353
uint8_t FEB_CAN_BRAKE_GetPercent(void)
5454
{
55-
return brake_state.brake_percent;
55+
/* brake_position is centi-percent (0-10000); return whole percent (0-100). */
56+
return (uint8_t)(brake_state.brake_position / 100u);
5657
}
5758

5859
bool FEB_CAN_BRAKE_IsDataFresh(uint32_t timeout_ms)

LVPDB/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.7.3
1+
1.7.4

PCU/Core/User/Inc/FEB_CAN_RMS.h

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@
55

66
#include "feb_can_lib.h"
77
#include "feb_can.h"
8+
#include <stdbool.h>
89
#include <string.h>
910

10-
/* RMS Motor Controller CAN IDs — resolved from generated feb_can.h */
11-
#define FEB_CAN_ID_RMS_VOLTAGE FEB_CAN_M160_TEMPERATURE_SET_1_FRAME_ID
11+
/* RMS Motor Controller CAN IDs — resolved from generated feb_can.h.
12+
* VOLTAGE is the real DC bus voltage broadcast (M167 / 0x0A7); STATES is the
13+
* inverter Internal States (M170 / 0x0AA, has VSM state + enable lockout) and
14+
* FAULTS is the POST/Run fault codes (M171 / 0x0AB). Subscribing to STATES and
15+
* FAULTS lets PCU|rms report *why* the inverter refuses to enable. */
16+
#define FEB_CAN_ID_RMS_VOLTAGE FEB_CAN_M167_VOLTAGE_INFO_FRAME_ID
1217
#define FEB_CAN_ID_RMS_MOTOR FEB_CAN_M165_MOTOR_POSITION_INFO_FRAME_ID
18+
#define FEB_CAN_ID_RMS_STATES FEB_CAN_M170_INTERNAL_STATES_FRAME_ID
19+
#define FEB_CAN_ID_RMS_FAULTS FEB_CAN_M171_FAULT_CODES_FRAME_ID
1320

1421
#define FAULT_CLEAR_ADDR_UNDERVOLT 140
1522
#define FAULT_CLEAR_ADDR_PARAM_SAFETY 20
@@ -21,13 +28,29 @@ extern uint8_t PARAM_BROADCAST_DATA[2];
2128

2229
typedef struct RMS_MESSAGE_TYPE
2330
{
24-
volatile int16_t HV_Bus_Voltage; // Updated in ISR, read in main loop (raw)
31+
volatile int16_t HV_Bus_Voltage; // M167 DC bus voltage, raw (tenths of V)
2532
volatile int16_t Motor_Speed; // Updated in ISR, read in main loop (RPM)
2633
volatile int16_t Motor_Angle; // Updated in ISR, read in main loop
2734
volatile int16_t Torque_Command; // Commanded torque (tenths of Nm)
2835
volatile int16_t Torque_Feedback; // Feedback torque (tenths of Nm)
29-
volatile float DC_Bus_Voltage_V; // DC bus voltage in Volts
36+
volatile float DC_Bus_Voltage_V; // DC bus voltage in Volts (from M167)
3037
volatile uint32_t last_rx_timestamp; // 0 = never received, else HAL_GetTick() when last RX
38+
39+
/* Inverter Internal States (M170 / 0x0AA) — written in ISR, read in main loop */
40+
volatile uint8_t vsm_state; // INV_VSM_State (0..15)
41+
volatile uint8_t inverter_state; // INV_Inverter_State (0..255)
42+
volatile uint8_t enable_state; // 0 = disabled, 1 = enabled
43+
volatile uint8_t enable_lockout; // 1 = inverter enable lockout active
44+
volatile uint8_t command_mode; // 0 = CAN mode, 1 = VSM mode
45+
volatile uint8_t echo_rolling_counter; // inverter-echoed rolling counter (0..15)
46+
volatile uint32_t states_rx_timestamp; // 0 = never received an M170 frame
47+
48+
/* Fault codes (M171 / 0x0AB) — each word is a fault bitfield (see PM100 manual) */
49+
volatile uint16_t post_fault_lo;
50+
volatile uint16_t post_fault_hi;
51+
volatile uint16_t run_fault_lo;
52+
volatile uint16_t run_fault_hi;
53+
volatile uint32_t faults_rx_timestamp; // 0 = never received an M171 frame
3154
} RMS_MESSAGE_TYPE;
3255

3356
// Global variable - defined in FEB_CAN_RMS.c
@@ -50,4 +73,21 @@ int16_t FEB_CAN_RMS_getMotorAngle(void);
5073
float FEB_CAN_RMS_getTorqueCommand(void);
5174
float FEB_CAN_RMS_getTorqueFeedback(void);
5275

76+
// Inverter Internal States (M170) accessors
77+
bool FEB_CAN_RMS_StatesSeen(void); // true once an M170 frame has been received
78+
uint8_t FEB_CAN_RMS_getVsmState(void); // INV_VSM_State (0..15)
79+
uint8_t FEB_CAN_RMS_getInverterState(void);
80+
bool FEB_CAN_RMS_getEnableState(void); // inverter-reported enable state
81+
bool FEB_CAN_RMS_getEnableLockout(void); // true = inverter enable lockout active
82+
bool FEB_CAN_RMS_getCommandModeVsm(void); // true = VSM mode, false = CAN mode
83+
uint8_t FEB_CAN_RMS_getEchoRollingCounter(void);
84+
85+
// Fault codes (M171) accessors
86+
bool FEB_CAN_RMS_FaultsSeen(void); // true once an M171 frame has been received
87+
bool FEB_CAN_RMS_HasActiveFault(void); // true if any POST/Run fault word is nonzero
88+
uint16_t FEB_CAN_RMS_getPostFaultLo(void);
89+
uint16_t FEB_CAN_RMS_getPostFaultHi(void);
90+
uint16_t FEB_CAN_RMS_getRunFaultLo(void);
91+
uint16_t FEB_CAN_RMS_getRunFaultHi(void);
92+
5393
#endif /* INC_FEB_CAN_RMS_H_ */

PCU/Core/User/Src/FEB_CAN_Diagnostics.c

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,25 @@ Brake_DataTypeDef Brake_Data;
55

66
void FEB_CAN_Diagnostics_TransmitBrakeData(void)
77
{
8-
uint8_t data[8] = {0};
9-
108
// Get latest brake data
119
FEB_ADC_GetBrakeData(&Brake_Data);
1210

13-
// Pack brake position (0-100%) into first two bytes (0-10000 centi-percent)
14-
uint16_t brake_position_centi_percent = (uint16_t)(Brake_Data.brake_position * 100.0f);
15-
data[0] = (brake_position_centi_percent >> 8) & 0xFF;
16-
data[1] = brake_position_centi_percent & 0xFF;
17-
18-
// Pack brake pressure sensors (0-100%) into next four bytes (0-10000 centi-percent)
19-
uint16_t pressure1_centi_percent = (uint16_t)(Brake_Data.pressure1_percent * 100.0f);
20-
uint16_t pressure2_centi_percent = (uint16_t)(Brake_Data.pressure2_percent * 100.0f);
21-
data[2] = (pressure1_centi_percent >> 8) & 0xFF;
22-
data[3] = pressure1_centi_percent & 0xFF;
23-
data[4] = (pressure2_centi_percent >> 8) & 0xFF;
24-
data[5] = pressure2_centi_percent & 0xFF;
25-
26-
// Pack status flags into last two bytes
27-
data[6] = (Brake_Data.plausible ? 0x01 : 0x00) | // Bit 0
28-
(Brake_Data.brake_pressed ? 0x02 : 0x00) | // Bit 1
29-
(Brake_Data.bots_active ? 0x04 : 0x00); // Bit 2
30-
data[7] = Brake_Data.brake_switch ? 0x02 : 0x01;
31-
32-
// Transmit CAN message
33-
FEB_CAN_Status_t status = FEB_CAN_TX_Send(FEB_CAN_INSTANCE_1, FEB_CAN_BRAKE_FRAME_ID, FEB_CAN_ID_STD, data, 8);
11+
// Position + per-sensor pressure are sent as centi-percent (0-10000); status
12+
// flags ride in bytes 6-7. Layout/endianness are owned by the generated brake
13+
// definition (common/FEB_CAN_Library_SN4) — pack through it, don't hand-roll.
14+
struct feb_can_brake_t msg = {0};
15+
msg.brake_position = (uint16_t)(Brake_Data.brake_position * 100.0f);
16+
msg.brake1_pct = (uint16_t)(Brake_Data.pressure1_percent * 100.0f);
17+
msg.brake2_pct = (uint16_t)(Brake_Data.pressure2_percent * 100.0f);
18+
msg.plausible = Brake_Data.plausible ? 1u : 0u;
19+
msg.brake_pressed = Brake_Data.brake_pressed ? 1u : 0u;
20+
msg.bots_active = Brake_Data.bots_active ? 1u : 0u;
21+
msg.brake_switch = Brake_Data.brake_switch ? 1u : 0u;
22+
23+
uint8_t data[FEB_CAN_BRAKE_LENGTH];
24+
int packed = feb_can_brake_pack(data, &msg, sizeof(data));
25+
FEB_CAN_Status_t status =
26+
FEB_CAN_TX_Send(FEB_CAN_INSTANCE_1, FEB_CAN_BRAKE_FRAME_ID, FEB_CAN_ID_STD, data, (uint8_t)packed);
3427
if (status != FEB_CAN_OK)
3528
{
3629
LOG_E(TAG_CAN, "Failed to transmit brake data: %s", FEB_CAN_StatusToString(status));

PCU/Core/User/Src/FEB_CAN_RMS.c

Lines changed: 125 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,74 @@ float FEB_CAN_RMS_getTorqueFeedback(void)
4444
return RMS_MESSAGE.Torque_Feedback / 10.0f;
4545
}
4646

47+
/* Inverter Internal States (M170) accessors */
48+
bool FEB_CAN_RMS_StatesSeen(void)
49+
{
50+
return RMS_MESSAGE.states_rx_timestamp != 0;
51+
}
52+
53+
uint8_t FEB_CAN_RMS_getVsmState(void)
54+
{
55+
return RMS_MESSAGE.vsm_state;
56+
}
57+
58+
uint8_t FEB_CAN_RMS_getInverterState(void)
59+
{
60+
return RMS_MESSAGE.inverter_state;
61+
}
62+
63+
bool FEB_CAN_RMS_getEnableState(void)
64+
{
65+
return RMS_MESSAGE.enable_state != 0;
66+
}
67+
68+
bool FEB_CAN_RMS_getEnableLockout(void)
69+
{
70+
return RMS_MESSAGE.enable_lockout != 0;
71+
}
72+
73+
bool FEB_CAN_RMS_getCommandModeVsm(void)
74+
{
75+
return RMS_MESSAGE.command_mode != 0;
76+
}
77+
78+
uint8_t FEB_CAN_RMS_getEchoRollingCounter(void)
79+
{
80+
return RMS_MESSAGE.echo_rolling_counter;
81+
}
82+
83+
/* Fault codes (M171) accessors */
84+
bool FEB_CAN_RMS_FaultsSeen(void)
85+
{
86+
return RMS_MESSAGE.faults_rx_timestamp != 0;
87+
}
88+
89+
bool FEB_CAN_RMS_HasActiveFault(void)
90+
{
91+
return (RMS_MESSAGE.post_fault_lo | RMS_MESSAGE.post_fault_hi | RMS_MESSAGE.run_fault_lo |
92+
RMS_MESSAGE.run_fault_hi) != 0;
93+
}
94+
95+
uint16_t FEB_CAN_RMS_getPostFaultLo(void)
96+
{
97+
return RMS_MESSAGE.post_fault_lo;
98+
}
99+
100+
uint16_t FEB_CAN_RMS_getPostFaultHi(void)
101+
{
102+
return RMS_MESSAGE.post_fault_hi;
103+
}
104+
105+
uint16_t FEB_CAN_RMS_getRunFaultLo(void)
106+
{
107+
return RMS_MESSAGE.run_fault_lo;
108+
}
109+
110+
uint16_t FEB_CAN_RMS_getRunFaultHi(void)
111+
{
112+
return RMS_MESSAGE.run_fault_hi;
113+
}
114+
47115
void FEB_CAN_RMS_Init(void)
48116
{
49117
LOG_I(TAG_CAN, "Initializing RMS CAN communication");
@@ -64,8 +132,15 @@ void FEB_CAN_RMS_Init(void)
64132
params.can_id = FEB_CAN_ID_RMS_MOTOR;
65133
FEB_CAN_RX_Register(&params);
66134

67-
LOG_I(TAG_CAN, "Registered RMS CAN callbacks (Voltage: 0x%03X, Motor: 0x%03X)", (unsigned)FEB_CAN_ID_RMS_VOLTAGE,
68-
(unsigned)FEB_CAN_ID_RMS_MOTOR);
135+
params.can_id = FEB_CAN_ID_RMS_STATES;
136+
FEB_CAN_RX_Register(&params);
137+
138+
params.can_id = FEB_CAN_ID_RMS_FAULTS;
139+
FEB_CAN_RX_Register(&params);
140+
141+
LOG_I(TAG_CAN, "Registered RMS CAN callbacks (Voltage: 0x%03X, Motor: 0x%03X, States: 0x%03X, Faults: 0x%03X)",
142+
(unsigned)FEB_CAN_ID_RMS_VOLTAGE, (unsigned)FEB_CAN_ID_RMS_MOTOR, (unsigned)FEB_CAN_ID_RMS_STATES,
143+
(unsigned)FEB_CAN_ID_RMS_FAULTS);
69144

70145
RMS_MESSAGE.HV_Bus_Voltage = 0;
71146
RMS_MESSAGE.Motor_Speed = 0;
@@ -74,6 +149,18 @@ void FEB_CAN_RMS_Init(void)
74149
RMS_MESSAGE.Torque_Feedback = 0;
75150
RMS_MESSAGE.DC_Bus_Voltage_V = 0.0f;
76151
RMS_MESSAGE.last_rx_timestamp = 0;
152+
RMS_MESSAGE.vsm_state = 0;
153+
RMS_MESSAGE.inverter_state = 0;
154+
RMS_MESSAGE.enable_state = 0;
155+
RMS_MESSAGE.enable_lockout = 0;
156+
RMS_MESSAGE.command_mode = 0;
157+
RMS_MESSAGE.echo_rolling_counter = 0;
158+
RMS_MESSAGE.states_rx_timestamp = 0;
159+
RMS_MESSAGE.post_fault_lo = 0;
160+
RMS_MESSAGE.post_fault_hi = 0;
161+
RMS_MESSAGE.run_fault_lo = 0;
162+
RMS_MESSAGE.run_fault_hi = 0;
163+
RMS_MESSAGE.faults_rx_timestamp = 0;
77164

78165
LOG_I(TAG_CAN, "Sending RMS parameter safety commands");
79166
for (int i = 0; i < 10; i++)
@@ -127,17 +214,42 @@ static void FEB_CAN_RMS_Callback(FEB_CAN_Instance_t instance, uint32_t can_id, F
127214

128215
if (can_id == FEB_CAN_ID_RMS_VOLTAGE)
129216
{
130-
struct feb_can_m160_temperature_set_1_t m160;
131-
feb_can_m160_temperature_set_1_unpack(&m160, data, length);
132-
RMS_MESSAGE.HV_Bus_Voltage = m160.inv_module_a;
133-
RMS_MESSAGE.DC_Bus_Voltage_V = (m160.inv_module_a - 50.0f) / 10.0f;
217+
/* M167 Voltage Info: INV_DC_Bus_Voltage is signed, scale 0.1 V, no offset. */
218+
struct feb_can_m167_voltage_info_t m167;
219+
feb_can_m167_voltage_info_unpack(&m167, data, length);
220+
RMS_MESSAGE.HV_Bus_Voltage = m167.inv_dc_bus_voltage;
221+
RMS_MESSAGE.DC_Bus_Voltage_V = m167.inv_dc_bus_voltage / 10.0f;
134222
}
135223
else if (can_id == FEB_CAN_ID_RMS_MOTOR)
136224
{
137225
struct feb_can_m165_motor_position_info_t m165;
138226
feb_can_m165_motor_position_info_unpack(&m165, data, length);
139227
RMS_MESSAGE.Motor_Speed = m165.inv_motor_speed;
140228
}
229+
else if (can_id == FEB_CAN_ID_RMS_STATES)
230+
{
231+
/* M170 Internal States: the "why won't it enable" frame. */
232+
struct feb_can_m170_internal_states_t m170;
233+
feb_can_m170_internal_states_unpack(&m170, data, length);
234+
RMS_MESSAGE.vsm_state = m170.inv_vsm_state;
235+
RMS_MESSAGE.inverter_state = m170.inv_inverter_state;
236+
RMS_MESSAGE.enable_state = m170.inv_inverter_enable_state;
237+
RMS_MESSAGE.enable_lockout = m170.inv_inverter_enable_lockout;
238+
RMS_MESSAGE.command_mode = m170.inv_inverter_command_mode;
239+
RMS_MESSAGE.echo_rolling_counter = m170.inv_rolling_counter;
240+
RMS_MESSAGE.states_rx_timestamp = RMS_MESSAGE.last_rx_timestamp;
241+
}
242+
else if (can_id == FEB_CAN_ID_RMS_FAULTS)
243+
{
244+
/* M171 Fault Codes: POST/Run fault bitfields (see PM100 manual). */
245+
struct feb_can_m171_fault_codes_t m171;
246+
feb_can_m171_fault_codes_unpack(&m171, data, length);
247+
RMS_MESSAGE.post_fault_lo = m171.inv_post_fault_lo;
248+
RMS_MESSAGE.post_fault_hi = m171.inv_post_fault_hi;
249+
RMS_MESSAGE.run_fault_lo = m171.inv_run_fault_lo;
250+
RMS_MESSAGE.run_fault_hi = m171.inv_run_fault_hi;
251+
RMS_MESSAGE.faults_rx_timestamp = RMS_MESSAGE.last_rx_timestamp;
252+
}
141253
}
142254

143255
/**
@@ -168,10 +280,17 @@ void FEB_CAN_RMS_Transmit_UpdateTorque(int16_t torque, uint8_t enabled)
168280

169281
RMS_MESSAGE.Torque_Command = torque;
170282

283+
/* The RMS' CAN message-validity check requires a rolling counter that changes
284+
* every command frame; a counter stuck at 0 makes it reject every frame as
285+
* stale and refuse to enable. Increment 0..15 (field range) on every TX. */
286+
static uint8_t rolling_counter = 0;
287+
171288
struct feb_can_m192_command_message_t msg = {0};
172289
msg.vcu_inv_torque_command = torque;
173290
msg.vcu_inv_direction_command = 1u;
174291
msg.vcu_inv_inverter_enable = enabled;
292+
msg.vcu_inv_rolling_counter = rolling_counter;
293+
rolling_counter = (uint8_t)((rolling_counter + 1u) & 0x0Fu);
175294

176295
uint8_t data[FEB_CAN_M192_COMMAND_MESSAGE_LENGTH];
177296
int packed = feb_can_m192_command_message_pack(data, &msg, sizeof(data));

0 commit comments

Comments
 (0)