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);
}
}
}