copy files over from slave
This commit is contained in:
106
Core/Inc/ADBMS_Abstraction.h
Normal file
106
Core/Inc/ADBMS_Abstraction.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* ADBMS_Abstraction.h
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_ADBMS_ABSTRACTION_H_
|
||||
#define INC_ADBMS_ABSTRACTION_H_
|
||||
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
#define MAXIMUM_CELL_VOLTAGES 16
|
||||
#define MAXIMUM_AUX_VOLTAGES 10
|
||||
#define MAXIMUM_GPIO 10
|
||||
|
||||
//see table 103 in datasheet (page 71)
|
||||
#define DEFAULT_UV 417 //VUV * 16 * 150 uV + 1.5 V Default Setting 2.5V
|
||||
#define DEFAULT_OV 1125 //VOV * 16 * 150 uV + 1.5 V Default Setting 4.2V
|
||||
|
||||
#define mV_from_ADBMS6830(x) (((((int16_t) (x))) * 0.150) + 1500)
|
||||
|
||||
struct ADBMS6830_Internal_Status {
|
||||
uint16 CS_FLT : 16; //ADC fault - mismatch between S- and C-ADC
|
||||
uint16 : 3;
|
||||
uint16 CCTS : 13; //Conversion counter
|
||||
uint16 VA_OV : 1; //5V analog supply overvoltage
|
||||
uint16 VA_UV : 1; //5V analog supply undervoltage
|
||||
uint16 VD_OV : 1; //3V digital supply overvoltage
|
||||
uint16 VD_UV : 1; //3V digital supply undervoltage
|
||||
uint16 CED : 1; //C-ADC single trim error (correctable)
|
||||
uint16 CMED : 1; //C-ADC multiple trim error (uncorrectable)
|
||||
uint16 SED : 1; //S-ADC single trim error (correctable)
|
||||
uint16 SMED : 1; //S-ADC multiple trim error (uncorrectable)
|
||||
uint16 VDEL : 1; //Latent supply voltage error
|
||||
uint16 VDE : 1; //Supply voltage error
|
||||
uint16 COMPARE : 1; //Comparasion between S- and C-ADC active
|
||||
uint16 SPIFLT : 1; //SPI fault
|
||||
uint16 SLEEP : 1; //Sleep mode previously entered
|
||||
uint16 THSD : 1; //Thermal shutdown
|
||||
uint16 TMODCHK : 1; //Test mode check
|
||||
uint16 OSCCHK : 1; //Oscillator check
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES];
|
||||
int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES];
|
||||
|
||||
struct ADBMS6830_Internal_Status status;
|
||||
uint16 internalDieTemp;
|
||||
uint16 analogSupplyVoltage;
|
||||
uint16 digitalSupplyVoltage;
|
||||
uint16 sumOfCellMeasurements;
|
||||
uint16 refVoltage;
|
||||
|
||||
uint16 GPIO_Values[MAXIMUM_GPIO];
|
||||
|
||||
uint32 overVoltage;
|
||||
uint32 underVoltage;
|
||||
|
||||
} Cell_Module;
|
||||
|
||||
uint8 amsReset();
|
||||
|
||||
uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux);
|
||||
uint8 amsWakeUp();
|
||||
|
||||
uint8 amsCellMeasurement(Cell_Module* module);
|
||||
uint8 amsConfigCellMeasurement(uint8 numberofChannels);
|
||||
|
||||
uint8 amsAuxAndStatusMeasurement(Cell_Module* module);
|
||||
uint8 amsConfigAuxMeasurement(uint16 Channels);
|
||||
|
||||
uint8 amsConfigGPIO(uint16 gpios);
|
||||
uint8 amsSetGPIO(uint16 gpios);
|
||||
uint8 readGPIO(Cell_Module* module);
|
||||
|
||||
uint8 amsConfigBalancing(uint32 Channels, uint8 dutyCycle);
|
||||
uint8 amsStartBalancing(uint8 dutyCycle);
|
||||
uint8 amsStopBalancing();
|
||||
|
||||
uint8 amsSelfTest();
|
||||
|
||||
uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage);
|
||||
|
||||
uint8 amsCheckUnderOverVoltage(Cell_Module* module);
|
||||
uint8 amsConfigOverVoltage(uint16 overVoltage);
|
||||
|
||||
uint8 amscheckOpenCellWire(Cell_Module* module);
|
||||
|
||||
uint8 amsClearStatus();
|
||||
uint8 amsClearAux();
|
||||
uint8 amsClearCells();
|
||||
|
||||
uint8 amsSendWarning();
|
||||
uint8 amsSendError();
|
||||
|
||||
uint8 amsClearWarning();
|
||||
uint8 amsClearError();
|
||||
|
||||
uint8 amsReadCellVoltages(Cell_Module* module);
|
||||
|
||||
#endif /* INC_ADBMS_ABSTRACTION_H_ */
|
||||
171
Core/Inc/ADBMS_CMD_MAKROS.h
Normal file
171
Core/Inc/ADBMS_CMD_MAKROS.h
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* ADBMS_CMD_MAKROS.h
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_ADBMS_CMD_MAKROS_H_
|
||||
#define INC_ADBMS_CMD_MAKROS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#define WRCFGA 0x0001 // Write Configuration Register Group A
|
||||
#define RDCFGA 0x0002 // Read Configuration Register Group A
|
||||
#define WRCFGB 0x0024 // Write Configuration Register Group B
|
||||
#define RDCFGB 0x0026 // Read Configuration Register Group B
|
||||
|
||||
#define WRPWMA 0x0020 // Write PWM Register Group A
|
||||
#define RDPWMA 0x0022 // Read PWM Register Group A
|
||||
#define WRPWMB 0x0021 // Write PWM Register Group B
|
||||
#define RDPWMB 0x0023 // Read PWM Register Group B
|
||||
|
||||
#define RDCVA 0x0004 // Read Cell Voltage Register Group A
|
||||
#define RDCVB 0x0006 // Read Cell Voltage Register Group B
|
||||
#define RDCVC 0x0008 // Read Cell Voltage Register Group C
|
||||
#define RDCVD 0x000A // Read Cell Voltage Register Group D
|
||||
#define RDCVE 0x0009 // Read Cell Voltage Register Group E
|
||||
#define RDCVF 0x000B // Read Cell Voltage Register Group F
|
||||
#define RDCVALL 0x000C // Read All Cell Voltage Register Groups
|
||||
|
||||
#define RDACA 0x0044 // Read averaged Cell Voltage Register Group A
|
||||
#define RDACB 0x0046 // Read averaged Cell Voltage Register Group B
|
||||
#define RDACC 0x0048 // Read averaged Cell Voltage Register Group C
|
||||
#define RDACD 0x004A // Read averaged Cell Voltage Register Group D
|
||||
#define RDACE 0x0049 // Read averaged Cell Voltage Register Group E
|
||||
#define RDACF 0x004B // Read averaged Cell Voltage Register Group F
|
||||
#define RDACALL 0x004C // Read averaged All Cell Voltage Register Groups
|
||||
|
||||
#define RDAUXA 0x0019 // Read Auxilliary Register Group A
|
||||
#define RDAUXB 0x001A // Read Auxilliary Register Group B
|
||||
#define RDAUXC 0x001B // Read Auxilliary Register Group C
|
||||
#define RDAUXD 0x001F // Read Auxilliary Register Group D
|
||||
|
||||
#define RDAUXALL 0x0035 // Read All Auxilliary and Status Register Groups
|
||||
|
||||
#define RDSTATA 0x0030 // Read Status Register Group A
|
||||
#define RDSTATB 0x0031 // Read Status Register Group B
|
||||
#define RDSTATC 0x0032 // Read Status Register Group C
|
||||
#define RDSTATD 0x0033 // Read Status Register Group D
|
||||
#define RDSTATE 0x0034 // Read Status Register Group E
|
||||
|
||||
#define ADCV 0x0260 // Start Cell Voltage Conversion with C-ADC
|
||||
#define ADCV_OW_0 (1u << 0)
|
||||
#define ADCV_OW_1 (1u << 1)
|
||||
#define ADCV_RSTF (1u << 2)
|
||||
#define ADCV_DCP (1u << 4)
|
||||
#define ADCV_CONT (1u << 7) // Continuous Mode
|
||||
#define ADCV_RD (1u << 8) // Redundancy Mode
|
||||
|
||||
#define ADSV 0x0168 // Start Cell Voltage Conversion with S-ADC
|
||||
#define ADSV_OW_0 (1u << 0)
|
||||
#define ADSV_OW_1 (1u << 1)
|
||||
#define ADSV_DCP (1u << 4)
|
||||
#define ADSV_CONT (1u << 7) // Continuous Mode
|
||||
|
||||
#define ADAX 0x0410 // Start GPIOs and Vref2 Conversion
|
||||
#define ADAX_CONV_ALL 0x0000 // Convert all GPIOs, VREF2, VD, VA, ITEMP
|
||||
#define ADAX_OW (1u << 8)
|
||||
|
||||
#define CLRCELL 0x0711 // Clear Cell Voltage Register Groups
|
||||
#define CLRAUX 0x0712 // Clear Auxiliary Register Groups
|
||||
#define CLOVUV 0x0715 // Clear Overvoltage and Undervoltage Flags
|
||||
#define CLRFLAG 0x0717 // Clear all Flags
|
||||
|
||||
#define PLADC 0x0718 // Poll ADC Conversion Status
|
||||
#define PLAUX 0x071E // Poll AUX Conversion Status
|
||||
|
||||
#define SRST 0x0027 //Soft reset
|
||||
|
||||
#define DIAGN 0x0715 // Diagnos MUX and Poll Status
|
||||
#define WRCOMM 0x0721 // Write COMM Register Group
|
||||
#define RDCOMM 0x0722 // Read COMM Register Group
|
||||
#define STCOMM 0x0723 // Start I2C/SPI Communication
|
||||
#define MUTE 0x0028 // Mute Discharge
|
||||
#define UNMUTE 0x0029 // Unmute Discharge
|
||||
|
||||
|
||||
|
||||
/* GPIO Selection for ADC Converion
|
||||
* 000: GPIO1 to 5, 2nd Reference, GPIO 6 to 9
|
||||
* 001: GPIO1 and GPIO6
|
||||
* 010 GPIO2 and GPIO7
|
||||
* 011 GPIO3 and GPIO8
|
||||
* 100 GPIO4 and GPIO9
|
||||
* 101 GPIO5
|
||||
* 110 2nd Reference
|
||||
*/
|
||||
|
||||
#define CHG000 (0x00)
|
||||
#define CHG001 (0x01)
|
||||
#define CHG010 (0x02)
|
||||
#define CHG011 (0x03)
|
||||
#define CHG100 (0x04)
|
||||
#define CHG101 (0x05)
|
||||
#define CHG110 (0x06)
|
||||
|
||||
/* Status Group Selection
|
||||
* 000: SC,ITMP,VA,VD
|
||||
* 001: SC
|
||||
* 010: ITMP
|
||||
* 011: VA
|
||||
* 100: VD
|
||||
*/
|
||||
|
||||
#define CHST000 (0x00)
|
||||
#define CHST001 (0x01)
|
||||
#define CHST010 (0x02)
|
||||
#define CHST011 (0x03)
|
||||
#define CHST100 (0x04)
|
||||
|
||||
#define PEC_FIELD_SIZE 2
|
||||
|
||||
#define CFG_GROUP_A_SIZE 6
|
||||
#define CFG_GROUP_B_SIZE 6
|
||||
|
||||
#define PWM_GROUP_A_SIZE 6
|
||||
#define PWM_GROUP_B_SIZE 2
|
||||
|
||||
#define CV_GROUP_A_SIZE 6
|
||||
#define CV_GROUP_B_SIZE 6
|
||||
#define CV_GROUP_C_SIZE 6
|
||||
#define CV_GROUP_D_SIZE 6
|
||||
#define CV_GROUP_E_SIZE 6
|
||||
#define CV_GROUP_F_SIZE 6
|
||||
|
||||
#define AUX_GROUP_A_SIZE 6
|
||||
#define AUX_GROUP_B_SIZE 6
|
||||
#define AUX_GROUP_C_SIZE 6
|
||||
#define AUX_GROUP_D_SIZE 6
|
||||
|
||||
#define STATUS_GROUP_A_SIZE 6
|
||||
#define STATUS_GROUP_B_SIZE 6
|
||||
#define STATUS_GROUP_C_SIZE 6
|
||||
#define STATUS_GROUP_D_SIZE 6
|
||||
#define STATUS_GROUP_E_SIZE 6
|
||||
#define COMM_GROUP_SIZE 6
|
||||
#define S_CONTROL_GROUP_SIZE 6
|
||||
#define PWM_GROUP_SIZE 6
|
||||
#define PWM_S_CONTROL_GROUP_B_SIZE 6
|
||||
|
||||
#define CFG_GROUP_A_ID 1
|
||||
#define CFG_GROUP_B_ID 2
|
||||
#define CV_GROUP_A_ID 3
|
||||
#define CV_GROUP_B_ID 4
|
||||
#define CV_GROUP_C_ID 5
|
||||
#define CV_GROUP_D_ID 6
|
||||
#define CV_GROUP_E_ID 7
|
||||
#define CV_GROUP_F_ID 8
|
||||
|
||||
#define AUX_GROUP_A_ID 9
|
||||
#define AUX_GROUP_B_ID 10
|
||||
#define AUX_GROUP_C_ID 11
|
||||
#define AUX_GROUP_D_ID 12
|
||||
|
||||
#define STATUS_GROUP_A_ID 13
|
||||
#define STATUS_GROUP_B_ID 14
|
||||
#define COMM_GROUP_ID 15
|
||||
#define S_CONTROL_GROUP_ID 16
|
||||
#define PWM_GROUP_ID 17
|
||||
#define PWM_S_CONTROL_GROUP_B_ID 18
|
||||
|
||||
#endif /* INC_ADBMS_CMD_MAKROS_H_ */
|
||||
44
Core/Inc/ADBMS_LL_Driver.h
Normal file
44
Core/Inc/ADBMS_LL_Driver.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ADBMS_LL_Driver.h
|
||||
*
|
||||
* Created on: 05.06.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef ADBMS_LL_DRIVER_H_
|
||||
#define ADBMS_LL_DRIVER_H_
|
||||
|
||||
#define TARGET_STM32
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#ifdef TARGET_STM32
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
#endif
|
||||
|
||||
uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi);
|
||||
uint8 calculateCommandPEC(uint8* data, uint8 datalen);
|
||||
uint16 updateCommandPEC(uint16 currentPEC, uint8 din);
|
||||
uint8 checkCommandPEC(uint8* data, uint8 datalen);
|
||||
|
||||
uint8 calculateDataPEC(uint8* data, uint8 datalen);
|
||||
uint16 updateDataPEC(uint16 currentPEC, uint8 din);
|
||||
uint8 checkDataPEC(uint8* data, uint8 datalen);
|
||||
|
||||
uint8 writeCMD(uint16 command, uint8* args, uint8 arglen);
|
||||
uint8 readCMD(uint16 command, uint8* buffer, uint8 buflen);
|
||||
uint8 pollCMD(uint16 command);
|
||||
|
||||
void mcuAdbmsCSLow();
|
||||
void mcuAdbmsCSHigh();
|
||||
|
||||
uint8 mcuSPITransmit(uint8* buffer, uint8 buffersize);
|
||||
uint8 mcuSPIReceive(uint8* buffer, uint8 buffersize);
|
||||
uint8 mcuSPITransmitReceive(uint8* rxbuffer, uint8* txbuffer, uint8 buffersize);
|
||||
|
||||
uint8 wakeUpCmd();
|
||||
void mcuDelay(uint16 delay);
|
||||
|
||||
#endif /* ADBMS_LL_DRIVER_H_ */
|
||||
36
Core/Inc/AMS_CAN.h
Normal file
36
Core/Inc/AMS_CAN.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* AMS_CAN.h
|
||||
*
|
||||
* Created on: Mar 19, 2022
|
||||
* Author: jasper
|
||||
*/
|
||||
|
||||
#ifndef INC_AMS_CAN_H_
|
||||
#define INC_AMS_CAN_H_
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include "stm32f3xx_hal_can.h"
|
||||
#include "stm32f3xx_hal_def.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void ams_can_init(CAN_HandleTypeDef* hcan);
|
||||
|
||||
void ams_can_handle_ams_msg(CAN_RxHeaderTypeDef* header, uint8_t* data);
|
||||
|
||||
void ams_can_send_status();
|
||||
/**
|
||||
* @brief Send an AMS Error via CAN.
|
||||
*
|
||||
* Data is taken from error_data
|
||||
*/
|
||||
void ams_can_send_error();
|
||||
|
||||
HAL_StatusTypeDef ams_can_wait_for_free_mailboxes(CAN_HandleTypeDef* handle,
|
||||
int num_mailboxes,
|
||||
uint32_t timeout);
|
||||
void ams_can_send_log();
|
||||
|
||||
#endif /* INC_AMS_CAN_H_ */
|
||||
52
Core/Inc/AMS_HighLevel.h
Normal file
52
Core/Inc/AMS_HighLevel.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* AMS_HighLevel.h
|
||||
*
|
||||
* Created on: 20.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_AMS_HIGHLEVEL_H_
|
||||
#define INC_AMS_HIGHLEVEL_H_
|
||||
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "AMS_CAN.h"
|
||||
|
||||
typedef enum {
|
||||
AMSDEACTIVE,
|
||||
AMSIDLE,
|
||||
AMSCHARGING,
|
||||
AMSIDLEBALANCING,
|
||||
AMSDISCHARGING,
|
||||
AMSWARNING,
|
||||
AMSERROR
|
||||
} amsState;
|
||||
|
||||
extern amsState currentAMSState;
|
||||
extern Cell_Module module;
|
||||
extern uint32_t balancedCells;
|
||||
extern uint8_t BalancingActive;
|
||||
extern uint8_t stateofcharge;
|
||||
|
||||
extern uint8_t amserrorcode;
|
||||
extern uint8_t amswarningcode;
|
||||
|
||||
extern uint8_t numberofCells;
|
||||
extern uint8_t numberofAux;
|
||||
|
||||
void AMS_Init(SPI_HandleTypeDef* hspi);
|
||||
void AMS_Loop();
|
||||
|
||||
uint8_t AMS_Balancing_Loop();
|
||||
uint8_t AMS_Idle_Loop();
|
||||
uint8_t AMS_Warning_Loop();
|
||||
uint8_t AMS_Error_Loop();
|
||||
uint8_t AMS_Charging_Loop();
|
||||
uint8_t AMS_Discharging_Loop();
|
||||
|
||||
uint8_t writeWarningLog(uint8_t warningCode);
|
||||
uint8_t writeErrorLog(uint8_t errorCode);
|
||||
uint8_t integrateCurrent();
|
||||
|
||||
#endif /* INC_AMS_HIGHLEVEL_H_ */
|
||||
18
Core/Inc/TMP1075.h
Normal file
18
Core/Inc/TMP1075.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef INC_TMP1075_H_
|
||||
#define INC_TMP1075_H_
|
||||
|
||||
#include "AMS_CAN.h"
|
||||
#include "common_defs.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include "stm32f3xx_hal_def.h"
|
||||
#include "stm32f3xx_hal_i2c.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint32_t tmp1075_failed_sensors;
|
||||
extern int16_t tmp1075_temps[N_TEMP_SENSORS];
|
||||
HAL_StatusTypeDef tmp1075_init(I2C_HandleTypeDef* hi2c);
|
||||
HAL_StatusTypeDef tmp1075_measure();
|
||||
HAL_StatusTypeDef tmp1075_sensor_init(int n);
|
||||
HAL_StatusTypeDef tmp1075_sensor_read(int n, int16_t* res);
|
||||
|
||||
#endif // INC_TMP1075_H_
|
||||
14
Core/Inc/common_defs.h
Normal file
14
Core/Inc/common_defs.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* common_defs.h
|
||||
*
|
||||
* Created on: 23 Mar 2022
|
||||
* Author: Jasper
|
||||
*/
|
||||
|
||||
#ifndef INC_COMMON_DEFS_H_
|
||||
#define INC_COMMON_DEFS_H_
|
||||
|
||||
#define N_CELLS 14
|
||||
#define N_TEMP_SENSORS 14
|
||||
|
||||
#endif /* INC_COMMON_DEFS_H_ */
|
||||
17
Core/Inc/eeprom.h
Normal file
17
Core/Inc/eeprom.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef INC_EEPROM_H_
|
||||
#define INC_EEPROM_H_
|
||||
|
||||
#include "stm32f3xx_hal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
__attribute__((packed)) typedef struct {
|
||||
uint8_t id;
|
||||
} EEPROMConfig;
|
||||
|
||||
extern EEPROMConfig eeprom_config;
|
||||
|
||||
void eeprom_init(I2C_HandleTypeDef* hi2c);
|
||||
void eeprom_config_save();
|
||||
|
||||
#endif // INC_EEPROM_H_
|
||||
41
Core/Inc/errors.h
Normal file
41
Core/Inc/errors.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef INC_ERRORS_H
|
||||
#define INC_ERRORS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ERROR_SOURCE_VOLTAGES (1 << 0)
|
||||
#define ERROR_SOURCE_TEMPERATURES (1 << 1)
|
||||
#define ERROR_SOURCE_TOO_FEW_WORKING_TEMP_SENSORS (1 << 2)
|
||||
#define ERROR_SOURCE_OPEN_CELL_CONNECTION (1 << 3)
|
||||
#define ERROR_SOURCE_EEPROM (1 << 4)
|
||||
#define ERROR_SOURCE_INTERNAL (1 << 5)
|
||||
|
||||
#define ERROR_TIME_THRESH 150 // ms
|
||||
|
||||
typedef enum {
|
||||
SEK_OVERTEMP = 0x0,
|
||||
SEK_UNDERTEMP = 0x1,
|
||||
SEK_OVERVOLT = 0x2,
|
||||
SEK_UNDERVOLT = 0x3,
|
||||
SEK_TOO_FEW_TEMPS = 0x4,
|
||||
SEK_OPENWIRE = 0x5,
|
||||
SEK_EEPROM_ERR = 0x6,
|
||||
SEK_INTERNAL_BMS_TIMEOUT = 0x7,
|
||||
SEK_INTERNAL_BMS_CHECKSUM_FAIL = 0x8,
|
||||
SEK_INTERNAL_BMS_OVERTEMP = 0x9,
|
||||
SEK_INTERNAL_BMS_FAULT = 0xA,
|
||||
} SlaveErrorKind;
|
||||
|
||||
typedef struct {
|
||||
int error_sources;
|
||||
SlaveErrorKind data_kind;
|
||||
uint8_t data[4];
|
||||
uint32_t errors_since;
|
||||
} SlaveErrorData;
|
||||
|
||||
extern SlaveErrorData error_data;
|
||||
|
||||
void set_error_source(int source);
|
||||
void clear_error_source(int source);
|
||||
|
||||
#endif // INC_ERRORS_H
|
||||
246
Core/Src/ADBMS_Abstraction.c
Normal file
246
Core/Src/ADBMS_Abstraction.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* ADBMS_Abstraction.c
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include <stddef.h>
|
||||
|
||||
uint8 numberofcells;
|
||||
uint8 numberofauxchannels;
|
||||
|
||||
#define CHECK_RETURN(x) \
|
||||
{ \
|
||||
uint8 status = x; \
|
||||
if (status != 0) \
|
||||
return status; \
|
||||
}
|
||||
|
||||
uint8 amsReset() {
|
||||
amsWakeUp();
|
||||
readCMD(SRST, NULL, 0);
|
||||
mcuDelay(10);
|
||||
amsWakeUp();
|
||||
amsStopBalancing();
|
||||
amsConfigOverUnderVoltage(DEFAULT_OV, DEFAULT_UV);
|
||||
|
||||
uint8 buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
CHECK_RETURN(writeCMD(CLRFLAG, buffer, 6)); //clear flags,
|
||||
CHECK_RETURN(writeCMD(CLOVUV, buffer, 6)); //OVUV flags
|
||||
CHECK_RETURN(writeCMD(ADCV | ADCV_CONT | ADCV_RD, NULL, 0)); //start continuous cell voltage measurement with redundancy
|
||||
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, NULL, 0)); //start aux measurement
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 initAMS(SPI_HandleTypeDef* hspi, uint8 numofcells, uint8 numofaux) {
|
||||
adbmsDriverInit(hspi);
|
||||
numberofcells = numofcells;
|
||||
numberofauxchannels = numofaux;
|
||||
|
||||
return amsReset();
|
||||
}
|
||||
|
||||
uint8 amsWakeUp() {
|
||||
uint8 buf[6];
|
||||
return readCMD(RDCFGA, buf, 6);
|
||||
}
|
||||
|
||||
uint8 amsCellMeasurement(Cell_Module* module) {
|
||||
#warning check conversion counter to ensure that continous conversion has not been stopped
|
||||
#warning check for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1
|
||||
return amsReadCellVoltages(module);
|
||||
}
|
||||
|
||||
uint8 amsConfigCellMeasurement(uint8 numberofChannels) {
|
||||
numberofcells = numberofChannels;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 amsAuxAndStatusMeasurement(Cell_Module* module) {
|
||||
uint8 rxbuf[AUX_GROUP_A_SIZE] = {};
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
|
||||
|
||||
module->status.CS_FLT = rxbuf[0] | (rxbuf[1] << 8);
|
||||
module->status.CCTS = rxbuf[2] | (rxbuf[3] << 8);
|
||||
module->status.VA_OV = (rxbuf[4] >> 7) & 0x01;
|
||||
module->status.VA_UV = (rxbuf[4] >> 6) & 0x01;
|
||||
module->status.VD_OV = (rxbuf[4] >> 5) & 0x01;
|
||||
module->status.VD_UV = (rxbuf[4] >> 4) & 0x01;
|
||||
module->status.CED = (rxbuf[4] >> 3) & 0x01;
|
||||
module->status.CMED = (rxbuf[4] >> 2) & 0x01;
|
||||
module->status.SED = (rxbuf[4] >> 1) & 0x01;
|
||||
module->status.SMED = (rxbuf[4] >> 0) & 0x01;
|
||||
module->status.VDEL = (rxbuf[5] >> 7) & 0x01;
|
||||
module->status.VDE = (rxbuf[5] >> 6) & 0x01;
|
||||
module->status.COMPARE= (rxbuf[5] >> 5) & 0x01;
|
||||
module->status.SPIFLT = (rxbuf[5] >> 4) & 0x01;
|
||||
module->status.SLEEP = (rxbuf[5] >> 3) & 0x01;
|
||||
module->status.THSD = (rxbuf[5] >> 2) & 0x01;
|
||||
module->status.TMODCHK= (rxbuf[5] >> 1) & 0x01;
|
||||
module->status.OSCCHK = (rxbuf[5] >> 0) & 0x01;
|
||||
|
||||
if (pollCMD(PLAUX) == 0x0) { //TODO: check for SPI fault
|
||||
return 0; // aux ADC data not ready
|
||||
}
|
||||
|
||||
CHECK_RETURN(readCMD(RDAUXA, rxbuf, AUX_GROUP_A_SIZE));
|
||||
|
||||
module->auxVoltages[0] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
|
||||
module->auxVoltages[1] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
|
||||
module->auxVoltages[2] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDAUXB, rxbuf, AUX_GROUP_A_SIZE));
|
||||
|
||||
module->auxVoltages[3] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
|
||||
module->auxVoltages[4] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
|
||||
module->auxVoltages[5] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDAUXC, rxbuf, AUX_GROUP_A_SIZE));
|
||||
|
||||
module->auxVoltages[6] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
|
||||
module->auxVoltages[7] = mV_from_ADBMS6830(rxbuf[2] | (rxbuf[3] << 8));
|
||||
module->auxVoltages[8] = mV_from_ADBMS6830(rxbuf[4] | (rxbuf[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDAUXD, rxbuf, AUX_GROUP_A_SIZE));
|
||||
|
||||
module->auxVoltages[9] = mV_from_ADBMS6830(rxbuf[0] | (rxbuf[1] << 8));
|
||||
|
||||
uint8 rxbuffer[STATUS_GROUP_A_SIZE];
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATA, rxbuffer, STATUS_GROUP_A_SIZE));
|
||||
|
||||
module->internalDieTemp = rxbuffer[2] | (rxbuffer[3] << 8);
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATB, rxbuffer, STATUS_GROUP_B_SIZE));
|
||||
module->digitalSupplyVoltage = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->analogSupplyVoltage = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->refVoltage = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, NULL, 0)); //start aux measurement for next cycle
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 amsConfigBalancing(uint32 channels, uint8 dutyCycle) {
|
||||
uint8 buffer_a[PWM_GROUP_A_SIZE] = {};
|
||||
uint8 buffer_b[PWM_GROUP_B_SIZE] = {};
|
||||
CHECK_RETURN(readCMD(RDPWMA, buffer_a, CFG_GROUP_A_SIZE));
|
||||
CHECK_RETURN(readCMD(RDPWMB, buffer_b, CFG_GROUP_B_SIZE));
|
||||
|
||||
if (dutyCycle > 0x0F) { // there are only 4 bits for duty cycle
|
||||
return 1;
|
||||
}
|
||||
|
||||
#warning fixme
|
||||
|
||||
for (size_t i = 0; i < 16; i += 2) {
|
||||
if (i < 12) { // cells 0, 1 are in regbuffer[0], cells 2, 3 in regbuffer[1], ...
|
||||
buffer_a[i / 2] = ((channels & (1 << (i + 1))) ? (dutyCycle << 4) : 0) |
|
||||
((channels & (1 << i)) ? dutyCycle : 0);
|
||||
} else {
|
||||
buffer_b[(i - 12) / 2] = ((channels & (1 << (i + 1))) ? (dutyCycle << 4) : 0) |
|
||||
((channels & (1 << i)) ? dutyCycle : 0);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_RETURN(writeCMD(WRPWMA, buffer_a, CFG_GROUP_A_SIZE));
|
||||
CHECK_RETURN(writeCMD(WRPWMB, buffer_b, CFG_GROUP_B_SIZE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 amsStartBalancing(uint8 dutyCycle) { return writeCMD(UNMUTE, NULL, 0); }
|
||||
|
||||
uint8 amsStopBalancing() { return writeCMD(MUTE, NULL, 0); }
|
||||
|
||||
uint8 amsSelfTest() { return 0; }
|
||||
|
||||
uint8 amsConfigOverUnderVoltage(uint16 overVoltage, uint16 underVoltage) {
|
||||
uint8 buffer[CFG_GROUP_A_SIZE];
|
||||
|
||||
if (underVoltage & 0xF000 || overVoltage & 0xF000) { // only 12 bits allowed
|
||||
return 1;
|
||||
}
|
||||
|
||||
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_A_SIZE));
|
||||
|
||||
//UV
|
||||
buffer[0] = (uint8) (underVoltage & 0xFF);
|
||||
buffer[1] &= 0xF0;
|
||||
buffer[1] |= (uint8) ((underVoltage >> 8) & 0x0F);
|
||||
|
||||
//OV
|
||||
buffer[1] &= 0x0F;
|
||||
buffer[1] |= (uint8) (overVoltage << 4);
|
||||
buffer[2] = (uint8) (overVoltage >> 4);
|
||||
|
||||
return writeCMD(WRCFGB, buffer, CFG_GROUP_A_SIZE);
|
||||
}
|
||||
|
||||
uint8 amsCheckUnderOverVoltage(Cell_Module* module) {
|
||||
uint8 regbuffer[STATUS_GROUP_D_SIZE];
|
||||
uint32 ov_uv_data = 0;
|
||||
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
|
||||
ov_uv_data = (regbuffer[0] << 0) | (regbuffer[1] << 8) |
|
||||
(regbuffer[2] << 16) | (regbuffer[3] << 24);
|
||||
|
||||
module->overVoltage = 0;
|
||||
module->underVoltage = 0;
|
||||
|
||||
for (size_t i = 0; i < numberofcells; i++) { // ov/uv flags are 1-bit flags for each cell C0UV, C0OV, C1UV, C1OV, ...
|
||||
module->underVoltage |= (ov_uv_data >> (i * 2)) & 0x01;
|
||||
module->overVoltage |= (ov_uv_data >> (i * 2 + 1)) & 0x01;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 amsClearAux() {
|
||||
uint8 buffer[6];
|
||||
return writeCMD(CLRAUX, buffer, 0);
|
||||
}
|
||||
|
||||
uint8 amsClearCells() {
|
||||
uint8 buffer[6];
|
||||
return writeCMD(CLRCELL, buffer, 0);
|
||||
}
|
||||
|
||||
uint8 amsReadCellVoltages(Cell_Module* module) {
|
||||
uint8 rxbuffer[CV_GROUP_A_SIZE];
|
||||
CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[0] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->cellVoltages[1] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->cellVoltages[2] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVB, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[3] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->cellVoltages[4] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->cellVoltages[5] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVC, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[6] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->cellVoltages[7] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->cellVoltages[8] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVD, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[9] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->cellVoltages[10] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->cellVoltages[11] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVE, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[12] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
module->cellVoltages[13] = mV_from_ADBMS6830(rxbuffer[2] | (rxbuffer[3] << 8));
|
||||
module->cellVoltages[14] = mV_from_ADBMS6830(rxbuffer[4] | (rxbuffer[5] << 8));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVF, rxbuffer, CV_GROUP_A_SIZE));
|
||||
module->cellVoltages[15] = mV_from_ADBMS6830(rxbuffer[0] | (rxbuffer[1] << 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
347
Core/Src/ADBMS_LL_Driver.c
Normal file
347
Core/Src/ADBMS_LL_Driver.c
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* ADBMS_LL_Driver.c
|
||||
*
|
||||
* Created on: 05.06.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define INITIAL_COMMAND_PEC 0x0010
|
||||
#define INITIAL_DATA_PEC 0x0010
|
||||
#define ADBMS_SPI_TIMEOUT 100 // Timeout in ms
|
||||
#warning ask about the timeout value
|
||||
|
||||
SPI_HandleTypeDef* adbmsspi;
|
||||
|
||||
uint8 adbmsDriverInit(SPI_HandleTypeDef* hspi) {
|
||||
mcuAdbmsCSLow();
|
||||
HAL_Delay(1);
|
||||
mcuAdbmsCSHigh();
|
||||
adbmsspi = hspi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//command PEC calculation
|
||||
//CRC-15
|
||||
//x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
|
||||
|
||||
uint8 calculateCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
uint16 currentpec = INITIAL_COMMAND_PEC;
|
||||
if (datalen >= 3) {
|
||||
for (int i = 0; i < (datalen - 2); i++) {
|
||||
for (int n = 0; n < 8; n++) {
|
||||
uint8 din = data[i] << (n);
|
||||
currentpec = updateCommandPEC(currentpec, din);
|
||||
}
|
||||
}
|
||||
|
||||
data[datalen - 2] = (currentpec >> 7) & 0xFF;
|
||||
data[datalen - 1] = (currentpec << 1) & 0xFF;
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 checkCommandPEC(uint8* data, uint8 datalen) {
|
||||
if (datalen <= 3) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
uint16 currentpec = INITIAL_COMMAND_PEC;
|
||||
|
||||
for (int i = 0; i < (datalen - 2); i++) {
|
||||
for (int n = 0; n < 8; n++) {
|
||||
uint8 din = data[i] << (n);
|
||||
currentpec = updateCommandPEC(currentpec, din);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 pechigh = (currentpec >> 7) & 0xFF;
|
||||
uint8 peclow = (currentpec << 1) & 0xFF;
|
||||
|
||||
if ((pechigh == data[datalen - 2]) && (peclow == data[datalen - 1])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16 updateCommandPEC(uint16 currentPEC, uint8 din) {
|
||||
din = (din >> 7) & 0x01;
|
||||
uint8 in0 = din ^ ((currentPEC >> 14) & 0x01);
|
||||
uint8 in3 = in0 ^ ((currentPEC >> 2) & 0x01);
|
||||
uint8 in4 = in0 ^ ((currentPEC >> 3) & 0x01);
|
||||
uint8 in7 = in0 ^ ((currentPEC >> 6) & 0x01);
|
||||
uint8 in8 = in0 ^ ((currentPEC >> 7) & 0x01);
|
||||
uint8 in10 = in0 ^ ((currentPEC >> 9) & 0x01);
|
||||
uint8 in14 = in0 ^ ((currentPEC >> 13) & 0x01);
|
||||
|
||||
uint16 newPEC = 0;
|
||||
|
||||
newPEC |= in14 << 14;
|
||||
newPEC |= (currentPEC & (0x01 << 12)) << 1;
|
||||
newPEC |= (currentPEC & (0x01 << 11)) << 1;
|
||||
newPEC |= (currentPEC & (0x01 << 10)) << 1;
|
||||
newPEC |= in10 << 10;
|
||||
newPEC |= (currentPEC & (0x01 << 8)) << 1;
|
||||
newPEC |= in8 << 8;
|
||||
newPEC |= in7 << 7;
|
||||
newPEC |= (currentPEC & (0x01 << 5)) << 1;
|
||||
newPEC |= (currentPEC & (0x01 << 4)) << 1;
|
||||
newPEC |= in4 << 4;
|
||||
newPEC |= in3 << 3;
|
||||
newPEC |= (currentPEC & (0x01 << 1)) << 1;
|
||||
newPEC |= (currentPEC & (0x01)) << 1;
|
||||
newPEC |= in0;
|
||||
|
||||
return newPEC;
|
||||
}
|
||||
|
||||
//data PEC calculation
|
||||
//CRC-10
|
||||
//x^10 + x^7 + x^3 + x^2 + x + 1
|
||||
|
||||
uint16_t pec10_calc(bool rx_cmd, int len, uint8_t* data) {
|
||||
uint16_t remainder = 16; /* PEC_SEED; 0000010000 */
|
||||
uint16_t polynom = 0x8F; /* x10 + x7 + x3 + x2 + x + 1 <- the CRC15 polynomial
|
||||
100 1000 1111 48F */
|
||||
|
||||
/* Perform modulo-2 division, a byte at a time. */
|
||||
for (uint8_t pbyte = 0; pbyte < len; ++pbyte) {
|
||||
/* Bring the next byte into the remainder. */
|
||||
remainder ^= (uint16_t)(data[pbyte] << 2);
|
||||
/* Perform modulo-2 division, a bit at a time.*/
|
||||
for (uint8_t bit_ = 8; bit_ > 0; --bit_) {
|
||||
/* Try to divide the current data bit. */
|
||||
if ((remainder & 0x200) >
|
||||
0) // equivalent to remainder & 2^14 simply check for MSB
|
||||
{
|
||||
remainder = (uint16_t)((remainder << 1));
|
||||
remainder = (uint16_t)(remainder ^ polynom);
|
||||
} else {
|
||||
remainder = (uint16_t)(remainder << 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rx_cmd == true) {
|
||||
remainder ^= (uint16_t)((data[len] & 0xFC) << 2);
|
||||
/* Perform modulo-2 division, a bit at a time */
|
||||
for (uint8_t bit_ = 6; bit_ > 0; --bit_) {
|
||||
/* Try to divide the current data bit */
|
||||
if ((remainder & 0x200) >
|
||||
0) // equivalent to remainder & 2^14 simply check for MSB
|
||||
{
|
||||
remainder = (uint16_t)((remainder << 1));
|
||||
remainder = (uint16_t)(remainder ^ polynom);
|
||||
} else {
|
||||
remainder = (uint16_t)((remainder << 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ((uint16_t)(remainder & 0x3FF));
|
||||
}
|
||||
|
||||
typedef uint16_t crc;
|
||||
crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes);
|
||||
|
||||
uint8 calculateDataPEC(uint8_t* data, uint8_t datalen) {
|
||||
|
||||
if (datalen >= 3) {
|
||||
|
||||
|
||||
crc currentpec = pec10_calc(true, datalen - 2, data) & 0x3FF; // mask to 10 bits
|
||||
|
||||
// memory layout is [[zeroes], PEC[9:8]], [PEC[7:0]]
|
||||
data[datalen - 2] = (currentpec >> 8) & 0xFF;
|
||||
data[datalen - 1] = currentpec & 0xFF;
|
||||
|
||||
volatile uint8 result = pec10_calc(true, datalen, data);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 checkDataPEC(uint8* data, uint8 len) {
|
||||
if (len <= 2) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
crc currentpec = F_CRC_CalculaCheckSum(data, len);
|
||||
|
||||
return (currentpec == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static crc F_CRC_ObtenValorDeTabla(uint8_t VP_Pos_Tabla) {
|
||||
crc VP_CRCTableValue = 0;
|
||||
uint8_t VP_Pos_bit = 0;
|
||||
|
||||
VP_CRCTableValue = ((crc)(VP_Pos_Tabla)) << (10 - 8);
|
||||
|
||||
for (VP_Pos_bit = 0; VP_Pos_bit < 8; VP_Pos_bit++) {
|
||||
if (VP_CRCTableValue & (((crc)1) << (10 - 1))) {
|
||||
VP_CRCTableValue = (VP_CRCTableValue << 1) ^ 0x8F;
|
||||
} else {
|
||||
VP_CRCTableValue = (VP_CRCTableValue << 1);
|
||||
}
|
||||
}
|
||||
return ((VP_CRCTableValue));
|
||||
}
|
||||
crc F_CRC_CalculaCheckSum(uint8_t const AF_Datos[], uint16_t VF_nBytes) {
|
||||
crc VP_CRCTableValue = 16;
|
||||
int16_t VP_bytes = 0;
|
||||
|
||||
for (VP_bytes = 0; VP_bytes < VF_nBytes; VP_bytes++) {
|
||||
|
||||
VP_CRCTableValue = (VP_CRCTableValue << 8) ^
|
||||
F_CRC_ObtenValorDeTabla(
|
||||
((uint8_t)((VP_CRCTableValue >> (10 - 8)) & 0xFF)) ^
|
||||
AF_Datos[VP_bytes]);
|
||||
}
|
||||
|
||||
if ((8 * sizeof(crc)) > 10) {
|
||||
VP_CRCTableValue = VP_CRCTableValue & ((((crc)(1)) << 10) - 1);
|
||||
}
|
||||
|
||||
return (VP_CRCTableValue ^ 0x0000);
|
||||
}
|
||||
|
||||
uint16 updateDataPEC(uint16 currentPEC, uint8 din) {
|
||||
din = (din >> 7) & 0x01;
|
||||
uint8 in0 = din ^ ((currentPEC >> 9) & 0x01);
|
||||
uint8 in2 = in0 ^ ((currentPEC >> 1) & 0x01);
|
||||
uint8 in3 = in0 ^ ((currentPEC >> 2) & 0x01);
|
||||
uint8 in7 = in0 ^ ((currentPEC >> 6) & 0x01);
|
||||
|
||||
uint16 newPEC = 0;
|
||||
|
||||
newPEC |= (currentPEC & (0x01 << 8)) << 1;
|
||||
newPEC |= (currentPEC & (0x01 << 7)) << 1;
|
||||
newPEC |= in7 << 7;
|
||||
newPEC |= (currentPEC & (0x01 << 5)) << 1;
|
||||
newPEC |= (currentPEC & (0x01 << 4)) << 1;
|
||||
newPEC |= in3 << 3;
|
||||
newPEC |= in2 << 2;
|
||||
newPEC |= (currentPEC & (0x01)) << 1;
|
||||
newPEC |= in0;
|
||||
|
||||
return newPEC;
|
||||
}
|
||||
|
||||
uint8 writeCMD(uint16 command, uint8* args, uint8 arglen) {
|
||||
uint8 ret;
|
||||
if (arglen > 0) {
|
||||
uint8 buffer[6 + arglen]; //command + PEC (2 bytes) + data + DPEC (2 bytes)
|
||||
buffer[0] = (command >> 8) & 0xFF;
|
||||
buffer[1] = (command) & 0xFF;
|
||||
|
||||
calculateCommandPEC(buffer, 4);
|
||||
|
||||
for (uint8 i = 0; i < arglen; i++) {
|
||||
buffer[4 + i] = args[i];
|
||||
}
|
||||
|
||||
calculateDataPEC(&buffer[4], arglen + 2); //DPEC is calculated over the data, not the command, and placed at the end of the data
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
ret = mcuSPITransmit(buffer, 6 + arglen);
|
||||
mcuAdbmsCSHigh();
|
||||
} else {
|
||||
uint8 buffer[4];
|
||||
buffer[0] = (command >> 8) & 0xFF;
|
||||
buffer[1] = (command) & 0xFF;
|
||||
calculateCommandPEC(buffer, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
|
||||
ret = mcuSPITransmit(buffer, 4);
|
||||
|
||||
mcuAdbmsCSHigh();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 readCMD(uint16 command, uint8* buffer, uint8 buflen) {
|
||||
uint8 txbuffer[6 + buflen] = {};
|
||||
uint8 rxbuffer[6 + buflen] = {};
|
||||
|
||||
txbuffer[0] = (command >> 8) & 0xFF;
|
||||
txbuffer[1] = (command)&0xFF;
|
||||
calculateCommandPEC(txbuffer, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
uint8 status = mcuSPITransmitReceive(rxbuffer, txbuffer, 6 + buflen);
|
||||
mcuAdbmsCSHigh();
|
||||
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < buflen; i++) {
|
||||
buffer[i] = rxbuffer[i + 4];
|
||||
}
|
||||
|
||||
[[maybe_unused]] uint8 commandCounter = rxbuffer[sizeof(rxbuffer) - 2] & 0xFC; //command counter is bits 7-2
|
||||
//TODO: check command counter?
|
||||
|
||||
return checkDataPEC(&rxbuffer[4], buflen + 2);
|
||||
}
|
||||
|
||||
//check poll command - no data PEC sent back
|
||||
uint8 pollCMD(uint16 command) {
|
||||
uint8 txbuffer[5] = {};
|
||||
uint8 rxbuffer[5] = {};
|
||||
|
||||
txbuffer[0] = (command >> 8) & 0xFF;
|
||||
txbuffer[1] = (command)&0xFF;
|
||||
calculateCommandPEC(txbuffer, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
uint8 status = mcuSPITransmitReceive(rxbuffer, txbuffer, 5);
|
||||
mcuAdbmsCSHigh();
|
||||
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return rxbuffer[4]; //last byte will be poll response
|
||||
}
|
||||
|
||||
void mcuAdbmsCSLow() {
|
||||
//HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void mcuAdbmsCSHigh() {
|
||||
//HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
uint8 mcuSPITransmit(uint8* buffer, uint8 buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
uint8 rxbuf[buffersize];
|
||||
status = HAL_SPI_TransmitReceive(adbmsspi, buffer, rxbuf, buffersize,
|
||||
ADBMS_SPI_TIMEOUT);
|
||||
__HAL_SPI_CLEAR_OVRFLAG(adbmsspi);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8 mcuSPIReceive(uint8* buffer, uint8 buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
status = HAL_SPI_Receive(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8 mcuSPITransmitReceive(uint8* rxbuffer, uint8* txbuffer,
|
||||
uint8 buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
status = HAL_SPI_TransmitReceive(adbmsspi, txbuffer, rxbuffer, buffersize,
|
||||
ADBMS_SPI_TIMEOUT);
|
||||
return status;
|
||||
}
|
||||
|
||||
inline void mcuDelay(uint16 delay) { HAL_Delay(delay); }
|
||||
113
Core/Src/AMS_CAN.c
Normal file
113
Core/Src/AMS_CAN.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* AMS_CAN.c
|
||||
*
|
||||
* Created on: Mar 19, 2022
|
||||
* Author: jasper
|
||||
*/
|
||||
|
||||
#include "AMS_CAN.h"
|
||||
|
||||
#include "ADBMS_Abstraction.h"
|
||||
|
||||
#include "AMS_HighLevel.h"
|
||||
#include "TMP1075.h"
|
||||
#include "common_defs.h"
|
||||
#include "eeprom.h"
|
||||
#include "errors.h"
|
||||
#include "main.h"
|
||||
#include "stm32f3xx.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include "stm32f3xx_hal_can.h"
|
||||
|
||||
#include "can-halal.h"
|
||||
#include "stm32f3xx_hal_gpio.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CAN_ID_SLAVE_PANIC 0x009
|
||||
#define CAN_ID_SLAVE_STATUS_BASE 0x080
|
||||
#define CAN_ID_SLAVE_LOG_BASE 0x600
|
||||
|
||||
void ams_can_init(CAN_HandleTypeDef* hcan) { ftcan_init(hcan); }
|
||||
|
||||
#define ITER_COUNT 10
|
||||
static uint8_t count = 0;
|
||||
static bool isOn = false;
|
||||
|
||||
void ams_can_send_status() {
|
||||
if (count == ITER_COUNT) {
|
||||
HAL_GPIO_WritePin(STATUS_LED_G_GPIO_Port, STATUS_LED_G_Pin, isOn ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(STATUS_LED_B_GPIO_Port, STATUS_LED_B_Pin, isOn ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
|
||||
count = 0;
|
||||
isOn = !isOn;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
|
||||
static uint8_t data[8];
|
||||
int error = error_data.error_sources != 0;
|
||||
data[0] = eeprom_config.id | (error << 7);
|
||||
data[1] = stateofcharge;
|
||||
uint8_t* ptr = &data[2];
|
||||
uint16_t min_volt = 0xFFFF;
|
||||
uint16_t max_volt = 0;
|
||||
for (size_t i = 0; i < numberofCells; i++) {
|
||||
if (module.cellVoltages[i] < min_volt) {
|
||||
min_volt = module.cellVoltages[i];
|
||||
}
|
||||
if (module.cellVoltages[i] > max_volt) {
|
||||
max_volt = module.cellVoltages[i];
|
||||
}
|
||||
}
|
||||
ptr = ftcan_marshal_unsigned(ptr, min_volt, 2);
|
||||
ptr = ftcan_marshal_unsigned(ptr, max_volt, 2);
|
||||
int16_t max_temp = -0x8000;
|
||||
for (size_t i = 0; i < N_TEMP_SENSORS; i++) {
|
||||
if (tmp1075_temps[i] > max_temp &&
|
||||
(tmp1075_failed_sensors & (1 << i)) == 0) {
|
||||
max_temp = tmp1075_temps[i];
|
||||
}
|
||||
}
|
||||
ftcan_marshal_unsigned(ptr, max_temp, 2);
|
||||
uint16_t id = CAN_ID_SLAVE_STATUS_BASE | eeprom_config.id;
|
||||
ftcan_transmit(id, data, sizeof(data));
|
||||
}
|
||||
|
||||
void ams_can_send_error() {
|
||||
static uint8_t data[6];
|
||||
data[0] = eeprom_config.id;
|
||||
data[1] = error_data.data_kind;
|
||||
memcpy(&data[2], error_data.data, 4);
|
||||
ftcan_transmit(CAN_ID_SLAVE_PANIC, data, sizeof(data));
|
||||
}
|
||||
|
||||
void ams_can_send_log() {
|
||||
static uint8_t call_count = 0;
|
||||
static uint8_t data[8];
|
||||
|
||||
uint16_t can_addr =
|
||||
CAN_ID_SLAVE_LOG_BASE | (eeprom_config.id << 4) | call_count;
|
||||
uint8_t* ptr = &data[0];
|
||||
|
||||
if (call_count < N_CELLS / 4) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
size_t offset = call_count * 4;
|
||||
ptr = ftcan_marshal_unsigned(ptr, module.cellVoltages[offset + i], 2);
|
||||
}
|
||||
ftcan_transmit(can_addr, data, sizeof(data));
|
||||
} else if (call_count == N_CELLS / 4) {
|
||||
// Send last cell & failed temperature sensors
|
||||
ptr = ftcan_marshal_unsigned(ptr, module.cellVoltages[N_CELLS - 1], 2);
|
||||
ptr = ftcan_marshal_unsigned(ptr, tmp1075_failed_sensors, 4);
|
||||
ftcan_transmit(can_addr, data, 6);
|
||||
} else {
|
||||
size_t offset = (call_count - N_CELLS / 4 - 1) * 8;
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
data[i] = tmp1075_temps[offset + i] >> 4;
|
||||
}
|
||||
ftcan_transmit(can_addr, data, sizeof(data));
|
||||
}
|
||||
call_count = (call_count + 1) % (N_CELLS / 4 + 1 + N_TEMP_SENSORS / 8);
|
||||
}
|
||||
348
Core/Src/AMS_HighLevel.c
Normal file
348
Core/Src/AMS_HighLevel.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* AMS_HighLevel.c
|
||||
*
|
||||
* Created on: 20.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "AMS_HighLevel.h"
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "AMS_CAN.h"
|
||||
#include "TMP1075.h"
|
||||
#include "can-halal.h"
|
||||
#include "errors.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
Cell_Module module = {};
|
||||
uint32_t balancedCells = 0;
|
||||
uint8_t BalancingActive = 0;
|
||||
uint8_t stateofcharge = 100;
|
||||
int64_t currentintegrator = 0;
|
||||
uint32_t lastticks = 0;
|
||||
uint32_t currenttick = 0;
|
||||
uint8_t eepromconfigured = 0;
|
||||
|
||||
uint8_t internalbalancingalgo = 1;
|
||||
uint16_t startbalancingthreshold = 41000;
|
||||
uint16_t stopbalancingthreshold = 30000;
|
||||
uint16_t balancingvoltagedelta = 10;
|
||||
|
||||
uint16_t amsuv = 0;
|
||||
uint16_t amsov = 0;
|
||||
|
||||
uint8_t amserrorcode = 0;
|
||||
uint8_t amswarningcode = 0;
|
||||
|
||||
uint8_t numberofCells = 16;
|
||||
uint8_t numberofAux = 0;
|
||||
|
||||
uint8_t packetChecksumFails = 0;
|
||||
#define MAX_PACKET_CHECKSUM_FAILS 5
|
||||
|
||||
uint8_t deviceSleeps = 0;
|
||||
#define MAX_DEVICE_SLEEP 3 //TODO: change to correct value
|
||||
|
||||
amsState currentAMSState = AMSDEACTIVE;
|
||||
amsState lastAMSState = AMSDEACTIVE;
|
||||
|
||||
struct pollingTimes {
|
||||
uint32_t S_ADC_OW_CHECK;
|
||||
uint32_t TMP1075;
|
||||
};
|
||||
|
||||
struct pollingTimes pollingTimes = {0, 0, 0, 0};
|
||||
|
||||
void AMS_Init(SPI_HandleTypeDef* hspi) {
|
||||
if (eepromconfigured == 1) {
|
||||
/*amsov = eepromcellovervoltage>>4;
|
||||
amsuv = (eepromcellundervoltage-1)>>4;
|
||||
numberofCells = eepromnumofcells;
|
||||
numberofAux = eepromnumofaux;
|
||||
initAMS(hspi, eepromnumofcells, eepromnumofaux);*/
|
||||
amsConfigOverUnderVoltage(amsov, amsuv);
|
||||
} else {
|
||||
initAMS(hspi, numberofCells, numberofAux);
|
||||
amsov = DEFAULT_OV;
|
||||
amsuv = DEFAULT_UV;
|
||||
}
|
||||
|
||||
pollingTimes = (struct pollingTimes) {HAL_GetTick(), HAL_GetTick()};
|
||||
|
||||
currentAMSState = AMSIDLE;
|
||||
}
|
||||
|
||||
void AMS_Loop() {
|
||||
|
||||
// On Transition Functions called ones if the State Changed
|
||||
|
||||
if (currentAMSState != lastAMSState) {
|
||||
switch (currentAMSState) {
|
||||
case AMSIDLE:
|
||||
break;
|
||||
case AMSDEACTIVE:
|
||||
break;
|
||||
case AMSCHARGING:
|
||||
break;
|
||||
case AMSIDLEBALANCING:
|
||||
break;
|
||||
case AMSDISCHARGING:
|
||||
break;
|
||||
case AMSWARNING:
|
||||
writeWarningLog(0x01);
|
||||
break;
|
||||
case AMSERROR:
|
||||
writeErrorLog(amserrorcode);
|
||||
break;
|
||||
}
|
||||
lastAMSState = currentAMSState;
|
||||
}
|
||||
|
||||
// Main Loops for different AMS States
|
||||
|
||||
switch (currentAMSState) {
|
||||
case AMSIDLE:
|
||||
AMS_Idle_Loop();
|
||||
break;
|
||||
case AMSDEACTIVE:
|
||||
break;
|
||||
case AMSCHARGING:
|
||||
break;
|
||||
case AMSIDLEBALANCING:
|
||||
AMS_Idle_Loop();
|
||||
break;
|
||||
case AMSDISCHARGING:
|
||||
break;
|
||||
case AMSWARNING:
|
||||
AMS_Warning_Loop();
|
||||
break;
|
||||
case AMSERROR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AMS_Idle_Loop() {
|
||||
if (!amsWakeUp()) {
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT;
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
}
|
||||
|
||||
packetChecksumFails += amsAuxAndStatusMeasurement(&module);
|
||||
|
||||
if (module.status.SLEEP) {
|
||||
deviceSleeps++;
|
||||
if (deviceSleeps > MAX_DEVICE_SLEEP) {
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT;
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
} else {
|
||||
amsReset();
|
||||
}
|
||||
}
|
||||
|
||||
if (module.status.CS_FLT || module.status.SPIFLT || module.status.CMED ||
|
||||
module.status.SMED || module.status.VDE || module.status.VDEL ||
|
||||
module.status.OSCCHK || module.status.TMODCHK) {
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_FAULT;
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
}
|
||||
|
||||
if (module.status.THSD) {
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_OVERTEMP;
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
}
|
||||
|
||||
packetChecksumFails += amsCellMeasurement(&module);
|
||||
packetChecksumFails += amsCheckUnderOverVoltage(&module);
|
||||
packetChecksumFails += integrateCurrent();
|
||||
|
||||
if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) {
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_CHECKSUM_FAIL;
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
}
|
||||
|
||||
tmp1075_measure();
|
||||
|
||||
int any_voltage_error = 0;
|
||||
for (size_t i = 0; i < numberofCells; i++) {
|
||||
if (module.cellVoltages[i] < 2500) {
|
||||
any_voltage_error = 1;
|
||||
error_data.data_kind = SEK_UNDERVOLT;
|
||||
error_data.data[0] = i;
|
||||
uint8_t* ptr = &error_data.data[1];
|
||||
ptr = ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2);
|
||||
} else if (module.cellVoltages[i] > 4200) {
|
||||
any_voltage_error = 1;
|
||||
error_data.data_kind = SEK_OVERVOLT;
|
||||
error_data.data[0] = i;
|
||||
uint8_t* ptr = &error_data.data[1];
|
||||
ptr = ftcan_marshal_unsigned(ptr, module.cellVoltages[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (module.internalDieTemp > 28000) { //TODO: change to correct value
|
||||
error_data.data_kind = SEK_INTERNAL_BMS_OVERTEMP;
|
||||
uint8_t* ptr = &error_data.data[0];
|
||||
ptr = ftcan_marshal_unsigned(ptr, module.internalDieTemp, 2);
|
||||
|
||||
set_error_source(ERROR_SOURCE_INTERNAL);
|
||||
} else {
|
||||
clear_error_source(ERROR_SOURCE_INTERNAL);
|
||||
}
|
||||
|
||||
if (any_voltage_error) {
|
||||
set_error_source(ERROR_SOURCE_VOLTAGES);
|
||||
} else {
|
||||
clear_error_source(ERROR_SOURCE_VOLTAGES);
|
||||
}
|
||||
|
||||
mcuDelay(10);
|
||||
|
||||
// static uint32_t channelstobalance = 1;
|
||||
|
||||
// channelstobalance = 0x1FFFF;
|
||||
/* if(channelstobalance & 0x20000){
|
||||
channelstobalance = 1;
|
||||
}*/
|
||||
|
||||
// amsConfigBalancing(channelstobalance);
|
||||
// amsStartBalancing(100);
|
||||
|
||||
if ((module.overVoltage | module.underVoltage)) {
|
||||
// amsSendWarning();
|
||||
// currentAMSState = AMSWARNING;
|
||||
}
|
||||
|
||||
// AMS_Balancing_Loop();
|
||||
|
||||
/* if(BalancingActive)
|
||||
{
|
||||
amsStartBalancing(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
amsStopBalancing();
|
||||
}*/
|
||||
// amsConfigBalancing(balancedCells);
|
||||
// volatile amscheck = amscheckOpenCellWire(&module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AMS_Warning_Loop() {
|
||||
|
||||
amsWakeUp();
|
||||
amsConfigOverUnderVoltage(amsov, amsuv);
|
||||
amsClearAux();
|
||||
amsCellMeasurement(&module);
|
||||
amsAuxAndStatusMeasurement(&module);
|
||||
amsCheckUnderOverVoltage(&module);
|
||||
|
||||
if (!(module.overVoltage | module.underVoltage)) {
|
||||
currentAMSState = AMSIDLE;
|
||||
// amsClearWarning();
|
||||
}
|
||||
amsStopBalancing();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AMS_Error_Loop() { return 0; }
|
||||
|
||||
uint8_t AMS_Charging_Loop() { return 0; }
|
||||
|
||||
uint8_t AMS_Discharging_Loop() { return 0; }
|
||||
|
||||
uint8_t AMS_Balancing_Loop() {
|
||||
uint8_t balancingdone = 1;
|
||||
if ((eepromconfigured == 1) && (internalbalancingalgo == 1) &&
|
||||
(module.internalDieTemp <
|
||||
28000 /*Thermal Protection 93°C*/)) // If the EEPROM is configured and
|
||||
// the internal Balancing Algorithm
|
||||
// should be used
|
||||
{
|
||||
uint16_t highestcellvoltage = module.cellVoltages[0];
|
||||
uint16_t lowestcellvoltage = module.cellVoltages[0];
|
||||
uint8_t highestcell = 0;
|
||||
uint8_t lowestcell = 0;
|
||||
|
||||
for (uint8_t n = 0; n < numberofCells; n++) {
|
||||
if (module.cellVoltages[n] > highestcellvoltage) {
|
||||
highestcellvoltage = module.cellVoltages[n];
|
||||
highestcell = n;
|
||||
}
|
||||
if (module.cellVoltages[n] < lowestcellvoltage) {
|
||||
lowestcellvoltage = module.cellVoltages[n];
|
||||
lowestcell = n;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentAMSState ==
|
||||
AMSCHARGING) // Balancing is only Active if the BMS is in Charging Mode
|
||||
{
|
||||
|
||||
uint32_t channelstobalance = 0;
|
||||
|
||||
if (highestcellvoltage > startbalancingthreshold) {
|
||||
for (uint8_t n = 0; n < numberofCells; n++) {
|
||||
if (module.cellVoltages[n] > stopbalancingthreshold) {
|
||||
uint16_t dv = module.cellVoltages[n] - lowestcellvoltage;
|
||||
if (dv > (balancingvoltagedelta * 1000)) {
|
||||
balancingdone = 0;
|
||||
channelstobalance |= 1 << n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amsConfigBalancing(channelstobalance, 0x0F);
|
||||
amsStartBalancing(100);
|
||||
}
|
||||
|
||||
else if (currentAMSState == AMSIDLEBALANCING) {
|
||||
|
||||
uint32_t channelstobalance = 0;
|
||||
|
||||
if (lowestcellvoltage <
|
||||
stopbalancingthreshold) // If under Voltage of one Cell is reached
|
||||
{
|
||||
amsStopBalancing();
|
||||
balancingdone = 1;
|
||||
} else // otherwise continue with regular Balancing Algorithm
|
||||
{
|
||||
for (uint8_t n = 0; n < numberofCells; n++) {
|
||||
uint16_t dv = module.cellVoltages[n] - lowestcellvoltage;
|
||||
if (dv > balancingvoltagedelta) {
|
||||
balancingdone = 0;
|
||||
channelstobalance |= 1 << n;
|
||||
}
|
||||
}
|
||||
|
||||
amsConfigBalancing(channelstobalance, 0x0F);
|
||||
amsStartBalancing(100);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
amsStopBalancing();
|
||||
balancingdone = 1;
|
||||
}
|
||||
return balancingdone;
|
||||
}
|
||||
|
||||
uint8_t writeWarningLog(uint8_t warningCode) {
|
||||
// eepromWriteWarningLog(warningCode);
|
||||
return 0;
|
||||
}
|
||||
uint8_t writeErrorLog(uint8_t errorCode) {
|
||||
// eepromWriteErrorLog(errorCode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t integrateCurrent() {
|
||||
lastticks = currenttick;
|
||||
currenttick = HAL_GetTick();
|
||||
if (currenttick < lastticks) {
|
||||
currentintegrator += (module.auxVoltages[0] - module.auxVoltages[2]) *
|
||||
(currenttick - lastticks);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
83
Core/Src/TMP1075.c
Normal file
83
Core/Src/TMP1075.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include "TMP1075.h"
|
||||
|
||||
#include "can-halal.h"
|
||||
|
||||
#include "errors.h"
|
||||
#include "stm32f3xx_hal_def.h"
|
||||
#include "stm32f3xx_hal_i2c.h"
|
||||
|
||||
#define MAX_TEMP ((int16_t)(59 / 0.0625f))
|
||||
#define MAX_FAILED_TEMP 12 //TODO: change value for compliance with the actual number of sensors
|
||||
#warning "change value for compliance with the actual number of sensors"
|
||||
|
||||
int16_t tmp1075_temps[N_TEMP_SENSORS] = {0};
|
||||
uint32_t tmp1075_failed_sensors = 0;
|
||||
uint8_t nfailed_temp_sensors = 0;
|
||||
|
||||
I2C_HandleTypeDef* hi2c;
|
||||
|
||||
HAL_StatusTypeDef tmp1075_init(I2C_HandleTypeDef* handle) {
|
||||
hi2c = handle;
|
||||
for (int i = 0; i < N_TEMP_SENSORS; i++) {
|
||||
HAL_StatusTypeDef status = tmp1075_sensor_init(i);
|
||||
if (status != HAL_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
void handle_over_maxtemp(uint8_t index, uint16_t value) {
|
||||
set_error_source(ERROR_SOURCE_TEMPERATURES);
|
||||
error_data.data_kind = SEK_OVERTEMP;
|
||||
error_data.data[0] = index;
|
||||
uint8_t* ptr = &error_data.data[1];
|
||||
ptr = ftcan_marshal_unsigned(ptr, value, 2);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef tmp1075_measure() {
|
||||
int err = 0;
|
||||
int temp_error = 0;
|
||||
for (int i = 0; i < N_TEMP_SENSORS; i++) {
|
||||
if (tmp1075_sensor_read(i, &tmp1075_temps[i]) != HAL_OK ||
|
||||
(tmp1075_temps[i] & 0x000F) != 0) {
|
||||
tmp1075_failed_sensors |= 1 << i;
|
||||
nfailed_temp_sensors++;
|
||||
err = 1;
|
||||
} else {
|
||||
tmp1075_temps[i] >>= 4;
|
||||
tmp1075_failed_sensors &= ~(1 << i);
|
||||
if (tmp1075_temps[i] >= MAX_TEMP) {
|
||||
temp_error = 1;
|
||||
handle_over_maxtemp(i, tmp1075_temps[i]);
|
||||
}
|
||||
#warning "check for under temp"
|
||||
}
|
||||
}
|
||||
if (nfailed_temp_sensors > MAX_FAILED_TEMP) {
|
||||
error_data.data_kind = SEK_TOO_FEW_TEMPS;
|
||||
set_error_source(ERROR_SOURCE_TEMPERATURES);
|
||||
} else if (!temp_error) {
|
||||
clear_error_source(ERROR_SOURCE_TEMPERATURES);
|
||||
}
|
||||
nfailed_temp_sensors = 0;
|
||||
return err ? HAL_ERROR : HAL_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef tmp1075_sensor_init(int n) {
|
||||
uint16_t addr = (0b1000000 | n) << 1;
|
||||
uint8_t data[] = {0};
|
||||
return HAL_I2C_Master_Transmit(hi2c, addr, data, sizeof(data), 100);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef tmp1075_sensor_read(int n, int16_t* res) {
|
||||
uint16_t addr = (0b1000000 | n) << 1;
|
||||
addr |= 1; // Read
|
||||
uint8_t result[2];
|
||||
HAL_StatusTypeDef status =
|
||||
HAL_I2C_Master_Receive(hi2c, addr, result, sizeof(result), 5); //5ms timeout for failure (cascading faliure max = 30 * 5 = 150ms)
|
||||
if (status == HAL_OK) {
|
||||
*res = (result[0] << 8) | result[1];
|
||||
}
|
||||
return status;
|
||||
}
|
||||
55
Core/Src/eeprom.c
Normal file
55
Core/Src/eeprom.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "eeprom.h"
|
||||
#include "errors.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include "stm32f3xx_hal_exti.h"
|
||||
#include "stm32f3xx_hal_i2c.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define EEPROM_I2C_ADDR 0xA0
|
||||
// Don't use the beginning of the EEPROM, since the testbench writes there
|
||||
#define EEPROM_CONFIG_BASE 0x0100
|
||||
#define EEPROM_CONFIG_ECC_OFFSET 0x20
|
||||
|
||||
EEPROMConfig eeprom_config;
|
||||
|
||||
static I2C_HandleTypeDef* hi2c;
|
||||
|
||||
void eeprom_init(I2C_HandleTypeDef* handle) {
|
||||
hi2c = handle;
|
||||
uint8_t buf[sizeof(EEPROMConfig) * 3];
|
||||
// Read 3 EEPROM config buffers at 32 byte offsets
|
||||
for (size_t ecc_i = 0; ecc_i < 3; ecc_i++) {
|
||||
HAL_I2C_Mem_Read(hi2c, EEPROM_I2C_ADDR,
|
||||
EEPROM_CONFIG_BASE + EEPROM_CONFIG_ECC_OFFSET * ecc_i, 2,
|
||||
buf + sizeof(EEPROMConfig) * ecc_i, sizeof(EEPROMConfig),
|
||||
100);
|
||||
}
|
||||
// ECC
|
||||
for (size_t i = 0; i < sizeof(EEPROMConfig); i++) {
|
||||
uint8_t a = buf[i + sizeof(EEPROMConfig) * 0];
|
||||
uint8_t b = buf[i + sizeof(EEPROMConfig) * 1];
|
||||
uint8_t c = buf[i + sizeof(EEPROMConfig) * 2];
|
||||
if (a == b || a == c) {
|
||||
buf[i] = a;
|
||||
} else if (b == c) {
|
||||
buf[i] = b;
|
||||
} else {
|
||||
set_error_source(ERROR_SOURCE_EEPROM);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&eeprom_config, buf, sizeof(EEPROMConfig));
|
||||
// Write back config
|
||||
eeprom_config.id = 10;
|
||||
eeprom_config_save();
|
||||
}
|
||||
|
||||
void eeprom_config_save() {
|
||||
for (size_t ecc_i = 0; ecc_i < 3; ecc_i++) {
|
||||
HAL_I2C_Mem_Write(hi2c, EEPROM_I2C_ADDR,
|
||||
EEPROM_CONFIG_BASE + EEPROM_CONFIG_ECC_OFFSET * ecc_i, 2,
|
||||
(uint8_t*)&eeprom_config, sizeof(eeprom_config), 100);
|
||||
HAL_Delay(100);
|
||||
}
|
||||
}
|
||||
13
Core/Src/errors.c
Normal file
13
Core/Src/errors.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include "errors.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
|
||||
SlaveErrorData error_data;
|
||||
|
||||
void set_error_source(int source) {
|
||||
if (!error_data.error_sources) {
|
||||
error_data.errors_since = HAL_GetTick();
|
||||
}
|
||||
error_data.error_sources |= source;
|
||||
}
|
||||
|
||||
void clear_error_source(int source) { error_data.error_sources &= ~source; }
|
||||
@ -21,7 +21,14 @@
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "AMS_CAN.h"
|
||||
#include "AMS_HighLevel.h"
|
||||
#include "TMP1075.h"
|
||||
#include "eeprom.h"
|
||||
#include "errors.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@ -109,7 +116,8 @@ int main(void)
|
||||
MX_USART1_UART_Init();
|
||||
MX_TIM1_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
tmp1075_init(&hi2c1);
|
||||
AMS_Init(&hspi1);
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
@ -119,6 +127,14 @@ int main(void)
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
AMS_Loop();
|
||||
|
||||
ams_can_send_status();
|
||||
if (error_data.error_sources &&
|
||||
HAL_GetTick() - error_data.errors_since >= ERROR_TIME_THRESH) {
|
||||
ams_can_send_error();
|
||||
}
|
||||
ams_can_send_log();
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
@ -139,7 +155,9 @@ void SystemClock_Config(void)
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
|
||||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
@ -149,7 +167,7 @@ void SystemClock_Config(void)
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
@ -273,11 +291,11 @@ static void MX_SPI1_Init(void)
|
||||
hspi1.Instance = SPI1;
|
||||
hspi1.Init.Mode = SPI_MODE_MASTER;
|
||||
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
|
||||
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
hspi1.Init.NSS = SPI_NSS_HARD_INPUT;
|
||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||
hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
|
||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
|
||||
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
|
||||
Reference in New Issue
Block a user