Import Master_Control code
This commit is contained in:
263
Core/Src/AIR_State_Maschine.c
Normal file
263
Core/Src/AIR_State_Maschine.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* AIR_State_Maschine.c
|
||||
*
|
||||
* Created on: Jun 15, 2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "AIR_State_Maschine.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include "stm32g4xx_hal.h"
|
||||
#include "stm32g4xx_hal_gpio.h"
|
||||
|
||||
DMA_HandleTypeDef* air_current_dma = {0};
|
||||
DMA_HandleTypeDef* sdc_voltage_dma = {0};
|
||||
|
||||
uint8_t air_adc_complete = 0;
|
||||
uint8_t sdc_adc_complete = 0;
|
||||
|
||||
static uint32_t pos_air_change_timestamp, neg_air_change_timestamp,
|
||||
precharge_change_timestamp;
|
||||
static GPIO_PinState neg_air_state, pos_air_state, precharge_state;
|
||||
|
||||
AIRStateHandler init_AIR_State_Maschine() {
|
||||
AIRStateHandler airstate = {0};
|
||||
|
||||
airstate.targetTSState = TS_INACTIVE;
|
||||
airstate.currentTSState = TS_INACTIVE;
|
||||
airstate.BatteryVoltageBatterySide = 0;
|
||||
airstate.BatteryVoltageVehicleSide = 0;
|
||||
|
||||
return airstate;
|
||||
}
|
||||
|
||||
void Update_AIR_Info(AIRStateHandler* airstate) {
|
||||
uint16_t relay_adc_buffer[4] = {0};
|
||||
uint16_t sdc_adc_buffer[1] = {0};
|
||||
|
||||
/*//HAL_ADC_Start_DMA(air_current_adc, (uint32_t*)relay_adc_buffer, 4);
|
||||
//HAL_ADC_Start_DMA(sdc_voltage_adc, (uint32_t*)sdc_adc_buffer, 1);
|
||||
HAL_ADC_Start(sdc_voltage_adc);
|
||||
HAL_StatusTypeDef status = HAL_ADC_PollForConversion(sdc_voltage_adc, 10);
|
||||
uint32_t adcval1 = HAL_ADC_GetValue(sdc_voltage_adc);
|
||||
HAL_ADC_Stop(sdc_voltage_adc);
|
||||
|
||||
HAL_ADC_Start(air_current_adc);
|
||||
status = HAL_ADC_PollForConversion(air_current_adc, 10);
|
||||
uint32_t adcval2 = HAL_ADC_GetValue(air_current_adc);
|
||||
HAL_ADC_Start(air_current_adc);
|
||||
status = HAL_ADC_PollForConversion(air_current_adc, 10);
|
||||
uint32_t adcval3 = HAL_ADC_GetValue(air_current_adc);
|
||||
HAL_ADC_Start(air_current_adc);
|
||||
status = HAL_ADC_PollForConversion(air_current_adc, 10);
|
||||
uint32_t adcval4 = HAL_ADC_GetValue(air_current_adc);
|
||||
HAL_ADC_Start(air_current_adc);
|
||||
status = HAL_ADC_PollForConversion(air_current_adc, 10);
|
||||
uint32_t adcval5 = HAL_ADC_GetValue(air_current_adc);
|
||||
HAL_ADC_Stop(air_current_adc);*/
|
||||
}
|
||||
|
||||
uint8_t Update_AIR_State(AIRStateHandler* airstate) {
|
||||
Update_AIR_Info(airstate);
|
||||
|
||||
//--------------------------------------------------State Transition
|
||||
// Rules----------------------------------------------------------
|
||||
|
||||
/*if(airstate->currentTSState == airstate->targetTSState) //Target TS
|
||||
State is Equal to actual TS State
|
||||
{
|
||||
return airstate->currentTSState;
|
||||
}*/
|
||||
|
||||
if (airstate->currentTSState == TS_ERROR) // No Escape from TS Error State
|
||||
{
|
||||
// Don't change anything, but prevent any other if from being entered
|
||||
}
|
||||
|
||||
else if (airstate->targetTSState ==
|
||||
TS_ERROR) // Error State is Entered if Target State is Error State
|
||||
{
|
||||
airstate->currentTSState = TS_ERROR;
|
||||
}
|
||||
|
||||
else if ((airstate->currentTSState == TS_INACTIVE) &&
|
||||
(airstate->targetTSState ==
|
||||
TS_ACTIVE)) // Transition from Inactive to Active via Precharge
|
||||
{
|
||||
airstate->currentTSState = TS_PRECHARGE;
|
||||
airstate->precharge95ReachedTimestamp = 0;
|
||||
}
|
||||
|
||||
else if ((airstate->currentTSState == TS_INACTIVE) &&
|
||||
(airstate->targetTSState == TS_CHARGING)) {
|
||||
airstate->currentTSState = TS_CHARGING_CHECK;
|
||||
airstate->chargingCheckTimestamp = HAL_GetTick();
|
||||
}
|
||||
|
||||
// TODO: Is it correct that we also go from precharge to discharge?
|
||||
else if ((airstate->currentTSState == TS_ACTIVE ||
|
||||
airstate->currentTSState == TS_PRECHARGE ||
|
||||
airstate->currentTSState == TS_CHARGING_CHECK ||
|
||||
airstate->currentTSState == TS_CHARGING) &&
|
||||
(airstate->targetTSState ==
|
||||
TS_INACTIVE)) // Transition from Active to Inactive via Discharge
|
||||
{
|
||||
airstate->currentTSState = TS_DISCHARGE;
|
||||
}
|
||||
|
||||
else if ((airstate->targetTSState == TS_CHARGING) &&
|
||||
(airstate->currentTSState == TS_CHARGING_CHECK)) {
|
||||
if (airstate->BatteryVoltageVehicleSide >
|
||||
airstate->BatteryVoltageBatterySide) {
|
||||
airstate->currentTSState = TS_CHARGING;
|
||||
} else if (HAL_GetTick() > airstate->chargingCheckTimestamp + 2000) {
|
||||
airstate->currentTSState = TS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
else if (airstate->currentTSState == TS_CHARGING) {
|
||||
if (airstate->shuntCurrent < 0) {
|
||||
airstate->currentTSState = TS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
else if (airstate->currentTSState ==
|
||||
TS_PRECHARGE) // Change from Precharge to Active at 95% TS Voltage at
|
||||
// Vehicle Side
|
||||
{
|
||||
if ((airstate->BatteryVoltageVehicleSide >
|
||||
LOWER_VEHICLE_SIDE_VOLTAGE_LIMIT)) {
|
||||
if (airstate->BatteryVoltageVehicleSide >
|
||||
(airstate->BatteryVoltageBatterySide * 0.95)) {
|
||||
if (airstate->precharge95ReachedTimestamp == 0) {
|
||||
airstate->precharge95ReachedTimestamp = HAL_GetTick();
|
||||
} else if (HAL_GetTick() - airstate->precharge95ReachedTimestamp >=
|
||||
PRECHARGE_95_DURATION) {
|
||||
airstate->currentTSState = TS_ACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (airstate->currentTSState ==
|
||||
TS_DISCHARGE) // Change from Discharge to Inactive at 95% TS
|
||||
// Voltage at Vehicle Side
|
||||
{
|
||||
airstate->currentTSState = TS_INACTIVE;
|
||||
}
|
||||
|
||||
//_-----------------------------------------------AIR
|
||||
// Positions--------------------------------------------------------
|
||||
|
||||
if (airstate->currentTSState == TS_PRECHARGE) {
|
||||
AIR_Precharge_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_DISCHARGE) {
|
||||
AIR_Discharge_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_CHARGING_CHECK) {
|
||||
AIR_Precharge_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_CHARGING) {
|
||||
AIR_Active_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_ACTIVE) {
|
||||
AIR_Active_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_INACTIVE) {
|
||||
AIR_Inactive_Position();
|
||||
}
|
||||
|
||||
if (airstate->currentTSState == TS_ERROR) {
|
||||
AIR_Error_Position();
|
||||
}
|
||||
|
||||
return airstate->currentTSState;
|
||||
}
|
||||
|
||||
void Activate_TS(AIRStateHandler* airstate) {
|
||||
airstate->targetTSState = TS_ACTIVE;
|
||||
}
|
||||
|
||||
void Deactivate_TS(AIRStateHandler* airstate) {
|
||||
airstate->targetTSState = TS_INACTIVE;
|
||||
}
|
||||
|
||||
void AIR_Precharge_Position() {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_SET);
|
||||
Set_Relay_Position(RELAY_AIR_NEG, GPIO_PIN_SET);
|
||||
Set_Relay_Position(RELAY_AIR_POS, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void AIR_Inactive_Position() {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_RESET);
|
||||
Set_Relay_Position(RELAY_AIR_NEG, GPIO_PIN_RESET);
|
||||
Set_Relay_Position(RELAY_AIR_POS, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void AIR_Discharge_Position() {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_SET);
|
||||
Set_Relay_Position(RELAY_AIR_NEG, GPIO_PIN_SET);
|
||||
Set_Relay_Position(RELAY_AIR_POS, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void AIR_Active_Position() {
|
||||
if (pos_air_state == GPIO_PIN_SET &&
|
||||
HAL_GetTick() - pos_air_change_timestamp > PRECHARGE_OPEN_AFTER) {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_RESET);
|
||||
} else {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_SET);
|
||||
}
|
||||
Set_Relay_Position(RELAY_AIR_NEG, GPIO_PIN_SET);
|
||||
Set_Relay_Position(RELAY_AIR_POS, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
void AIR_Error_Position() {
|
||||
Set_Relay_Position(RELAY_PRECHARGE, GPIO_PIN_RESET);
|
||||
Set_Relay_Position(RELAY_AIR_NEG, GPIO_PIN_RESET);
|
||||
Set_Relay_Position(RELAY_AIR_POS, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void Set_Relay_Position(Relay relay, GPIO_PinState position) {
|
||||
// Add a small delay after closing relays in order to not draw too much
|
||||
// current
|
||||
switch (relay) {
|
||||
case RELAY_AIR_NEG:
|
||||
HAL_GPIO_WritePin(NEG_AIR_CTRL_GPIO_Port, NEG_AIR_CTRL_Pin, position);
|
||||
if (position != neg_air_state) {
|
||||
neg_air_change_timestamp = HAL_GetTick();
|
||||
}
|
||||
if (position == GPIO_PIN_SET && neg_air_state == GPIO_PIN_RESET) {
|
||||
HAL_Delay(10);
|
||||
}
|
||||
neg_air_state = position;
|
||||
break;
|
||||
case RELAY_AIR_POS:
|
||||
HAL_GPIO_WritePin(POS_AIR_CTRL_GPIO_Port, POS_AIR_CTRL_Pin, position);
|
||||
if (position != pos_air_state) {
|
||||
pos_air_change_timestamp = HAL_GetTick();
|
||||
}
|
||||
if (position == GPIO_PIN_SET && pos_air_state == GPIO_PIN_RESET) {
|
||||
HAL_Delay(10);
|
||||
}
|
||||
pos_air_state = position;
|
||||
break;
|
||||
case RELAY_PRECHARGE:
|
||||
HAL_GPIO_WritePin(PRECHARGE_CTRL_GPIO_Port, PRECHARGE_CTRL_Pin, position);
|
||||
if (position != precharge_state) {
|
||||
precharge_change_timestamp = HAL_GetTick();
|
||||
}
|
||||
if (position == GPIO_PIN_SET && precharge_state == GPIO_PIN_RESET) {
|
||||
HAL_Delay(10);
|
||||
}
|
||||
precharge_state = position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
210
Core/Src/CAN_Communication.c
Normal file
210
Core/Src/CAN_Communication.c
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* CAN_Communication.c
|
||||
*
|
||||
* Created on: Apr 26, 2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "CAN_Communication.h"
|
||||
|
||||
#include "Error_Check.h"
|
||||
|
||||
#include "stm32g4xx_hal_fdcan.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
const uint16_t slave_CAN_id_to_slave_index[10] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 255, 8}; // TODO: Make this pretty pls
|
||||
canFrame framebuffer[CANFRAMEBUFFERSIZE] = {0};
|
||||
uint32_t framebufferwritepointer = 0;
|
||||
uint32_t framebufferreadpointer = 0;
|
||||
uint32_t frames_read = 0;
|
||||
|
||||
void CAN_Init(FDCAN_HandleTypeDef* hcan) {
|
||||
HAL_FDCAN_Stop(hcan);
|
||||
|
||||
framebufferreadpointer = 0;
|
||||
framebufferwritepointer = 0;
|
||||
|
||||
FDCAN_FilterTypeDef fdfilter = {0};
|
||||
|
||||
fdfilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
||||
fdfilter.FilterID1 = 0x000; // ID
|
||||
fdfilter.FilterID2 = 0x000; // Mask
|
||||
fdfilter.FilterIndex = 0;
|
||||
|
||||
fdfilter.FilterType = FDCAN_FILTER_MASK;
|
||||
fdfilter.IdType = FDCAN_STANDARD_ID;
|
||||
|
||||
HAL_FDCAN_ConfigFilter(hcan, &fdfilter);
|
||||
|
||||
HAL_StatusTypeDef status = HAL_FDCAN_Start(hcan);
|
||||
|
||||
if (status) {
|
||||
return;
|
||||
}
|
||||
|
||||
status =
|
||||
HAL_FDCAN_ActivateNotification(hcan, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
|
||||
}
|
||||
|
||||
uint8_t CAN_Receive(FDCAN_HandleTypeDef* hcan) {
|
||||
frames_read = 0;
|
||||
while (framebufferreadpointer != framebufferwritepointer) {
|
||||
framebufferreadpointer++;
|
||||
|
||||
if (framebufferreadpointer >= CANFRAMEBUFFERSIZE) {
|
||||
framebufferreadpointer = 0;
|
||||
}
|
||||
|
||||
canFrame rxFrame = framebuffer[framebufferreadpointer];
|
||||
frames_read++;
|
||||
|
||||
if ((rxFrame.FrameID & SLAVE_STATUS_BASE_ADDRESS) ==
|
||||
SLAVE_STATUS_BASE_ADDRESS) {
|
||||
uint16_t msg = rxFrame.FrameID - SLAVE_STATUS_BASE_ADDRESS;
|
||||
uint8_t slaveID = (msg & 0x0F0) >> 4;
|
||||
slaveID = slave_CAN_id_to_slave_index[slaveID];
|
||||
uint8_t messageID = msg & 0x00F;
|
||||
updateSlaveInfo(slaveID, messageID, rxFrame);
|
||||
} else if (rxFrame.FrameID == SLAVE_EMERGENCY_ADDRESS) {
|
||||
uint8_t slave_id = rxFrame.data[0];
|
||||
slaves[slave_id].error = 1;
|
||||
memcpy(slaves[slave_id].error_frame, rxFrame.data, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t CAN_Transmit(FDCAN_HandleTypeDef* hcan, uint16_t frameid,
|
||||
uint8_t* buffer, uint8_t datalen) {
|
||||
FDCAN_TxHeaderTypeDef txheader = {0};
|
||||
|
||||
txheader.Identifier = frameid;
|
||||
txheader.IdType = FDCAN_STANDARD_ID;
|
||||
txheader.TxFrameType = FDCAN_FRAME_CLASSIC;
|
||||
txheader.DataLength = ((uint32_t)datalen) << 16;
|
||||
txheader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
||||
txheader.BitRateSwitch = FDCAN_BRS_OFF;
|
||||
txheader.FDFormat = FDCAN_CLASSIC_CAN;
|
||||
txheader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
|
||||
txheader.MessageMarker = 0;
|
||||
|
||||
HAL_FDCAN_AddMessageToTxFifoQ(hcan, &txheader, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef* hcan) {}
|
||||
|
||||
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef* handle,
|
||||
uint32_t interrupt_flags) {
|
||||
|
||||
FDCAN_RxHeaderTypeDef rxFrameHeader;
|
||||
uint8_t data[8];
|
||||
framebufferwritepointer++;
|
||||
|
||||
if (framebufferwritepointer >= CANFRAMEBUFFERSIZE) {
|
||||
framebufferwritepointer = 0;
|
||||
}
|
||||
|
||||
if (!(interrupt_flags & FDCAN_IT_RX_FIFO0_NEW_MESSAGE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HAL_FDCAN_GetRxMessage(handle, FDCAN_RX_FIFO0, &rxFrameHeader, data) !=
|
||||
HAL_OK) {
|
||||
framebuffer[framebufferwritepointer].error = 1;
|
||||
} else {
|
||||
framebuffer[framebufferwritepointer].error = 0;
|
||||
}
|
||||
|
||||
if (rxFrameHeader.IdType != FDCAN_STANDARD_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
framebuffer[framebufferwritepointer].FrameID =
|
||||
(int16_t)rxFrameHeader.Identifier;
|
||||
framebuffer[framebufferwritepointer].length =
|
||||
(uint8_t)rxFrameHeader.DataLength >> 16;
|
||||
|
||||
for (int i = 0; i < (rxFrameHeader.DataLength >> 16); i++) {
|
||||
framebuffer[framebufferwritepointer].data[i] = data[i];
|
||||
}
|
||||
|
||||
framebuffer[framebufferwritepointer].timestamp = HAL_GetTick();
|
||||
}
|
||||
|
||||
void updateSlaveInfo(uint8_t slaveID, uint8_t MessageID, canFrame rxFrame) {
|
||||
if (slaveID < NUMBEROFSLAVES) {
|
||||
switch (MessageID) {
|
||||
case 0x00:
|
||||
slaves[slaveID].cellVoltages[0] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellVoltages[1] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellVoltages[2] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellVoltages[3] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x01:
|
||||
slaves[slaveID].cellVoltages[4] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellVoltages[5] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellVoltages[6] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellVoltages[7] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x02:
|
||||
slaves[slaveID].cellVoltages[8] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellVoltages[9] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
break;
|
||||
case 0x03:
|
||||
slaves[slaveID].cellTemps[0] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[1] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[2] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[3] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x04:
|
||||
slaves[slaveID].cellTemps[4] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[5] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[6] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[7] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x05:
|
||||
slaves[slaveID].cellTemps[8] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[9] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[10] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[11] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x06:
|
||||
slaves[slaveID].cellTemps[12] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[13] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[14] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[15] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x07:
|
||||
slaves[slaveID].cellTemps[16] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[17] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[18] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[19] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x08:
|
||||
slaves[slaveID].cellTemps[20] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[21] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[22] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[23] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x09:
|
||||
slaves[slaveID].cellTemps[24] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[25] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[26] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[27] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
case 0x0A:
|
||||
slaves[slaveID].cellTemps[28] = rxFrame.data[0] | rxFrame.data[1] << 8;
|
||||
slaves[slaveID].cellTemps[29] = rxFrame.data[2] | rxFrame.data[3] << 8;
|
||||
slaves[slaveID].cellTemps[30] = rxFrame.data[4] | rxFrame.data[5] << 8;
|
||||
slaves[slaveID].cellTemps[31] = rxFrame.data[6] | rxFrame.data[7] << 8;
|
||||
break;
|
||||
}
|
||||
slaves[slaveID].timestamp = rxFrame.timestamp;
|
||||
slaves[slaveID].frame_timestamps[MessageID] = rxFrame.timestamp;
|
||||
}
|
||||
}
|
||||
35
Core/Src/Clock_Sync.c
Normal file
35
Core/Src/Clock_Sync.c
Normal file
@ -0,0 +1,35 @@
|
||||
#include "Clock_Sync.h"
|
||||
|
||||
#include "CAN_Communication.h"
|
||||
|
||||
#include "stm32g4xx_hal.h"
|
||||
#include "stm32g4xx_hal_fdcan.h"
|
||||
#include "stm32g4xx_hal_tim.h"
|
||||
|
||||
static FDCAN_HandleTypeDef* can;
|
||||
static TIM_HandleTypeDef* sync_timer;
|
||||
static TIM_HandleTypeDef* heartbeat_timer;
|
||||
|
||||
static uint8_t clock_sync_counter = 0;
|
||||
|
||||
void clock_sync_init(FDCAN_HandleTypeDef* can_handle,
|
||||
TIM_HandleTypeDef* sync_timer_handle,
|
||||
TIM_HandleTypeDef* heartbeat_timer_handle) {
|
||||
can = can_handle;
|
||||
sync_timer = sync_timer_handle;
|
||||
heartbeat_timer = heartbeat_timer_handle;
|
||||
HAL_TIM_Base_Start_IT(heartbeat_timer);
|
||||
// Delay between starting the timers so the interrupts don't fire at the same
|
||||
// time
|
||||
HAL_Delay(50);
|
||||
HAL_TIM_Base_Start_IT(sync_timer);
|
||||
}
|
||||
|
||||
void clock_sync_handle_timer_complete(TIM_HandleTypeDef* timer) {
|
||||
if (timer == sync_timer) {
|
||||
CAN_Transmit(can, CLOCK_SYNC_ADDRESS, &clock_sync_counter, 1);
|
||||
clock_sync_counter++;
|
||||
} else if (timer == heartbeat_timer) {
|
||||
CAN_Transmit(can, MASTER_HEARTBEAT_ADDRESS, NULL, 0);
|
||||
}
|
||||
}
|
||||
13
Core/Src/Error_Check.c
Normal file
13
Core/Src/Error_Check.c
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Error_Check.c
|
||||
*
|
||||
* Created on: Jun 16, 2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "Error_Check.h"
|
||||
|
||||
ErrorFlags CheckErrorFlags() {
|
||||
ErrorFlags errors = {0};
|
||||
return errors;
|
||||
}
|
||||
104
Core/Src/Slave_Monitoring.c
Normal file
104
Core/Src/Slave_Monitoring.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Slave_Monitoring.c
|
||||
*
|
||||
* Created on: Jun 15, 2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "Slave_Monitoring.h"
|
||||
|
||||
#include "AMS_Errorcodes.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "stm32g4xx_hal.h"
|
||||
#include "stm32g4xx_hal_gpio.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SlaveHandler slaves[NUMBEROFSLAVES];
|
||||
|
||||
void initSlaves() {
|
||||
HAL_GPIO_WritePin(SLAVES_ENABLE_GPIO_Port, SLAVES_ENABLE_Pin, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(BOOT0_FF_DATA_GPIO_Port, BOOT0_FF_DATA_Pin, GPIO_PIN_RESET);
|
||||
|
||||
for (int i = 0; i < NUMBEROFSLAVES + 5; i++) {
|
||||
HAL_GPIO_WritePin(BOOT0_FF_CLK_GPIO_Port, BOOT0_FF_CLK_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
HAL_GPIO_WritePin(BOOT0_FF_CLK_GPIO_Port, BOOT0_FF_CLK_Pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(1);
|
||||
}
|
||||
|
||||
HAL_Delay(5);
|
||||
HAL_GPIO_WritePin(SLAVES_ENABLE_GPIO_Port, SLAVES_ENABLE_Pin, GPIO_PIN_SET);
|
||||
|
||||
for (int n = 0; n < NUMBEROFSLAVES; n++) {
|
||||
for (int i = 0; i < NUMBEROFTEMPS; i++)
|
||||
slaves[n].cellTemps[i] = 0;
|
||||
|
||||
for (int j = 0; j < NUMBEROFCELLS; j++)
|
||||
slaves[n].cellVoltages[j] = 32768;
|
||||
|
||||
slaves[n].error = 0;
|
||||
slaves[n].timeout = 0;
|
||||
slaves[n].timestamp = HAL_GetTick();
|
||||
slaves[n].slaveID = n;
|
||||
for (int i = 0; i < SLAVE_HEARTBEAT_FRAMES; i++) {
|
||||
slaves[n].frame_timestamps[i] = HAL_GetTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t checkSlaveTimeout() {
|
||||
if (HAL_GetTick() < 10000) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int n = 0; n < NUMBEROFSLAVES; n++) {
|
||||
if (((int)(HAL_GetTick() - slaves[n].timestamp)) > SLAVETIMEOUT) {
|
||||
slaves[n].timeout = 1;
|
||||
|
||||
AMSErrorHandle timeouterror;
|
||||
timeouterror.errorcode = SlavesTimeoutError;
|
||||
timeouterror.errorarg[0] = n;
|
||||
|
||||
AMS_Error_Handler(&timeouterror);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (slaves[n].error) {
|
||||
AMSErrorHandle errorframe;
|
||||
errorframe.errorcode = SlavesErrorFrameError;
|
||||
memcpy(errorframe.errorarg, slaves[n].error_frame, 7);
|
||||
AMS_Error_Handler(&errorframe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SLAVE_HEARTBEAT_FRAMES; i++) {
|
||||
if ((int)(HAL_GetTick() - slaves[n].frame_timestamps[i]) >
|
||||
SLAVETIMEOUT * 2) {
|
||||
slaves[n].timeout = 1;
|
||||
AMSErrorHandle timeouterror;
|
||||
timeouterror.errorcode = SLAVES_FRAME_TIMEOUT_ERROR;
|
||||
timeouterror.errorarg[0] = n;
|
||||
timeouterror.errorarg[1] = i;
|
||||
AMS_Error_Handler(&timeouterror);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int working_cell_temps = 0;
|
||||
for (int i = 0; i < NUMBEROFTEMPS; i++) {
|
||||
if (slaves[n].cellTemps[i] != 0) {
|
||||
working_cell_temps++;
|
||||
}
|
||||
}
|
||||
if (working_cell_temps < SLAVE_MIN_TEMP_SENSORS) {
|
||||
AMSErrorHandle temperror;
|
||||
temperror.errorcode = SLAVES_TOO_FEW_TEMPS;
|
||||
temperror.errorarg[0] = n;
|
||||
AMS_Error_Handler(&temperror);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
132
Core/Src/main.c
132
Core/Src/main.c
@ -21,7 +21,11 @@
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "AIR_State_Maschine.h"
|
||||
#include "CAN_Communication.h"
|
||||
#include "Clock_Sync.h"
|
||||
#include "Error_Check.h"
|
||||
#include "Slave_Monitoring.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@ -41,7 +45,9 @@
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
FDCAN_HandleTypeDef hfdcan1;
|
||||
|
||||
TIM_HandleTypeDef htim1;
|
||||
TIM_HandleTypeDef htim3;
|
||||
TIM_HandleTypeDef htim8;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
@ -52,13 +58,17 @@ void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
static void MX_TIM3_Init(void);
|
||||
static void MX_FDCAN1_Init(void);
|
||||
static void MX_TIM1_Init(void);
|
||||
static void MX_TIM8_Init(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
void setAMSError(void);
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
AIRStateHandler airstates;
|
||||
ErrorFlags errorflags;
|
||||
AMSErrorHandle defaulterrorhandle = {0};
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
@ -91,8 +101,13 @@ int main(void) {
|
||||
MX_GPIO_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_FDCAN1_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_TIM8_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
airstates = init_AIR_State_Maschine();
|
||||
CAN_Init(&hfdcan1);
|
||||
clock_sync_init(&hfdcan1, &htim1, &htim8);
|
||||
initSlaves();
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
@ -101,6 +116,11 @@ int main(void) {
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
CAN_Receive(&hfdcan1); // Run CAN Event Loop
|
||||
errorflags = CheckErrorFlags(); // Check for Errors
|
||||
Update_AIR_Info(&airstates);
|
||||
checkSlaveTimeout(); // check for Slave Timeout
|
||||
Update_AIR_State(&airstates); // Update AIR State Maschine
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
@ -181,6 +201,48 @@ static void MX_FDCAN1_Init(void) {
|
||||
/* USER CODE END FDCAN1_Init 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM1 Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_TIM1_Init(void) {
|
||||
|
||||
/* USER CODE BEGIN TIM1_Init 0 */
|
||||
|
||||
/* USER CODE END TIM1_Init 0 */
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
|
||||
/* USER CODE BEGIN TIM1_Init 1 */
|
||||
|
||||
/* USER CODE END TIM1_Init 1 */
|
||||
htim1.Instance = TIM1;
|
||||
htim1.Init.Prescaler = 1599;
|
||||
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim1.Init.Period = 9999;
|
||||
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim1.Init.RepetitionCounter = 0;
|
||||
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
if (HAL_TIM_Base_Init(&htim1) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM1_Init 2 */
|
||||
|
||||
/* USER CODE END TIM1_Init 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM3 Initialization Function
|
||||
* @param None
|
||||
@ -225,6 +287,48 @@ static void MX_TIM3_Init(void) {
|
||||
HAL_TIM_MspPostInit(&htim3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM8 Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_TIM8_Init(void) {
|
||||
|
||||
/* USER CODE BEGIN TIM8_Init 0 */
|
||||
|
||||
/* USER CODE END TIM8_Init 0 */
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
|
||||
/* USER CODE BEGIN TIM8_Init 1 */
|
||||
|
||||
/* USER CODE END TIM8_Init 1 */
|
||||
htim8.Instance = TIM8;
|
||||
htim8.Init.Prescaler = 1599;
|
||||
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim8.Init.Period = 999;
|
||||
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim8.Init.RepetitionCounter = 0;
|
||||
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
if (HAL_TIM_Base_Init(&htim8) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM8_Init 2 */
|
||||
|
||||
/* USER CODE END TIM8_Init 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO Initialization Function
|
||||
* @param None
|
||||
@ -282,7 +386,27 @@ static void MX_GPIO_Init(void) {
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
void AMS_Error_Handler(AMSErrorHandle* errorinfo) {
|
||||
while (1) {
|
||||
setAMSError();
|
||||
airstates.targetTSState = TS_ERROR;
|
||||
Update_AIR_State(&airstates);
|
||||
CAN_Receive(&hfdcan1);
|
||||
errorflags = CheckErrorFlags();
|
||||
}
|
||||
}
|
||||
|
||||
void setAMSError() {
|
||||
static int errors = 0;
|
||||
errors++;
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
GPIO_InitStruct.Pin = AMS_ERR_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(AMS_ERR_GPIO_Port, &GPIO_InitStruct);
|
||||
HAL_GPIO_WritePin(AMS_ERR_GPIO_Port, AMS_ERR_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
|
||||
@ -158,6 +158,39 @@ void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* hfdcan)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM_Base MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param htim_base: TIM_Base handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
|
||||
{
|
||||
if(htim_base->Instance==TIM1)
|
||||
{
|
||||
/* USER CODE BEGIN TIM1_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM1_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_TIM1_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM1_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM1_MspInit 1 */
|
||||
}
|
||||
else if(htim_base->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM8_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_TIM8_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM8_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM8_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM_PWM MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
@ -206,6 +239,39 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief TIM_Base MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param htim_base: TIM_Base handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
|
||||
{
|
||||
if(htim_base->Instance==TIM1)
|
||||
{
|
||||
/* USER CODE BEGIN TIM1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM1_CLK_DISABLE();
|
||||
/* USER CODE BEGIN TIM1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM1_MspDeInit 1 */
|
||||
}
|
||||
else if(htim_base->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM8_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM8_CLK_DISABLE();
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM8_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM_PWM MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
|
||||
Reference in New Issue
Block a user