first commit
This commit is contained in:
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); }
|
||||
69
Core/Src/AMS_HighLevel.c
Normal file
69
Core/Src/AMS_HighLevel.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* AMS_HighLevel.c
|
||||
*
|
||||
* Created on: 20.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "AMS_HighLevel.h"
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "TMP1075.h"
|
||||
#include "stm32f3xx_hal.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
Cell_Module module = {};
|
||||
|
||||
uint16_t amsuv = 0;
|
||||
uint16_t amsov = 0;
|
||||
|
||||
uint8_t numberofCells = 15;
|
||||
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
|
||||
|
||||
struct pollingTimes {
|
||||
uint32_t S_ADC_OW_CHECK;
|
||||
uint32_t TMP1075;
|
||||
};
|
||||
|
||||
struct pollingTimes pollingTimes = {0, 0};
|
||||
|
||||
uint8_t AMS_Init(SPI_HandleTypeDef* hspi) {
|
||||
uint8_t ret = initAMS(hspi, numberofCells, numberofAux);
|
||||
amsov = DEFAULT_OV;
|
||||
amsuv = DEFAULT_UV;
|
||||
|
||||
pollingTimes = (struct pollingTimes) {HAL_GetTick(), HAL_GetTick()};
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t AMS_Idle_Loop() {
|
||||
if (!amsWakeUp()) {
|
||||
//error_data.data_kind = SEK_INTERNAL_BMS_TIMEOUT; //we don't receive data for the wakeup command
|
||||
//set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out
|
||||
}
|
||||
|
||||
packetChecksumFails += amsAuxAndStatusMeasurement(&module);
|
||||
|
||||
if (module.status.SLEEP) {
|
||||
deviceSleeps++;
|
||||
if (deviceSleeps > MAX_DEVICE_SLEEP) {
|
||||
|
||||
} else {
|
||||
amsReset();
|
||||
}
|
||||
}
|
||||
|
||||
packetChecksumFails += amsCellMeasurement(&module);
|
||||
packetChecksumFails += amsCheckUnderOverVoltage(&module);
|
||||
|
||||
//tmp1075_measure();
|
||||
|
||||
return 0;
|
||||
}
|
||||
55
Core/Src/TMP1075.c
Normal file
55
Core/Src/TMP1075.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include "TMP1075.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_TEMP ((int16_t)(59 / 0.0625f))
|
||||
#define MIN_TEMP 0
|
||||
#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};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
HAL_StatusTypeDef tmp1075_measure() {
|
||||
for (int i = 0; i < N_TEMP_SENSORS; i++) {
|
||||
if (tmp1075_sensor_read(i, &tmp1075_temps[i]) != HAL_OK ||
|
||||
(tmp1075_temps[i] & 0x000F) != 0) {
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
return 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;
|
||||
}
|
||||
266
Core/Src/main.c
Normal file
266
Core/Src/main.c
Normal file
@ -0,0 +1,266 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2024 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "AMS_HighLevel.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
SPI_HandleTypeDef hspi2;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
static void MX_SPI2_Init(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/**
|
||||
* @brief The application entry point.
|
||||
* @retval int
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
|
||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||
HAL_Init();
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_SPI2_Init();
|
||||
AMS_Init(&hspi2);
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE END WHILE */
|
||||
AMS_Idle_Loop();
|
||||
/* USER CODE BEGIN 3 */
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
|
||||
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI2 Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_SPI2_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN SPI2_Init 0 */
|
||||
|
||||
/* USER CODE END SPI2_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN SPI2_Init 1 */
|
||||
|
||||
/* USER CODE END SPI2_Init 1 */
|
||||
/* SPI2 parameter configuration*/
|
||||
hspi2.Instance = SPI2;
|
||||
hspi2.Init.Mode = SPI_MODE_MASTER;
|
||||
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
hspi2.Init.DataSize = SPI_DATASIZE_4BIT;
|
||||
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
hspi2.Init.NSS = SPI_NSS_SOFT;
|
||||
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
hspi2.Init.CRCPolynomial = 7;
|
||||
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
|
||||
hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
|
||||
if (HAL_SPI_Init(&hspi2) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN SPI2_Init 2 */
|
||||
|
||||
/* USER CODE END SPI2_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO Initialization Function
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void MX_GPIO_Init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
/* USER CODE BEGIN MX_GPIO_Init_1 */
|
||||
/* USER CODE END MX_GPIO_Init_1 */
|
||||
|
||||
/* GPIO Ports Clock Enable */
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(CSB_GPIO_Port, CSB_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin : B1_Pin */
|
||||
GPIO_InitStruct.Pin = B1_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : USART_TX_Pin USART_RX_Pin */
|
||||
GPIO_InitStruct.Pin = USART_TX_Pin|USART_RX_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : CSB_Pin */
|
||||
GPIO_InitStruct.Pin = CSB_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
HAL_GPIO_Init(CSB_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN MX_GPIO_Init_2 */
|
||||
/* USER CODE END MX_GPIO_Init_2 */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
* @brief This function is executed in case of error occurrence.
|
||||
* @retval None
|
||||
*/
|
||||
void Error_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
__disable_irq();
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(uint8_t *file, uint32_t line)
|
||||
{
|
||||
/* USER CODE BEGIN 6 */
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
151
Core/Src/stm32f3xx_hal_msp.c
Normal file
151
Core/Src/stm32f3xx_hal_msp.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f3xx_hal_msp.c
|
||||
* @brief This file provides code for the MSP Initialization
|
||||
* and de-Initialization codes.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2024 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN TD */
|
||||
|
||||
/* USER CODE END TD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Define */
|
||||
|
||||
/* USER CODE END Define */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Macro */
|
||||
|
||||
/* USER CODE END Macro */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* External functions --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ExternalFunctions */
|
||||
|
||||
/* USER CODE END ExternalFunctions */
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
/**
|
||||
* Initializes the Global MSP.
|
||||
*/
|
||||
void HAL_MspInit(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN MspInit 0 */
|
||||
|
||||
/* USER CODE END MspInit 0 */
|
||||
|
||||
__HAL_RCC_SYSCFG_CLK_ENABLE();
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
|
||||
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
|
||||
|
||||
/* System interrupt init*/
|
||||
|
||||
/* USER CODE BEGIN MspInit 1 */
|
||||
|
||||
/* USER CODE END MspInit 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(hspi->Instance==SPI2)
|
||||
{
|
||||
/* USER CODE BEGIN SPI2_MspInit 0 */
|
||||
|
||||
/* USER CODE END SPI2_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_SPI2_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
/**SPI2 GPIO Configuration
|
||||
PB13 ------> SPI2_SCK
|
||||
PB14 ------> SPI2_MISO
|
||||
PB15 ------> SPI2_MOSI
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN SPI2_MspInit 1 */
|
||||
|
||||
/* USER CODE END SPI2_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param hspi: SPI handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
|
||||
{
|
||||
if(hspi->Instance==SPI2)
|
||||
{
|
||||
/* USER CODE BEGIN SPI2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END SPI2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_SPI2_CLK_DISABLE();
|
||||
|
||||
/**SPI2 GPIO Configuration
|
||||
PB13 ------> SPI2_SCK
|
||||
PB14 ------> SPI2_MISO
|
||||
PB15 ------> SPI2_MOSI
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
|
||||
|
||||
/* USER CODE BEGIN SPI2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END SPI2_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
203
Core/Src/stm32f3xx_it.c
Normal file
203
Core/Src/stm32f3xx_it.c
Normal file
@ -0,0 +1,203 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f3xx_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2024 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "stm32f3xx_it.h"
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN TD */
|
||||
|
||||
/* USER CODE END TD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN EV */
|
||||
|
||||
/* USER CODE END EV */
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M4 Processor Interruption and Exception Handlers */
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @brief This function handles Non maskable interrupt.
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard fault interrupt.
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END HardFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Memory management fault.
|
||||
*/
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
||||
|
||||
/* USER CODE END MemoryManagement_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
|
||||
/* USER CODE END W1_MemoryManagement_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pre-fetch fault, memory access fault.
|
||||
*/
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN BusFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END BusFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
|
||||
/* USER CODE END W1_BusFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Undefined instruction or illegal state.
|
||||
*/
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UsageFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END UsageFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
|
||||
/* USER CODE END W1_UsageFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System service call via SWI instruction.
|
||||
*/
|
||||
void SVC_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SVCall_IRQn 0 */
|
||||
|
||||
/* USER CODE END SVCall_IRQn 0 */
|
||||
/* USER CODE BEGIN SVCall_IRQn 1 */
|
||||
|
||||
/* USER CODE END SVCall_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Debug monitor.
|
||||
*/
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
|
||||
|
||||
/* USER CODE END DebugMonitor_IRQn 0 */
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
|
||||
|
||||
/* USER CODE END DebugMonitor_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pendable request for system service.
|
||||
*/
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN PendSV_IRQn 0 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 0 */
|
||||
/* USER CODE BEGIN PendSV_IRQn 1 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System tick timer.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
HAL_IncTick();
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F3xx Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/* For the available peripheral interrupt handler names, */
|
||||
/* please refer to the startup file (startup_stm32f3xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
176
Core/Src/syscalls.c
Normal file
176
Core/Src/syscalls.c
Normal file
@ -0,0 +1,176 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file syscalls.c
|
||||
* @author Auto-generated by STM32CubeMX
|
||||
* @brief Minimal System calls file
|
||||
*
|
||||
* For more information about which c-functions
|
||||
* need which of these lowlevel functions
|
||||
* please consult the Newlib libc-manual
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2020-2024 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes */
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
|
||||
|
||||
/* Variables */
|
||||
extern int __io_putchar(int ch) __attribute__((weak));
|
||||
extern int __io_getchar(void) __attribute__((weak));
|
||||
|
||||
|
||||
char *__env[1] = { 0 };
|
||||
char **environ = __env;
|
||||
|
||||
|
||||
/* Functions */
|
||||
void initialise_monitor_handles()
|
||||
{
|
||||
}
|
||||
|
||||
int _getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _kill(int pid, int sig)
|
||||
{
|
||||
(void)pid;
|
||||
(void)sig;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void _exit (int status)
|
||||
{
|
||||
_kill(status, -1);
|
||||
while (1) {} /* Make sure we hang here */
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _read(int file, char *ptr, int len)
|
||||
{
|
||||
(void)file;
|
||||
int DataIdx;
|
||||
|
||||
for (DataIdx = 0; DataIdx < len; DataIdx++)
|
||||
{
|
||||
*ptr++ = __io_getchar();
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _write(int file, char *ptr, int len)
|
||||
{
|
||||
(void)file;
|
||||
int DataIdx;
|
||||
|
||||
for (DataIdx = 0; DataIdx < len; DataIdx++)
|
||||
{
|
||||
__io_putchar(*ptr++);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int _close(int file)
|
||||
{
|
||||
(void)file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int _fstat(int file, struct stat *st)
|
||||
{
|
||||
(void)file;
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _isatty(int file)
|
||||
{
|
||||
(void)file;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _lseek(int file, int ptr, int dir)
|
||||
{
|
||||
(void)file;
|
||||
(void)ptr;
|
||||
(void)dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _open(char *path, int flags, ...)
|
||||
{
|
||||
(void)path;
|
||||
(void)flags;
|
||||
/* Pretend like we always fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _wait(int *status)
|
||||
{
|
||||
(void)status;
|
||||
errno = ECHILD;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _unlink(char *name)
|
||||
{
|
||||
(void)name;
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _times(struct tms *buf)
|
||||
{
|
||||
(void)buf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _stat(char *file, struct stat *st)
|
||||
{
|
||||
(void)file;
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _link(char *old, char *new)
|
||||
{
|
||||
(void)old;
|
||||
(void)new;
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fork(void)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _execve(char *name, char **argv, char **env)
|
||||
{
|
||||
(void)name;
|
||||
(void)argv;
|
||||
(void)env;
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
79
Core/Src/sysmem.c
Normal file
79
Core/Src/sysmem.c
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file sysmem.c
|
||||
* @author Generated by STM32CubeMX
|
||||
* @brief System Memory calls file
|
||||
*
|
||||
* For more information about which C functions
|
||||
* need which of these lowlevel functions
|
||||
* please consult the newlib libc manual
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2024 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes */
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Pointer to the current high watermark of the heap usage
|
||||
*/
|
||||
static uint8_t *__sbrk_heap_end = NULL;
|
||||
|
||||
/**
|
||||
* @brief _sbrk() allocates memory to the newlib heap and is used by malloc
|
||||
* and others from the C library
|
||||
*
|
||||
* @verbatim
|
||||
* ############################################################################
|
||||
* # .data # .bss # newlib heap # MSP stack #
|
||||
* # # # # Reserved by _Min_Stack_Size #
|
||||
* ############################################################################
|
||||
* ^-- RAM start ^-- _end _estack, RAM end --^
|
||||
* @endverbatim
|
||||
*
|
||||
* This implementation starts allocating at the '_end' linker symbol
|
||||
* The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
|
||||
* The implementation considers '_estack' linker symbol to be RAM end
|
||||
* NOTE: If the MSP stack, at any point during execution, grows larger than the
|
||||
* reserved size, please increase the '_Min_Stack_Size'.
|
||||
*
|
||||
* @param incr Memory size
|
||||
* @return Pointer to allocated memory
|
||||
*/
|
||||
void *_sbrk(ptrdiff_t incr)
|
||||
{
|
||||
extern uint8_t _end; /* Symbol defined in the linker script */
|
||||
extern uint8_t _estack; /* Symbol defined in the linker script */
|
||||
extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
|
||||
const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
|
||||
const uint8_t *max_heap = (uint8_t *)stack_limit;
|
||||
uint8_t *prev_heap_end;
|
||||
|
||||
/* Initialize heap end at first call */
|
||||
if (NULL == __sbrk_heap_end)
|
||||
{
|
||||
__sbrk_heap_end = &_end;
|
||||
}
|
||||
|
||||
/* Protect heap from growing into the reserved MSP stack */
|
||||
if (__sbrk_heap_end + incr > max_heap)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
prev_heap_end = __sbrk_heap_end;
|
||||
__sbrk_heap_end += incr;
|
||||
|
||||
return (void *)prev_heap_end;
|
||||
}
|
||||
287
Core/Src/system_stm32f3xx.c
Normal file
287
Core/Src/system_stm32f3xx.c
Normal file
@ -0,0 +1,287 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f3xx.c
|
||||
* @author MCD Application Team
|
||||
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* 1. This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f3xx.s" file.
|
||||
*
|
||||
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
|
||||
* by the user application to setup the SysTick
|
||||
* timer or configure other parameters.
|
||||
*
|
||||
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
|
||||
* be called whenever the core clock is changed
|
||||
* during program execution.
|
||||
*
|
||||
* 2. After each device reset the HSI (8 MHz) is used as system clock source.
|
||||
* Then SystemInit() function is called, in "startup_stm32f3xx.s" file, to
|
||||
* configure the system clock before to branch to main program.
|
||||
*
|
||||
* 3. This file configures the system clock as follows:
|
||||
*=============================================================================
|
||||
* Supported STM32F3xx device
|
||||
*-----------------------------------------------------------------------------
|
||||
* System Clock source | HSI
|
||||
*-----------------------------------------------------------------------------
|
||||
* SYSCLK(Hz) | 8000000
|
||||
*-----------------------------------------------------------------------------
|
||||
* HCLK(Hz) | 8000000
|
||||
*-----------------------------------------------------------------------------
|
||||
* AHB Prescaler | 1
|
||||
*-----------------------------------------------------------------------------
|
||||
* APB2 Prescaler | 1
|
||||
*-----------------------------------------------------------------------------
|
||||
* APB1 Prescaler | 1
|
||||
*-----------------------------------------------------------------------------
|
||||
* USB Clock | DISABLE
|
||||
*-----------------------------------------------------------------------------
|
||||
*=============================================================================
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2016 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f3xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "stm32f3xx.h"
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
|
||||
This value can be provided and adapted by the user application. */
|
||||
#endif /* HSE_VALUE */
|
||||
|
||||
#if !defined (HSI_VALUE)
|
||||
#define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
|
||||
This value can be provided and adapted by the user application. */
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/* Note: Following vector table addresses must be defined in line with linker
|
||||
configuration. */
|
||||
/*!< Uncomment the following line if you need to relocate the vector table
|
||||
anywhere in Flash or Sram, else the vector table is kept at the automatic
|
||||
remap of boot address selected */
|
||||
/* #define USER_VECT_TAB_ADDRESS */
|
||||
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
/*!< Uncomment the following line if you need to relocate your vector Table
|
||||
in Sram else user remap will be done in Flash. */
|
||||
/* #define VECT_TAB_SRAM */
|
||||
#if defined(VECT_TAB_SRAM)
|
||||
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#else
|
||||
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
|
||||
This value must be a multiple of 0x200. */
|
||||
#endif /* VECT_TAB_SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_Variables
|
||||
* @{
|
||||
*/
|
||||
/* This variable is updated in three ways:
|
||||
1) by calling CMSIS function SystemCoreClockUpdate()
|
||||
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
|
||||
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
|
||||
Note: If you use this function to configure the system clock there is no need to
|
||||
call the 2 first functions listed above, since SystemCoreClock variable is
|
||||
updated automatically.
|
||||
*/
|
||||
uint32_t SystemCoreClock = 8000000;
|
||||
|
||||
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F3xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* FPU settings --------------------------------------------------------------*/
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
|
||||
#endif
|
||||
|
||||
/* Configure the Vector Table location -------------------------------------*/
|
||||
#if defined(USER_VECT_TAB_ADDRESS)
|
||||
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
|
||||
#endif /* USER_VECT_TAB_ADDRESS */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
* The SystemCoreClock variable contains the core clock (HCLK), it can
|
||||
* be used by the user application to setup the SysTick timer or configure
|
||||
* other parameters.
|
||||
*
|
||||
* @note Each time the core clock (HCLK) changes, this function must be called
|
||||
* to update SystemCoreClock variable value. Otherwise, any configuration
|
||||
* based on this variable will be incorrect.
|
||||
*
|
||||
* @note - The system frequency computed by this function is not the real
|
||||
* frequency in the chip. It is calculated based on the predefined
|
||||
* constant and the selected clock source:
|
||||
*
|
||||
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
|
||||
*
|
||||
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
*
|
||||
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
|
||||
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
|
||||
*
|
||||
* (*) HSI_VALUE is a constant defined in stm32f3xx_hal.h file (default value
|
||||
* 8 MHz) but the real value may vary depending on the variations
|
||||
* in voltage and temperature.
|
||||
*
|
||||
* (**) HSE_VALUE is a constant defined in stm32f3xx_hal.h file (default value
|
||||
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
|
||||
* frequency of the crystal used. Otherwise, this function may
|
||||
* have wrong result.
|
||||
*
|
||||
* - The result of this function could be not correct when using fractional
|
||||
* value for HSE crystal.
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemCoreClockUpdate (void)
|
||||
{
|
||||
uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
|
||||
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
|
||||
/* Get PLL clock source and multiplication factor ----------------------*/
|
||||
pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
|
||||
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
|
||||
pllmull = ( pllmull >> 18) + 2;
|
||||
|
||||
#if defined (STM32F302xE) || defined (STM32F303xE) || defined (STM32F398xx)
|
||||
predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
|
||||
if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
|
||||
{
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / predivfactor) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* HSI oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull;
|
||||
}
|
||||
#else
|
||||
if (pllsource == RCC_CFGR_PLLSRC_HSI_DIV2)
|
||||
{
|
||||
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
|
||||
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / predivfactor) * pllmull;
|
||||
}
|
||||
#endif /* STM32F302xE || STM32F303xE || STM32F398xx */
|
||||
break;
|
||||
default: /* HSI used as system clock */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
/* Compute HCLK clock frequency ----------------*/
|
||||
/* Get HCLK prescaler */
|
||||
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
|
||||
/* HCLK clock frequency */
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
Reference in New Issue
Block a user