31 Commits

Author SHA1 Message Date
01de4ce2cf first soap ideals 2023-06-29 23:57:29 +02:00
75b9136a1d fixed soe function declaration 2023-06-29 23:45:03 +02:00
484de3f7d9 Added State of Energy LUT 2023-06-29 23:35:08 +02:00
6c0bbb83f6 My own algo Branch with Blackjack and Hookers 2023-06-29 23:17:41 +02:00
c4543e7e01 Implementation of SoC Prediction
untested. Maybe revert to Jaspers Version
2023-06-21 13:13:38 +02:00
78fe61e231 Discharge if SDC is open and TS_Activate is sent
If we never leave TS_INACTIVE, the ABX keeps sending TS_Activate, and we
activate the TS as soon as the SDC is closed.
2023-06-13 20:49:43 +02:00
6d6c1c1f15 Only leave TS_INACTIVE if SDC is closed 2023-06-05 18:45:41 +02:00
cf018f9e4a Full battery 2023-06-05 18:17:16 +02:00
25d6ab2667 Shunt timeout 2023-05-31 00:46:49 +02:00
bf11004c64 Receive individual slave status messages 2023-05-14 19:52:24 +02:00
c54f3a65e3 Fix slave error source 2023-05-03 17:13:10 +02:00
ce4d7253eb Send AMS error messages 2023-04-30 00:57:42 +02:00
48ae56fbdf Set AMS Error pin 2023-04-30 00:04:00 +02:00
6810790349 Don't wait after reaching 95% 2023-04-29 23:45:59 +02:00
c43b6a3b6e Broadcast SDC state 2023-04-29 23:44:45 +02:00
29b411e4af Make SDC state globally available 2023-04-26 13:18:54 +02:00
6c27b83377 Motors turning 2023-04-24 19:20:21 +02:00
f5e26aad24 Run main loop every 50ms 2023-04-15 22:47:16 +02:00
f09665ad28 Decouple slave IDs from slaves array indices 2023-04-15 22:23:41 +02:00
e86a0f90fb Open AIRs in error handlers 2023-04-15 22:13:33 +02:00
ca6bdec839 Handle slave status frames 2023-04-15 22:01:22 +02:00
66d9baba7a Go into discharge for 5s
The discharge circuit is only active while the SDC is open. If the SDC
never opens (or opens for a very short time only), but we go to
TS_INACTIVE, then the discharge circuit will never be active. Going into
a discharge state for 5s allows the PDU to open the SDC for long enough
to reach <60V.
2023-04-15 16:58:40 +02:00
0b2010797e AMS_ERROR pin is actually inverted 2023-04-04 14:51:55 +02:00
1e87137cc4 Update can-halal 2023-04-02 01:06:28 +02:00
f8b74a0aa3 Send min voltage & max temp as 16 bit ints 2023-03-18 23:01:52 +01:00
3ac8e0e746 FT_CAN_AL -> can-halal 2023-03-18 20:24:07 +01:00
5c5bc3678a Temperature is 12-bit 2023-03-18 18:46:02 +01:00
e18135558d Use FaSTTUBe CAN Abstraction Layer 2023-03-15 18:07:38 +01:00
9355595b73 Reset timestamps when leaving their state 2023-03-12 23:01:13 +01:00
838c6195bb Configure PROFET 2023-03-12 21:15:32 +01:00
ea4c10a093 Remove unused variable 2023-03-12 21:10:51 +01:00
22 changed files with 414 additions and 207 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
/.cache/ /.cache/
.clangd .clangd
TouchGFX/build TouchGFX/build
.gitmodules

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "Core/Lib/can-halal"]
path = Core/Lib/can-halal
url = https://git.fasttube.de/FaSTTUBe/can-halal.git

View File

@ -5,9 +5,13 @@
#include "stm32f3xx_hal_can.h" #include "stm32f3xx_hal_can.h"
#include "stm32f3xx_hal_def.h" #include "stm32f3xx_hal_def.h"
#include "ts_state_machine.h"
#define CAN_ID_SLAVE_PANIC 0x009 #define CAN_ID_SLAVE_PANIC 0x009
#define CAN_ID_AMS_STATUS 0x00A #define CAN_ID_AMS_STATUS 0x00A
#define CAN_ID_AMS_IN 0x00B #define CAN_ID_AMS_IN 0x00B
#define CAN_ID_AMS_ERROR 0x00C
#define CAN_ID_SLAVE_STATUS_BASE 0x080
#define CAN_ID_SLAVE_LOG 0x4F4 #define CAN_ID_SLAVE_LOG 0x4F4
#define CAN_ID_SHUNT_BASE 0x520 #define CAN_ID_SHUNT_BASE 0x520
#define CAN_ID_SHUNT_CURRENT 0x521 #define CAN_ID_SHUNT_CURRENT 0x521
@ -20,9 +24,9 @@
#define CAN_ID_SHUNT_ENERGY_COUNTER 0x528 #define CAN_ID_SHUNT_ENERGY_COUNTER 0x528
void can_init(CAN_HandleTypeDef *handle); void can_init(CAN_HandleTypeDef *handle);
HAL_StatusTypeDef can_transmit(uint8_t id, uint8_t *data, size_t datalen);
HAL_StatusTypeDef can_send_status(); HAL_StatusTypeDef can_send_status();
HAL_StatusTypeDef can_send_error(TSErrorKind kind, uint8_t arg);
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *handle); void ftcan_msg_received_cb(uint16_t id, size_t datalen, const uint8_t *data);
#endif // INC_CAN_H #endif // INC_CAN_H

View File

