208 lines
6.6 KiB
C
208 lines
6.6 KiB
C
/*
|
|
* can.h
|
|
*
|
|
* Created on: 07.07.2024
|
|
* Author: Hamza
|
|
*/
|
|
|
|
#include "can.h"
|
|
#include "AMS_HighLevel.h"
|
|
#include "PWM_control.h"
|
|
#include "TMP1075.h"
|
|
#include "can-halal.h"
|
|
#include "eeprom.h"
|
|
#include "soc_estimation.h"
|
|
#include "state_machine.h"
|
|
#include "stm32f3xx_hal.h"
|
|
#include "stm32f3xx_hal_def.h"
|
|
#include <stdint.h>
|
|
|
|
#define CAN_ID_IN 0x501
|
|
#define CAN_ID_OUT 0x502
|
|
#define CAN_ID_LOG 0x503
|
|
|
|
// Every X ms, send message
|
|
#define CAN_STATUS_FREQ 1000
|
|
#define CAN_LOGGING_FREQ 200
|
|
#define CAN_DUMP_FREQ 10
|
|
// Delay between the resets of last_message
|
|
#define CAN_RESET_DELAY 5000
|
|
// Max time to wait for CAN messages. If we reach it then we target state is set to STATE_ERROR.
|
|
#define CAN_TIMEOUT 10000
|
|
|
|
uint8_t id_to_log;
|
|
uint8_t last_message[8];
|
|
uint32_t can_status_timer, can_log_timer, can_timeout_timer, can_reset_timer;
|
|
|
|
void can_init(CAN_HandleTypeDef* hcan) {
|
|
ftcan_init(hcan);
|
|
ftcan_add_filter(CAN_ID_IN, 0xFFF);
|
|
last_message[0] = -1;
|
|
last_message[1] = -1;
|
|
can_status_timer = HAL_GetTick() + CAN_STATUS_FREQ;
|
|
can_log_timer = HAL_GetTick() + CAN_LOGGING_FREQ;
|
|
can_timeout_timer = HAL_GetTick() + CAN_TIMEOUT;
|
|
can_reset_timer = HAL_GetTick() + CAN_RESET_DELAY;
|
|
id_to_log = 0;
|
|
}
|
|
|
|
/*
|
|
This function sends the status of the mvbms, the battery and of powerground.
|
|
once every 1s in states: INACTIVE, PRECHARGE, DISCHARGE, CHARGING, ERROR.
|
|
once every 0.5s in states: READY, ACTIVE.
|
|
with format of:
|
|
CAN Messages:
|
|
Error bit
|
|
MVBMS state
|
|
Powerground Status 0-100%
|
|
Errors
|
|
Battery state of charge
|
|
Pack Voltage
|
|
Current
|
|
Battery temperature (12 bit)
|
|
|
|
Min/Max. Cell Temp (ID, Min Temp, ID, Max Temp)(3B),
|
|
Min/Max Cell Voltage (ID, Min Voltage, ID, Max Voltage)(3B)
|
|
|
|
bit 0 (1b): empty
|
|
bit 1-3 (3b): state
|
|
bit 4-11 (8b): powerground status
|
|
bit 12-19 (8b): error
|
|
bit 20-27 (8b): state of charge from 0-100%
|
|
bit 28-39 (12b): battery voltage
|
|
bit 40-51 (12b): current measurement
|
|
bit 52-63 (12b): temperature of the cell with highest temperature
|
|
|
|
|
|
bit 0-3 (4b): ID of the sensor with highest temperature
|
|
bit 4-7 (4b): ID of the sensor with lowest temperataure
|
|
bit 8-19 (12b): temperature of the coldest cell
|
|
bit 20-23 (4b): ID of the cell with the lowest voltage
|
|
bit 24-35 (12b): lowest cell voltage
|
|
bit 36-39 (4b): ID of the cell the the highest voltage
|
|
bit 40-51 (12b): highest cell voltage
|
|
bit 52-63 (12b): empty
|
|
*/
|
|
|
|
void can_handle_send_status() {
|
|
if (can_status_timer > HAL_GetTick())
|
|
return;
|
|
else {
|
|
uint8_t data[8] = {};
|
|
can_status_timer = HAL_GetTick() + CAN_STATUS_FREQ;
|
|
|
|
uint8_t id_highest_temp = 0;
|
|
uint16_t highest_temp = 0;
|
|
sm_check_battery_temperature(&id_highest_temp, &highest_temp);
|
|
|
|
data[0] = (state.current_state); // 8 bit state (only 3 are use)
|
|
data[1] = (current_powerground_status); // 8 bit powerground
|
|
data[2] = (state.error_source); // 8 bit error
|
|
data[3] = ((int) current_soc); // 8 bit state of charge
|
|
data[4] = (roundf(RELAY_BAT_SIDE_VOLTAGE / 1000.0)); // 8 bit battery voltage
|
|
data[5] = (roundf(RELAY_ESC_SIDE_VOLTAGE / 1000.0)); // 8 bit Inverter voltage
|
|
data[6] = (roundf(CURRENT_MEASUREMENT / 1000.0)); // 8 bit Current
|
|
data[7] = ((highest_temp) >> 4); // 8 bit highest cell temperature
|
|
//data[7] = state.error_source;
|
|
ftcan_transmit(CAN_ID_OUT, data, sizeof(data));
|
|
}
|
|
}
|
|
|
|
void can_handle_send_log(){
|
|
if (can_log_timer > HAL_GetTick())
|
|
return;
|
|
else {
|
|
uint8_t data[4] = {};
|
|
can_log_timer = HAL_GetTick() + CAN_LOGGING_FREQ;
|
|
data[0] = id_to_log;
|
|
data[1] = module.cellVoltages[id_to_log] >> 8;
|
|
data[2] = module.cellVoltages[id_to_log];
|
|
data[3] = tmp1075_temps[id_to_log] >> 4;
|
|
ftcan_transmit(CAN_ID_LOG, data, 4);
|
|
id_to_log++;
|
|
if (id_to_log == 13)
|
|
id_to_log = 0;
|
|
}
|
|
/*
|
|
021E 30
|
|
0232 50
|
|
0238 60
|
|
0246 70
|
|
0250 80
|
|
025A 90
|
|
0264 100
|
|
*/
|
|
}
|
|
|
|
/*
|
|
can_handle_recieve_command() should only check if the message is valid and then hand it
|
|
to the sm_handle_ams_in() which handles the state machine transition.
|
|
|
|
This function recieves a command from the Autobox with the CAN ID of 0x501.
|
|
with format of:
|
|
data[0] = target state
|
|
0x00 STATE_INACTIVE | disconnect power to the ESC of powerground. Send it to return the mvbms to idle/monitoring mode. If data[1] != 0 -> assume bad CAN message.
|
|
0x01 STATE_READY | connect power to the ESC of powerground and but with no PWM signal. If data[1] != 0 -> assume bad CAN message.
|
|
0x02 STATE_ACTIVE | activate powerground at (data[1]) percent. If data[1] > 100 -> assume bad CAN message.
|
|
|
|
allowed transitions:
|
|
STATE_INACTIVE -> STATE_READY
|
|
STATE_READY -> STATE_INACTIVE, STATE_ACTIVE
|
|
STATE_ACTIVE -> STATE_INACTIVE, STATE_READY
|
|
*/
|
|
void can_handle_recieve_command(const uint8_t *data){
|
|
if (data[0] == 0x00){
|
|
sm_handle_ams_in(data);
|
|
} else if (data[0] == 0x01 && data[1] == 0x00){
|
|
sm_handle_ams_in(data);
|
|
} else if (data[0] == 0x02 && data[1] <= 100) {
|
|
sm_handle_ams_in(data);
|
|
} else if (data[0] == 0xF0 && data[1] == 0x00) {
|
|
sm_handle_ams_in(data);
|
|
} else if (data[0] == 0xF1 && data[1] == 0x00) {
|
|
//sm_handle_ams_in(data);
|
|
} else if (data[0] == 0xFF && data[1] == 0x00) {
|
|
//sm_handle_ams_in(data);
|
|
}
|
|
}
|
|
|
|
void can_handle_dump() {
|
|
uint8_t* data = {};
|
|
HAL_StatusTypeDef status = HAL_OK;
|
|
while (status == HAL_OK){
|
|
HAL_Delay(2);
|
|
eeprom_read(data, 62);
|
|
for (int i = 0; i < (EEPROM_MEMORY_SIZE-8)/8; i += 8) {
|
|
ftcan_transmit(CAN_ID_OUT, &data[i], 8);
|
|
}
|
|
ftcan_transmit(CAN_ID_OUT, &data[56], 6);
|
|
}
|
|
read_address = 0;
|
|
}
|
|
|
|
/*
|
|
implements the _weak method ftcan_msg_recieved_cb() which throws an interrupt when a CAN message is recieved.
|
|
it only checks if the id is and datalen is correct thans hands data over to can_handle_recieve_command().
|
|
|
|
in MXCUBE under CAN NVIC settings "USB low priority or CAN_RX0 interrupts" has to be on
|
|
*/
|
|
void ftcan_msg_received_cb(uint16_t id, size_t datalen, const uint8_t *data){
|
|
if (programming_mode == 1){
|
|
can_handle_recieve_command(data);
|
|
return;
|
|
}
|
|
|
|
if (id == 0x501 && datalen == 2){
|
|
can_timeout_timer = HAL_GetTick() + CAN_TIMEOUT;
|
|
if (state.current_state == STATE_ERROR){
|
|
last_message[0] = 0;
|
|
last_message[1] = 0;
|
|
}
|
|
if (last_message[0] != data[0] || last_message[1] != data[1]){
|
|
last_message[0] = data[0];
|
|
last_message[1] = data[1];
|
|
can_handle_recieve_command(data);
|
|
}
|
|
}
|
|
}
|