/* * 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 #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); } } }