@ -41,7 +41,7 @@ extern "C" {
/* Exported constants --------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */ /* USER CODE BEGIN EC */
extern int sdc_closed;
/* USER CODE END EC */ /* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/ /* Exported macro ------------------------------------------------------------*/
@ -97,8 +97,8 @@ void Error_Handler(void);
#define STATUS3_GPIO_Port GPIOB #define STATUS3_GPIO_Port GPIOB
#define STATUS4_Pin GPIO_PIN_7 #define STATUS4_Pin GPIO_PIN_7
#define STATUS4_GPIO_Port GPIOB #define STATUS4_GPIO_Port GPIOB
#define AMS_ERROR_Pin GPIO_PIN_8 #define AMS_NERROR_Pin GPIO_PIN_8
#define AMS_ERROR_GPIO_Port GPIOB #define AMS_NERROR_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */ /* USER CODE BEGIN Private defines */

View File

@ -5,12 +5,14 @@
#include "stm32f3xx_hal.h" #include "stm32f3xx_hal.h"
#define THRESH_OVERCURRENT 300000 // mA #define SHUNT_TIMEOUT 300 // ms
#define SHUNT_THRESH_OVERCURRENT 300000 // mA
#define SHUNT_THRESH_OVERTEMP 1000 // 1/10 °C
typedef struct { typedef struct {
int32_t current; int32_t current;
int32_t voltage1; int32_t voltage_bat;
int32_t voltage2; int32_t voltage_veh;
int32_t voltage3; int32_t voltage3;
int32_t busbartemp; int32_t busbartemp;
int32_t power; int32_t power;
@ -24,6 +26,8 @@ extern ShuntData shunt_data;
void shunt_init(); void shunt_init();
void shunt_check(); void shunt_check();
void shunt_handle_can_msg(CAN_RxHeaderTypeDef *header, uint8_t *data); void shunt_handle_can_msg(uint16_t id, const uint8_t *data);
int32_t shunt_getcurrent();
#endif // INC_SHUNT_MONITORING_H #endif // INC_SHUNT_MONITORING_H

View File

@ -20,7 +20,8 @@ typedef enum {
SLAVE_ERR_OT, SLAVE_ERR_OT,
SLAVE_ERR_UT, SLAVE_ERR_UT,
SLAVE_ERR_OV, SLAVE_ERR_OV,
SLAVE_ERR_UV SLAVE_ERR_UV,
SLAVE_ERR_UNKNOWN,
} SlaveErrorKind; } SlaveErrorKind;
typedef struct { typedef struct {
@ -31,8 +32,10 @@ typedef struct {
typedef struct { typedef struct {
uint8_t id; uint8_t id;
SlaveError error; SlaveError error;
uint16_t voltages[N_CELLS_SERIES]; uint8_t soc;
int16_t temperatures[N_TEMP_SENSORS]; uint16_t min_voltage;
uint16_t max_voltage;
int16_t max_temp;
uint32_t last_message; uint32_t last_message;
} SlaveHandle; } SlaveHandle;
@ -43,7 +46,9 @@ extern int16_t max_temp;
void slaves_init(); void slaves_init();
void slaves_check(); void slaves_check();
void slaves_handle_panic(uint8_t *data); void slaves_handle_panic(const uint8_t *data);
void slaves_handle_log(uint8_t *data); void slaves_handle_status(const uint8_t *data);
void slaves_handle_log(const uint8_t *data);
uint16_t slaves_get_minimum_voltage();
#endif // INC_SLAVE_MONITORING_H #endif // INC_SLAVE_MONITORING_H

View File

@ -5,7 +5,14 @@
extern uint8_t current_soc; extern uint8_t current_soc;
#define N_MODELPARAMETERS 11
#define BATTERYCAPACITYAs (20000.0*3600) //TODO Check if value is correct Cap in Ah * 3600 (Convert to As)
#define SOAP_MINIMUM_VOLTAGE 2.5
void soc_init(); void soc_init();
void soc_update(); void soc_update(int32_t shunt_current);
float soe_update();
void soap_update();
#endif // INC_SOC_ESTIMATION_H #endif // INC_SOC_ESTIMATION_H

View File

@ -8,7 +8,10 @@
// Minimum vehicle side voltage to exit precharge // Minimum vehicle side voltage to exit precharge
#define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV #define MIN_VEHICLE_SIDE_VOLTAGE 150000 // mV
// Time to wait after reaching 95% of battery voltage before exiting precharge // Time to wait after reaching 95% of battery voltage before exiting precharge
#define PRECHARGE_95_DURATION 500 // ms // Set this to 1000 in scruti to demonstrate the voltage on the multimeter
#define PRECHARGE_95_DURATION 0 // ms
// Time to wait for discharge
#define DISCHARGE_DURATION 5000 // ms
// Time to wait after there is no more error condition before exiting TS_ERROR // Time to wait after there is no more error condition before exiting TS_ERROR
#define NO_ERROR_TIME 1000 // ms #define NO_ERROR_TIME 1000 // ms
// Time to wait for charger voltage before going to TS_ERROR // Time to wait for charger voltage before going to TS_ERROR
@ -26,6 +29,14 @@ typedef enum {
TS_CHARGING TS_CHARGING
} TSState; } TSState;
typedef enum {
TS_ERRORKIND_NONE = 0x00,
TS_ERRORKIND_SLAVE_TIMEOUT = 0x01,
TS_ERRORKIND_SLAVE_PANIC = 0x02,
TS_ERRORKIND_SHUNT_TIMEOUT = 0x03,
TS_ERRORKIND_SHUNT_OVERCURRENT = 0x04,
TS_ERRORKIND_SHUNT_OVERTEMP = 0x05
} TSErrorKind;
#define TS_ERROR_SOURCE_SHUNT (1 << 0) #define TS_ERROR_SOURCE_SHUNT (1 << 0)
#define TS_ERROR_SOURCE_SLAVES (1 << 1) #define TS_ERROR_SOURCE_SLAVES (1 << 1)
@ -53,7 +64,7 @@ void ts_sm_set_relay_positions(TSState state);
void ts_sm_set_relay_position(Relay relay, int closed); void ts_sm_set_relay_position(Relay relay, int closed);
void ts_sm_check_close_wait(int *is_closed, int should_close); void ts_sm_check_close_wait(int *is_closed, int should_close);
void ts_sm_handle_ams_in(uint8_t *data); void ts_sm_handle_ams_in(const uint8_t *data);
void ts_sm_set_error_source(uint32_t flag, int state); void ts_sm_set_error_source(uint32_t flag, int state);

View File

@ -5,8 +5,4 @@
void set_error_led(); void set_error_led();
uint64_t ntohll(uint64_t netlonglong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
#endif // INC_UTIL_H #endif // INC_UTIL_H

1
Core/Lib/can-halal Submodule

Submodule Core/Lib/can-halal added at 433a142732

View File

@ -4,89 +4,46 @@
#include "shunt_monitoring.h" #include "shunt_monitoring.h"
#include "slave_monitoring.h" #include "slave_monitoring.h"
#include "soc_estimation.h" #include "soc_estimation.h"
#include "stm32f3xx_hal_can.h"
#include "stm32f3xx_hal_gpio.h"
#include "ts_state_machine.h" #include "ts_state_machine.h"
#include "util.h"
#include "can-halal.h"
#include <stdint.h> #include <stdint.h>
static CAN_HandleTypeDef *hcan;
void can_init(CAN_HandleTypeDef *handle) { void can_init(CAN_HandleTypeDef *handle) {
hcan = handle; ftcan_init(handle);
ftcan_add_filter(CAN_ID_SHUNT_BASE, 0xFF0);
CAN_FilterTypeDef filter; ftcan_add_filter(CAN_ID_AMS_IN, 0xFFF);
filter.FilterIdHigh = CAN_ID_SHUNT_BASE & 0xFF0; ftcan_add_filter(CAN_ID_SLAVE_PANIC, 0xFFF);
filter.FilterMaskIdHigh = 0xFF0; ftcan_add_filter(CAN_ID_SLAVE_STATUS_BASE, 0xFF0);
filter.FilterIdLow = CAN_ID_AMS_IN; ftcan_add_filter(CAN_ID_SLAVE_LOG, 0xFFF);
filter.FilterMaskIdLow = 0xFFF;
filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
filter.FilterBank = 0;
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_16BIT;
if (HAL_CAN_ConfigFilter(hcan, &filter) != HAL_OK) {
Error_Handler();
}
// TODO: Slave status?
filter.FilterIdHigh = CAN_ID_SLAVE_PANIC;
filter.FilterMaskIdHigh = 0xFFF;
filter.FilterIdLow = CAN_ID_SLAVE_LOG;
filter.FilterMaskIdLow = 0xFFF;
filter.FilterBank = 1;
if (HAL_CAN_ConfigFilter(hcan, &filter) != HAL_OK) {
Error_Handler();
}
if (HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING) !=
HAL_OK) {
Error_Handler();
}
if (HAL_CAN_Start(hcan) != HAL_OK) {
Error_Handler();
}
}
HAL_StatusTypeDef can_transmit(uint8_t id, uint8_t *data, size_t datalen) {
static CAN_TxHeaderTypeDef header;
header.StdId = id;
header.IDE = CAN_ID_STD;
header.RTR = CAN_RTR_DATA;
header.DLC = datalen;
uint32_t mailbox;
return HAL_CAN_AddTxMessage(hcan, &header, data, &mailbox);
} }
HAL_StatusTypeDef can_send_status() { HAL_StatusTypeDef can_send_status() {
uint8_t data[4]; uint8_t data[6];
data[0] = ts_state.current_state; data[0] = ts_state.current_state | (sdc_closed << 7);
data[1] = current_soc; data[1] = current_soc;
data[2] = min_voltage >> 8; ftcan_marshal_unsigned(&data[2], min_voltage, 2);
data[3] = max_temp >> 8; ftcan_marshal_signed(&data[4], max_temp, 2);
return can_transmit(CAN_ID_AMS_STATUS, data, 4); return ftcan_transmit(CAN_ID_AMS_STATUS, data, sizeof(data));
} }
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *handle) { HAL_StatusTypeDef can_send_error(TSErrorKind kind, uint8_t arg) {
if (handle != hcan) { uint8_t data[2];
return; data[0] = kind;
data[1] = arg;
return ftcan_transmit(CAN_ID_AMS_ERROR, data, sizeof(data));
} }
CAN_RxHeaderTypeDef header; void ftcan_msg_received_cb(uint16_t id, size_t datalen, const uint8_t *data) {
uint8_t data[8]; if ((id & 0xFF0) == CAN_ID_SHUNT_BASE) {
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &header, data) != HAL_OK) { shunt_handle_can_msg(id, data);
set_error_led(); return;
} else if ((id & 0xFF0) == CAN_ID_SLAVE_STATUS_BASE) {
slaves_handle_status(data);
return; return;
} }
switch (id) {
if (header.IDE != CAN_ID_STD) {
return;
}
if ((header.StdId & 0xFF0) == CAN_ID_SHUNT_BASE) {
shunt_handle_can_msg(&header, data);
return;
}
switch (header.StdId) {
case CAN_ID_SLAVE_PANIC: case CAN_ID_SLAVE_PANIC:
slaves_handle_panic(data); slaves_handle_panic(data);
break; break;

View File

@ -50,12 +50,13 @@
/* Private variables ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc2; ADC_HandleTypeDef hadc2;
CAN_HandleTypeDef hcan; CAN_HandleTypeDef hcan;
UART_HandleTypeDef huart1; UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */ /* USER CODE BEGIN PV */
int sdc_closed = 0;
/* USER CODE END PV */ /* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
@ -70,7 +71,19 @@ static void MX_USART1_UART_Init(void);
/* Private user code ---------------------------------------------------------*/ /* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */ /* USER CODE BEGIN 0 */
#define MAIN_LOOP_PERIOD 50
static void loop_delay() {
static uint32_t last_loop = 0;
uint32_t dt = HAL_GetTick() - last_loop;
if (dt < MAIN_LOOP_PERIOD) {
HAL_Delay(MAIN_LOOP_PERIOD - dt);
HAL_GPIO_WritePin(STATUS2_GPIO_Port, STATUS2_Pin, GPIO_PIN_RESET);
} else {
HAL_GPIO_WritePin(STATUS2_GPIO_Port, STATUS2_Pin, GPIO_PIN_SET);
}
last_loop = HAL_GetTick();
}
/* USER CODE END 0 */ /* USER CODE END 0 */
/** /**
@ -79,7 +92,7 @@ static void MX_USART1_UART_Init(void);
*/ */
int main(void) { int main(void) {
/* USER CODE BEGIN 1 */ /* USER CODE BEGIN 1 */
uint8_t soc_init_complete = 0;
/* USER CODE END 1 */ /* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/ /* MCU Configuration--------------------------------------------------------*/
@ -109,7 +122,7 @@ int main(void) {
slaves_init(); slaves_init();
shunt_init(); shunt_init();
ts_sm_init(); ts_sm_init();
soc_init(); HAL_GPIO_WritePin(AMS_NERROR_GPIO_Port, AMS_NERROR_Pin, GPIO_PIN_SET);
/* USER CODE END 2 */ /* USER CODE END 2 */
/* Infinite loop */ /* Infinite loop */
@ -119,14 +132,23 @@ int main(void) {
/* USER CODE BEGIN 3 */ /* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(STATUS1_GPIO_Port, STATUS1_Pin); HAL_GPIO_TogglePin(STATUS1_GPIO_Port, STATUS1_Pin);
sdc_closed = HAL_GPIO_ReadPin(SDC_VOLTAGE_GPIO_Port, SDC_VOLTAGE_Pin) ==
GPIO_PIN_SET;
slaves_check(); slaves_check();
shunt_check(); shunt_check();
ts_sm_update(); ts_sm_update();
soc_update(); if(soc_init_complete){
soc_update(shunt_getcurrent());
}
else
{
soc_init();
soc_init_complete = 1;
}
can_send_status(); can_send_status();
loop_delay();
HAL_Delay(10);
} }
/* USER CODE END 3 */ /* USER CODE END 3 */
} }
@ -315,7 +337,8 @@ static void MX_GPIO_Init(void) {
SLAVE_POWER_1_Pin | SLAVE_POWER_DSEL_Pin | SLAVE_POWER_1_Pin | SLAVE_POWER_DSEL_Pin |
SLAVE_POWER_DEN_Pin | SLAVE_POWER_0_Pin | SLAVE_POWER_DEN_Pin | SLAVE_POWER_0_Pin |
POS_AIR_CTRL_Pin | NEG_AIR_CTRL_Pin | STATUS1_Pin | POS_AIR_CTRL_Pin | NEG_AIR_CTRL_Pin | STATUS1_Pin |
STATUS2_Pin | STATUS3_Pin | STATUS4_Pin | AMS_ERROR_Pin, STATUS2_Pin | STATUS3_Pin | STATUS4_Pin |
AMS_NERROR_Pin,
GPIO_PIN_RESET); GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */ /*Configure GPIO pin Output Level */
@ -340,11 +363,11 @@ static void MX_GPIO_Init(void) {
/*Configure GPIO pins : SLAVE_POWER_1_Pin SLAVE_POWER_DSEL_Pin /*Configure GPIO pins : SLAVE_POWER_1_Pin SLAVE_POWER_DSEL_Pin
SLAVE_POWER_DEN_Pin SLAVE_POWER_0_Pin POS_AIR_CTRL_Pin NEG_AIR_CTRL_Pin SLAVE_POWER_DEN_Pin SLAVE_POWER_0_Pin POS_AIR_CTRL_Pin NEG_AIR_CTRL_Pin
STATUS1_Pin STATUS2_Pin STATUS3_Pin STATUS4_Pin AMS_ERROR_Pin */ STATUS1_Pin STATUS2_Pin STATUS3_Pin STATUS4_Pin AMS_NERROR_Pin */
GPIO_InitStruct.Pin = SLAVE_POWER_1_Pin | SLAVE_POWER_DSEL_Pin | GPIO_InitStruct.Pin =
SLAVE_POWER_DEN_Pin | SLAVE_POWER_0_Pin | SLAVE_POWER_1_Pin | SLAVE_POWER_DSEL_Pin | SLAVE_POWER_DEN_Pin |
POS_AIR_CTRL_Pin | NEG_AIR_CTRL_Pin | STATUS1_Pin | SLAVE_POWER_0_Pin | POS_AIR_CTRL_Pin | NEG_AIR_CTRL_Pin | STATUS1_Pin |
STATUS2_Pin | STATUS3_Pin | STATUS4_Pin | AMS_ERROR_Pin; STATUS2_Pin | STATUS3_Pin | STATUS4_Pin | AMS_NERROR_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
@ -374,6 +397,9 @@ void Error_Handler(void) {
/* User can add his own implementation to report the HAL error return state */ /* User can add his own implementation to report the HAL error return state */
__disable_irq(); __disable_irq();
while (1) { while (1) {
ts_sm_set_relay_position(RELAY_NEG, 0);
ts_sm_set_relay_position(RELAY_POS, 0);
ts_sm_set_relay_position(RELAY_PRECHARGE, 0);
} }
/* USER CODE END Error_Handler_Debug */ /* USER CODE END Error_Handler_Debug */
} }

View File

@ -6,12 +6,14 @@
#include "ts_state_machine.h" #include "ts_state_machine.h"
#include "util.h" #include "util.h"
#include "can-halal.h"
ShuntData shunt_data; ShuntData shunt_data;
void shunt_init() { void shunt_init() {
shunt_data.current = 0; shunt_data.current = 0;
shunt_data.voltage1 = 0; shunt_data.voltage_veh = 0;
shunt_data.voltage2 = 0; shunt_data.voltage_bat = 0;
shunt_data.voltage3 = 0; shunt_data.voltage3 = 0;
shunt_data.busbartemp = 0; shunt_data.busbartemp = 0;
shunt_data.power = 0; shunt_data.power = 0;
@ -21,32 +23,35 @@ void shunt_init() {
} }
void shunt_check() { void shunt_check() {
int is_error = shunt_data.current >= THRESH_OVERCURRENT; int is_error = 0;
if (HAL_GetTick() - shunt_data.last_message > SHUNT_TIMEOUT) {
is_error = 1;
can_send_error(TS_ERRORKIND_SHUNT_TIMEOUT, 0);
} else if (shunt_data.current >= SHUNT_THRESH_OVERCURRENT) {
is_error = 1;
can_send_error(TS_ERRORKIND_SHUNT_OVERTEMP, 0);
} else if (shunt_data.busbartemp >= SHUNT_THRESH_OVERTEMP) {
is_error = 1;
can_send_error(TS_ERRORKIND_SHUNT_OVERTEMP, 0);
}
ts_sm_set_error_source(TS_ERROR_SOURCE_SHUNT, is_error); ts_sm_set_error_source(TS_ERROR_SOURCE_SHUNT, is_error);
} }
void shunt_handle_can_msg(CAN_RxHeaderTypeDef *header, uint8_t *data) { void shunt_handle_can_msg(uint16_t id, const uint8_t *data) {
// All result messages contain a big-endian 6-byte integer shunt_data.last_message = HAL_GetTick();
data[7] = 0;
data[8] = 0;
uint64_t result;
memcpy(&result, data, 8);
result = ntohll(result);
// Top two bytes should always be zero in our usecase (or 0xFF for a signed
// number)
if ((result >> 4) != 0 && (result >> 4) != 0xFFFF) {
set_error_led();
}
switch (header->StdId) { // All result messages contain a big-endian 6-byte integer
uint64_t result = ftcan_unmarshal_unsigned(&data, 6);
switch (id) {
case CAN_ID_SHUNT_CURRENT: case CAN_ID_SHUNT_CURRENT:
shunt_data.current = result; shunt_data.current = result;
break; break;
case CAN_ID_SHUNT_VOLTAGE1: case CAN_ID_SHUNT_VOLTAGE1:
shunt_data.voltage1 = result; shunt_data.voltage_bat = result;
break; break;
case CAN_ID_SHUNT_VOLTAGE2: case CAN_ID_SHUNT_VOLTAGE2:
shunt_data.voltage2 = result; shunt_data.voltage_veh = result;
break; break;
case CAN_ID_SHUNT_VOLTAGE3: case CAN_ID_SHUNT_VOLTAGE3:
shunt_data.voltage3 = result; shunt_data.voltage3 = result;
@ -65,3 +70,8 @@ void shunt_handle_can_msg(CAN_RxHeaderTypeDef *header, uint8_t *data) {
break; break;
} }
} }
int32_t shunt_getcurrent()
{
return shunt_data.current;
}

View File

@ -1,8 +1,14 @@
#include "slave_monitoring.h" #include "slave_monitoring.h"
#include "stm32f3xx_hal.h" #include "can.h"
#include "main.h"
#include "ts_state_machine.h" #include "ts_state_machine.h"
#include "can-halal.h"
#include "stm32f3xx_hal.h"
#include "stm32f3xx_hal_gpio.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -10,14 +16,43 @@ SlaveHandle slaves[N_SLAVES];
uint16_t min_voltage; uint16_t min_voltage;
int16_t max_temp; int16_t max_temp;
static uint8_t slave_id_to_index[128] = {0xFF};
static size_t get_slave_index(uint8_t slave_id) {
// Slave IDs are 7-bit, so we can use a 128-element array to map them to
// indices. 0xFF is used to mark unseen slave IDs, since the highest index we
// could need is N_SLAVES - 1 (i.e. 5).
static size_t next_slave_index = 0;
if (slave_id_to_index[slave_id] == 0xFF) {
if (next_slave_index >= N_SLAVES) {
// We've seen more than N_SLAVES slave IDs, this shouldn't happen.
Error_Handler();
}
slave_id_to_index[slave_id] = next_slave_index;
slaves[next_slave_index].id = slave_id;
next_slave_index++;
}
return slave_id_to_index[slave_id];
}
void slaves_init() { void slaves_init() {
memset(slave_id_to_index, 0xFF, sizeof(slave_id_to_index));
for (int i = 0; i < N_SLAVES; i++) { for (int i = 0; i < N_SLAVES; i++) {
slaves[i].id = i; slaves[i].id = 0xFF;
slaves[i].error.kind = SLAVE_ERR_NONE; slaves[i].error.kind = SLAVE_ERR_NONE;
slaves[i].last_message = 0; slaves[i].last_message = 0;
memset(&slaves[i].voltages, 0, sizeof(slaves[i].voltages)); slaves[i].min_voltage = 0;
memset(&slaves[i].temperatures, 0, sizeof(slaves[i].temperatures)); slaves[i].max_voltage = 0;
slaves[i].max_temp = 0;
} }
HAL_GPIO_WritePin(SLAVE_POWER_0_GPIO_Port, SLAVE_POWER_0_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SLAVE_POWER_1_GPIO_Port, SLAVE_POWER_1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(SLAVE_POWER_DSEL_GPIO_Port, SLAVE_POWER_DSEL_Pin,
GPIO_PIN_RESET);
// TODO: Enable & read out current
HAL_GPIO_WritePin(SLAVE_POWER_DEN_GPIO_Port, SLAVE_POWER_DEN_Pin,
GPIO_PIN_RESET);
} }
void slaves_check() { void slaves_check() {
@ -26,25 +61,23 @@ void slaves_check() {
uint16_t min_voltage_new = 0xFFFF; uint16_t min_voltage_new = 0xFFFF;
int16_t max_temp_new = 0xFFFF; int16_t max_temp_new = 0xFFFF;
for (int i = 0; i < N_SLAVES; i++) { for (int i = 0; i < N_SLAVES; i++) {
// Update timeout errors
if (now - slaves[i].last_message >= SLAVE_TIMEOUT) { if (now - slaves[i].last_message >= SLAVE_TIMEOUT) {
// Don't overwrite a different error kind // Don't overwrite a different error kind
if (slaves[i].error.kind == SLAVE_ERR_NONE) { if (slaves[i].error.kind == SLAVE_ERR_NONE) {
slaves[i].error.kind = SLAVE_ERR_TIMEOUT; slaves[i].error.kind = SLAVE_ERR_TIMEOUT;
can_send_error(TS_ERRORKIND_SLAVE_TIMEOUT, slaves[i].id);
} }
} else if (slaves[i].error.kind == SLAVE_ERR_TIMEOUT) { } else if (slaves[i].error.kind == SLAVE_ERR_TIMEOUT) {
slaves[i].error.kind = SLAVE_ERR_NONE; slaves[i].error.kind = SLAVE_ERR_NONE;
} }
for (int j = 0; j < N_CELLS_SERIES; j++) {
uint16_t v = slaves[i].voltages[j]; // Determine min/max
if (v < min_voltage_new) { if (slaves[i].min_voltage < min_voltage_new) {
min_voltage_new = v; min_voltage_new = slaves[i].min_voltage;
}
}
for (int j = 0; j < N_TEMP_SENSORS; j++) {
int16_t t = slaves[i].temperatures[j];
if (t > max_temp_new) {
max_temp_new = t;
} }
if (slaves[i].max_temp > max_temp_new) {
max_temp_new = slaves[i].max_temp;
} }
if (slaves[i].error.kind != SLAVE_ERR_NONE) { if (slaves[i].error.kind != SLAVE_ERR_NONE) {
@ -54,31 +87,63 @@ void slaves_check() {
min_voltage = min_voltage_new; min_voltage = min_voltage_new;
max_temp = max_temp_new; max_temp = max_temp_new;
if (any_slave_error) { ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, any_slave_error);
ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, 1);
}
} }
void slaves_handle_panic(uint8_t *data) { void slaves_handle_panic(const uint8_t *data) {
uint8_t slave_id = data[0]; uint8_t slave_id = ftcan_unmarshal_unsigned(&data, 1);
switch (data[1]) { uint8_t idx = get_slave_index(slave_id);
uint8_t error_kind = ftcan_unmarshal_unsigned(&data, 1);
switch (error_kind) {
case SLAVE_PANIC_OT: case SLAVE_PANIC_OT:
slaves[slave_id].error.kind = SLAVE_ERR_OT; slaves[idx].error.kind = SLAVE_ERR_OT;
break; break;
case SLAVE_PANIC_UT: case SLAVE_PANIC_UT:
slaves[slave_id].error.kind = SLAVE_ERR_UT; slaves[idx].error.kind = SLAVE_ERR_UT;
break; break;
case SLAVE_PANIC_OV: case SLAVE_PANIC_OV:
slaves[slave_id].error.kind = SLAVE_ERR_OV; slaves[idx].error.kind = SLAVE_ERR_OV;
break; break;
case SLAVE_PANIC_UV: case SLAVE_PANIC_UV:
slaves[slave_id].error.kind = SLAVE_ERR_UV; slaves[idx].error.kind = SLAVE_ERR_UV;
break; break;
} }
memcpy(&slaves[slave_id].error.data, &data[2], 4); slaves[idx].error.data = ftcan_unmarshal_unsigned(&data, 4);
slaves[slave_id].last_message = HAL_GetTick(); slaves[idx].last_message = HAL_GetTick();
ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, 1);
can_send_error(TS_ERRORKIND_SLAVE_PANIC, slave_id);
} }
void slaves_handle_log(uint8_t *data) { void slaves_handle_status(const uint8_t *data) {
uint8_t slave_id = data[0] & 0x7F;
uint8_t idx = get_slave_index(slave_id);
int error = data[0] & 0x80;
if (error) {
if (slaves[idx].error.kind == SLAVE_ERR_NONE) {
slaves[idx].error.kind = SLAVE_ERR_UNKNOWN;
}
} else {
slaves[idx].error.kind = SLAVE_ERR_NONE;
}
slaves[idx].soc = data[1];
const uint8_t *ptr = &data[2];
slaves[idx].min_voltage = ftcan_unmarshal_unsigned(&ptr, 2);
slaves[idx].max_voltage = ftcan_unmarshal_unsigned(&ptr, 2);
slaves[idx].max_temp = ftcan_unmarshal_unsigned(&ptr, 2);
slaves[idx].last_message = HAL_GetTick();
}
void slaves_handle_log(const uint8_t *data) {
// TODO // TODO
} }
uint16_t slaves_get_minimum_voltage()
{
uint16_t minvoltage = 50000;
for(uint8_t idx = 0; idx < N_SLAVES;idx++){
if(slaves->min_voltage < minvoltage){
min_voltage = slaves->min_voltage;
}
}
return minvoltage;
}

View File

@ -1,14 +1,118 @@
#include "soc_estimation.h" #include "soc_estimation.h"
#include <stdint.h> #include <stdint.h>
#include "slave_monitoring.h"
#include "stm32f3xx_hal.h"
//------------------------------------Battery RC and OCV-SoC Parameters-----------------------------------------
//@Note Parameters were obtained by EIS Measurements at the start of the season
//If the errror with this values is to large, consider retesting some cells
const float SOC[N_MODELPARAMETERS]={0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1};
const float R0[N_MODELPARAMETERS]={0.0089,0.0087,0.0090,0.0087,0.0087,0.0087,0.0088,0.0088,0.0087,0.0088,0.0089};
const float R1[N_MODELPARAMETERS]={0.0164,0.0063,0.0050,0.0055,0.0051,0.0052,0.0057,0.0048,0.0059,0.0055,0.0061};
const float C1[N_MODELPARAMETERS]={2.5694,0.2649,0.2876,0.2594,0.2415,0.2360,0.2946,0.2558,0.2818,0.2605,0.2763};
const float OCV_Data[N_MODELPARAMETERS]={2.762504,3.326231,3.460875,3.57681,3.655326,3.738444,3.835977,3.925841,4.032575,4.078275,4.191449};
const float SOE_Data[N_MODELPARAMETERS]={0.0,0.079358,0.165140,0.256008,0.348836,0.445961,0.549115,0.655642,0.769677,0.875699,1.0};
//---------------------------------------------------------------------------------------------------------------
float soc_approxparameterbysoc(float,float*, uint8_t);
float soc_approxsocbyocv(float);
uint8_t current_soc; uint8_t current_soc;
float current_floatsoc;
float batterycapacity;
/**
* @brief This Function initializes the SoC Prediction
* @note Because SoC is initalized using the OCV-Curve of the Cell, it is necessary to obtain a valid value
* for the lowest cell voltage before calling this function
*/
void soc_init() { void soc_init() {
current_soc = 0; float minvoltage = ((float)slaves_get_minimum_voltage())/1000;
// TODO current_floatsoc = soc_approxsocbyocv(minvoltage);
batterycapacity = BATTERYCAPACITYAs*current_floatsoc;
current_soc = (uint8_t)(current_floatsoc*100);
} }
void soc_update() { /**
* @brief Update Function for the State of Charge. Call this Function every time the shunt sends a new current
* @note The SoC Prediction works using a Coulomb Counter to track the SoC. Alternativly and maybe more elegant
* would be to track the SoC using the integrated current counter of the shunt.
* @param shunt_current
*/
void soc_update(int32_t shunt_current) {
// TODO // TODO
static uint32_t lasttick = 0;
if(lasttick != 0)
{
uint32_t dt = HAL_GetTick() - lasttick;
batterycapacity += batterycapacity + ((float) dt*shunt_current)/1000;
current_floatsoc = batterycapacity/BATTERYCAPACITYAs;
current_soc = (uint8_t) (current_floatsoc*100);
}
lasttick=HAL_GetTick();
}
float soe_update()
{
return soc_approxparameterbysoc(current_floatsoc, SOE_Data, N_MODELPARAMETERS);
}
void soap_update()
{
float r0 = soc_approxparameterbysoc(current_floatsoc, R0, N_MODELPARAMETERS);
float r1 = soc_approxparameterbysoc(current_floatsoc, R1, N_MODELPARAMETERS);
float ocv = soc_approxparameterbysoc(current_floatsoc, OCV_Data, N_MODELPARAMETERS);
float allowedvoltagedrop = ocv - SOAP_MINIMUM_VOLTAGE;
float rin = r0+r1;
float maxcurrent = allowedvoltagedrop/rin;
//TODO think about how to pass parameters
}
float soc_approxparameterbysoc(float soc,float* lut, uint8_t lutlen)
{
uint8_t idx = (uint8_t) (soc*(lutlen-1));
if(idx == (lutlen-1))
return lut[lutlen-1];
float linapprox = 10*(soc-(((float)idx)/((float)(lutlen-1))))*(lut[idx+1]-lut[idx]);
linapprox += lut[idx];
return linapprox;
}
float soc_approxsocbyocv(float ocv)
{
if(ocv < OCV_Data[0])
return 0;
if(ocv > OCV_Data[N_MODELPARAMETERS])
return 1;
//Iterate through OCV Lookup
uint8_t ocvindex = 0;
for(uint8_t i = 0; i < (N_MODELPARAMETERS-1);i++)
{
if((OCV_Data[i] <= ocv) && (OCV_Data[i+1] > ocv))
{
ocvindex = i;
}
}
float m = (ocv-OCV_Data[ocvindex])/(OCV_Data[ocvindex+1]-OCV_Data[ocvindex]);
float soc = (SOC[ocvindex+1] - SOC[ocvindex])*m + SOC[ocvindex];
return soc;
} }

View File

@ -74,6 +74,7 @@ void NMI_Handler(void)
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */ /* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1) while (1)
{ {
Error_Handler();
} }
/* USER CODE END NonMaskableInt_IRQn 1 */ /* USER CODE END NonMaskableInt_IRQn 1 */
} }
@ -89,6 +90,7 @@ void HardFault_Handler(void)
while (1) while (1)
{ {
/* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE BEGIN W1_HardFault_IRQn 0 */
Error_Handler();
/* USER CODE END W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */
} }
} }
@ -104,6 +106,7 @@ void MemManage_Handler(void)
while (1) while (1)
{ {
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
Error_Handler();
/* USER CODE END W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */
} }
} }
@ -119,6 +122,7 @@ void BusFault_Handler(void)
while (1) while (1)
{ {
/* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE BEGIN W1_BusFault_IRQn 0 */
Error_Handler();
/* USER CODE END W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */
} }
} }
@ -134,6 +138,7 @@ void UsageFault_Handler(void)
while (1) while (1)
{ {
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE BEGIN W1_UsageFault_IRQn 0 */
Error_Handler();
/* USER CODE END W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */
} }
} }

View File

@ -10,6 +10,7 @@ TSStateHandle ts_state;
static uint32_t precharge_95_reached_timestamp = 0; static uint32_t precharge_95_reached_timestamp = 0;
static uint32_t charging_check_timestamp = 0; static uint32_t charging_check_timestamp = 0;
static uint32_t discharge_begin_timestamp = 0;
void ts_sm_init() { void ts_sm_init() {
ts_state.current_state = TS_INACTIVE; ts_state.current_state = TS_INACTIVE;
@ -51,18 +52,27 @@ void ts_sm_update() {
TSState ts_sm_update_inactive() { TSState ts_sm_update_inactive() {
if (ts_state.target_state == TS_ACTIVE) { if (ts_state.target_state == TS_ACTIVE) {
if (sdc_closed) {
precharge_95_reached_timestamp = 0; precharge_95_reached_timestamp = 0;
return TS_PRECHARGE; return TS_PRECHARGE;
} else {
return TS_DISCHARGE;
}
} else if (ts_state.target_state == TS_CHARGING) { } else if (ts_state.target_state == TS_CHARGING) {
if (sdc_closed) {
charging_check_timestamp = HAL_GetTick(); charging_check_timestamp = HAL_GetTick();
return TS_CHARGING_CHECK; return TS_CHARGING_CHECK;
} else {
return TS_DISCHARGE;
}
} }
return TS_INACTIVE; return TS_INACTIVE;
} }
TSState ts_sm_update_active() { TSState ts_sm_update_active() {
if (ts_state.target_state == TS_INACTIVE) { if (ts_state.target_state == TS_INACTIVE || !sdc_closed) {
discharge_begin_timestamp = HAL_GetTick();
return TS_DISCHARGE; return TS_DISCHARGE;
} }
@ -70,15 +80,17 @@ TSState ts_sm_update_active() {
} }
TSState ts_sm_update_precharge() { TSState ts_sm_update_precharge() {
if (ts_state.target_state == TS_INACTIVE) { if (ts_state.target_state == TS_INACTIVE || !sdc_closed) {
discharge_begin_timestamp = HAL_GetTick();
return TS_DISCHARGE; return TS_DISCHARGE;
} }
if (shunt_data.voltage2 > MIN_VEHICLE_SIDE_VOLTAGE && if (shunt_data.voltage_veh > MIN_VEHICLE_SIDE_VOLTAGE &&
shunt_data.voltage2 > 0.95 * shunt_data.voltage3) { shunt_data.voltage_veh > 0.95 * shunt_data.voltage_bat) {
uint32_t now = HAL_GetTick(); uint32_t now = HAL_GetTick();
if (precharge_95_reached_timestamp == 0) { if (precharge_95_reached_timestamp == 0) {
precharge_95_reached_timestamp = now; precharge_95_reached_timestamp = now;
} else if (now - precharge_95_reached_timestamp >= PRECHARGE_95_DURATION) { } else if (now - precharge_95_reached_timestamp >= PRECHARGE_95_DURATION) {
precharge_95_reached_timestamp = 0;
return TS_ACTIVE; return TS_ACTIVE;
} }
} }
@ -87,8 +99,11 @@ TSState ts_sm_update_precharge() {
} }
TSState ts_sm_update_discharge() { TSState ts_sm_update_discharge() {
// TODO: Actually wait for discharge if (HAL_GetTick() - discharge_begin_timestamp >= DISCHARGE_DURATION) {
return TS_INACTIVE; return TS_INACTIVE;
} else {
return TS_DISCHARGE;
}
} }
TSState ts_sm_update_error() { TSState ts_sm_update_error() {
@ -98,19 +113,23 @@ TSState ts_sm_update_error() {
if (no_error_since == 0) { if (no_error_since == 0) {
no_error_since = now; no_error_since = now;
} else if (now - no_error_since > NO_ERROR_TIME) { } else if (now - no_error_since > NO_ERROR_TIME) {
no_error_since = 0;
HAL_GPIO_WritePin(AMS_NERROR_GPIO_Port, AMS_NERROR_Pin, GPIO_PIN_SET);
return TS_INACTIVE; return TS_INACTIVE;
} }
} }
HAL_GPIO_WritePin(AMS_NERROR_GPIO_Port, AMS_NERROR_Pin, GPIO_PIN_RESET);
return TS_ERROR; return TS_ERROR;
} }
TSState ts_sm_update_charging_check() { TSState ts_sm_update_charging_check() {
if (ts_state.target_state == TS_INACTIVE) { if (ts_state.target_state == TS_INACTIVE || !sdc_closed) {
discharge_begin_timestamp = HAL_GetTick();
return TS_DISCHARGE; return TS_DISCHARGE;
} }
if (shunt_data.voltage2 > shunt_data.voltage3) { if (shunt_data.voltage_veh > shunt_data.voltage_bat) {
return TS_CHARGING; return TS_CHARGING;
} else if (HAL_GetTick() - charging_check_timestamp > } else if (HAL_GetTick() - charging_check_timestamp >
MAX_CHARGING_CHECK_DURATION) { MAX_CHARGING_CHECK_DURATION) {
@ -121,7 +140,8 @@ TSState ts_sm_update_charging_check() {
} }
TSState ts_sm_update_charging() { TSState ts_sm_update_charging() {
if (ts_state.target_state == TS_INACTIVE) { if (ts_state.target_state == TS_INACTIVE || !sdc_closed) {
discharge_begin_timestamp = HAL_GetTick();
return TS_DISCHARGE; return TS_DISCHARGE;
} }
if (shunt_data.current < 0) { if (shunt_data.current < 0) {
@ -134,6 +154,7 @@ TSState ts_sm_update_charging() {
void ts_sm_set_relay_positions(TSState state) { void ts_sm_set_relay_positions(TSState state) {
switch (state) { switch (state) {
case TS_INACTIVE: case TS_INACTIVE:
case TS_DISCHARGE:
case TS_ERROR: case TS_ERROR:
ts_sm_set_relay_position(RELAY_NEG, 0); ts_sm_set_relay_position(RELAY_NEG, 0);
ts_sm_set_relay_position(RELAY_POS, 0); ts_sm_set_relay_position(RELAY_POS, 0);
@ -141,7 +162,6 @@ void ts_sm_set_relay_positions(TSState state) {
break; break;
case TS_ACTIVE: case TS_ACTIVE:
case TS_CHARGING: case TS_CHARGING:
case TS_DISCHARGE:
ts_sm_set_relay_position(RELAY_NEG, 1); ts_sm_set_relay_position(RELAY_NEG, 1);
ts_sm_set_relay_position(RELAY_POS, 1); ts_sm_set_relay_position(RELAY_POS, 1);
ts_sm_set_relay_position(RELAY_PRECHARGE, 1); ts_sm_set_relay_position(RELAY_PRECHARGE, 1);
@ -160,7 +180,6 @@ void ts_sm_set_relay_position(Relay relay, int closed) {
static int neg_closed = 0; static int neg_closed = 0;
static int pos_closed = 0; static int pos_closed = 0;
static int precharge_closed = 0; static int precharge_closed = 0;
static uint32_t last_close_timestamp = 0;
GPIO_PinState state = closed ? GPIO_PIN_SET : GPIO_PIN_RESET; GPIO_PinState state = closed ? GPIO_PIN_SET : GPIO_PIN_RESET;
switch (relay) { switch (relay) {
@ -193,7 +212,7 @@ void ts_sm_check_close_wait(int *is_closed, int should_close) {
} }
} }
void ts_sm_handle_ams_in(uint8_t *data) { void ts_sm_handle_ams_in(const uint8_t *data) {
if (data[0] & 0x01) { if (data[0] & 0x01) {
ts_state.target_state = TS_ACTIVE; ts_state.target_state = TS_ACTIVE;
} else { } else {

View File

@ -5,22 +5,3 @@
void set_error_led() { void set_error_led() {
HAL_GPIO_WritePin(STATUS2_GPIO_Port, STATUS2_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(STATUS2_GPIO_Port, STATUS2_Pin, GPIO_PIN_SET);
} }
uint64_t ntohll(uint64_t netlonglong) {
uint8_t *p = (uint8_t *)&netlonglong;
return ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) |
((uint64_t)p[2] << 40) | ((uint64_t)p[3] << 32) |
((uint64_t)p[4] << 24) | ((uint64_t)p[5] << 16) |
((uint64_t)p[6] << 8) | ((uint64_t)p[7] << 0);
}
uint32_t ntohl(uint32_t netlong) {
uint8_t *p = (uint8_t *)&netlong;
return ((uint32_t)p[3] << 24) | ((uint32_t)p[2] << 16) |
((uint32_t)p[1] << 8) | ((uint32_t)p[0] << 0);
}
uint16_t ntohs(uint16_t netshort) {
uint8_t *p = (uint8_t *)&netshort;
return ((uint16_t)p[1] << 8) | ((uint16_t)p[0] << 0);
}

View File

@ -1,5 +1,5 @@
########################################################################################################################## ##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [3.19.2] date: [Sun Mar 12 19:36:18 CET 2023] # File automatically-generated by tool: [projectgenerator] version: [3.19.2] date: [Sun Apr 02 01:03:50 CEST 2023]
########################################################################################################################## ##########################################################################################################################
# ------------------------------------------------ # ------------------------------------------------

View File

@ -10,7 +10,7 @@ target: ams-master-23
# Can be C or C++ # Can be C or C++
language: C language: C
optimization: Og optimization: O0 -Og
# MCU settings # MCU settings
targetMCU: stm32f3x targetMCU: stm32f3x
@ -23,6 +23,7 @@ ldscript: STM32F302CBTx_FLASH.ld # linker script
cDefinitions: cDefinitions:
- USE_HAL_DRIVER - USE_HAL_DRIVER
- STM32F302xC - STM32F302xC
- STM32F3
cxxDefinitions: cxxDefinitions:
- USE_HAL_DRIVER - USE_HAL_DRIVER
@ -45,7 +46,6 @@ assemblyFlags: []
linkerFlags: linkerFlags:
- -specs=nano.specs - -specs=nano.specs
# libraries to be included. The -l prefix to the library will be automatically added. # libraries to be included. The -l prefix to the library will be automatically added.
libraries: libraries:
- c - c
@ -66,7 +66,6 @@ excludes:
- "**/example/**" - "**/example/**"
- "**_template.*" - "**_template.*"
# Include directories (directories containing .h or .hpp files) # Include directories (directories containing .h or .hpp files)
# If a CubeMX makefile is present it will automatically include the include directories from that makefile. # If a CubeMX makefile is present it will automatically include the include directories from that makefile.
includeDirectories: includeDirectories:
@ -82,7 +81,6 @@ includeDirectories:
- Core/Src/** - Core/Src/**
- Core/Lib/** - Core/Lib/**
# Files that should be included in the compilation. # Files that should be included in the compilation.
# If a CubeMX makefile is present it will automatically include the c and cpp/cxx files from that makefile. # If a CubeMX makefile is present it will automatically include the c and cpp/cxx files from that makefile.
# Glob patterns (https://www.wikiwand.com/en/Glob_(programming)) can be used. # Glob patterns (https://www.wikiwand.com/en/Glob_(programming)) can be used.
@ -118,7 +116,6 @@ sourceFiles:
- Core/Src/** - Core/Src/**
- Core/Lib/** - Core/Lib/**
# When no makefile is present it will show a warning pop-up. # When no makefile is present it will show a warning pop-up.
# However when compilation without the CubeMX Makefile is desired, this can be turned of. # However when compilation without the CubeMX Makefile is desired, this can be turned of.
suppressMakefileWarning: false suppressMakefileWarning: false
@ -135,4 +132,3 @@ customMakefileRules:
makeFlags: makeFlags:
# - -O # use this option when the output of make is mixed up only works for make version 4.0 and upwards # - -O # use this option when the output of make is mixed up only works for make version 4.0 and upwards
# - --silent # use this option to silence the output of the build # - --silent # use this option to silence the output of the build

View File

@ -22,7 +22,7 @@ TARGET = ams-master-23
# debug build? # debug build?
DEBUG = 1 DEBUG = 1
# optimization # optimization
OPT = -Og OPT = -O0 -Og
####################################### #######################################
@ -36,6 +36,7 @@ BUILD_DIR = build
###################################### ######################################
# C sources # C sources
C_SOURCES = \ C_SOURCES = \
Core/Lib/can-halal/can-halal.c \
Core/Src/can.c \ Core/Src/can.c \
Core/Src/main.c \ Core/Src/main.c \
Core/Src/shunt_monitoring.c \ Core/Src/shunt_monitoring.c \
@ -84,7 +85,7 @@ PREFIX = arm-none-eabi-
POSTFIX = " POSTFIX = "
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx) # The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable. # either it can be added to the PATH environment variable.
GCC_PATH="/home/jasper/.config/Code/User/globalStorage/bmd.stm32-for-vscode/@xpack-dev-tools/arm-none-eabi-gcc/11.3.1-1.1.2/.content/bin GCC_PATH="c:/Users/max/AppData/Roaming/Code/User/globalStorage/bmd.stm32-for-vscode/@xpack-dev-tools/arm-none-eabi-gcc/11.2.1-1.2.2/.content/bin
ifdef GCC_PATH ifdef GCC_PATH
CXX = $(GCC_PATH)/$(PREFIX)g++$(POSTFIX) CXX = $(GCC_PATH)/$(PREFIX)g++$(POSTFIX)
CC = $(GCC_PATH)/$(PREFIX)gcc$(POSTFIX) CC = $(GCC_PATH)/$(PREFIX)gcc$(POSTFIX)
@ -122,6 +123,7 @@ AS_DEFS =
# C defines # C defines
C_DEFS = \ C_DEFS = \
-DSTM32F3 \
-DSTM32F302xC \ -DSTM32F302xC \
-DUSE_HAL_DRIVER -DUSE_HAL_DRIVER
@ -138,6 +140,7 @@ AS_INCLUDES = \
# C includes # C includes
C_INCLUDES = \ C_INCLUDES = \
-ICore/Inc \ -ICore/Inc \
-ICore/Lib/can-halal \
-IDrivers/CMSIS/Device/ST/STM32F3xx/Include \ -IDrivers/CMSIS/Device/ST/STM32F3xx/Include \
-IDrivers/CMSIS/Include \ -IDrivers/CMSIS/Include \
-IDrivers/STM32F3xx_HAL_Driver/Inc \ -IDrivers/STM32F3xx_HAL_Driver/Inc \
@ -196,8 +199,14 @@ vpath %.cpp $(sort $(dir $(CPP_SOURCES)))
# list of C objects # list of C objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o))) OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES))) vpath %.c $(sort $(dir $(C_SOURCES)))
# list of ASM program objects # list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o))) # list of ASM program objects
UPPER_CASE_ASM_SOURCES = $(filter %.S,$(ASM_SOURCES))
LOWER_CASE_ASM_SOURCES = $(filter %.s,$(ASM_SOURCES))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(UPPER_CASE_ASM_SOURCES:.S=.o)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(LOWER_CASE_ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES))) vpath %.s $(sort $(dir $(ASM_SOURCES)))
$(BUILD_DIR)/%.o: %.cpp STM32Make.make | $(BUILD_DIR) $(BUILD_DIR)/%.o: %.cpp STM32Make.make | $(BUILD_DIR)
@ -212,6 +221,9 @@ $(BUILD_DIR)/%.o: %.c STM32Make.make | $(BUILD_DIR)
$(BUILD_DIR)/%.o: %.s STM32Make.make | $(BUILD_DIR) $(BUILD_DIR)/%.o: %.s STM32Make.make | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@ $(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/%.o: %.S STM32Make.make | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) STM32Make.make $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) STM32Make.make
$(CC) $(OBJECTS) $(LDFLAGS) -o $@ $(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@ $(SZ) $@
@ -229,19 +241,19 @@ $(BUILD_DIR):
# flash # flash
####################################### #######################################
flash: $(BUILD_DIR)/$(TARGET).elf flash: $(BUILD_DIR)/$(TARGET).elf
"/home/jasper/.config/Code/User/globalStorage/bmd.stm32-for-vscode/@xpack-dev-tools/openocd/0.11.0-5.1/.content/bin/openocd" -f ./openocd.cfg -c "program $(BUILD_DIR)/$(TARGET).elf verify reset exit" "C:/USERS/MAX/APPDATA/ROAMING/CODE/USER/GLOBALSTORAGE/BMD.STM32-FOR-VSCODE/@XPACK-DEV-TOOLS/OPENOCD/0.11.0-4.1/.CONTENT/BIN/OPENOCD.EXE" -f ./openocd.cfg -c "program $(BUILD_DIR)/$(TARGET).elf verify reset exit"
####################################### #######################################
# erase # erase
####################################### #######################################
erase: $(BUILD_DIR)/$(TARGET).elf erase: $(BUILD_DIR)/$(TARGET).elf
"/home/jasper/.config/Code/User/globalStorage/bmd.stm32-for-vscode/@xpack-dev-tools/openocd/0.11.0-5.1/.content/bin/openocd" -f ./openocd.cfg -c "init; reset halt; stm32f3x mass_erase 0; exit" "C:/USERS/MAX/APPDATA/ROAMING/CODE/USER/GLOBALSTORAGE/BMD.STM32-FOR-VSCODE/@XPACK-DEV-TOOLS/OPENOCD/0.11.0-4.1/.CONTENT/BIN/OPENOCD.EXE" -f ./openocd.cfg -c "init; reset halt; stm32f3x mass_erase 0; exit"
####################################### #######################################
# clean up # clean up
####################################### #######################################
clean: clean:
-rm -fR $(BUILD_DIR) cmd /c rd /s /q $(BUILD_DIR)
####################################### #######################################
# custom makefile rules # custom makefile rules

View File

@ -185,7 +185,7 @@ PB7.GPIO_Label=STATUS4
PB7.Locked=true PB7.Locked=true
PB7.Signal=GPIO_Output PB7.Signal=GPIO_Output
PB8.GPIOParameters=GPIO_Label PB8.GPIOParameters=GPIO_Label
PB8.GPIO_Label=AMS_ERROR PB8.GPIO_Label=AMS_NERROR
PB8.Locked=true PB8.Locked=true
PB8.Signal=GPIO_Output PB8.Signal=GPIO_Output
PF0-OSC_IN.Mode=HSE-External-Oscillator PF0-OSC_IN.Mode=HSE-External-Oscillator