Moved firmware to subfoler firmware
This commit is contained in:
143
firmware/Core/Src/DPC_Timeout.c
Normal file
143
firmware/Core/Src/DPC_Timeout.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : DPC_Timeout.c
|
||||
* @brief : Timeout Module
|
||||
******************************************************************************
|
||||
*
|
||||
* COPYRIGHT(c) 2020 STMicroelectronics
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "DPC_Timeout.h"
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup Private_Variables Private Variables
|
||||
* @{
|
||||
*/
|
||||
TimeoutDataStr_T Timeout_List[TO_MAX_NUMBER];
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup Private_function Private Variables
|
||||
* @{
|
||||
*/
|
||||
void DPC_TO_Init(void)
|
||||
{
|
||||
for ( uint8_t Temp = 0; Temp < TO_MAX_NUMBER; Temp++){
|
||||
Timeout_List[Temp].State = TO_OFF;
|
||||
Timeout_List[Temp].Count = 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Private_function Private Variables
|
||||
* @{
|
||||
*/
|
||||
TO_RET_STATE DPC_TO_Set(uint8_t TO_Num, uint32_t Val)
|
||||
{
|
||||
TO_RET_STATE RetState = TO_OUT_ERR;
|
||||
|
||||
if(Timeout_List[TO_Num].State == TO_OFF || Timeout_List[TO_Num].State == TO_RUN){
|
||||
Timeout_List[TO_Num].State = TO_RUN;
|
||||
Timeout_List[TO_Num].Count = Val;
|
||||
RetState = TO_OUT_OK;
|
||||
}
|
||||
return RetState;
|
||||
}
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Private_function Private Variables
|
||||
* @{
|
||||
*/
|
||||
TO_RET_STATE DPC_TO_Check(uint8_t TO_Num)
|
||||
{
|
||||
TO_RET_STATE RetState = TO_OUT_ERR;
|
||||
if(Timeout_List[TO_Num].State == TO_RUN){
|
||||
RetState = TO_OUT_OK;
|
||||
}
|
||||
else if(Timeout_List[TO_Num].State == TO_TOOK){
|
||||
RetState = TO_OUT_TOOK;
|
||||
Timeout_List[TO_Num].State = TO_OFF;
|
||||
}
|
||||
return RetState;
|
||||
}
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Private_function Private Variables
|
||||
* @{
|
||||
*/
|
||||
void TimeoutMng(void)
|
||||
{
|
||||
for ( uint8_t Temp = 0; Temp < TO_MAX_NUMBER; Temp++){
|
||||
|
||||
if(Timeout_List[Temp].State == TO_RUN){
|
||||
if(Timeout_List[Temp].Count == 0){
|
||||
Timeout_List[Temp].State = TO_TOOK;
|
||||
}
|
||||
else{
|
||||
Timeout_List[Temp].Count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief manage the command Load
|
||||
*/
|
||||
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Declare the Rx done flag
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Init the Telemetry package
|
||||
*/
|
||||
|
||||
/**
|
||||
*@}
|
||||
*/
|
||||
|
||||
/******************* (C) COPYRIGHT 2019 STMicroelectronics *****END OF FILE****/
|
||||
1646
firmware/Core/Src/GSM.c
Normal file
1646
firmware/Core/Src/GSM.c
Normal file
File diff suppressed because it is too large
Load Diff
572
firmware/Core/Src/SD_Card.c
Normal file
572
firmware/Core/Src/SD_Card.c
Normal file
@@ -0,0 +1,572 @@
|
||||
|
||||
#include "SD_Card.h"
|
||||
#include "DPC_Timeout.h"
|
||||
#include "string.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdio.h"
|
||||
#include "rtc.h"
|
||||
|
||||
volatile ff_search_struct FileSearchStruct;
|
||||
|
||||
void SD_Card_Var_Init(SD_CARD_Global_Struct* SD_Struct){
|
||||
|
||||
HTTP_DATA_Struct* HTTP_DATA;
|
||||
HTTP_DATA=&SD_Struct->CSV_DATA;
|
||||
|
||||
SD_Struct->DATA0 = &SD_Struct->DATA0_ch[0];
|
||||
|
||||
SD_Struct->Header = "serial_number;"
|
||||
"started_at;"
|
||||
"ended_at;"
|
||||
"status_indication;"
|
||||
"energy_sum;"
|
||||
"battery_level_at_start;"
|
||||
"battery_level_at_end;"
|
||||
"battery_voltage_at_start;"
|
||||
"battery_voltage_at_end;"
|
||||
"battery_temperature_at_end;"
|
||||
"latitude;"
|
||||
"longitude;"
|
||||
"maximum_load_current;"
|
||||
"maximum_charge_current;"
|
||||
"internal_resistance;"
|
||||
"is_moderated;"
|
||||
"event_time;"
|
||||
"battery_condition_id\r";
|
||||
|
||||
|
||||
SD_Struct->FileName = &SD_Struct->Filename_ch[0];
|
||||
SD_Struct->Path = &SD_Struct->Path_ch[0];
|
||||
|
||||
|
||||
|
||||
HTTP_DATA->Serial_Number = &HTTP_DATA->Serial_Number_var[0];
|
||||
HTTP_DATA->Battery_Condition_ID = &HTTP_DATA->Battery_Condition_ID_var[0];
|
||||
HTTP_DATA->Event_time = &HTTP_DATA->Event_time_var[0];
|
||||
HTTP_DATA->Started_At_Time = &HTTP_DATA->Started_At_Time_var[0];
|
||||
HTTP_DATA->Ended_At_Time = &HTTP_DATA->Ended_At_Time_var[0];
|
||||
HTTP_DATA->Status_Indication = &HTTP_DATA->Status_Indication_var[0];
|
||||
HTTP_DATA->Energy_Sum = &HTTP_DATA->Energy_Sum_var[0];
|
||||
HTTP_DATA->Battery_Level_At_Start = &HTTP_DATA->Battery_Level_At_Start_var[0];
|
||||
HTTP_DATA->Battery_Level_At_End = &HTTP_DATA->Battery_Level_At_End_var[0];
|
||||
HTTP_DATA->Battery_Voltage_At_Start = &HTTP_DATA->Battery_Voltage_At_Start_var[0];
|
||||
HTTP_DATA->Battery_Voltage_At_End = &HTTP_DATA->Battery_Voltage_At_End_var[0];
|
||||
HTTP_DATA->Battery_Temperature_At_End = &HTTP_DATA->Battery_Temperature_At_End_var[0];
|
||||
HTTP_DATA->Latitude = &HTTP_DATA->Latitude_var[0];
|
||||
HTTP_DATA->Longitude = &HTTP_DATA->Longitude_var[0];
|
||||
HTTP_DATA->Maximum_Load_Current = &HTTP_DATA->Maximum_Load_Current_var[0];
|
||||
HTTP_DATA->Maximum_Charge_Current = &HTTP_DATA->Maximum_Charge_Current_var[0];
|
||||
HTTP_DATA->Internal_Resistance = &HTTP_DATA->Internal_Resistance_var[0];
|
||||
HTTP_DATA->Moderated = &HTTP_DATA->Moderated_var[0];
|
||||
HTTP_DATA->Current_time = &HTTP_DATA->Current_time_var[0];
|
||||
|
||||
}
|
||||
|
||||
uint8_t SD_Received_LOOKFOR(char* answ, char* LOOKFOR){
|
||||
uint8_t result=0;
|
||||
char *istr='\0';
|
||||
istr=strstr(answ, LOOKFOR);
|
||||
if (istr=='\0')
|
||||
{
|
||||
result=0; //nothing found
|
||||
}
|
||||
else
|
||||
{
|
||||
result=1; //found
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SD_Card_states SD_Set_Command(SD_CARD_Global_Struct* SD_Struct, SD_Op_Commands CMD, uint32_t Timeout){
|
||||
|
||||
if (SD_Struct->SD_State_to_return == SD_READY){
|
||||
//Battery_Data_to_String_Converter(Sim_Struct);
|
||||
SD_Struct->SD_Active_Command = CMD;
|
||||
SD_Struct->SD_State_to_return = SD_BUSY;
|
||||
DPC_TO_Set(TO_SD_Card,Timeout);
|
||||
//CSV_Data_Compilation(SD_Struct);
|
||||
return SD_COMMAND_SET;
|
||||
}
|
||||
else return SD_COMMAND_NOT_SET;
|
||||
}
|
||||
|
||||
|
||||
void SD_Card_Processing(SD_CARD_Global_Struct* SD_Struct){
|
||||
|
||||
SD_Stages* Active_Stage;
|
||||
SD_Op_Commands* CMD;
|
||||
Time_Struct rtc_time;
|
||||
char Filename_ch[20];
|
||||
char* Filename = &Filename_ch[0];
|
||||
char Path_ch[100];
|
||||
char* Path=&Path_ch[0];
|
||||
|
||||
FileSearchStruct.filename=&FileSearchStruct.filename_ch[0];
|
||||
FileSearchStruct.fullpath=&FileSearchStruct.fullpath_ch[0];
|
||||
|
||||
strcpy(Path,"");
|
||||
strcpy(Filename,"");
|
||||
|
||||
|
||||
CMD = &SD_Struct->SD_Active_Command;
|
||||
Active_Stage = &SD_Struct->SD_Stages_list;
|
||||
|
||||
SD_Struct->SD_CARD_ChipDetect = HAL_GPIO_ReadPin(SD_CD_GPIO_Port, SD_CD_Pin);
|
||||
|
||||
if (DPC_TO_Check(TO_SD_Card)==TO_OUT_TOOK){
|
||||
if (*Active_Stage != SD_IDLE) {
|
||||
SD_Struct->SD_Stages_list = SD_UMOUNT;
|
||||
}
|
||||
}
|
||||
|
||||
switch (*Active_Stage){
|
||||
|
||||
case SD_IDLE:
|
||||
|
||||
if (SD_Struct->Mount_Flag){
|
||||
if (*CMD == SD_OP_WRITE_STATUS){
|
||||
CSV_Status_Data_Compilation(SD_Struct);
|
||||
*Active_Stage = SD_OPEN_DIR;
|
||||
}
|
||||
else if (*CMD == SD_OP_WRITE_PARAM){
|
||||
CSV_Param_Data_Compilation(SD_Struct);
|
||||
*Active_Stage = SD_OPEN_DIR;
|
||||
}
|
||||
else if(*CMD == SD_OP_WRITE_HEADER){
|
||||
*Active_Stage = SD_OPEN_DIR;
|
||||
}
|
||||
else if (*CMD == SD_OP_DELETEOLD){
|
||||
RTC_Get_Values(&rtc_time);
|
||||
if (rtc_time.year>20){
|
||||
*Active_Stage = SD_DELETE_OLD_FILES;
|
||||
}
|
||||
else *Active_Stage = SD_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (*CMD == SD_OP_MOUNT){
|
||||
*Active_Stage = SD_MOUNT;
|
||||
}
|
||||
else if (*CMD == SD_OP_UMOUNT){
|
||||
*Active_Stage = SD_UMOUNT;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case SD_MOUNT:
|
||||
|
||||
fres = f_mount(&FatFs, "", 1); //1=mount now
|
||||
if (fres != FR_OK) {
|
||||
SD_Struct->Fat_result=fres;
|
||||
}
|
||||
else if(fres==FR_OK){
|
||||
SD_Struct->Mount_Flag = 1;
|
||||
*Active_Stage = SD_CHECK_FREE_SPACE;
|
||||
}
|
||||
break;
|
||||
case SD_CHECK_FREE_SPACE:
|
||||
fres = f_getfree("", &free_clusters, &getFreeFs);
|
||||
if (fres == FR_OK) {
|
||||
total_sectors = (getFreeFs->n_fatent - 2) * getFreeFs->csize;
|
||||
free_sectors = free_clusters * getFreeFs->csize;
|
||||
|
||||
#if _MAX_SS != _MIN_SS
|
||||
free_space=free_sectors*getFreeFs->ssize;
|
||||
#else
|
||||
free_space = free_sectors * 512;
|
||||
#endif
|
||||
|
||||
if (free_space < __MIN_FREE_SPACE_REQUIRED){
|
||||
*Active_Stage = SD_DELETE_OLD_FILES;
|
||||
}
|
||||
else {
|
||||
SD_Struct->Mount_Flag = 1;
|
||||
*Active_Stage = SD_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SD_DELETE_OLD_FILES:
|
||||
FileSearchStruct.Oldest_FN_Month=99;
|
||||
FileSearchStruct.Oldest_FN_Year=99;
|
||||
FileSearchStruct.Oldest_FN_Value=0;
|
||||
Search_for_Oldest(&FileSearchStruct, Path, SD_Struct->Battery_Serial);
|
||||
|
||||
strcat(FileSearchStruct.fullpath,"/");
|
||||
strcat(FileSearchStruct.fullpath,FileSearchStruct.filename);
|
||||
if (FileSearchStruct.isDir==1){
|
||||
fres = delete_node(FileSearchStruct.fullpath, sizeof(FileSearchStruct.fullpath_ch), &flinf);
|
||||
}
|
||||
else{
|
||||
fres=f_unlink(FileSearchStruct.fullpath);
|
||||
}
|
||||
if (fres==FR_OK){
|
||||
*Active_Stage = SD_CHECK_FREE_SPACE;
|
||||
}
|
||||
else *Active_Stage = SD_CHECK_FREE_SPACE;
|
||||
break;
|
||||
case SD_OPEN_DIR:
|
||||
|
||||
//strcpy(Path,"/");
|
||||
//itoa(SD_Struct->Battery_Serial,Path+1,sizeof(SD_Struct->Battery_Serial)+6);
|
||||
SD_Update_Path(SD_Struct);
|
||||
|
||||
fres = f_opendir(&dir, SD_Struct->Path);
|
||||
if (fres == FR_OK) {
|
||||
*Active_Stage = SD_OPEN_FILE;
|
||||
}
|
||||
else if (fres == FR_NO_PATH){
|
||||
fres = f_mkdir(SD_Struct->Path);
|
||||
*Active_Stage = SD_OPEN_DIR;
|
||||
}
|
||||
else *Active_Stage = SD_OPEN_DIR;
|
||||
|
||||
break;
|
||||
case SD_OPEN_FILE:
|
||||
strcat(SD_Struct->Path,"/");
|
||||
strcat(SD_Struct->Path,SD_Struct->FileName);
|
||||
if (f_open(&fil, SD_Struct->Path, FA_READ | FA_WRITE | FA_OPEN_ALWAYS )==FR_OK){
|
||||
if (fil.fsize==0){
|
||||
*Active_Stage = SD_WRITE_HEADER;
|
||||
}
|
||||
else {
|
||||
*Active_Stage = SD_READ;
|
||||
}
|
||||
|
||||
}
|
||||
//fres = f_open(&fil, "1221.csv" /* SD_Struct->FileName*/, FA_READ | FA_WRITE | FA_OPEN_ALWAYS | FA_CREATE_ALWAYS);
|
||||
|
||||
break;
|
||||
case SD_READ:
|
||||
fres = f_read(&fil, &readbuff[0], strlen(SD_Struct->Header), &nRead);
|
||||
//f_gets(&readbuff[0], sizeof(SD_Struct->Header),&fil);
|
||||
//if (fres == FR_OK){
|
||||
if(SD_Received_LOOKFOR(&readbuff[0], SD_Struct->Header)){
|
||||
*Active_Stage = SD_WRITE;
|
||||
}
|
||||
else *Active_Stage = SD_WRITE_HEADER;
|
||||
//}
|
||||
break;
|
||||
case SD_WRITE_HEADER:
|
||||
f_puts(SD_Struct->Header, &fil);
|
||||
*Active_Stage = SD_WRITE;
|
||||
break;
|
||||
case SD_WRITE:
|
||||
fres = f_lseek(&fil, f_size(&fil));
|
||||
fres = f_write(&fil, SD_Struct->DATA0, strlen(SD_Struct->DATA0), &BytesWr);
|
||||
//f_puts(SD_Struct->DATA0, &fil);
|
||||
*Active_Stage = SD_CLOSE;
|
||||
break;
|
||||
|
||||
case SD_CLOSE:
|
||||
if(f_close(&fil) == FR_OK){
|
||||
if (f_closedir(&dir)==FR_OK){
|
||||
*Active_Stage = SD_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SD_UMOUNT:
|
||||
if(f_mount(NULL, "", 1) == FR_OK){
|
||||
*Active_Stage = SD_IDLE;
|
||||
SD_Struct->Mount_Flag = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (*Active_Stage == SD_IDLE) {
|
||||
SD_Struct->SD_Active_Command = SD_OP_DONOTHING;
|
||||
SD_Struct->SD_State_to_return = SD_READY;
|
||||
|
||||
}
|
||||
else SD_Struct->SD_State_to_return = SD_BUSY;
|
||||
}
|
||||
|
||||
void SD_Update_Path(SD_CARD_Global_Struct* source){
|
||||
uint64_t Raw;
|
||||
char* part1="/";
|
||||
char* stringptr=&source->Raw_var[0];
|
||||
|
||||
Raw=source->Battery_Serial;
|
||||
|
||||
itoa(Raw,stringptr,sizeof(Raw)+2);
|
||||
strcpy(source->Path,part1);
|
||||
strcat(source->Path,stringptr);
|
||||
//strcat(source->Path,part1);
|
||||
|
||||
}
|
||||
|
||||
void Search_for_Oldest(volatile ff_search_struct* sourceStruct,char* Path, uint64_t ActualSerial){
|
||||
|
||||
uint32_t Raw;
|
||||
uint64_t Raw64;
|
||||
|
||||
char Path2_ch[100];
|
||||
char* Path2=&Path2_ch[0];
|
||||
|
||||
char Filename_ch[20];
|
||||
char* Filename = &Filename_ch[0];
|
||||
|
||||
|
||||
// Oldest_FN_Year = 99;
|
||||
// Oldest_FN_Month = 99;
|
||||
// Oldest_FN_Value = 0;
|
||||
|
||||
fres = f_opendir(&dir,Path);
|
||||
if (fres == FR_OK) {
|
||||
|
||||
//i = strlen(Path);
|
||||
for (;;) {
|
||||
fres = f_readdir(&dir, &flinf); /* Read a directory item */
|
||||
if (fres != FR_OK || flinf.fname[0] == 0) break; /* Break on error or end of dir */
|
||||
if (flinf.fname[0] == '.') continue; /* Ignore dot entry */
|
||||
|
||||
#if _USE_LFN
|
||||
Filename = *flinf.lfname ? fno.lfname : fno.fname;
|
||||
#else
|
||||
Filename = flinf.fname;
|
||||
#endif
|
||||
|
||||
if ((flinf.fattrib & AM_DIR) && !(flinf.fattrib & AM_SYS) && !(flinf.fattrib & AM_HID) ){
|
||||
Raw64=atol(Filename);
|
||||
if (Raw64 != ActualSerial){
|
||||
strcpy(sourceStruct->fullpath,Path);
|
||||
strcpy(sourceStruct->filename,Filename);
|
||||
sourceStruct->isDir=1;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
strcpy(Path2,Path);
|
||||
strcat(Path2,"/");
|
||||
strcat(Path2,Filename);
|
||||
Search_for_Oldest(sourceStruct,Path2,ActualSerial);
|
||||
}
|
||||
// if (sourceStruct->value!=0){
|
||||
// sourceStruct->Lastfound_FN_Month=(uint8_t)(sourceStruct->value/100);
|
||||
// Raw=sourceStruct->Lastfound_FN_Month*100;
|
||||
// sourceStruct->Lastfound_FN_Year=(uint8_t)(sourceStruct->value-Raw);
|
||||
// }
|
||||
}
|
||||
else if ( !(flinf.fattrib & AM_DIR) && !(flinf.fattrib & AM_SYS) && !(flinf.fattrib & AM_HID) ) {
|
||||
sourceStruct->isDir=0;
|
||||
sourceStruct->value = Filename_to_Value(Filename);
|
||||
if (sourceStruct->value!=0){
|
||||
sourceStruct->Lastfound_FN_Month=(uint8_t)(sourceStruct->value/100);
|
||||
Raw=sourceStruct->Lastfound_FN_Month*100;
|
||||
sourceStruct->Lastfound_FN_Year=(uint8_t)(sourceStruct->value-Raw);
|
||||
|
||||
|
||||
// if (Lastfound_FN_Month<=Oldest_FN_Month && Lastfound_FN_Year<=Oldest_FN_Year){
|
||||
// Oldest_FN_Year = Lastfound_FN_Year;
|
||||
// Oldest_FN_Month = Lastfound_FN_Month;
|
||||
// Oldest_FN_Value = FN_Value;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceStruct->Lastfound_FN_Month!=0 || sourceStruct->Lastfound_FN_Year!=0){
|
||||
if (sourceStruct->Lastfound_FN_Month<=sourceStruct->Oldest_FN_Month && sourceStruct->Lastfound_FN_Year<=sourceStruct->Oldest_FN_Year){
|
||||
sourceStruct->Oldest_FN_Year = sourceStruct->Lastfound_FN_Year;
|
||||
sourceStruct->Oldest_FN_Month = sourceStruct->Lastfound_FN_Month;
|
||||
//sourceStruct->Oldest_FN_Value = sourceStruct->value;
|
||||
strcpy(sourceStruct->fullpath,Path);
|
||||
strcpy(sourceStruct->filename,Filename);
|
||||
}
|
||||
}
|
||||
|
||||
// if (flinf.fattrib & AM_DIR) { /* It is a directory */
|
||||
// //res = scan_files(path);
|
||||
// //if (res != FR_OK) break;
|
||||
// //path[i] = 0;
|
||||
// } else { /* It is a file. */
|
||||
//
|
||||
// //printf("%s/%s\n", path, fn);
|
||||
// }
|
||||
}
|
||||
|
||||
// if (Oldest_FN_Value!=0){
|
||||
// Configure_Path_to_delete(Path, Oldest_FN_Value);
|
||||
// }
|
||||
//fres = f_unlink()
|
||||
}
|
||||
}
|
||||
|
||||
void Battery_Data_to_CSV_Converter(SD_CARD_Global_Struct* Sd_Struct, HTTP_DATA_Struct* DST){
|
||||
Battery_Data_Struct* Bat_data;
|
||||
HTTP_DATA_Struct CSV_Data_DST;
|
||||
CSV_Data_DST = *DST;
|
||||
|
||||
char* Raw = &Sd_Struct->Raw_var[0];
|
||||
int Size;
|
||||
Bat_data = &Sd_Struct->BATTERY_DATA;
|
||||
|
||||
|
||||
itoa(Bat_data->Serial,Raw,sizeof(Bat_data->Serial)+2);
|
||||
strcpy(Sd_Struct->CSV_DATA.Serial_Number, Raw);
|
||||
|
||||
itoa(Bat_data->Battery_cond_ID,Raw,10);
|
||||
strcpy(Sd_Struct->CSV_DATA.Battery_Condition_ID, Raw);
|
||||
|
||||
SIM800_Time_To_String(&Bat_data->Event_time,CSV_Data_DST.Event_time);
|
||||
SIM800_Time_To_String(&Bat_data->Started_At_Time,CSV_Data_DST.Started_At_Time);
|
||||
SIM800_Time_To_String(&Bat_data->Ended_At_Time,CSV_Data_DST.Ended_At_Time);
|
||||
|
||||
itoa(Bat_data->Status_Indication,Raw,10);
|
||||
strcpy(CSV_Data_DST.Status_Indication, Raw);
|
||||
|
||||
itoa(Bat_data->Energy_Sum,Raw,10);
|
||||
strcpy(CSV_Data_DST.Energy_Sum, Raw);
|
||||
|
||||
itoa(Bat_data->Battery_Level_At_Start,Raw,10);
|
||||
strcpy(CSV_Data_DST.Battery_Level_At_Start, Raw);
|
||||
|
||||
itoa(Bat_data->Battery_Level_At_End,Raw,10);
|
||||
strcpy(CSV_Data_DST.Battery_Level_At_End, Raw);
|
||||
|
||||
sprintf(Raw, "%f", Bat_data->Battery_Voltage_At_Start);
|
||||
//ftoa(Bat_data->Battery_Voltage_At_Start,Raw,sizeof(Bat_data->Battery_Voltage_At_Start));
|
||||
strcpy(CSV_Data_DST.Battery_Voltage_At_Start, Raw);
|
||||
|
||||
sprintf(Raw, "%f", Bat_data->Battery_Voltage_At_End);
|
||||
//ftoa(Bat_data->Battery_Voltage_At_End,Raw,sizeof(Bat_data->Battery_Voltage_At_End));
|
||||
strcpy(CSV_Data_DST.Battery_Voltage_At_End, Raw);
|
||||
|
||||
itoa(Bat_data->Battery_Temperature_At_End,Raw,10);
|
||||
strcpy(CSV_Data_DST.Battery_Temperature_At_End, Raw);
|
||||
|
||||
itoa(Bat_data->Maximum_Load_Current,Raw,10);
|
||||
strcpy(CSV_Data_DST.Maximum_Load_Current, Raw);
|
||||
|
||||
itoa(Bat_data->Maximum_Charge_Current,Raw,10);
|
||||
strcpy(CSV_Data_DST.Maximum_Charge_Current, Raw);
|
||||
|
||||
sprintf(Raw, "%f", Bat_data->Internal_Resistance);
|
||||
//ftoa(Bat_data->Internal_Resistance,Raw,sizeof(Bat_data->Internal_Resistance));
|
||||
strcpy(CSV_Data_DST.Internal_Resistance, Raw);
|
||||
|
||||
if (Bat_data->Moderated){
|
||||
strcpy(CSV_Data_DST.Moderated,"true");
|
||||
}
|
||||
else strcpy(CSV_Data_DST.Moderated,"false");
|
||||
|
||||
//memcpy(DST,&CSV_Data_DST, sizeof(CSV_Data_DST));
|
||||
|
||||
memset(Raw,0,100);
|
||||
}
|
||||
|
||||
uint64_t Filename_to_Value(char* FN){
|
||||
Time_Struct rtc_time;
|
||||
uint32_t Raw;
|
||||
uint32_t FN_month;
|
||||
char* istr="/0";
|
||||
//char* test1_ptr=&test1[0];
|
||||
|
||||
|
||||
istr=strstr(FN,".CSV");
|
||||
if (istr=='\0')
|
||||
{
|
||||
Raw=0; //nothing found
|
||||
}
|
||||
else
|
||||
{
|
||||
Raw=atoi(istr-4); //found
|
||||
}
|
||||
return Raw;
|
||||
}
|
||||
|
||||
uint8_t Configure_Path_to_delete(char* path, uint32_t Value){
|
||||
char service[10];
|
||||
char* csv=".CSV";
|
||||
char* service_ptr=&service[0];
|
||||
|
||||
itoa(Value,service_ptr,sizeof(Value)+6);
|
||||
strcat(path,service_ptr);
|
||||
strcat(path,csv);
|
||||
}
|
||||
|
||||
void CSV_Status_Data_Compilation(SD_CARD_Global_Struct* Sd_Struct){
|
||||
|
||||
char* Delimeter=";";
|
||||
char* EndOfString = "\r";
|
||||
|
||||
strcpy(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Serial_Number);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Event_time);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Condition_ID);
|
||||
//strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,EndOfString);
|
||||
}
|
||||
|
||||
void CSV_Param_Data_Compilation(SD_CARD_Global_Struct* Sd_Struct){
|
||||
|
||||
char* Delimeter=";";
|
||||
char* EndOfString = "\n";
|
||||
|
||||
strcpy(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Serial_Number);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Started_At_Time);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Ended_At_Time);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Status_Indication);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Energy_Sum);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Level_At_Start);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Level_At_End);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Voltage_At_Start);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Voltage_At_End);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Battery_Temperature_At_End);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Latitude);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Longitude);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Maximum_Load_Current);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Maximum_Charge_Current);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Internal_Resistance);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,Sd_Struct->CSV_DATA.Moderated);
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,"");
|
||||
//strcat(Sd_Struct->DATA0,Delimeter);
|
||||
strcat(Sd_Struct->DATA0,EndOfString);
|
||||
}
|
||||
330
firmware/Core/Src/can.c
Normal file
330
firmware/Core/Src/can.c
Normal file
@@ -0,0 +1,330 @@
|
||||
//
|
||||
// Created by enik on 02.06.22.
|
||||
//
|
||||
|
||||
#include "can.h"
|
||||
|
||||
//#include "Settings.h"
|
||||
|
||||
#if CAN_TESTING_LOOPBACK
|
||||
#define CAN_BASIC_MODE CAN_MODE_SILENT_LOOPBACK
|
||||
#else
|
||||
#define CAN_BASIC_MODE CAN_MODE_NORMAL
|
||||
#endif
|
||||
|
||||
//#include "can_messenger.h"
|
||||
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern CAN_HandleTypeDef hcan2;
|
||||
|
||||
CAN_FilterTypeDef can1Filter;
|
||||
CAN_FilterTypeDef can2Filter;
|
||||
CAN_RxHeaderTypeDef can1RX, can2RX;
|
||||
u8_t can1Data[8] = {0,}, can2Data[8] = {0,};
|
||||
|
||||
typedef struct CAN_SPD_VAL {
|
||||
u32_t Prescaler;
|
||||
u32_t TimeSeg1;
|
||||
u32_t TimeSeg2;
|
||||
} CAN_SPD_VAL;
|
||||
|
||||
// PSC - 2 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd1000 = {.Prescaler = 2, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 3 | Time1 - 12 | Time2 - 2
|
||||
const CAN_SPD_VAL spd800 = {.Prescaler = 3, .TimeSeg1 = CAN_BS1_12TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 4 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd500 = {.Prescaler = 4, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 8 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd250 = {.Prescaler = 8, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 16 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd125 = {.Prescaler = 16, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 20 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd100 = {.Prescaler = 20, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 40 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd50 = {.Prescaler = 40, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 100 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd20 = {.Prescaler = 100, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
// PSC - 200 | Time1 - 15 | Time2 - 2
|
||||
const CAN_SPD_VAL spd10 = {.Prescaler = 200, .TimeSeg1 = CAN_BS1_15TQ, .TimeSeg2 = CAN_BS2_2TQ};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set Speed for CAN Bus
|
||||
* @param[in] spd #CAN_SPEED enum
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetSpeed(CAN_SPEED spd, CAN_HandleTypeDef *can) {
|
||||
//if (HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING)
|
||||
HAL_CAN_Stop(can);
|
||||
can->Instance = (can == &hcan1) ? CAN1 : CAN2; // Can Instance
|
||||
can->Init.SyncJumpWidth = CAN_SJW_1TQ; // Default
|
||||
can->Init.TimeTriggeredMode = DISABLE; // Default
|
||||
can->Init.AutoBusOff = ENABLE; // Default
|
||||
can->Init.AutoWakeUp = ENABLE; // Default
|
||||
can->Init.AutoRetransmission = DISABLE; // Default
|
||||
can->Init.ReceiveFifoLocked = DISABLE; // Default
|
||||
can->Init.TransmitFifoPriority = ENABLE; // Default
|
||||
can->Init.Mode = CAN_BASIC_MODE; // Set Mode
|
||||
switch (spd) {
|
||||
case CAN_SPD_1000:
|
||||
can->Init.Prescaler = spd1000.Prescaler;
|
||||
can->Init.TimeSeg1 = spd1000.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd1000.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_800:
|
||||
can->Init.Prescaler = spd800.Prescaler;
|
||||
can->Init.TimeSeg1 = spd800.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd800.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_500:
|
||||
can->Init.Prescaler = spd500.Prescaler;
|
||||
can->Init.TimeSeg1 = spd500.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd500.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_250:
|
||||
can->Init.Prescaler = spd250.Prescaler;
|
||||
can->Init.TimeSeg1 = spd250.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd250.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_125:
|
||||
can->Init.Prescaler = spd125.Prescaler;
|
||||
can->Init.TimeSeg1 = spd125.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd125.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_100:
|
||||
can->Init.Prescaler = spd100.Prescaler;
|
||||
can->Init.TimeSeg1 = spd100.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd100.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_50:
|
||||
can->Init.Prescaler = spd50.Prescaler;
|
||||
can->Init.TimeSeg1 = spd50.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd50.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_20:
|
||||
can->Init.Prescaler = spd20.Prescaler;
|
||||
can->Init.TimeSeg1 = spd20.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd20.TimeSeg2;
|
||||
break;
|
||||
case CAN_SPD_10:
|
||||
can->Init.Prescaler = spd10.Prescaler;
|
||||
can->Init.TimeSeg1 = spd10.TimeSeg1;
|
||||
can->Init.TimeSeg2 = spd10.TimeSeg2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (HAL_CAN_Init(can) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
filt->FilterBank = 0;
|
||||
filt->FilterFIFOAssignment = CAN_RX_FIFO0;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
filt->FilterBank = 14;
|
||||
filt->FilterFIFOAssignment = CAN_RX_FIFO1;
|
||||
filt->SlaveStartFilterBank = 14;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
filt->FilterMode = CAN_FILTERMODE_IDMASK;
|
||||
filt->FilterScale = CAN_FILTERSCALE_32BIT;
|
||||
filt->FilterIdHigh = 0x0000;
|
||||
filt->FilterIdLow = 0x0000;
|
||||
filt->FilterMaskIdHigh = 0x0000;
|
||||
filt->FilterMaskIdLow = 0x0000;
|
||||
filt->FilterActivation = ENABLE;
|
||||
if (HAL_CAN_ConfigFilter(can, filt) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
// HAL_CAN_Start(can);
|
||||
volatile HAL_StatusTypeDef status = HAL_CAN_Start(can);
|
||||
__NOP();
|
||||
volatile HAL_CAN_StateTypeDef st = HAL_CAN_GetState(can);
|
||||
if (st != HAL_CAN_STATE_LISTENING){
|
||||
__USR_BKPT();
|
||||
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET);
|
||||
} else {
|
||||
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
|
||||
}
|
||||
HAL_CAN_ActivateNotification(can,
|
||||
((can == &hcan1) ? CAN_IT_RX_FIFO0_MSG_PENDING : CAN_IT_RX_FIFO1_MSG_PENDING)
|
||||
| CAN_IT_ERROR | CAN_IT_BUSOFF | CAN_IT_LAST_ERROR_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Silent mode
|
||||
* @param[in] is_silent 1 if silent mode needed
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetMode(bool is_silent, CAN_HandleTypeDef *can) {
|
||||
can->Init.Mode = !is_silent ? CAN_MODE_NORMAL : CAN_MODE_SILENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Silent Loopback mode
|
||||
* @param[in] is_loopback 1 if loopback mode needed
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetLoopback(bool is_loopback, CAN_HandleTypeDef *can) {
|
||||
can->Init.Mode = !is_loopback ? CAN_MODE_NORMAL : CAN_MODE_SILENT_LOOPBACK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is opened
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Opened / 0 if Closed
|
||||
*/
|
||||
bool CAN_IsOpened(CAN_HandleTypeDef *can) {
|
||||
return HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is in silent mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Silent / 0 if not
|
||||
*/
|
||||
bool CAN_IsSilent(CAN_HandleTypeDef *can) {
|
||||
return (HAL_CAN_GetState(can) == HAL_CAN_STATE_LISTENING &&
|
||||
(can->Init.Mode == CAN_MODE_SILENT ||
|
||||
can->Init.Mode == CAN_MODE_SILENT_LOOPBACK)) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if CAN is in silent loopbsck mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
* @return 1 if Silent Loopback / 0 if else
|
||||
*/
|
||||
bool CAN_IsLoopback(CAN_HandleTypeDef *can) {
|
||||
return (can->Init.Mode == CAN_MODE_SILENT_LOOPBACK) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set filter mode
|
||||
* @param[in] id_only 1 if ID_LIST mode / 0 if ID_MASK mode
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterMode(bool id_only, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
filt->FilterMode = id_only ? CAN_FILTERMODE_IDLIST : CAN_FILTERMODE_IDMASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set ID for filter
|
||||
* @warning Not realized
|
||||
* @param[in] filt_id Pointer to filter ID array
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterID(u8_t *filt_id, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Mask for filter
|
||||
* @warning Not realized
|
||||
* @param[in] filt_mask Pointer to filter mask
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_SetFilterMask(u8_t *filt_mask, CAN_HandleTypeDef *can) {
|
||||
CAN_FilterTypeDef *filt;
|
||||
if (can == &hcan1) {
|
||||
filt = &can1Filter;
|
||||
} else if (can == &hcan2) {
|
||||
filt = &can2Filter;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common transmit prototype
|
||||
* @param[in] id CAN Packet ID
|
||||
* @param[in] ext 0 if 11-bit ID / 1 if 29-bit ID
|
||||
* @param[in] rtr 0 if standard frame / 1 if remote frame
|
||||
* @param[in] len Length of payload
|
||||
* @param[in] data Pointer to payload array
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_Transmit_Proto(u32_t id, bool ext, bool rtr, u8_t len, u8_t *data, CAN_HandleTypeDef *can) {
|
||||
CAN_TxHeaderTypeDef tx;
|
||||
tx.StdId = !ext ? id : 0;
|
||||
tx.ExtId = ext ? id : 0;
|
||||
tx.RTR = !rtr ? CAN_RTR_DATA : CAN_RTR_REMOTE;
|
||||
tx.IDE = !ext ? CAN_ID_STD : CAN_ID_EXT;
|
||||
tx.DLC = len;
|
||||
tx.TransmitGlobalTime = 0;
|
||||
u32_t mb;
|
||||
HAL_CAN_AddTxMessage(can, &tx, data, &mb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit standard (11-bit) data frame
|
||||
* @param[in] id 11-bit frame ID
|
||||
* @param[in] data Pointer to payload to be sent
|
||||
* @param[in] len Length of the payload to be sent
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_Transmit(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 0, 0, len, data, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit extended (29-bit) data frame
|
||||
* @param[in] id 29-bit frame ID
|
||||
* @param[in] data Pointer to payload to be sent
|
||||
* @param[in] len Length of the payload to be sent
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitExt(u32_t id, u8_t *data, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto(id, 1, 0, len, data, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit standard (11-bit) remote frame
|
||||
* @param[in] id 11-bit frame ID
|
||||
* @param[in] len Length of remote frame
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 0, 1, len, NULL, can);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit extended (29-bit) remote frame
|
||||
* @param[in] id 29-bit frame ID
|
||||
* @param[in] len Length of remote frame
|
||||
* @param[in] can Pointer to HAL CAN_HandleTypeDef
|
||||
*/
|
||||
void CAN_TransmitExtRTR(u32_t id, u8_t len, CAN_HandleTypeDef *can) {
|
||||
CAN_Transmit_Proto((u32_t) id, 1, 1, len, NULL, can);
|
||||
}
|
||||
|
||||
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
|
||||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &can1RX, can1Data) == HAL_OK) {
|
||||
//can_irq_receive(&can1RX, can1Data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) {
|
||||
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &can2RX, can2Data) == HAL_OK) {
|
||||
//can_irq_receive(&can2RX, can2Data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
2
firmware/Core/Src/desktop.ini
Normal file
2
firmware/Core/Src/desktop.ini
Normal file
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Program Files\Google\Drive File Stream\54.0.3.0\GoogleDriveFS.exe,23
|
||||
700
firmware/Core/Src/driverHWEEPROM.c
Normal file
700
firmware/Core/Src/driverHWEEPROM.c
Normal file
@@ -0,0 +1,700 @@
|
||||
#include "driverHWEEPROM.h"
|
||||
|
||||
/* Global variable used to store variable value in read sequence */
|
||||
uint16_t DataVar = 0;
|
||||
|
||||
uint16_t driverHWEEPROMNumberOfVars = 0;
|
||||
|
||||
/* Virtual address defined by the user: 0xFFFF value is prohibited */
|
||||
extern uint16_t *driverHWEEPROMVirtAddVarTab;
|
||||
|
||||
static HAL_StatusTypeDef driverHWEEPROMFormat(void);
|
||||
static uint16_t driverHWEEPROMFindValidPage(uint8_t Operation);
|
||||
static uint16_t driverHWEEPROMVerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
|
||||
static uint16_t driverHWEEPROMPageTransfer(uint16_t VirtAddress, uint16_t Data);
|
||||
static uint16_t driverHWEEPROMVerifyPageFullyErased(uint32_t Address);
|
||||
|
||||
/**
|
||||
* @brief Restore the pages to a known good state in case of page's status
|
||||
* corruption after a power loss.
|
||||
* @param None.
|
||||
* @retval - Flash error code: on write Flash error
|
||||
* - FLASH_COMPLETE: on success
|
||||
*/
|
||||
uint16_t driverHWEEPROMInit(uint16_t numberOfVars) {
|
||||
driverHWEEPROMNumberOfVars = numberOfVars;
|
||||
|
||||
uint16_t pagestatus0 = 6, pagestatus1 = 6;
|
||||
uint16_t varidx = 0;
|
||||
uint16_t eepromstatus = 0, readstatus = 0;
|
||||
int16_t x = -1;
|
||||
HAL_StatusTypeDef flashstatus;
|
||||
uint32_t page_error = 0;
|
||||
FLASH_EraseInitTypeDef s_eraseinit;
|
||||
|
||||
/* Get Page0 status */
|
||||
pagestatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
|
||||
/* Get Page1 status */
|
||||
pagestatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
|
||||
|
||||
/* Fill EraseInit structure*/
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE0_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
|
||||
/* Check for invalid header states and repair if necessary */
|
||||
switch (pagestatus0)
|
||||
{
|
||||
case ERASED:
|
||||
if (pagestatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
|
||||
{
|
||||
/* Erase Page0 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE0_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pagestatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
|
||||
{
|
||||
/* Erase Page0 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE0_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
/* Mark Page1 as valid */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
|
||||
{
|
||||
/* Erase both Page0 and Page1 and set Page0 as valid page */
|
||||
flashstatus = driverHWEEPROMFormat();
|
||||
/* If erase/program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RECEIVE_DATA:
|
||||
if (pagestatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
|
||||
{
|
||||
/* Transfer data from Page1 to Page0 */
|
||||
for (varidx = 0; varidx < driverHWEEPROMNumberOfVars; varidx++)
|
||||
{
|
||||
if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == driverHWEEPROMVirtAddVarTab[varidx])
|
||||
{
|
||||
x = varidx;
|
||||
}
|
||||
if (varidx != x)
|
||||
{
|
||||
/* Read the last variables' updates */
|
||||
readstatus = driverHWEEPROMReadVariable(driverHWEEPROMVirtAddVarTab[varidx], &DataVar);
|
||||
/* In case variable corresponding to the virtual address was found */
|
||||
if (readstatus != 0x1)
|
||||
{
|
||||
/* Transfer the variable to the Page0 */
|
||||
eepromstatus = driverHWEEPROMVerifyPageFullWriteVariable(driverHWEEPROMVirtAddVarTab[varidx], DataVar);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (eepromstatus != HAL_OK)
|
||||
{
|
||||
return eepromstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Mark Page0 as valid */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE1_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
/* Erase Page1 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE1_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pagestatus1 == ERASED) /* Page0 receive, Page1 erased */
|
||||
{
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE1_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
/* Erase Page1 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE1_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
/* Mark Page0 as valid */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
else /* Invalid state -> format eeprom */
|
||||
{
|
||||
/* Erase both Page0 and Page1 and set Page0 as valid page */
|
||||
flashstatus = driverHWEEPROMFormat();
|
||||
/* If erase/program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VALID_PAGE:
|
||||
if (pagestatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
|
||||
{
|
||||
/* Erase both Page0 and Page1 and set Page0 as valid page */
|
||||
flashstatus = driverHWEEPROMFormat();
|
||||
/* If erase/program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
else if (pagestatus1 == ERASED) /* Page0 valid, Page1 erased */
|
||||
{
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE1_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
/* Erase Page1 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE1_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Page0 valid, Page1 receive */
|
||||
{
|
||||
/* Transfer data from Page0 to Page1 */
|
||||
for (varidx = 0; varidx < driverHWEEPROMNumberOfVars; varidx++)
|
||||
{
|
||||
if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == driverHWEEPROMVirtAddVarTab[varidx])
|
||||
{
|
||||
x = varidx;
|
||||
}
|
||||
if (varidx != x)
|
||||
{
|
||||
/* Read the last variables' updates */
|
||||
readstatus = driverHWEEPROMReadVariable(driverHWEEPROMVirtAddVarTab[varidx], &DataVar);
|
||||
/* In case variable corresponding to the virtual address was found */
|
||||
if (readstatus != 0x1)
|
||||
{
|
||||
/* Transfer the variable to the Page1 */
|
||||
eepromstatus = driverHWEEPROMVerifyPageFullWriteVariable(driverHWEEPROMVirtAddVarTab[varidx], DataVar);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (eepromstatus != HAL_OK)
|
||||
{
|
||||
return eepromstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Mark Page1 as valid */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE0_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
/* Erase Page0 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE0_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* Any other state -> format eeprom */
|
||||
/* Erase both Page0 and Page1 and set Page0 as valid page */
|
||||
flashstatus = driverHWEEPROMFormat();
|
||||
/* If erase/program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
uint16_t driverHWEEPROMEraseFlash(void) {
|
||||
FLASH_EraseInitTypeDef s_eraseinit;
|
||||
HAL_StatusTypeDef flashstatus;
|
||||
uint32_t page_error = 0;
|
||||
|
||||
/* Fill EraseInit structure*/
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE0_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify if specified page is fully erased.
|
||||
* @param Address: page address
|
||||
* This parameter can be one of the following values:
|
||||
* @arg PAGE0_BASE_ADDRESS: Page0 base address
|
||||
* @arg PAGE1_BASE_ADDRESS: Page1 base address
|
||||
* @retval page fully erased status:
|
||||
* - 0: if Page not erased
|
||||
* - 1: if Page erased
|
||||
*/
|
||||
uint16_t driverHWEEPROMVerifyPageFullyErased(uint32_t Address)
|
||||
{
|
||||
uint32_t readstatus = 1;
|
||||
uint16_t addressvalue = 0x5555;
|
||||
|
||||
/* Check each active page address starting from end */
|
||||
while (Address <= PAGE0_END_ADDRESS)
|
||||
{
|
||||
/* Get the current location content to be compared with virtual address */
|
||||
addressvalue = (*(__IO uint16_t*)Address);
|
||||
|
||||
/* Compare the read address with the virtual address */
|
||||
if (addressvalue != ERASED)
|
||||
{
|
||||
|
||||
/* In case variable value is read, reset readstatus flag */
|
||||
readstatus = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
/* Next address location */
|
||||
Address = Address + 4;
|
||||
}
|
||||
|
||||
/* Return readstatus value: (0: Page not erased, 1: Page erased) */
|
||||
return readstatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the last stored variable data, if found, which correspond to
|
||||
* the passed virtual address
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: Global variable contains the read variable value
|
||||
* @retval Success or error status:
|
||||
* - 0: if variable was found
|
||||
* - 1: if the variable was not found
|
||||
* - NO_VALID_PAGE: if no valid page was found.
|
||||
*/
|
||||
uint16_t driverHWEEPROMReadVariable(uint16_t VirtAddress, uint16_t* Data)
|
||||
{
|
||||
uint16_t validpage = PAGE0;
|
||||
uint16_t addressvalue = 0x5555, readstatus = 1;
|
||||
uint32_t address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;
|
||||
|
||||
/* Get active Page for read operation */
|
||||
validpage = driverHWEEPROMFindValidPage(READ_FROM_VALID_PAGE);
|
||||
|
||||
/* Check if there is no valid page */
|
||||
if (validpage == NO_VALID_PAGE)
|
||||
{
|
||||
return NO_VALID_PAGE;
|
||||
}
|
||||
|
||||
/* Get the valid Page start Address */
|
||||
PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(validpage * PAGE_SIZE));
|
||||
|
||||
/* Get the valid Page end Address */
|
||||
address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + validpage) * PAGE_SIZE));
|
||||
|
||||
/* Check each active page address starting from end */
|
||||
while (address > (PageStartAddress + 2))
|
||||
{
|
||||
/* Get the current location content to be compared with virtual address */
|
||||
addressvalue = (*(__IO uint16_t*)address);
|
||||
|
||||
/* Compare the read address with the virtual address */
|
||||
if (addressvalue == VirtAddress)
|
||||
{
|
||||
/* Get content of Address-2 which is variable value */
|
||||
*Data = (*(__IO uint16_t*)(address - 2));
|
||||
|
||||
/* In case variable value is read, reset readstatus flag */
|
||||
readstatus = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Next address location */
|
||||
address = address - 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return readstatus value: (0: variable exist, 1: variable doesn't exist) */
|
||||
return readstatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes/upadtes variable data in EEPROM.
|
||||
* @param VirtAddress: Variable virtual address
|
||||
* @param Data: 16 bit data to be written
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
uint16_t driverHWEEPROMWriteVariable(uint16_t VirtAddress, uint16_t Data)
|
||||
{
|
||||
uint16_t Status = 0;
|
||||
|
||||
/* Write the variable virtual address and value in the EEPROM */
|
||||
Status = driverHWEEPROMVerifyPageFullWriteVariable(VirtAddress, Data);
|
||||
|
||||
/* In case the EEPROM active page is full */
|
||||
if (Status == PAGE_FULL)
|
||||
{
|
||||
/* Perform Page transfer */
|
||||
Status = driverHWEEPROMPageTransfer(VirtAddress, Data);
|
||||
}
|
||||
|
||||
/* Return last operation status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
|
||||
* @param None
|
||||
* @retval Status of the last operation (Flash write or erase) done during
|
||||
* EEPROM formating
|
||||
*/
|
||||
static HAL_StatusTypeDef driverHWEEPROMFormat(void)
|
||||
{
|
||||
HAL_StatusTypeDef flashstatus = HAL_OK;
|
||||
uint32_t page_error = 0;
|
||||
FLASH_EraseInitTypeDef s_eraseinit;
|
||||
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = PAGE0_BASE_ADDRESS;
|
||||
s_eraseinit.NbPages = 2;
|
||||
/* Erase Page0 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE0_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
/* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
s_eraseinit.PageAddress = PAGE1_BASE_ADDRESS;
|
||||
/* Erase Page1 */
|
||||
if(!driverHWEEPROMVerifyPageFullyErased(PAGE1_BASE_ADDRESS))
|
||||
{
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find valid Page for write or read operation
|
||||
* @param Operation: operation to achieve on the valid page.
|
||||
* This parameter can be one of the following values:
|
||||
* @arg READ_FROM_VALID_PAGE: read operation from valid page
|
||||
* @arg WRITE_IN_VALID_PAGE: write operation from valid page
|
||||
* @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
|
||||
* of no valid page was found
|
||||
*/
|
||||
static uint16_t driverHWEEPROMFindValidPage(uint8_t Operation)
|
||||
{
|
||||
uint16_t pagestatus0 = 6, pagestatus1 = 6;
|
||||
|
||||
/* Get Page0 actual status */
|
||||
pagestatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
|
||||
|
||||
/* Get Page1 actual status */
|
||||
pagestatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
|
||||
|
||||
/* Write or read operation */
|
||||
switch (Operation)
|
||||
{
|
||||
case WRITE_IN_VALID_PAGE: /* ---- Write operation ---- */
|
||||
if (pagestatus1 == VALID_PAGE)
|
||||
{
|
||||
/* Page0 receiving data */
|
||||
if (pagestatus0 == RECEIVE_DATA)
|
||||
{
|
||||
return PAGE0; /* Page0 valid */
|
||||
}
|
||||
else
|
||||
{
|
||||
return PAGE1; /* Page1 valid */
|
||||
}
|
||||
}
|
||||
else if (pagestatus0 == VALID_PAGE)
|
||||
{
|
||||
/* Page1 receiving data */
|
||||
if (pagestatus1 == RECEIVE_DATA)
|
||||
{
|
||||
return PAGE1; /* Page1 valid */
|
||||
}
|
||||
else
|
||||
{
|
||||
return PAGE0; /* Page0 valid */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NO_VALID_PAGE; /* No valid Page */
|
||||
}
|
||||
|
||||
case READ_FROM_VALID_PAGE: /* ---- Read operation ---- */
|
||||
if (pagestatus0 == VALID_PAGE)
|
||||
{
|
||||
return PAGE0; /* Page0 valid */
|
||||
}
|
||||
else if (pagestatus1 == VALID_PAGE)
|
||||
{
|
||||
return PAGE1; /* Page1 valid */
|
||||
}
|
||||
else
|
||||
{
|
||||
return NO_VALID_PAGE ; /* No valid Page */
|
||||
}
|
||||
|
||||
default:
|
||||
return PAGE0; /* Page0 valid */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verify if active page is full and Writes variable in EEPROM.
|
||||
* @param VirtAddress: 16 bit virtual address of the variable
|
||||
* @param Data: 16 bit data to be written as variable value
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
|
||||
static uint16_t driverHWEEPROMVerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data)
|
||||
{
|
||||
HAL_StatusTypeDef flashstatus = HAL_OK;
|
||||
uint16_t validpage = PAGE0;
|
||||
uint32_t address = EEPROM_START_ADDRESS, pageendaddress = EEPROM_START_ADDRESS+PAGE_SIZE;
|
||||
|
||||
/* Get valid Page for write operation */
|
||||
validpage = driverHWEEPROMFindValidPage(WRITE_IN_VALID_PAGE);
|
||||
|
||||
/* Check if there is no valid page */
|
||||
if (validpage == NO_VALID_PAGE)
|
||||
{
|
||||
return NO_VALID_PAGE;
|
||||
}
|
||||
|
||||
/* Get the valid Page start address */
|
||||
address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(validpage * PAGE_SIZE));
|
||||
|
||||
/* Get the valid Page end address */
|
||||
pageendaddress = (uint32_t)((EEPROM_START_ADDRESS - 1) + (uint32_t)((validpage + 1) * PAGE_SIZE));
|
||||
|
||||
/* Check each active page address starting from begining */
|
||||
while (address < pageendaddress)
|
||||
{
|
||||
/* Verify if address and address+2 contents are 0xFFFFFFFF */
|
||||
if ((*(__IO uint32_t*)address) == 0xFFFFFFFF)
|
||||
{
|
||||
/* Set variable data */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, Data);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
/* Set variable virtual address */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address + 2, VirtAddress);
|
||||
/* Return program operation status */
|
||||
return flashstatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Next address location */
|
||||
address = address + 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return PAGE_FULL in case the valid page is full */
|
||||
return PAGE_FULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transfers last updated variables data from the full Page to
|
||||
* an empty one.
|
||||
* @param VirtAddress: 16 bit virtual address of the variable
|
||||
* @param Data: 16 bit data to be written as variable value
|
||||
* @retval Success or error status:
|
||||
* - FLASH_COMPLETE: on success
|
||||
* - PAGE_FULL: if valid page is full
|
||||
* - NO_VALID_PAGE: if no valid page was found
|
||||
* - Flash error code: on write Flash error
|
||||
*/
|
||||
static uint16_t driverHWEEPROMPageTransfer(uint16_t VirtAddress, uint16_t Data)
|
||||
{
|
||||
HAL_StatusTypeDef flashstatus = HAL_OK;
|
||||
uint32_t newpageaddress = EEPROM_START_ADDRESS;
|
||||
uint32_t oldpageid = 0;
|
||||
uint16_t validpage = PAGE0, varidx = 0;
|
||||
uint16_t eepromstatus = 0, readstatus = 0;
|
||||
uint32_t page_error = 0;
|
||||
FLASH_EraseInitTypeDef s_eraseinit;
|
||||
|
||||
/* Get active Page for read operation */
|
||||
validpage = driverHWEEPROMFindValidPage(READ_FROM_VALID_PAGE);
|
||||
|
||||
if (validpage == PAGE1) /* Page1 valid */
|
||||
{
|
||||
/* New page address where variable will be moved to */
|
||||
newpageaddress = PAGE0_BASE_ADDRESS;
|
||||
|
||||
/* Old page ID where variable will be taken from */
|
||||
oldpageid = PAGE1_BASE_ADDRESS;
|
||||
}
|
||||
else if (validpage == PAGE0) /* Page0 valid */
|
||||
{
|
||||
/* New page address where variable will be moved to */
|
||||
newpageaddress = PAGE1_BASE_ADDRESS;
|
||||
|
||||
/* Old page ID where variable will be taken from */
|
||||
oldpageid = PAGE0_BASE_ADDRESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NO_VALID_PAGE; /* No valid Page */
|
||||
}
|
||||
|
||||
/* Set the new Page status to RECEIVE_DATA status */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, newpageaddress, RECEIVE_DATA);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
/* Write the variable passed as parameter in the new active page */
|
||||
eepromstatus = driverHWEEPROMVerifyPageFullWriteVariable(VirtAddress, Data);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (eepromstatus != HAL_OK)
|
||||
{
|
||||
return eepromstatus;
|
||||
}
|
||||
|
||||
/* Transfer process: transfer variables from old to the new active page */
|
||||
for (varidx = 0; varidx < driverHWEEPROMNumberOfVars; varidx++)
|
||||
{
|
||||
if (driverHWEEPROMVirtAddVarTab[varidx] != VirtAddress) /* Check each variable except the one passed as parameter */
|
||||
{
|
||||
/* Read the other last variable updates */
|
||||
readstatus = driverHWEEPROMReadVariable(driverHWEEPROMVirtAddVarTab[varidx], &DataVar);
|
||||
/* In case variable corresponding to the virtual address was found */
|
||||
if (readstatus != 0x1)
|
||||
{
|
||||
/* Transfer the variable to the new active page */
|
||||
eepromstatus = driverHWEEPROMVerifyPageFullWriteVariable(driverHWEEPROMVirtAddVarTab[varidx], DataVar);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (eepromstatus != HAL_OK)
|
||||
{
|
||||
return eepromstatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
s_eraseinit.PageAddress = oldpageid;
|
||||
s_eraseinit.NbPages = 2;
|
||||
|
||||
/* Erase the old Page: Set old Page status to ERASED status */
|
||||
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
|
||||
/* If erase operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
/* Set new Page status to VALID_PAGE status */
|
||||
flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, newpageaddress, VALID_PAGE);
|
||||
/* If program operation was failed, a Flash error code is returned */
|
||||
if (flashstatus != HAL_OK)
|
||||
{
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return last operation flash status */
|
||||
return flashstatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
34
firmware/Core/Src/driverHWPowerState.c
Normal file
34
firmware/Core/Src/driverHWPowerState.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "driverHWPowerState.h"
|
||||
|
||||
const PowerStatePortStruct driverHWPorts[NoOfPowersSTATs] = // Holds all status configuration data
|
||||
{
|
||||
{GPIOB,0,GPIO_PIN_5,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // P_STAT_POWER_ENABLE
|
||||
{GPIOB,0,GPIO_PIN_4,GPIO_MODE_INPUT,GPIO_PULLUP}, // P_STAT_BUTTON_INPUT
|
||||
{GPIOE,0,GPIO_PIN_9,GPIO_MODE_INPUT,GPIO_PULLDOWN} // P_STAT_CHARGE_DETECT
|
||||
};
|
||||
|
||||
void driverHWPowerStateInit(void) {
|
||||
GPIO_InitTypeDef PowerStatePortHolder;
|
||||
uint8_t STATPointer;
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
|
||||
for(STATPointer = 0; STATPointer < NoOfPowersSTATs; STATPointer++) {
|
||||
//RCC->AHBENR |= driverHWPorts[STATPointer].ClkRegister; // Enable clock de desired port
|
||||
PowerStatePortHolder.Mode = driverHWPorts[STATPointer].Mode; // Push pull output
|
||||
PowerStatePortHolder.Pin = driverHWPorts[STATPointer].Pin; // Points to status pin
|
||||
PowerStatePortHolder.Pull = driverHWPorts[STATPointer].Pull; // No pullup
|
||||
PowerStatePortHolder.Speed = GPIO_SPEED_HIGH; // GPIO clock speed
|
||||
HAL_GPIO_Init(driverHWPorts[STATPointer].Port,&PowerStatePortHolder); // Perform the IO init
|
||||
};
|
||||
};
|
||||
|
||||
void driverHWPowerStateSetOutput(PowerStateIDTypedef outputPort, PowerStateStateTypedef newState) {
|
||||
HAL_GPIO_WritePin(driverHWPorts[outputPort].Port,driverHWPorts[outputPort].Pin,(GPIO_PinState)newState); // Set desired pin to desired state
|
||||
};
|
||||
|
||||
bool driverHWPowerStateReadInput(PowerStateIDTypedef inputPort) {
|
||||
return (bool) !HAL_GPIO_ReadPin(driverHWPorts[inputPort].Port,driverHWPorts[inputPort].Pin);
|
||||
};
|
||||
74
firmware/Core/Src/driverHWSPI1.c
Normal file
74
firmware/Core/Src/driverHWSPI1.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "driverHWSPI1.h"
|
||||
|
||||
SPI_HandleTypeDef driverHWSPI1Handle;
|
||||
|
||||
void driverHWSPI1Init(GPIO_TypeDef* GPIOCSPort, uint16_t GPIO_CSPin) {
|
||||
driverHWSPI1Handle.Instance = SPI3;
|
||||
driverHWSPI1Handle.Init.Mode = SPI_MODE_MASTER;
|
||||
driverHWSPI1Handle.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
driverHWSPI1Handle.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
driverHWSPI1Handle.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
||||
//driverHWSPI1Handle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
driverHWSPI1Handle.Init.CLKPhase = SPI_PHASE_2EDGE;
|
||||
driverHWSPI1Handle.Init.NSS = SPI_NSS_HARD_OUTPUT;
|
||||
driverHWSPI1Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
|
||||
// driverHWSPI1Handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
||||
driverHWSPI1Handle.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
driverHWSPI1Handle.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
driverHWSPI1Handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
driverHWSPI1Handle.Init.CRCPolynomial = 7;
|
||||
|
||||
|
||||
|
||||
|
||||
// driverHWSPI1Handle.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
|
||||
// driverHWSPI1Handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
||||
if (HAL_SPI_Init(&driverHWSPI1Handle) != HAL_OK)
|
||||
{
|
||||
while(true);
|
||||
}
|
||||
|
||||
HAL_GPIO_WritePin(GPIOCSPort,GPIO_CSPin,GPIO_PIN_SET);
|
||||
};
|
||||
|
||||
bool driverHWSPI1Write(uint8_t *writeBuffer, uint8_t noOfBytesToWrite, GPIO_TypeDef* GPIOCSPort, uint16_t GPIO_CSPin) {
|
||||
uint8_t *readBuffer; // Make fake buffer holder
|
||||
HAL_StatusTypeDef halReturnStatus; // Make holder for HAL state
|
||||
readBuffer = malloc(noOfBytesToWrite); // Make fake buffer for
|
||||
|
||||
HAL_GPIO_WritePin(GPIOCSPort,GPIO_CSPin,GPIO_PIN_RESET); // Make CS low
|
||||
halReturnStatus = HAL_SPI_TransmitReceive(&driverHWSPI1Handle,writeBuffer,readBuffer,noOfBytesToWrite,driverHWSPI1DefaultTimeout); // Write desired data to slave and store the received data in readBuffer
|
||||
while( driverHWSPI1Handle.State == HAL_SPI_STATE_BUSY ); // Wait until transmission is complete
|
||||
HAL_GPIO_WritePin(GPIOCSPort,GPIO_CSPin,GPIO_PIN_SET); // Make CS High
|
||||
|
||||
free(readBuffer); // Dump de fake buffer
|
||||
|
||||
return (halReturnStatus == HAL_OK); // Return true if all went OK
|
||||
};
|
||||
|
||||
bool driverHWSPI1WriteRead(uint8_t *writeBuffer, uint8_t noOfBytesToWrite, uint8_t *readBuffer, uint8_t noOfBytesToRead, GPIO_TypeDef* GPIOCSPort, uint16_t GPIO_CSPin) {
|
||||
uint8_t *writeArray, *readArray;
|
||||
HAL_StatusTypeDef halReturnStatus; // Make holder for HAL state
|
||||
|
||||
writeArray = malloc(sizeof(uint8_t)*(noOfBytesToWrite+noOfBytesToRead));
|
||||
readArray = malloc(sizeof(uint8_t)*(noOfBytesToWrite+noOfBytesToRead));
|
||||
|
||||
memset(writeArray,0xFF,noOfBytesToWrite+noOfBytesToRead);
|
||||
memcpy(writeArray,writeBuffer,noOfBytesToWrite);
|
||||
|
||||
HAL_GPIO_WritePin(GPIOCSPort,GPIO_CSPin,GPIO_PIN_RESET);
|
||||
halReturnStatus = HAL_SPI_TransmitReceive(&driverHWSPI1Handle,writeArray,readArray,noOfBytesToWrite+noOfBytesToRead,driverHWSPI1DefaultTimeout);
|
||||
while( driverHWSPI1Handle.State == HAL_SPI_STATE_BUSY ); // wait xmission complete
|
||||
HAL_GPIO_WritePin(GPIOCSPort,GPIO_CSPin,GPIO_PIN_SET);
|
||||
|
||||
memcpy(readBuffer,readArray+noOfBytesToWrite,noOfBytesToRead);
|
||||
|
||||
free(writeArray);
|
||||
free(readArray);
|
||||
|
||||
return (halReturnStatus == HAL_OK); // Return true if all went OK
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
65
firmware/Core/Src/driverHWSwitches.c
Normal file
65
firmware/Core/Src/driverHWSwitches.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "driverHWSwitches.h"
|
||||
|
||||
const driverHWSwitchesPortStruct driverHWSwitchesPorts[NoOfSwitches] = // Hold all status configuration data
|
||||
{
|
||||
// {GPIOB,0,GPIO_PIN_2,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // SWITCH_COOLING or SWITCH_CHARGE_BYPASS
|
||||
// {GPIOB,0,GPIO_PIN_0,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // SWITCH_CHARGE
|
||||
// {GPIOB,0,GPIO_PIN_11,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // SWITCH_PRECHARGE
|
||||
// {GPIOB,0,GPIO_PIN_10,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // SWITCH_DISCHARGE
|
||||
// {GPIOC,0,GPIO_PIN_15,GPIO_MODE_OUTPUT_PP,GPIO_NOPULL}, // SWITCH_DISCHARGEHV
|
||||
// {GPIOC,0,GPIO_PIN_13,GPIO_MODE_OUTPUT_OD,GPIO_NOPULL}//, // SWITCH_SAFETY_OUTPUT
|
||||
};
|
||||
|
||||
void driverHWSwitchesInit(void) {
|
||||
GPIO_InitTypeDef switchPortHolder;
|
||||
uint8_t SwitchPointer;
|
||||
|
||||
// for(SwitchPointer = 0; SwitchPointer < NoOfSwitches; SwitchPointer++) {
|
||||
// // RCC->AHBENR |= driverHWSwitchesPorts[SwitchPointer].ClkRegister; // Enable clock de desired port
|
||||
// switchPortHolder.Mode = driverHWSwitchesPorts[SwitchPointer].Mode; // Push pull output
|
||||
// switchPortHolder.Pin = driverHWSwitchesPorts[SwitchPointer].Pin; // Points to status pin
|
||||
// switchPortHolder.Pull = driverHWSwitchesPorts[SwitchPointer].Pull; // Pullup
|
||||
// //switchPortHolder.Speed = GPIO_SPEED_HIGH; // GPIO clock speed
|
||||
// HAL_GPIO_Init(driverHWSwitchesPorts[SwitchPointer].Port,&switchPortHolder);// Perform the IO init
|
||||
// };
|
||||
//
|
||||
driverHWSwitchesSetSwitchState(SWITCH_SAFETY_OUTPUT,SWITCH_SET);
|
||||
};
|
||||
|
||||
void driverHWSwitchesSetSwitchState(driverHWSwitchesIDTypedef switchID, driverHWSwitchesStateTypedef newState) {
|
||||
// HAL_GPIO_WritePin(driverHWSwitchesPorts[switchID].Port,driverHWSwitchesPorts[switchID].Pin,(GPIO_PinState)newState); // Set desired pin to desired state
|
||||
};
|
||||
|
||||
void driverHWSwitchesDisableAll(void) {
|
||||
uint8_t SwitchPointer;
|
||||
// for(SwitchPointer = 0; SwitchPointer < NoOfSwitches; SwitchPointer++) {
|
||||
// HAL_GPIO_WritePin(driverHWSwitchesPorts[SwitchPointer].Port,driverHWSwitchesPorts[SwitchPointer].Pin,(GPIO_PinState)SWITCH_RESET); // Set desired pin to desired state
|
||||
// };
|
||||
};
|
||||
|
||||
|
||||
bool driverHWSwitchesGetSwitchState(driverHWSwitchesIDTypedef switchID) {
|
||||
return (bool) HAL_GPIO_ReadPin(driverHWSwitchesPorts[switchID].Port,driverHWSwitchesPorts[switchID].Pin); // Set desired pin to desired state
|
||||
};
|
||||
|
||||
|
||||
173
firmware/Core/Src/driverHWUART2.c
Normal file
173
firmware/Core/Src/driverHWUART2.c
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "driverHWUART2.h"
|
||||
|
||||
UART_HandleTypeDef driverHWUART2Handle;
|
||||
DMA_HandleTypeDef driverHWUART2HDMAHandleRX;
|
||||
uint8_t driverHWUART2ReceivedChar;
|
||||
|
||||
uint8_t driverHWUART2ReceiveBuffer[RX_UART_BUFFER_SIZE]; // Buffer that stores received chars
|
||||
uint8_t driverHWUART2ReceiveBuffer_usb[RX_UART_BUFFER_SIZE];
|
||||
uint32_t driverHWUART2Receive_CNDTR = RX_UART_BUFFER_SIZE;
|
||||
uint8_t driverHWUART2Receive_CNDTR_resetFlag = 0;
|
||||
|
||||
void driverHWUART2Init(uint32_t baudRate) {
|
||||
// memset(driverHWUART2ReceiveBuffer,0,sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t));
|
||||
//
|
||||
// /* DMA controller clock enable */
|
||||
// __HAL_RCC_DMA1_CLK_ENABLE();
|
||||
//
|
||||
// driverHWUART2HDMAHandleRX.Instance = DMA1_Channel6; // Will handle transfer of received char to buffer
|
||||
// driverHWUART2HDMAHandleRX.Init.Direction = DMA_PERIPH_TO_MEMORY;
|
||||
// driverHWUART2HDMAHandleRX.Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
// driverHWUART2HDMAHandleRX.Init.MemInc = DMA_MINC_ENABLE;
|
||||
// driverHWUART2HDMAHandleRX.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
|
||||
// driverHWUART2HDMAHandleRX.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
|
||||
// driverHWUART2HDMAHandleRX.Init.Mode = DMA_CIRCULAR;
|
||||
// driverHWUART2HDMAHandleRX.Init.Priority = DMA_PRIORITY_MEDIUM;
|
||||
//
|
||||
// if (HAL_DMA_Init(&driverHWUART2HDMAHandleRX) != HAL_OK)
|
||||
// {
|
||||
// while(true);
|
||||
// }
|
||||
//
|
||||
// __HAL_LINKDMA(&driverHWUART2Handle,hdmarx,driverHWUART2HDMAHandleRX);
|
||||
//
|
||||
// driverHWUART2Handle.Instance = USART2;
|
||||
// driverHWUART2Handle.Init.BaudRate = baudRate;
|
||||
// driverHWUART2Handle.Init.WordLength = UART_WORDLENGTH_8B;
|
||||
// driverHWUART2Handle.Init.StopBits = UART_STOPBITS_1;
|
||||
// driverHWUART2Handle.Init.Parity = UART_PARITY_NONE;
|
||||
// driverHWUART2Handle.Init.Mode = UART_MODE_TX_RX;
|
||||
// driverHWUART2Handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||
// driverHWUART2Handle.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||
// // driverHWUART2Handle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
|
||||
// // driverHWUART2Handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
||||
//
|
||||
// if (HAL_UART_Init(&driverHWUART2Handle) != HAL_OK) {
|
||||
// while(true);
|
||||
// }
|
||||
//
|
||||
// volatile HAL_StatusTypeDef temp = HAL_UART_Receive_DMA(&driverHWUART2Handle,driverHWUART2ReceiveBuffer,sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t)); // Start receive to DMA transfer
|
||||
//
|
||||
// HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0); // Will realise interrupt on half and full DMA transfer
|
||||
// HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
|
||||
};
|
||||
|
||||
void driverHWUART2SendChar(uint8_t character) {
|
||||
uint8_t usb_out_buffer[1];
|
||||
uint8_t usb_result = 1;
|
||||
uint32_t usb_start_time;
|
||||
usb_start_time = HAL_GetTick();
|
||||
|
||||
usb_out_buffer[0] = character;
|
||||
while(usb_result == 1){
|
||||
//) || ((HAL_GetTick() - usb_start_time < 10))
|
||||
usb_result = CDC_Transmit_FS(usb_out_buffer, 1);
|
||||
}
|
||||
//HAL_UART_Transmit(&driverHWUART2Handle,&character,sizeof(character)/sizeof(uint8_t),10); // Send single char over serial port
|
||||
};
|
||||
|
||||
bool driverHWUART2GetChar(char *character) {
|
||||
static uint32_t bufferTail = 0; // Initiate tail to 0
|
||||
uint32_t bufferHead = sizeof(driverHWUART2ReceiveBuffer_usb)/sizeof(uint8_t) - driverHWUART2Receive_CNDTR; // Tranform to be transferred bytes to bytes transferred.
|
||||
|
||||
// if(driverHWUART2Receive_CNDTR_resetFlag){
|
||||
// bufferTail = 0;
|
||||
// driverHWUART2Receive_CNDTR_resetFlag = 0;
|
||||
// //bufferHead = 0;
|
||||
// }
|
||||
|
||||
if(bufferTail != bufferHead){ // If head and tail differs there is something in the buffer
|
||||
*character = driverHWUART2ReceiveBuffer_usb[bufferTail]; // Get char from tail of buffer
|
||||
bufferTail++; // Move the tail forward
|
||||
bufferTail %= (sizeof(driverHWUART2ReceiveBuffer_usb)/sizeof(uint8_t)); // Wrap it around the end
|
||||
return true; // Indicate there is a char in buffer
|
||||
}else
|
||||
return false; // Indicate there is no char in buffer
|
||||
};
|
||||
|
||||
//bool driverHWUART2GetChar(char *character) {
|
||||
// static uint32_t bufferTail = 0;
|
||||
// __IO uint32_t a = 0;
|
||||
// __IO uint32_t b = 0;
|
||||
// uint32_t usb_start_time;
|
||||
// __IO uint32_t bufferHead = 0;
|
||||
// usb_start_time = HAL_GetTick();// Initiate tail to 0
|
||||
// uint32_t cndtr_buf = driverHWUART2HDMAHandleRX.Instance->CNDTR;
|
||||
//
|
||||
// if(driverHWUART2Receive_CNDTR_resetFlag){
|
||||
// bufferTail = 0;
|
||||
// driverHWUART2Receive_CNDTR_resetFlag = 0;
|
||||
// //bufferHead = 0;
|
||||
//
|
||||
// }
|
||||
//
|
||||
// //uint32_t bufferHead = sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t) - driverHWUART2HDMAHandleRX.Instance->CNDTR; // Tranform to be transferred bytes to bytes transferred.
|
||||
// bufferHead = sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t) - driverHWUART2Receive_CNDTR; // Tranform to be transferred bytes to bytes transferred.
|
||||
// // 1024 - 1016 = 8
|
||||
// a = bufferHead - bufferTail;
|
||||
// if(a != 0) {
|
||||
// *character = driverHWUART2ReceiveBuffer_usb[bufferTail];
|
||||
// bufferTail++;
|
||||
//
|
||||
// bufferTail %= (sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t));
|
||||
// return true;
|
||||
// } else{
|
||||
// if(driverHWUART2Receive_CNDTR < 1000) {
|
||||
// return false;
|
||||
// }
|
||||
// return false; // Indicate there is no char in buffer
|
||||
// }
|
||||
// //if(bufferTail != bufferHead) { // If head and tail differs there is something in the buffer
|
||||
// //while (bufferTail != bufferHead) {
|
||||
//// //if(bufferTail < 20) {
|
||||
//// //*character = driverHWUART2ReceiveBuffer[bufferTail]; // Get char from tail of buffer
|
||||
//// *character = driverHWUART2ReceiveBuffer_usb[bufferTail];
|
||||
//// bufferTail++;
|
||||
//// // Move the tail forward
|
||||
//// bufferTail %= (sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t)); // Wrap it around the end
|
||||
//// // bufferTail = bufferTail % 1024
|
||||
//// // bufferTail = 1024 % 1024 = 0
|
||||
//// return true; // Indicate there is a char in buffer
|
||||
//// }else{
|
||||
//// if(driverHWUART2Receive_CNDTR < 1000) {
|
||||
//// return false;
|
||||
//// }
|
||||
//// return false; // Indicate there is no char in buffer
|
||||
//// }
|
||||
//};
|
||||
|
||||
//void driverHWUART2SendChar(uint8_t character) {
|
||||
// //HAL_UART_Transmit(&driverHWUART2Handle,&character,sizeof(character)/sizeof(uint8_t),10); // Send single char over serial port
|
||||
//// CDC_Transmit_FS(character, 1);
|
||||
// uint8_t testDataToSend[8];
|
||||
// // for (uint8_t i = 0; i < 8; i++)
|
||||
// // {
|
||||
// // testDataToSend[i] = i;
|
||||
// // }
|
||||
//
|
||||
// testDataToSend[0] = character;
|
||||
// CDC_Transmit_FS(testDataToSend, 1);
|
||||
//
|
||||
// //uint8_t buf[1];
|
||||
// //buf[0] = character;
|
||||
// //CDC_Transmit_FS(buf[0], 1);
|
||||
//};
|
||||
//
|
||||
//bool driverHWUART2GetChar(char *character) {
|
||||
// static uint32_t bufferTail = 0; // Initiate tail to 0
|
||||
// uint32_t bufferHead = sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t) - driverHWUART2Receive_CNDTR; // Tranform to be transferred bytes to bytes transferred.
|
||||
// if(bufferHead == 12) {
|
||||
//// bufferTail = 1;
|
||||
// }
|
||||
// if(bufferTail != bufferHead){ // If head and tail differs there is something in the buffer
|
||||
// *character = driverHWUART2ReceiveBuffer[bufferTail]; // Get char from tail of buffer
|
||||
// bufferTail++; // Move the tail forward
|
||||
// bufferTail %= (sizeof(driverHWUART2ReceiveBuffer)/sizeof(uint8_t)); // Wrap it around the end
|
||||
// return true; // Indicate there is a char in buffer
|
||||
// }else
|
||||
// return false; // Indicate there is no char in buffer
|
||||
//};
|
||||
|
||||
void DMA1_Channel6_IRQHandler(void) { // Will trigger on halve and full
|
||||
// HAL_DMA_IRQHandler(&driverHWUART2HDMAHandleRX);
|
||||
}
|
||||
789
firmware/Core/Src/driverSWLTC6804.c
Normal file
789
firmware/Core/Src/driverSWLTC6804.c
Normal file
@@ -0,0 +1,789 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "driverSWLTC6804.h"
|
||||
#define LTC6804_CS_Pin GPIO_PIN_3
|
||||
#define LTC6804_CS_GPIO_Port GPIOC
|
||||
uint8_t driverSWLTC6804TotalNumberOfICs = 0;
|
||||
|
||||
uint8_t driverSWLTC6804MaxNoOfCellPerModule = 0;
|
||||
uint8_t driverSWLTC6804MaxNoOfTempSensorPerModule = 0;
|
||||
|
||||
driverLTC6804ConfigStructTypedef driverSWLTC6804ConfigStruct;
|
||||
|
||||
void driverSWLTC6804DelayMS(uint32_t delayMS) {
|
||||
uint32_t currentTick = HAL_GetTick();
|
||||
while(!modDelayTick1ms(¤tTick,delayMS)){};
|
||||
}
|
||||
|
||||
void driverSWLTC6804Init(driverLTC6804ConfigStructTypedef configStruct, uint8_t totalNumberOfLTCs, uint8_t noOfCellPerModule, uint8_t noOfTempSensorPerModule, uint8_t cellMonitorType) {
|
||||
driverSWLTC6804ConfigStruct = configStruct;
|
||||
driverSWLTC6804TotalNumberOfICs = totalNumberOfLTCs;
|
||||
driverSWLTC6804MaxNoOfCellPerModule = noOfCellPerModule;
|
||||
driverSWLTC6804MaxNoOfTempSensorPerModule = noOfTempSensorPerModule;
|
||||
|
||||
uint8_t rxConfig [driverSWLTC6804TotalNumberOfICs][8];
|
||||
uint8_t LTCScanCount = 0;
|
||||
int8_t returnPEC = -1;
|
||||
|
||||
driverHWSPI1Init(LTC6804_CS_GPIO_Port,LTC6804_CS_Pin);
|
||||
driverSWLTC6804WakeIC();
|
||||
|
||||
while((LTCScanCount < 5) && (returnPEC == -1)){
|
||||
returnPEC = driverSWLTC6804ReadConfigRegister(driverSWLTC6804TotalNumberOfICs,rxConfig);
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804WriteConfigRegister(driverSWLTC6804TotalNumberOfICs,0,false);
|
||||
if(cellMonitorType==CELL_MON_LTC6812_1 || cellMonitorType == CELL_MON_LTC6813_1){
|
||||
driverSWLTC6804WriteConfigRegisterB(driverSWLTC6804TotalNumberOfICs,0,false);
|
||||
}
|
||||
driverSWLTC6804WakeIC();
|
||||
LTCScanCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void driverSWLTC6804ResetCellVoltageRegisters(void) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
|
||||
cmd[0] = 0x07;
|
||||
cmd[1] = 0x11;
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec );
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804ResetAuxRegisters(void) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
|
||||
cmd[0] = 0x07;
|
||||
cmd[1] = 0x12;
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec );
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804ResetStatusRegisters(void) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
|
||||
cmd[0] = 0x07;
|
||||
cmd[1] = 0x13;
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec );
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804StartCellAndAuxVoltageConversion(uint8_t MD,uint8_t DCP) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
uint8_t ADCVAX[2]; //!< Cell Voltage conversion command.
|
||||
|
||||
ADCVAX[0] = ((MD & 0x02) >> 1) + 0x04;
|
||||
ADCVAX[1] = ((MD & 0x01) << 7) + 0x6F + (DCP<<4);
|
||||
|
||||
cmd[0] = ADCVAX[0];
|
||||
cmd[1] = ADCVAX[1];
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, ADCVAX);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804StartCellVoltageConversion(uint8_t MD,uint8_t DCP, uint8_t CH) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
uint8_t ADCV[2]; //!< Cell Voltage conversion command.
|
||||
|
||||
ADCV[0] = ((MD & 0x02) >> 1) + 0x02;
|
||||
ADCV[1] = ((MD & 0x01) << 7) + 0x60 + (DCP<<4) + CH;
|
||||
|
||||
cmd[0] = ADCV[0];
|
||||
cmd[1] = ADCV[1];
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, ADCV);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804StartLoadedCellVoltageConversion(uint8_t MD,uint8_t DCP, uint8_t CH,uint8_t PUP) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
uint8_t ADOW[2]; //!< Cell Voltage conversion command.
|
||||
|
||||
ADOW[0] = ((MD & 0x02) >> 1) + 0x02;
|
||||
ADOW[1] = ((MD & 0x01) << 7) + 0x28 + (DCP<<4) + CH + (PUP<<6);
|
||||
|
||||
cmd[0] = ADOW[0];
|
||||
cmd[1] = ADOW[1];
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, ADOW);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
void driverSWLTC6804StartAuxVoltageConversion(uint8_t MD, uint8_t CHG) {
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
uint8_t ADAX[2]; //!< GPIO conversion command.
|
||||
|
||||
ADAX[0] = ((MD & 0x02) >> 1) + 0x04;
|
||||
ADAX[1] = ((MD & 0x01) << 7) + 0x60 + CHG ;
|
||||
|
||||
cmd[0] = ADAX[0];
|
||||
cmd[1] = ADAX[1];
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, ADAX);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,4);
|
||||
}
|
||||
|
||||
|
||||
//bool driverSWLTC6804ReadCellVoltagesArray(float cellVoltagesArray[][driverSWLTC6804MaxNoOfCellPerModule]) {
|
||||
bool driverSWLTC6804ReadCellVoltagesArray(float cellVoltagesArray[][18]) {
|
||||
bool dataValid = true;
|
||||
// uint8_t driverSWLTC6804MaxNoOfCellPerModule1 = 12;
|
||||
//uint8_t i = 0;
|
||||
uint16_t cellVoltageArrayCodes[driverSWLTC6804TotalNumberOfICs][driverSWLTC6804MaxNoOfCellPerModule];
|
||||
|
||||
|
||||
driverSWLTC6804ReadCellVoltageRegisters(CELL_CH_ALL,driverSWLTC6804TotalNumberOfICs,cellVoltageArrayCodes);
|
||||
for(uint8_t modulePointer = 0; modulePointer < driverSWLTC6804TotalNumberOfICs; modulePointer++) {
|
||||
for(uint8_t cellPointer = 0; cellPointer < driverSWLTC6804MaxNoOfCellPerModule; cellPointer++){
|
||||
|
||||
if (cellVoltageArrayCodes[modulePointer][cellPointer]*0.0001f < 10.0f) {
|
||||
cellVoltagesArray[modulePointer][cellPointer] = cellVoltageArrayCodes[modulePointer][cellPointer]*0.0001f;
|
||||
// cellVoltagesArray[modulePointer][cellPointer] = i++;
|
||||
} else {
|
||||
dataValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cellVoltagesArray[0][0] = 1;
|
||||
// cellVoltagesArray[0][1] = 2;
|
||||
// cellVoltagesArray[0][2] = 3;
|
||||
// cellVoltagesArray[0][3] = 4;
|
||||
// cellVoltagesArray[0][4] = 5;
|
||||
// cellVoltagesArray[0][5] = 6;
|
||||
// cellVoltagesArray[0][6] = 7;
|
||||
// cellVoltagesArray[0][7] = 8;
|
||||
// cellVoltagesArray[0][8] = 9;
|
||||
// cellVoltagesArray[0][9] = 10;
|
||||
// cellVoltagesArray[0][10] = 11;
|
||||
// cellVoltagesArray[0][11] = 12;
|
||||
//
|
||||
// cellVoltagesArray[1][0] = 13;
|
||||
// cellVoltagesArray[1][1] = 14;
|
||||
// cellVoltagesArray[1][2] = 15;
|
||||
// cellVoltagesArray[1][3] = 16;
|
||||
// cellVoltagesArray[1][4] = 17;
|
||||
// cellVoltagesArray[1][5] = 18;
|
||||
// cellVoltagesArray[1][6] = 13;
|
||||
// cellVoltagesArray[1][7] = 14;
|
||||
// cellVoltagesArray[1][8] = 15;
|
||||
// cellVoltagesArray[1][9] = 16;
|
||||
// cellVoltagesArray[1][10] = 17;
|
||||
// cellVoltagesArray[1][11] = 18;
|
||||
|
||||
// cellVoltagesArray[0][4] = cellVoltagesArray[0][6]; // 5=7
|
||||
// cellVoltagesArray[0][5] = cellVoltagesArray[0][7]; // 6=8
|
||||
// cellVoltagesArray[0][6] = cellVoltagesArray[0][8]; // 7=9
|
||||
// cellVoltagesArray[0][7] = cellVoltagesArray[0][9]; // 8=10
|
||||
// cellVoltagesArray[0][8] = 0;
|
||||
// cellVoltagesArray[0][9] = 0;
|
||||
// cellVoltagesArray[0][10] = 0;
|
||||
// cellVoltagesArray[0][11] = 0;
|
||||
|
||||
|
||||
return dataValid;
|
||||
}
|
||||
|
||||
uint8_t driverSWLTC6804ReadCellVoltageRegisters(uint8_t reg, uint8_t total_ic, uint16_t cell_codes[][driverSWLTC6804MaxNoOfCellPerModule]) {
|
||||
const uint8_t NUM_RX_BYT = 8;
|
||||
const uint8_t BYT_IN_REG = 6;
|
||||
const uint8_t CELL_IN_REG = 3;
|
||||
|
||||
uint8_t *cell_data;
|
||||
int8_t pec_error = 0;
|
||||
uint16_t parsed_cell;
|
||||
uint16_t received_pec;
|
||||
uint16_t data_pec;
|
||||
uint8_t data_counter=0; //data counter
|
||||
cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
|
||||
|
||||
if (reg == 0) {
|
||||
for(uint8_t cell_reg = 1; cell_reg<((driverSWLTC6804MaxNoOfCellPerModule/3)+1); cell_reg++) { //executes once for each of the LTC6804 cell voltage registers
|
||||
data_counter = 0;
|
||||
driverSWLTC6804ReadCellVoltageGroups(cell_reg, total_ic,cell_data ); //Reads a single Cell voltage register
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6804 in the daisy chain current_ic is used as the IC counter
|
||||
for(uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) { // This loop parses the read back data into cell voltages, it loops once for each of the 3 cell voltage codes in the register
|
||||
parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8); //Each cell code is received as two bytes and is combined to create the parsed cell voltage code
|
||||
cell_codes[current_ic][current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
|
||||
data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter must increment by two for each parsed cell code
|
||||
}
|
||||
received_pec = (cell_data[data_counter] << 8) + cell_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 cell voltage data bytes
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the serial data
|
||||
}
|
||||
data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter must be incremented by 2 bytes to point to the next ICs cell voltage data
|
||||
}
|
||||
}
|
||||
}else{
|
||||
driverSWLTC6804ReadCellVoltageGroups(reg, total_ic,cell_data);
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6804 in the daisy chain current_ic is used as the IC counter
|
||||
for(uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) { // This loop parses the read back data into cell voltages, it loops once for each of the 3 cell voltage codes in the register
|
||||
parsed_cell = cell_data[data_counter] + (cell_data[data_counter+1]<<8); //Each cell code is received as two bytes and is combined to create the parsed cell voltage code
|
||||
cell_codes[current_ic][current_cell + ((reg - 1) * CELL_IN_REG)] = 0x0000FFFF & parsed_cell;
|
||||
data_counter= data_counter + 2; //Because cell voltage codes are two bytes the data counter must increment by two for each parsed cell code
|
||||
}
|
||||
received_pec = (cell_data[data_counter] << 8 )+ cell_data[data_counter + 1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 cell voltage data bytes
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
|
||||
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the serial data
|
||||
}
|
||||
data_counter= data_counter + 2; //Because the transmitted PEC code is 2 bytes long the data_counter must be incremented by 2 bytes to point to the next ICs cell voltage data
|
||||
}
|
||||
}
|
||||
|
||||
free(cell_data);
|
||||
return(pec_error);
|
||||
}
|
||||
|
||||
void driverSWLTC6804ReadCellVoltageGroups(uint8_t reg, uint8_t total_ic, uint8_t *data ) {
|
||||
const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
//static uint8_t clean_flag = 0;
|
||||
// uint8_t unlimbuf[1024];
|
||||
//if(clean_flag==0){
|
||||
// memset(unlimbuf,0,1023);
|
||||
//clean_flag=1;
|
||||
// }
|
||||
|
||||
if (reg == 1) { //1: RDCVA
|
||||
cmd[1] = 0x04;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 2) { //2: RDCVB
|
||||
cmd[1] = 0x06;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 3) { //3: RDCVC
|
||||
cmd[1] = 0x08;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 4) { //4: RDCVD
|
||||
cmd[1] = 0x0A;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 5) { //5: RDCVE - LTC6812 & LTC6813 only
|
||||
cmd[1] = 0x09;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 6) { //6: RDCVF - LTC6813 only
|
||||
cmd[1] = 0x0B;
|
||||
cmd[0] = 0x00;
|
||||
}
|
||||
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC(); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
|
||||
driverSWLTC6804WriteRead(cmd,4,data,(REG_LEN*total_ic));
|
||||
// driverSWLTC6804WriteRead(cmd,4,unlimbuf,(REG_LEN*total_ic));
|
||||
}
|
||||
|
||||
bool driverSWLTC6804ReadVoltageFlags(uint32_t *underVoltageFlags, uint32_t *overVoltageFlags, uint32_t lastICMask, uint8_t noOfParallelModules, uint32_t dieTemperature[]) {
|
||||
// Variables
|
||||
uint32_t newVoltageUnder = 0;
|
||||
uint32_t newVoltageOver = 0;
|
||||
driverSWLTC6804StatusStructTypedef driverSWLTC6804StatusStruct[driverSWLTC6804TotalNumberOfICs];
|
||||
|
||||
// Get the data from the modules
|
||||
driverSWLTC6804ReadStatusValues(driverSWLTC6804TotalNumberOfICs,driverSWLTC6804StatusStruct);
|
||||
|
||||
// Combine it
|
||||
for(uint8_t modulePointer = 0; modulePointer < driverSWLTC6804TotalNumberOfICs; modulePointer++) {
|
||||
dieTemperature[modulePointer] = driverSWLTC6804StatusStruct[modulePointer].dieTemperature;
|
||||
//if we have a different number of cells monitored in the last IC, disable error bits with mask
|
||||
if((modulePointer+1) % (driverSWLTC6804TotalNumberOfICs/noOfParallelModules) == 0 && modulePointer != 0){
|
||||
driverSWLTC6804StatusStruct[modulePointer].underVoltage &= lastICMask;
|
||||
driverSWLTC6804StatusStruct[modulePointer].overVoltage &= lastICMask;
|
||||
|
||||
newVoltageUnder |= driverSWLTC6804StatusStruct[modulePointer].underVoltage;
|
||||
newVoltageOver |= driverSWLTC6804StatusStruct[modulePointer].overVoltage;
|
||||
}else{
|
||||
newVoltageUnder |= driverSWLTC6804StatusStruct[modulePointer].underVoltage;
|
||||
newVoltageOver |= driverSWLTC6804StatusStruct[modulePointer].overVoltage;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer the data to the output
|
||||
*underVoltageFlags = newVoltageUnder;
|
||||
*overVoltageFlags = newVoltageOver;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t driverSWLTC6804ReadStatusValues(uint8_t total_ic, driverSWLTC6804StatusStructTypedef statusArray[]) {
|
||||
const uint8_t NUM_RX_BYT = 8;
|
||||
const uint8_t BYT_IN_REG = 6;
|
||||
|
||||
uint32_t registersCombined;
|
||||
uint32_t registersCombinedTemp;
|
||||
int8_t pec_error = 0;
|
||||
uint16_t received_pec;
|
||||
uint16_t data_pec;
|
||||
uint8_t data_counter = 0; //data counter
|
||||
uint8_t *status_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
|
||||
|
||||
driverSWLTC6804ReadStatusGroups(1,total_ic,status_data);
|
||||
data_counter = 0;
|
||||
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) {
|
||||
// Extract DATA
|
||||
statusArray[current_ic].sumOfCells = ((status_data[data_counter+1] << 8) | status_data[data_counter]) * 0.0001f;
|
||||
statusArray[current_ic].dieTemperature = (((status_data[data_counter+3] << 8) | status_data[data_counter+2]) * 0.0001f)/0.0075f - 273.0f;
|
||||
statusArray[current_ic].voltageAnalogSupply = ((status_data[data_counter+5] << 8) | status_data[data_counter+4]) * 0.0001f;
|
||||
data_counter += 6;
|
||||
// Calculate PEC
|
||||
received_pec = (status_data[data_counter] << 8) + status_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 cell voltage data bytes
|
||||
data_counter += 2;
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &status_data[current_ic * NUM_RX_BYT]);
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the serial data
|
||||
}
|
||||
}
|
||||
|
||||
driverSWLTC6804ReadStatusGroups(2,total_ic,status_data);
|
||||
data_counter = 0;
|
||||
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) {
|
||||
// Reset vlag registers
|
||||
statusArray[current_ic].underVoltage = 0;
|
||||
statusArray[current_ic].overVoltage = 0;
|
||||
|
||||
// Extract DATA
|
||||
statusArray[current_ic].voltageDigitalSupply = ((status_data[data_counter+1] << 8) | status_data[data_counter]) * 0.0001f;
|
||||
|
||||
registersCombined = (status_data[data_counter+4] << 16) | (status_data[data_counter+3] << 8) | status_data[data_counter+2]; // Combine all registers in one variable
|
||||
registersCombinedTemp = registersCombined & 0x00555555; // Filter out only the undervoltage bits
|
||||
|
||||
for(int bitPointer = 0; bitPointer < driverSWLTC6804ConfigStruct.noOfCells; bitPointer++)
|
||||
statusArray[current_ic].underVoltage |= (registersCombinedTemp & (1 << bitPointer*2)) ? (1 << bitPointer) : 0; // Shift undervoltage bits closer together and store them in *underVoltageFlags
|
||||
|
||||
registersCombinedTemp = registersCombined & 0x00AAAAAA; // Filter out only the overvoltage bits
|
||||
registersCombinedTemp = registersCombinedTemp >> 1; // Move everything one bit to the right
|
||||
|
||||
for(int bitPointer = 0; bitPointer < driverSWLTC6804ConfigStruct.noOfCells; bitPointer++)
|
||||
statusArray[current_ic].overVoltage |= (registersCombinedTemp & (1 << bitPointer*2)) ? (1 << bitPointer) : 0; // And do the same for the overvoltage bits
|
||||
|
||||
statusArray[current_ic].muxFail = 0;
|
||||
data_counter += 6;
|
||||
// Calculate PEC
|
||||
received_pec = (status_data[data_counter] << 8) + status_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 cell voltage data bytes
|
||||
data_counter += 2;
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &status_data[current_ic * NUM_RX_BYT]);
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the serial data
|
||||
}
|
||||
}
|
||||
|
||||
// Execute for higher cell count with auxiliary group D OV & UV flags
|
||||
if(driverSWLTC6804MaxNoOfCellPerModule > 12){
|
||||
|
||||
driverSWLTC6804ReadStatusGroups(3,total_ic,status_data);
|
||||
data_counter = 0;
|
||||
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) {
|
||||
|
||||
//Extract DATA for under & over voltage flags STBR4, STBR3, & STBR2
|
||||
registersCombined = (status_data[data_counter+5] << 8) | (status_data[data_counter+4]); // Combine all registers in one variable
|
||||
registersCombinedTemp = registersCombined & 0x00000555; // Filter out only the undervoltage bits
|
||||
|
||||
for(int bitPointer = 0; bitPointer < (driverSWLTC6804ConfigStruct.noOfCells-12); bitPointer++){
|
||||
statusArray[current_ic].underVoltage |= (((registersCombinedTemp & (1 << bitPointer*2)) ? (1 << bitPointer) : 0) << 12) ; // Shift undervoltage bits closer together and store them in *underVoltageFlags + shift 12 bits
|
||||
|
||||
registersCombinedTemp = registersCombined & 0x00000AAA; // Filter out only the overvoltage bits
|
||||
registersCombinedTemp = registersCombinedTemp >> 1; // Move everything one bit to the right
|
||||
|
||||
for(int bitPointer = 0; bitPointer < driverSWLTC6804ConfigStruct.noOfCells-12; bitPointer++)
|
||||
statusArray[current_ic].overVoltage |= (((registersCombinedTemp & (1 << bitPointer*2)) ? (1 << bitPointer) : 0) << 12); // And do the same for the overvoltage bits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(status_data);
|
||||
return pec_error;
|
||||
}
|
||||
|
||||
void driverSWLTC6804ReadStatusGroups(uint8_t reg, uint8_t total_ic, uint8_t *data ) {
|
||||
const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
|
||||
if (reg == 1) { //1: RDSTATA
|
||||
cmd[1] = 0x10;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 2) { //2: RDSTATB
|
||||
cmd[1] = 0x12;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 3) { //Read auxiliary group D LTC6812 & LTC6813 only for AVDR4 & AVDR5 OV & UV flags
|
||||
cmd[1] = 0x0F;
|
||||
cmd[0] = 0x00;
|
||||
}
|
||||
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WriteRead(cmd,4,data,(REG_LEN*total_ic));
|
||||
}
|
||||
|
||||
bool driverSWLTC6804ReadAuxVoltagesArray(float auxVoltagesArray[][12],uint32_t ntcNominal,uint32_t ntcSeriesResistance, uint16_t ntcBetaFactor,float ntcNominalTemp) {
|
||||
bool dataValid = true;
|
||||
uint16_t auxVoltageArrayCodes[driverSWLTC6804TotalNumberOfICs][driverSWLTC6804MaxNoOfTempSensorPerModule];
|
||||
|
||||
driverSWLTC6804ReadAuxVoltageRegisters(AUX_CH_ALL,driverSWLTC6804TotalNumberOfICs,auxVoltageArrayCodes);
|
||||
|
||||
for(uint8_t modulePointer = 0; modulePointer < driverSWLTC6804TotalNumberOfICs; modulePointer++) {
|
||||
for(uint8_t auxPointer = 0; auxPointer < driverSWLTC6804MaxNoOfTempSensorPerModule; auxPointer++){
|
||||
if(auxVoltageArrayCodes[modulePointer][auxPointer]*0.0001f < 10.0f)
|
||||
auxVoltagesArray[modulePointer][auxPointer] = driverSWLTC6804ConvertTemperatureExt(auxVoltageArrayCodes[modulePointer][auxPointer], ntcNominal, ntcSeriesResistance, ntcBetaFactor, ntcNominalTemp);
|
||||
else
|
||||
dataValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
return dataValid;
|
||||
}
|
||||
|
||||
int8_t driverSWLTC6804ReadAuxVoltageRegisters(uint8_t reg, uint8_t total_ic, uint16_t aux_codes[][driverSWLTC6804MaxNoOfTempSensorPerModule]) {
|
||||
const uint8_t NUM_RX_BYT = 8;
|
||||
const uint8_t BYT_IN_REG = 6;
|
||||
const uint8_t GPIO_IN_REG = 3;
|
||||
|
||||
uint8_t *data;
|
||||
uint8_t data_counter = 0;
|
||||
int8_t pec_error = 0;
|
||||
uint16_t parsed_aux;
|
||||
uint16_t received_pec;
|
||||
uint16_t data_pec;
|
||||
data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
|
||||
//1.a
|
||||
if (reg == 0) {
|
||||
for(uint8_t gpio_reg = 1; gpio_reg<((driverSWLTC6804MaxNoOfTempSensorPerModule/3)+1); gpio_reg++) { //executes once for each of the LTC6804 aux voltage registers
|
||||
data_counter = 0;
|
||||
driverSWLTC6804ReadAuxGroups(gpio_reg, total_ic,data); //Reads the raw auxiliary register data into the data[] array
|
||||
for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6804 in the daisy chain current_ic is used as the IC counter
|
||||
for(uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it loops once for each of the 3 gpio voltage codes in the register
|
||||
parsed_aux = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to create the parsed gpio voltage code
|
||||
aux_codes[current_ic][current_gpio +((gpio_reg-1)*GPIO_IN_REG)] = parsed_aux;
|
||||
data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter must increment by two for each parsed gpio voltage code
|
||||
}
|
||||
|
||||
received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 gpio voltage data bytes
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the received serial data
|
||||
}
|
||||
data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter must be incremented by 2 bytes to point to the next ICs gpio voltage data
|
||||
}
|
||||
}
|
||||
}else{
|
||||
driverSWLTC6804ReadAuxGroups(reg, total_ic, data);
|
||||
for (int current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6804 in the daisy chain current_ic is used as an IC counter
|
||||
|
||||
for(int current_gpio = 0; current_gpio<GPIO_IN_REG; current_gpio++) { // This loop parses the read back data. Loops once for each aux voltage in the register
|
||||
parsed_aux = (data[data_counter] + (data[data_counter+1]<<8)); //Each gpio codes is received as two bytes and is combined to create the parsed gpio voltage code
|
||||
aux_codes[current_ic][current_gpio +((reg-1)*GPIO_IN_REG)] = parsed_aux;
|
||||
data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter must increment by two for each parsed gpio voltage code
|
||||
}
|
||||
received_pec = (data[data_counter]<<8) + data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th after the 6 gpio voltage data bytes
|
||||
data_pec = driverSWLTC6804CalcPEC15(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
|
||||
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1; //The pec_error variable is simply set negative if any PEC errors are detected in the received serial data
|
||||
}
|
||||
|
||||
data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter must be incremented by 2 bytes to point to the next ICs gpio voltage data
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
return (pec_error);
|
||||
}
|
||||
|
||||
void driverSWLTC6804ReadAuxGroups(uint8_t reg, uint8_t total_ic, uint8_t *data) {
|
||||
const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
|
||||
uint8_t cmd[4];
|
||||
uint16_t cmd_pec;
|
||||
|
||||
//1
|
||||
if (reg == 1) { //Read back auxiliary group A
|
||||
cmd[1] = 0x0C;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 2) { //Read back auxiliary group B
|
||||
cmd[1] = 0x0E;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 3) { //Read auxiliary group C LTC6812 & LTC6813 only
|
||||
cmd[1] = 0x0D;
|
||||
cmd[0] = 0x00;
|
||||
}else if(reg == 4) { //Read auxiliary group D LTC6812 & LTC6813 only
|
||||
cmd[1] = 0x0F;
|
||||
cmd[0] = 0x00;
|
||||
}else{ //Read back auxiliary group A
|
||||
cmd[1] = 0x0C;
|
||||
cmd[0] = 0x00;
|
||||
}
|
||||
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
|
||||
driverSWLTC6804WakeIC(); //This will guarantee that the LTC6804 isoSPI port is awake, this command can be removed.
|
||||
driverSWLTC6804WriteRead(cmd,4,data,(REG_LEN*total_ic));
|
||||
}
|
||||
|
||||
__IO double VuV_dbl;
|
||||
|
||||
void driverSWLTC6804WriteConfigRegister(uint8_t totalNumberOfLTCs, uint32_t *balanceEnableMaskArray, bool useArray) {
|
||||
const uint8_t BYTES_IN_REG = 6;
|
||||
const uint8_t CMD_LEN = 4+(8*totalNumberOfLTCs);
|
||||
uint8_t *cmd;
|
||||
uint16_t cfg_pec;
|
||||
uint8_t cmd_index; //command counter
|
||||
uint8_t tx_cfg[totalNumberOfLTCs][6];
|
||||
|
||||
|
||||
//VuV_buf = driverSWLTC6804ConfigStruct.CellUnderVoltageLimit;
|
||||
//VuV_buf = 2.29999995 * 625;
|
||||
//VuV_buf = ggg * VuV_buf_del;
|
||||
//driverSWLTC6804ConfigStruct.CellUnderVoltageLimit
|
||||
|
||||
VuV_dbl = driverSWLTC6804ConfigStruct.CellUnderVoltageLimit/(16*0.0001);
|
||||
//uint16_t VuV = driverSWLTC6804ConfigStruct.CellUnderVoltageLimit/(16*0.0001);
|
||||
uint16_t VuV = VuV_dbl;
|
||||
//VuV = 2;
|
||||
uint16_t VoV = driverSWLTC6804ConfigStruct.CellOverVoltageLimit/(16*0.0001);
|
||||
//uint16_t VoV = 4.19 * 625;
|
||||
uint32_t activeBalanceMask=0;
|
||||
|
||||
for(int i = 0; i<totalNumberOfLTCs;i++) {
|
||||
if(useArray)
|
||||
activeBalanceMask = balanceEnableMaskArray[i];
|
||||
else
|
||||
activeBalanceMask = driverSWLTC6804ConfigStruct.DisChargeEnableMask;
|
||||
|
||||
tx_cfg[i][0] = (driverSWLTC6804ConfigStruct.GPIO5 << 7) | (driverSWLTC6804ConfigStruct.GPIO4 << 6) | (driverSWLTC6804ConfigStruct.GPIO3 << 5) | (driverSWLTC6804ConfigStruct.GPIO2 << 4) | (driverSWLTC6804ConfigStruct.GPIO1 << 3) | (driverSWLTC6804ConfigStruct.ReferenceON << 2) | (driverSWLTC6804ConfigStruct.ADCOption);
|
||||
tx_cfg[i][1] = (VuV & 0xFF) ;
|
||||
tx_cfg[i][2] = ((VoV & 0x0F) << 4) | (VuV >> 8) ;
|
||||
tx_cfg[i][3] = (VoV >> 4) ;
|
||||
tx_cfg[i][4] = (activeBalanceMask & 0xFF) ;
|
||||
tx_cfg[i][5] = ((driverSWLTC6804ConfigStruct.DischargeTimout & 0x0F) << 4) | (activeBalanceMask >> 8) ;
|
||||
}
|
||||
|
||||
cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
|
||||
cmd[0] = 0x00; // config register command
|
||||
cmd[1] = 0x01; // config register command
|
||||
cmd[2] = 0x3d; // PEC
|
||||
cmd[3] = 0x6e; // PEC
|
||||
cmd_index = 4;
|
||||
|
||||
for (uint8_t current_ic = totalNumberOfLTCs; current_ic > 0; current_ic--) { // executes for each LTC6804 in daisy chain, this loops starts with the last IC on the stack. The first configuration written is received by the last IC in the daisy chain
|
||||
for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) { // executes for each of the 6 bytes in the CFGR register current_byte is the byte counter
|
||||
cmd[cmd_index] = tx_cfg[current_ic-1][current_byte]; //adding the config data to the array to be sent
|
||||
cmd_index = cmd_index + 1;
|
||||
}
|
||||
cfg_pec = (uint16_t)driverSWLTC6804CalcPEC15(BYTES_IN_REG, &tx_cfg[current_ic-1][0]); // calculating the PEC for each ICs configuration register data
|
||||
cmd[cmd_index] = (uint8_t)(cfg_pec >> 8);
|
||||
cmd[cmd_index + 1] = (uint8_t)cfg_pec;
|
||||
cmd_index = cmd_index + 2;
|
||||
}
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,CMD_LEN);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
void driverSWLTC6804WriteConfigRegisterB(uint8_t totalNumberOfLTCs, uint32_t *balanceEnableMaskArray, bool useArray) {
|
||||
const uint8_t BYTES_IN_REG = 6;
|
||||
const uint8_t CMD_LEN = 4+(8*totalNumberOfLTCs);
|
||||
uint8_t *cmd;
|
||||
uint16_t cfg_pec;
|
||||
uint8_t cmd_index; //command counter
|
||||
uint8_t tx_cfg[totalNumberOfLTCs][6];
|
||||
uint32_t activeBalanceMask=0;
|
||||
uint16_t cmd_pec;
|
||||
|
||||
for(int i = 0; i<totalNumberOfLTCs;i++) {
|
||||
if(useArray)
|
||||
activeBalanceMask = balanceEnableMaskArray[i];
|
||||
else
|
||||
activeBalanceMask = driverSWLTC6804ConfigStruct.DisChargeEnableMask;
|
||||
|
||||
|
||||
tx_cfg[i][0] = ((activeBalanceMask >> 8 ) & 0x000000F0) | (driverSWLTC6804ConfigStruct.GPIO9 << 3) | (driverSWLTC6804ConfigStruct.GPIO8 << 2) | (driverSWLTC6804ConfigStruct.GPIO7 << 1) | (driverSWLTC6804ConfigStruct.GPIO6) ;
|
||||
tx_cfg[i][1] = ((activeBalanceMask >> 16 ) & 0x00000003) ;
|
||||
tx_cfg[i][2] = 0;
|
||||
tx_cfg[i][3] = 0;
|
||||
tx_cfg[i][4] = 0;
|
||||
tx_cfg[i][5] = 0;
|
||||
}
|
||||
|
||||
cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
|
||||
cmd[0] = 0x00; // config register B command
|
||||
cmd[1] = 0x24; // config register B command
|
||||
cmd_pec = driverSWLTC6804CalcPEC15(2, cmd);
|
||||
cmd[2] = (uint8_t)(cmd_pec >> 8);
|
||||
cmd[3] = (uint8_t)(cmd_pec);
|
||||
cmd_index = 4;
|
||||
|
||||
for (uint8_t current_ic = totalNumberOfLTCs; current_ic > 0; current_ic--) { // executes for each LTC6804 in daisy chain, this loops starts with the last IC on the stack. The first configuration written is received by the last IC in the daisy chain
|
||||
for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) { // executes for each of the 6 bytes in the CFGR register current_byte is the byte counter
|
||||
cmd[cmd_index] = tx_cfg[current_ic-1][current_byte]; //adding the config data to the array to be sent
|
||||
cmd_index = cmd_index + 1;
|
||||
}
|
||||
cfg_pec = (uint16_t)driverSWLTC6804CalcPEC15(BYTES_IN_REG, &tx_cfg[current_ic-1][0]); // calculating the PEC for each ICs configuration register data
|
||||
cmd[cmd_index] = (uint8_t)(cfg_pec >> 8);
|
||||
cmd[cmd_index + 1] = (uint8_t)cfg_pec;
|
||||
cmd_index = cmd_index + 2;
|
||||
}
|
||||
|
||||
driverSWLTC6804WakeIC();
|
||||
driverSWLTC6804Write(cmd,CMD_LEN);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
void driverSWLTC6804EnableBalanceResistors(uint32_t enableMask,uint8_t cellMonitorType) {
|
||||
driverSWLTC6804ConfigStruct.DisChargeEnableMask = enableMask;
|
||||
driverSWLTC6804WriteConfigRegister(driverSWLTC6804TotalNumberOfICs,0,false);
|
||||
if(cellMonitorType==CELL_MON_LTC6812_1 || cellMonitorType == CELL_MON_LTC6813_1){
|
||||
driverSWLTC6804WriteConfigRegisterB(driverSWLTC6804TotalNumberOfICs,0,false);
|
||||
}
|
||||
}
|
||||
|
||||
void driverSWLTC6804EnableBalanceResistorsArray(uint32_t *enableMask, uint8_t cellMonitorType) {
|
||||
driverSWLTC6804WriteConfigRegister(driverSWLTC6804TotalNumberOfICs,enableMask,true);
|
||||
if(cellMonitorType==CELL_MON_LTC6812_1 || cellMonitorType == CELL_MON_LTC6813_1){
|
||||
driverSWLTC6804WriteConfigRegisterB(driverSWLTC6804TotalNumberOfICs,enableMask,true);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t driverSWLTC6804CalcPEC15(uint8_t len, uint8_t *data) {
|
||||
uint16_t remainder,addr;
|
||||
|
||||
remainder = 16;//initialize the PEC
|
||||
for(uint8_t i = 0; i<len;i++) // loops for each byte in data array
|
||||
{
|
||||
addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
|
||||
remainder = (remainder<<8)^crc15Table[addr];
|
||||
}
|
||||
return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
|
||||
}
|
||||
|
||||
int8_t driverSWLTC6804ReadConfigRegister(uint8_t total_ic, uint8_t r_config[][8]) {
|
||||
const uint8_t BYTES_IN_REG = 8;
|
||||
|
||||
uint8_t cmd[4];
|
||||
uint8_t *rx_data;
|
||||
int8_t pec_error = 0;
|
||||
uint16_t data_pec;
|
||||
uint16_t received_pec;
|
||||
|
||||
rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
|
||||
|
||||
cmd[0] = 0x00;
|
||||
cmd[1] = 0x02;
|
||||
cmd[2] = 0x2b;
|
||||
cmd[3] = 0x0A;
|
||||
|
||||
driverSWLTC6804WriteRead(cmd, 4, rx_data, (BYTES_IN_REG*total_ic));
|
||||
|
||||
for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) { //executes for each LTC6804 in the daisy chain and packs the data into the r_config array as well as check the received Config data for any bit errors
|
||||
for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
|
||||
r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
|
||||
}
|
||||
received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
|
||||
data_pec = driverSWLTC6804CalcPEC15(6, &r_config[current_ic][0]);
|
||||
if(received_pec != data_pec) {
|
||||
pec_error = -1;
|
||||
}
|
||||
}
|
||||
free(rx_data);
|
||||
return(pec_error);
|
||||
}
|
||||
|
||||
// Coupling of drivers
|
||||
void driverSWLTC6804Write(uint8_t *writeBytes, uint8_t writeLength) {
|
||||
driverHWSPI1Write(writeBytes,writeLength,LTC6804_CS_GPIO_Port,LTC6804_CS_Pin);
|
||||
};
|
||||
|
||||
// Coupling of drivers
|
||||
void driverSWLTC6804WriteRead(uint8_t *writeBytes, uint8_t writeLength, uint8_t *readBytes, uint8_t readLength) {
|
||||
uint8_t buf[100];
|
||||
uint8_t buf_out[100];
|
||||
memset(buf_out,0x00,99);
|
||||
memcpy(buf_out, writeBytes, writeLength);
|
||||
memset(buf,0x00,99);
|
||||
driverHWSPI1WriteRead(writeBytes,writeLength,readBytes,readLength,LTC6804_CS_GPIO_Port,LTC6804_CS_Pin);
|
||||
// driverHWSPI1WriteRead(writeBytes,writeLength,buf,readLength,LTC6804_CS_GPIO_Port,LTC6804_CS_Pin);
|
||||
};
|
||||
|
||||
void driverSWLTC6804WakeIC(void){
|
||||
driverSWLTC6804DelayMS(1);
|
||||
HAL_GPIO_WritePin(LTC6804_CS_GPIO_Port,LTC6804_CS_Pin,GPIO_PIN_RESET);
|
||||
driverSWLTC6804DelayMS(1);
|
||||
HAL_GPIO_WritePin(LTC6804_CS_GPIO_Port,LTC6804_CS_Pin,GPIO_PIN_SET);
|
||||
driverSWLTC6804DelayMS(1);
|
||||
}
|
||||
|
||||
float driverSWLTC6804ConvertTemperatureExt(uint16_t inputValue,uint32_t ntcNominal,uint32_t ntcSeriesResistance,uint16_t ntcBetaFactor, float ntcNominalTemp) {
|
||||
static float scalar;
|
||||
static float steinhart;
|
||||
|
||||
scalar = 30000.0f / (float)inputValue - 1.0f;
|
||||
scalar = (float)ntcSeriesResistance / scalar;
|
||||
steinhart = scalar / (float)ntcNominal; // (R/Ro)
|
||||
steinhart = log(steinhart); // ln(R/Ro)
|
||||
steinhart /= (float)ntcBetaFactor; // 1/B * ln(R/Ro)
|
||||
steinhart += 1.0f / ((float)ntcNominalTemp + 273.15f); // + (1/To)
|
||||
steinhart = 1.0f / steinhart; // Invert
|
||||
steinhart -= 273.15f; // convert to degree
|
||||
|
||||
if(steinhart < -50.0f || (float)inputValue >= 30000.0f)
|
||||
steinhart = 0.0f;
|
||||
|
||||
return steinhart;
|
||||
}
|
||||
93
firmware/Core/Src/driverSWStorageManager.c
Normal file
93
firmware/Core/Src/driverSWStorageManager.c
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "driverSWStorageManager.h"
|
||||
|
||||
uint16_t *driverHWEEPROMVirtAddVarTab;
|
||||
|
||||
bool driverSWStorageManagerConfigEmpty = false;
|
||||
bool driverSWStorageManagerStateOfChargeEmpty = false;
|
||||
uint16_t driverSWStorageManagerDataSize = 0;
|
||||
uint16_t driverSWStorageManagerConfigStructSize = 0;
|
||||
uint16_t driverSWStorageManagerStateOfChargeStructSize = 0;
|
||||
|
||||
void driverSWStorageManagerInit(void) {
|
||||
driverSWStorageManagerDataSize = driverSWStorageManagerConfigStructSize + driverSWStorageManagerStateOfChargeStructSize;// Calculate the total desired space
|
||||
|
||||
// Generate EEPROM enviroment
|
||||
driverHWEEPROMVirtAddVarTab = malloc(driverSWStorageManagerDataSize*sizeof(uint16_t)); // Make room for the addres array
|
||||
HAL_FLASH_Unlock(); // Unlock FLASH to allow EEPROM lib to write
|
||||
|
||||
if(driverHWEEPROMInit(driverSWStorageManagerDataSize) != HAL_OK) // Init EEPROM and tell EEPROM manager the disered size
|
||||
while(true); // Something went wrong in the init
|
||||
|
||||
for(uint16_t addresPointer=0 ; addresPointer<driverSWStorageManagerDataSize ; addresPointer++)
|
||||
driverHWEEPROMVirtAddVarTab[addresPointer] = addresPointer; // Generate addres array
|
||||
|
||||
// Check EEPROM Contents
|
||||
uint16_t readVariable; // Define variable to write EEPROM contents to if any
|
||||
if(driverHWEEPROMReadVariable(driverHWEEPROMVirtAddVarTab[0], &readVariable) == 1) { // Try to read from first memory location
|
||||
driverSWStorageManagerConfigEmpty = true;
|
||||
driverSWStorageManagerStateOfChargeEmpty = true;
|
||||
}
|
||||
};
|
||||
|
||||
bool driverSWStorageManagerEraseData(void) {
|
||||
return (driverHWEEPROMEraseFlash() == HAL_OK);
|
||||
}
|
||||
|
||||
bool driverSWStorageManagerStoreStruct(void *configStruct, StorageLocationTypedef storageLocation) {
|
||||
uint8_t returnStatus = 0;
|
||||
uint16_t *dataPointer = (uint16_t*)configStruct; // Trick to convert struct to a 16 bit pointer.
|
||||
uint16_t dataOffset = driverSWStorageManagerGetOffsetFromLocation(storageLocation); // Get addres offset
|
||||
uint16_t dataSize = driverSWStorageManagerGetStructSize(storageLocation); // Get data size
|
||||
|
||||
for(uint16_t addresPointer=0 ; addresPointer<dataSize ; addresPointer++) { // Scan trough all adresses
|
||||
returnStatus |= driverHWEEPROMWriteVariable(driverHWEEPROMVirtAddVarTab[addresPointer+dataOffset],dataPointer[addresPointer]);// Store data in EEPROM
|
||||
}
|
||||
|
||||
return (returnStatus == HAL_OK);
|
||||
};
|
||||
|
||||
bool driverSWStorageManagerGetStruct(void *configStruct, StorageLocationTypedef storageLocation) {
|
||||
uint8_t returnStatus = 0;
|
||||
uint16_t *dataPointer = (uint16_t*)configStruct; // Trick to convert struct to a 16 bit pointer.
|
||||
uint16_t dataOffset = driverSWStorageManagerGetOffsetFromLocation(storageLocation); // Get addres offset
|
||||
uint16_t dataSize = driverSWStorageManagerGetStructSize(storageLocation); // Get data size
|
||||
|
||||
for(uint16_t addresPointer=0 ; addresPointer<dataSize ; addresPointer++) // Scan trough all adresses
|
||||
returnStatus |= driverHWEEPROMReadVariable(driverHWEEPROMVirtAddVarTab[addresPointer+dataOffset],&dataPointer[addresPointer]);// Get data from EEPROM
|
||||
|
||||
return (returnStatus == HAL_OK);
|
||||
};
|
||||
|
||||
uint16_t driverSWStorageManagerGetOffsetFromLocation(StorageLocationTypedef storageLocation) {
|
||||
int16_t locationPointer = -1;
|
||||
switch(storageLocation) {
|
||||
case STORAGE_CONFIG:
|
||||
locationPointer = 0; // StorageStruct starts at addres 0
|
||||
break;
|
||||
case STORAGE_STATEOFCHARGE:
|
||||
locationPointer = driverSWStorageManagerConfigStructSize; // StateOfCharge starts after configStruct
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return locationPointer;
|
||||
};
|
||||
|
||||
uint16_t driverSWStorageManagerGetStructSize(StorageLocationTypedef storageLocation) {
|
||||
int16_t sizeIndicator = -1;
|
||||
switch(storageLocation) {
|
||||
case STORAGE_CONFIG:
|
||||
sizeIndicator = driverSWStorageManagerConfigStructSize; // Config struct size
|
||||
break;
|
||||
case STORAGE_STATEOFCHARGE:
|
||||
sizeIndicator = driverSWStorageManagerStateOfChargeStructSize; // StateOfCharge struct size
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return sizeIndicator;
|
||||
};
|
||||
|
||||
|
||||
34
firmware/Core/Src/driverSWUART2.c
Normal file
34
firmware/Core/Src/driverSWUART2.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "driverSWUART2.h"
|
||||
|
||||
libRingBufferTypedef *driverSWUART2OutputBuffer;
|
||||
|
||||
void driverSWUART2Init(uint32_t baudRate) {
|
||||
driverSWUART2OutputBuffer = libRingBufferNew(sizeof(uint8_t),RINGBUFFERSIZE); // Make new output buffer
|
||||
|
||||
if(!driverSWUART2OutputBuffer) // Check if buffer pointer is generated
|
||||
while(true); // Out of memory error
|
||||
|
||||
driverHWUART2Init(baudRate); // Initialize serial port and pass function that should be called when a byte is received
|
||||
};
|
||||
|
||||
char driverSWUART2PutCharInOutputBuffer(char character, FILE *stream) {
|
||||
// TODO: If buffer is full, first send a character out, then place new char. This should however never happen
|
||||
if(!driverSWUART2OutputBuffer->isFull(driverSWUART2OutputBuffer)) {
|
||||
driverSWUART2OutputBuffer->add(driverSWUART2OutputBuffer,&character);
|
||||
}else{
|
||||
driverSWUART2Task();
|
||||
driverSWUART2OutputBuffer->add(driverSWUART2OutputBuffer,&character);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
bool driverSWUART2Task(void) {
|
||||
char outputChar;
|
||||
|
||||
if(!driverSWUART2OutputBuffer->isEmpty(driverSWUART2OutputBuffer)){ // Check if there is data in the ouput buffer
|
||||
driverSWUART2OutputBuffer->pull(driverSWUART2OutputBuffer,&outputChar); // Pull the data from ouput buffer
|
||||
driverHWUART2SendChar(outputChar); // And send it to the uart
|
||||
}
|
||||
|
||||
return !driverSWUART2OutputBuffer->isEmpty(driverSWUART2OutputBuffer);
|
||||
};
|
||||
66
firmware/Core/Src/fatfs.c
Normal file
66
firmware/Core/Src/fatfs.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file fatfs.c
|
||||
* @brief Code for fatfs applications
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "fatfs.h"
|
||||
|
||||
uint8_t retUSER; /* Return value for USER */
|
||||
char USERPath[4]; /* USER logical drive path */
|
||||
FATFS USERFatFS; /* File system object for USER logical drive */
|
||||
FIL USERFile; /* File object for USER */
|
||||
|
||||
/* USER CODE BEGIN Variables */
|
||||
|
||||
/* USER CODE END Variables */
|
||||
|
||||
void MX_FATFS_Init(void)
|
||||
{
|
||||
/*## FatFS: Link the USER driver ###########################*/
|
||||
retUSER = FATFS_LinkDriver(&USER_Driver, USERPath);
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
/* additional user code for init */
|
||||
/* USER CODE END Init */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets Time from RTC
|
||||
* @param None
|
||||
* @retval Time in DWORD
|
||||
*/
|
||||
DWORD get_fattime(void)
|
||||
{
|
||||
/* USER CODE BEGIN get_fattime */
|
||||
return 0;
|
||||
/* USER CODE END get_fattime */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Application */
|
||||
|
||||
void MX_FATFS_DeInit(void)
|
||||
{
|
||||
/*## FatFS: Link the USER driver ###########################*/
|
||||
retUSER = FATFS_UnLinkDriver(USERPath);
|
||||
|
||||
/* USER CODE BEGIN Init */
|
||||
/* additional user code for init */
|
||||
/* USER CODE END Init */
|
||||
}
|
||||
|
||||
/* USER CODE END Application */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
231
firmware/Core/Src/libBuffer.c
Normal file
231
firmware/Core/Src/libBuffer.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
Copyright 2016 Benjamin Vedder benjamin@vedder.se
|
||||
|
||||
This file is part of the VESC firmware.
|
||||
|
||||
The VESC firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "libBuffer.h"
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void libBufferAppend_int8(uint8_t* buffer, int8_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint8(uint8_t* buffer, uint8_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_int16(uint8_t* buffer, int16_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint16(uint8_t* buffer, uint16_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_int32(uint8_t* buffer, int32_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number >> 24;
|
||||
buffer[(*index)++] = number >> 16;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint32(uint8_t* buffer, uint32_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number >> 24;
|
||||
buffer[(*index)++] = number >> 16;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint64(uint8_t* buffer, uint64_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number >> 56;
|
||||
buffer[(*index)++] = number >> 48;
|
||||
buffer[(*index)++] = number >> 40;
|
||||
buffer[(*index)++] = number >> 32;
|
||||
buffer[(*index)++] = number >> 24;
|
||||
buffer[(*index)++] = number >> 16;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number;
|
||||
}
|
||||
|
||||
void libBufferAppend_int16_LSBFirst(uint8_t* buffer, int16_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint16_LSBFirst(uint8_t* buffer, uint16_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
}
|
||||
|
||||
void libBufferAppend_int32_LSBFirst(uint8_t* buffer, int32_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number >> 16;
|
||||
buffer[(*index)++] = number >> 24;
|
||||
}
|
||||
|
||||
void libBufferAppend_uint32_LSBFirst(uint8_t* buffer, uint32_t number, int32_t *index) {
|
||||
buffer[(*index)++] = number;
|
||||
buffer[(*index)++] = number >> 8;
|
||||
buffer[(*index)++] = number >> 16;
|
||||
buffer[(*index)++] = number >> 24;
|
||||
}
|
||||
|
||||
void libBufferAppend_float16(uint8_t* buffer, float number, float scale, int32_t *index) {
|
||||
libBufferAppend_int16(buffer, (int16_t)(number * scale), index);
|
||||
}
|
||||
|
||||
void libBufferAppend_float32(uint8_t* buffer, float number, float scale, int32_t *index) {
|
||||
libBufferAppend_int32(buffer, (int32_t)(number * scale), index);
|
||||
}
|
||||
|
||||
/*
|
||||
* See my question:
|
||||
* http://stackoverflow.com/questions/40416682/portable-way-to-serialize-float-as-32-bit-integer
|
||||
*
|
||||
* Regarding the float32_auto functions:
|
||||
*
|
||||
* Noticed that frexp and ldexp fit the format of the IEEE float representation, so
|
||||
* they should be quite fast. They are (more or less) equivalent with the following:
|
||||
*
|
||||
* float frexp_slow(float f, int *e) {
|
||||
* if (f == 0.0) {
|
||||
* *e = 0;
|
||||
* return 0.0;
|
||||
* }
|
||||
*
|
||||
* *e = ceilf(log2f(fabsf(f)));
|
||||
* float res = f / powf(2.0, (float)*e);
|
||||
*
|
||||
* if (res >= 1.0) {
|
||||
* res -= 0.5;
|
||||
* *e += 1;
|
||||
* }
|
||||
*
|
||||
* if (res <= -1.0) {
|
||||
* res += 0.5;
|
||||
* *e += 1;
|
||||
* }
|
||||
*
|
||||
* return res;
|
||||
* }
|
||||
*
|
||||
* float ldexp_slow(float f, int e) {
|
||||
* return f * powf(2.0, (float)e);
|
||||
* }
|
||||
*
|
||||
* 8388608.0 is 2^23, which scales the result to fit within 23 bits if sig_abs < 1.0.
|
||||
*
|
||||
* This should be a relatively fast and efficient way to serialize
|
||||
* floating point numbers in a fully defined manner.
|
||||
*/
|
||||
void libBufferAppend_float32_auto(uint8_t* buffer, float number, int32_t *index) {
|
||||
int e = 0;
|
||||
float sig = frexpf(number, &e);
|
||||
float sig_abs = fabsf(sig);
|
||||
uint32_t sig_i = 0;
|
||||
|
||||
if (sig_abs >= 0.5f) {
|
||||
sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
|
||||
e += 126;
|
||||
}
|
||||
|
||||
uint32_t res = ((e & 0xFF) << 23) | (sig_i & 0x7FFFFF);
|
||||
if (sig < 0) {
|
||||
//res |= 1 << 31;
|
||||
res |= 0x80000000;
|
||||
}
|
||||
|
||||
libBufferAppend_uint32(buffer, res, index);
|
||||
}
|
||||
|
||||
int8_t libBufferGet_int8(const uint8_t *buffer, int32_t *index) {
|
||||
int8_t res = ((uint8_t) buffer[*index]);
|
||||
*index += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t libBufferGet_uint8(const uint8_t *buffer, int32_t *index) {
|
||||
uint8_t res = ((uint8_t) buffer[*index]);
|
||||
*index += 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
int16_t libBufferGet_int16(const uint8_t *buffer, int32_t *index) {
|
||||
int16_t res = ((uint16_t) buffer[*index]) << 8 |
|
||||
((uint16_t) buffer[*index + 1]);
|
||||
*index += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint16_t libBufferGet_uint16(const uint8_t *buffer, int32_t *index) {
|
||||
uint16_t res = ((uint16_t) buffer[*index]) << 8 |
|
||||
((uint16_t) buffer[*index + 1]);
|
||||
*index += 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t libBufferGet_int32(const uint8_t *buffer, int32_t *index) {
|
||||
int32_t res = ((uint32_t) buffer[*index]) << 24 |
|
||||
((uint32_t) buffer[*index + 1]) << 16 |
|
||||
((uint32_t) buffer[*index + 2]) << 8 |
|
||||
((uint32_t) buffer[*index + 3]);
|
||||
*index += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t libBufferGet_uint32(const uint8_t *buffer, int32_t *index) {
|
||||
uint32_t res = ((uint32_t) buffer[*index]) << 24 |
|
||||
((uint32_t) buffer[*index + 1]) << 16 |
|
||||
((uint32_t) buffer[*index + 2]) << 8 |
|
||||
((uint32_t) buffer[*index + 3]);
|
||||
*index += 4;
|
||||
return res;
|
||||
}
|
||||
|
||||
float libBufferGet_float16(const uint8_t *buffer, float scale, int32_t *index) {
|
||||
return (float)libBufferGet_int16(buffer, index) / scale;
|
||||
}
|
||||
|
||||
float libBufferGet_float32(const uint8_t *buffer, float scale, int32_t *index) {
|
||||
return (float)libBufferGet_int32(buffer, index) / scale;
|
||||
}
|
||||
|
||||
float libBufferGet_float32_auto(const uint8_t *buffer, int32_t *index) {
|
||||
uint32_t res = libBufferGet_uint32(buffer, index);
|
||||
|
||||
int e = (res >> 23) & 0xFF;
|
||||
uint32_t sig_i = res & 0x7FFFFF;
|
||||
//bool neg = res & (1 << 31);
|
||||
bool neg = res & (0x80000000);
|
||||
|
||||
|
||||
float sig = 0.0;
|
||||
if (e != 0 || sig_i != 0) {
|
||||
sig = (float)sig_i / (8388608.0 * 2.0) + 0.5;
|
||||
e -= 126;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
sig = -sig;
|
||||
}
|
||||
|
||||
return ldexpf(sig, e);
|
||||
}
|
||||
60
firmware/Core/Src/libCRC.c
Normal file
60
firmware/Core/Src/libCRC.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2016 Benjamin Vedder benjamin@vedder.se
|
||||
|
||||
This file is part of the VESC firmware.
|
||||
|
||||
The VESC firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "libCRC.h"
|
||||
|
||||
// CRC Table
|
||||
const unsigned short libCRCLookupTable[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084,
|
||||
0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad,
|
||||
0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7,
|
||||
0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a,
|
||||
0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672,
|
||||
0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719,
|
||||
0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7,
|
||||
0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948,
|
||||
0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50,
|
||||
0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b,
|
||||
0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97,
|
||||
0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe,
|
||||
0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca,
|
||||
0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3,
|
||||
0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d,
|
||||
0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214,
|
||||
0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c,
|
||||
0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3,
|
||||
0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d,
|
||||
0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806,
|
||||
0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e,
|
||||
0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1,
|
||||
0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b,
|
||||
0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0,
|
||||
0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 };
|
||||
|
||||
unsigned short libCRCCalcCRC16(unsigned char *buf, unsigned int len) {
|
||||
unsigned int i;
|
||||
unsigned short cksum = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
cksum = libCRCLookupTable[(((cksum >> 8) ^ *buf++) & 0xFF)] ^ (cksum << 8);
|
||||
}
|
||||
return cksum;
|
||||
}
|
||||
170
firmware/Core/Src/libPacket.c
Normal file
170
firmware/Core/Src/libPacket.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Copyright 2016 Benjamin Vedder benjamin@vedder.se
|
||||
|
||||
This file is part of the VESC firmware.
|
||||
|
||||
The VESC firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "libPacket.h"
|
||||
#include "libCRC.h"
|
||||
|
||||
typedef struct {
|
||||
volatile unsigned char rx_state;
|
||||
volatile unsigned char rx_timeout;
|
||||
void(*send_func)(unsigned char *data, unsigned int len);
|
||||
void(*process_func)(unsigned char *data, unsigned int len);
|
||||
unsigned int payload_length;
|
||||
unsigned char rx_buffer[PACKET_MAX_PL_LEN];
|
||||
unsigned char tx_buffer[PACKET_MAX_PL_LEN + 6];
|
||||
unsigned int rx_data_ptr;
|
||||
unsigned char crc_low;
|
||||
unsigned char crc_high;
|
||||
} PACKET_STATE_t;
|
||||
|
||||
static PACKET_STATE_t libPacketHandlerStates[PACKET_HANDLERS];
|
||||
|
||||
void libPacketInit(void (*s_func)(unsigned char *data, unsigned int len),
|
||||
void (*p_func)(unsigned char *data, unsigned int len), int handler_num) {
|
||||
libPacketHandlerStates[handler_num].send_func = s_func;
|
||||
libPacketHandlerStates[handler_num].process_func = p_func;
|
||||
}
|
||||
|
||||
void libPacketSendPacket(unsigned char *data, unsigned int len, int handler_num) {
|
||||
if (len > PACKET_MAX_PL_LEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
int b_ind = 0;
|
||||
|
||||
if (len <= 256) {
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = 2;
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = len;
|
||||
} else {
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = 3;
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = len >> 8;
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = len & 0xFF;
|
||||
}
|
||||
|
||||
memcpy(libPacketHandlerStates[handler_num].tx_buffer + b_ind, data, len);
|
||||
b_ind += len;
|
||||
|
||||
unsigned short crc = libCRCCalcCRC16(data, len);
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = (uint8_t)(crc >> 8);
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = (uint8_t)(crc & 0xFF);
|
||||
libPacketHandlerStates[handler_num].tx_buffer[b_ind++] = 3;
|
||||
|
||||
if (libPacketHandlerStates[handler_num].send_func) {
|
||||
libPacketHandlerStates[handler_num].send_func(libPacketHandlerStates[handler_num].tx_buffer, b_ind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function every millisecond.
|
||||
*/
|
||||
void libPacketTimerFunc(void) {
|
||||
uint8_t a;
|
||||
for (int i = 0;i < PACKET_HANDLERS;i++) {
|
||||
if (libPacketHandlerStates[i].rx_timeout!=0) {
|
||||
libPacketHandlerStates[i].rx_timeout--;
|
||||
}
|
||||
else {
|
||||
// if(libPacketHandlerStates[i].rx_state==6){
|
||||
// libPacketHandlerStates[i].rx_state = 0;
|
||||
// }
|
||||
// libPacketHandlerStates[i].rx_timeout=0;
|
||||
// a=0;
|
||||
libPacketHandlerStates[i].rx_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void libPacketProcessByte(uint8_t rx_data, int handler_num) {
|
||||
switch (libPacketHandlerStates[handler_num].rx_state) {
|
||||
case 0:
|
||||
if (rx_data == 2) {
|
||||
// 1 byte PL len
|
||||
libPacketHandlerStates[handler_num].rx_state += 2;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
libPacketHandlerStates[handler_num].rx_data_ptr = 0;
|
||||
libPacketHandlerStates[handler_num].payload_length = 0;
|
||||
} else if (rx_data == 3) {
|
||||
// 2 byte PL len
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
libPacketHandlerStates[handler_num].rx_data_ptr = 0;
|
||||
libPacketHandlerStates[handler_num].payload_length = 0;
|
||||
} else {
|
||||
libPacketHandlerStates[handler_num].rx_state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
libPacketHandlerStates[handler_num].payload_length = (unsigned int)rx_data << 8;
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
libPacketHandlerStates[handler_num].payload_length |= (unsigned int)rx_data;
|
||||
if (libPacketHandlerStates[handler_num].payload_length > 0 &&
|
||||
libPacketHandlerStates[handler_num].payload_length <= PACKET_MAX_PL_LEN) {
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
} else {
|
||||
libPacketHandlerStates[handler_num].rx_state = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
libPacketHandlerStates[handler_num].rx_buffer[libPacketHandlerStates[handler_num].rx_data_ptr++] = rx_data;
|
||||
if (libPacketHandlerStates[handler_num].rx_data_ptr == libPacketHandlerStates[handler_num].payload_length) {
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
}
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
libPacketHandlerStates[handler_num].crc_high = rx_data;
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
libPacketHandlerStates[handler_num].crc_low = rx_data;
|
||||
libPacketHandlerStates[handler_num].rx_state++;
|
||||
libPacketHandlerStates[handler_num].rx_timeout = PACKET_RX_TIMEOUT;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
if (rx_data == 3) {
|
||||
if (libCRCCalcCRC16(libPacketHandlerStates[handler_num].rx_buffer, libPacketHandlerStates[handler_num].payload_length)
|
||||
== ((unsigned short)libPacketHandlerStates[handler_num].crc_high << 8
|
||||
| (unsigned short)libPacketHandlerStates[handler_num].crc_low)) {
|
||||
// Packet received!
|
||||
if (libPacketHandlerStates[handler_num].process_func) {
|
||||
libPacketHandlerStates[handler_num].process_func(libPacketHandlerStates[handler_num].rx_buffer,
|
||||
libPacketHandlerStates[handler_num].payload_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
libPacketHandlerStates[handler_num].rx_state = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
libPacketHandlerStates[handler_num].rx_state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
140
firmware/Core/Src/libRingbuffer.c
Normal file
140
firmware/Core/Src/libRingbuffer.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "libRingbuffer.h"
|
||||
|
||||
libRingBufferTypedef *libRingBufferNew(int size, int len) {
|
||||
libRingBufferTypedef *self = (libRingBufferTypedef *)malloc(sizeof(libRingBufferTypedef));
|
||||
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
memset(self, 0, sizeof(libRingBufferTypedef));
|
||||
|
||||
if (libRingBufferInit(self, size, len) < 0) {
|
||||
free(self);
|
||||
return NULL;
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
int libRingBufferInit(libRingBufferTypedef *self, int size, int len) {
|
||||
self->buf = (unsigned char *)malloc(size*len);
|
||||
if (!self->buf) return -1;
|
||||
memset(self->buf, 0, size*len);
|
||||
|
||||
self->size = size;
|
||||
self->len = len;
|
||||
self->start = 0;
|
||||
self->end = 0;
|
||||
self->elements = 0;
|
||||
|
||||
self->next_end_index = &libRingBufferNextEndIndex;
|
||||
self->incr_end_index = &libRingBufferIncrEnd;
|
||||
self->incr_start_index = &libRingBufferIncrStart;
|
||||
self->isFull = &libRingBufferIsFull;
|
||||
self->isEmpty = &libRingBufferIsEmpty;
|
||||
self->add = &libRingBufferAdd;
|
||||
self->numElements = &libRingBufferNumElements;
|
||||
self->peek = &libRingBufferPeek;
|
||||
self->pull = &libRingBufferPull;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int libRingBufferDelete(libRingBufferTypedef *self) {
|
||||
free(self->buf);
|
||||
free(self);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/////// PRIVATE METHODS //////////
|
||||
// get next empty index
|
||||
int libRingBufferNextEndIndex(libRingBufferTypedef *self) {
|
||||
//buffer is full
|
||||
if (self->isFull(self)) return -1;
|
||||
//if empty dont incriment
|
||||
return (self->end+(unsigned int)!self->isEmpty(self))%self->len;
|
||||
};
|
||||
|
||||
// incriment index of RingBuf struct, only call if safe to do so
|
||||
int libRingBufferIncrEnd(libRingBufferTypedef *self) {
|
||||
self->end = (self->end+1)%self->len;
|
||||
return self->end;
|
||||
};
|
||||
|
||||
|
||||
// incriment index of RingBuf struct, only call if safe to do so
|
||||
int libRingBufferIncrStart(libRingBufferTypedef *self) {
|
||||
self->start = (self->start+1)%self->len;
|
||||
return self->start;
|
||||
};
|
||||
|
||||
/////// PUBLIC METHODS //////////
|
||||
// Add an object struct to RingBuf
|
||||
int libRingBufferAdd(libRingBufferTypedef *self, const void *object) {
|
||||
int index;
|
||||
// Perform all atomic opertaions
|
||||
index = self->next_end_index(self);
|
||||
//if not full
|
||||
if (index >= 0) {
|
||||
memcpy(self->buf + index*self->size, object, self->size);
|
||||
if (!self->isEmpty(self)) self->incr_end_index(self);
|
||||
self->elements++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Return pointer to num element, return null on empty or num out of bounds
|
||||
void *libRingBufferPeek(libRingBufferTypedef *self, unsigned int num) {
|
||||
void *ret = NULL;
|
||||
|
||||
//empty or out of bounds
|
||||
if (self->isEmpty(self) || num > self->elements - 1)
|
||||
ret = NULL;
|
||||
else
|
||||
ret = &self->buf[((self->start + num)%self->len)*self->size];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Returns and removes first buffer element
|
||||
void *libRingBufferPull(libRingBufferTypedef *self, void *object) {
|
||||
void *ret = NULL;
|
||||
|
||||
if (self->isEmpty(self))
|
||||
ret = NULL;
|
||||
else{
|
||||
memcpy(object, self->buf+self->start*self->size, self->size);
|
||||
self->elements--;
|
||||
// don't incriment start if removing last element
|
||||
if (!self->isEmpty(self)) self->incr_start_index(self);
|
||||
ret = object;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Returns number of elemnts in buffer
|
||||
unsigned int libRingBufferNumElements(libRingBufferTypedef *self) {
|
||||
unsigned int elements;
|
||||
|
||||
elements = self->elements;
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
// Returns true if buffer is full
|
||||
bool libRingBufferIsFull(libRingBufferTypedef *self) {
|
||||
bool ret;
|
||||
|
||||
ret = self->elements == self->len;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Returns true if buffer is empty
|
||||
bool libRingBufferIsEmpty(libRingBufferTypedef *self) {
|
||||
bool ret;
|
||||
|
||||
ret = !self->elements;
|
||||
|
||||
return ret;
|
||||
}
|
||||
2994
firmware/Core/Src/main.c
Normal file
2994
firmware/Core/Src/main.c
Normal file
File diff suppressed because it is too large
Load Diff
571
firmware/Core/Src/modCommands.c
Normal file
571
firmware/Core/Src/modCommands.c
Normal file
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "modCommands.h"
|
||||
|
||||
// Private variables
|
||||
static uint8_t modCommandsSendBuffer[PACKET_MAX_PL_LEN];
|
||||
static void(*modCommandsSendFunction)(unsigned char *data, unsigned int len) = 0;
|
||||
bool jumpBootloaderTrue;
|
||||
modConfigGeneralConfigStructTypedef *modCommandsGeneralConfig;
|
||||
modConfigGeneralConfigStructTypedef *modCommandsToBeSendConfig;
|
||||
modConfigGeneralConfigStructTypedef modCommandsConfigStorage;
|
||||
modPowerElectronicsPackStateTypedef *modCommandsGeneralState;
|
||||
|
||||
void modCommandsInit(modPowerElectronicsPackStateTypedef *generalState,modConfigGeneralConfigStructTypedef *configPointer) {
|
||||
modCommandsGeneralConfig = configPointer;
|
||||
modCommandsGeneralState = generalState;
|
||||
jumpBootloaderTrue = false;
|
||||
}
|
||||
|
||||
void modCommandsSetSendFunction(void(*func)(unsigned char *data, unsigned int len)) {
|
||||
modCommandsSendFunction = func;
|
||||
}
|
||||
|
||||
void modCommandsSendPacket(unsigned char *data, unsigned int len) {
|
||||
if (modCommandsSendFunction) {
|
||||
modCommandsSendFunction(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void modCommandsProcessPacket(unsigned char *data, unsigned int len) {
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t RawSerial;
|
||||
uint32_t* RawSerialPtr;
|
||||
float RawSerialPtrfl;
|
||||
|
||||
|
||||
COMM_PACKET_ID packet_id;
|
||||
int32_t ind = 0;
|
||||
uint16_t flash_res;
|
||||
uint32_t new_app_offset;
|
||||
uint32_t delayTick;
|
||||
uint8_t cellPointer;
|
||||
uint8_t auxPointer;
|
||||
uint8_t expPointer;
|
||||
uint8_t i;
|
||||
|
||||
packet_id = (COMM_PACKET_ID) data[0];
|
||||
data++;
|
||||
len--;
|
||||
|
||||
|
||||
switch (packet_id) {
|
||||
case COMM_FW_VERSION:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_FW_VERSION;
|
||||
modCommandsSendBuffer[ind++] = FW_VERSION_MAJOR;
|
||||
modCommandsSendBuffer[ind++] = FW_VERSION_MINOR;
|
||||
strcpy((char*)(modCommandsSendBuffer + ind), HW_NAME);
|
||||
ind += strlen(HW_NAME) + 1;
|
||||
memcpy(modCommandsSendBuffer + ind, STM32_UUID, 12);
|
||||
ind += 12;
|
||||
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_JUMP_TO_BOOTLOADER:
|
||||
jumpBootloaderTrue = true;
|
||||
delayTick = HAL_GetTick();
|
||||
break;
|
||||
case COMM_ERASE_NEW_APP:
|
||||
ind = 0;
|
||||
flash_res = modFlashEraseNewAppData(libBufferGet_uint32(data, &ind));
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_ERASE_NEW_APP;
|
||||
modCommandsSendBuffer[ind++] = flash_res == HAL_OK ? true : false;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_WRITE_NEW_APP_DATA:
|
||||
ind = 0;
|
||||
new_app_offset = libBufferGet_uint32(data, &ind);
|
||||
flash_res = modFlashWriteNewAppData(new_app_offset, data + ind, len - ind);
|
||||
//flash_res = 0;
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_WRITE_NEW_APP_DATA;
|
||||
modCommandsSendBuffer[ind++] = flash_res == HAL_OK ? 1 : 0;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_GET_VALUES:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_GET_VALUES;
|
||||
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->packVoltage, 1e3, &ind);
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->packCurrent, 1e3, &ind);
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, (uint8_t)round(modCommandsGeneralState->SoC), &ind);
|
||||
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->cellVoltageHigh, 1e3, &ind);
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->cellVoltageAverage, 1e3, &ind);
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->cellVoltageLow, 1e3, &ind);
|
||||
libBufferAppend_float32(modCommandsSendBuffer, modCommandsGeneralState->cellVoltageMisMatch, 1e3, &ind);
|
||||
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->loCurrentLoadVoltage, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->loCurrentLoadCurrent, 1e1, &ind);
|
||||
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->chargerVoltage, 1e1, &ind);
|
||||
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBatteryHigh, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBatteryAverage, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBatteryLow, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBMSHigh, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBMSAverage, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->tempBMSLow, 1e1, &ind);
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->humidity, 1e1, &ind);
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, (uint8_t)modCommandsGeneralState->operationalState, &ind);
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, (uint8_t)modCommandsGeneralState->chargeBalanceActive, &ind); // Indicator for charging
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, (uint8_t)modCommandsGeneralState->faultState, &ind);
|
||||
|
||||
modCommandsSendBuffer[ind++] = modCommandsGeneralConfig->CANID;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
|
||||
break;
|
||||
case COMM_GET_BMS_CELLS:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_GET_BMS_CELLS;
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsGeneralConfig->noOfCellsSeries*modCommandsGeneralConfig->noOfParallelModules, &ind); // Cell count
|
||||
for(cellPointer = 0; cellPointer < modCommandsGeneralConfig->noOfCellsSeries*modCommandsGeneralConfig->noOfParallelModules; cellPointer++){
|
||||
if(modCommandsGeneralState->cellVoltagesIndividual[cellPointer].cellBleedActive)
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->cellVoltagesIndividual[cellPointer].cellVoltage*-1.0f, 1e3, &ind); // Individual cells
|
||||
else
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->cellVoltagesIndividual[cellPointer].cellVoltage, 1e3, &ind); // Individual cells
|
||||
}
|
||||
|
||||
modCommandsSendBuffer[ind++] = modCommandsGeneralConfig->CANID;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_GET_BMS_AUX:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_GET_BMS_AUX;
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsGeneralConfig->cellMonitorICCount*modCommandsGeneralConfig->noOfTempSensorPerModule, &ind); // Total aux count
|
||||
for(auxPointer = 0; auxPointer < modCommandsGeneralConfig->cellMonitorICCount*modCommandsGeneralConfig->noOfTempSensorPerModule; auxPointer++){
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->auxVoltagesIndividual[auxPointer].auxVoltage, 1e1, &ind); // Individual aux
|
||||
}
|
||||
|
||||
modCommandsSendBuffer[ind++] = modCommandsGeneralConfig->CANID;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_GET_BMS_EXP_TEMP:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_GET_BMS_EXP_TEMP;
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsGeneralConfig->noOfExpansionBoard*modCommandsGeneralConfig->noOfTempSensorPerExpansionBoard, &ind); // Total aux count
|
||||
for(expPointer = 0; expPointer < modCommandsGeneralConfig->noOfExpansionBoard*modCommandsGeneralConfig->noOfTempSensorPerExpansionBoard; expPointer++){
|
||||
libBufferAppend_float16(modCommandsSendBuffer, modCommandsGeneralState->expVoltagesIndividual[expPointer].expVoltage, 1e1, &ind); // Individual aux
|
||||
}
|
||||
|
||||
modCommandsSendBuffer[ind++] = modCommandsGeneralConfig->CANID;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_SET_MCCONF:
|
||||
ind = 0;
|
||||
modCommandsGeneralConfig->noOfCellsSeries = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->noOfCellsParallel = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->noOfParallelModules = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->batteryCapacity = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellHardUnderVoltage = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellHardOverVoltage = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellLCSoftUnderVoltage = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellSoftOverVoltage = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellBalanceDifferenceThreshold = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellBalanceStart = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellBalanceAllTime = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->cellThrottleUpperStart = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellThrottleLowerStart = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellThrottleUpperMargin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->cellThrottleLowerMargin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->packVoltageDataSource = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->packCurrentDataSource = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->buzzerSignalSource = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->buzzerSignalPersistant = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->shuntLCFactor = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->voltageLCFactor = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->voltageLCOffset = libBufferGet_int16(data,&ind); // 2
|
||||
modCommandsGeneralConfig->loadVoltageFactor = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->loadVoltageOffset = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->chargerVoltageFactor = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->chargerVoltageOffset = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->throttleChargeIncreaseRate = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->throttleDisChargeIncreaseRate = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->cellBalanceUpdateInterval = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->maxSimultaneousDischargingCells = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->timeoutDischargeRetry = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->hysteresisDischarge = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->timeoutChargeRetry = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->hysteresisCharge = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->timeoutChargeCompleted = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->timeoutChargingCompletedMinimalMismatch = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->maxMismatchThreshold = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->chargerEnabledThreshold = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->timeoutChargerDisconnected = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->minimalPrechargePercentage = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->timeoutLCPreCharge = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->maxAllowedCurrent = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattDischargingMax = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattDischargingMin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattChargingMax = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattChargingMin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattCoolingMax = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBattCoolingMin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBMSMax = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->allowedTempBMSMin = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->displayTimeoutBatteryDead = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->displayTimeoutBatteryError = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->displayTimeoutBatteryErrorPreCharge = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->displayTimeoutSplashScreen = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->displayStyle = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->maxUnderAndOverVoltageErrorCount = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->maxUnderAndOverTemperatureErrorCount = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->notUsedCurrentThreshold = libBufferGet_float32_auto(data,&ind); // 4
|
||||
modCommandsGeneralConfig->notUsedTimeout = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->stateOfChargeStoreInterval = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->stateOfChargeMethod = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->CANID = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->CANIDStyle = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->canBusSpeed = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->emitStatusOverCAN = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->emitStatusProtocol = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->tempEnableMaskBMS = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->tempEnableMaskBattery = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->tempEnableMaskExpansion = libBufferGet_uint32(data,&ind); // 4
|
||||
modCommandsGeneralConfig->noOfTempSensorPerModule = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->noOfExpansionBoard = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->noOfTempSensorPerExpansionBoard= libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->LCUseDischarge = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->LCUsePrecharge = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->allowChargingDuringDischarge = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->allowForceOn = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->pulseToggleButton = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->useCANSafetyInput = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->useCANDelayedPowerDown = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->NTCTopResistor[modConfigNTCGroupLTCExt] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTC25DegResistance[modConfigNTCGroupLTCExt] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTCBetaFactor[modConfigNTCGroupLTCExt] = libBufferGet_uint16(data,&ind);// 2
|
||||
modCommandsGeneralConfig->NTCTopResistor[modConfigNTCGroupMasterPCB] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTC25DegResistance[modConfigNTCGroupMasterPCB] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTCBetaFactor[modConfigNTCGroupMasterPCB] = libBufferGet_uint16(data,&ind);// 2
|
||||
modCommandsGeneralConfig->NTCTopResistor[modConfigNTCGroupExp] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTC25DegResistance[modConfigNTCGroupExp] = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->NTCBetaFactor[modConfigNTCGroupExp] = libBufferGet_uint16(data,&ind);// 2
|
||||
modCommandsGeneralConfig->cellMonitorType = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->cellMonitorICCount = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->externalEnableOperationalState = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->chargeEnableOperationalState = libBufferGet_uint8(data,&ind); // 1
|
||||
modCommandsGeneralConfig->powerDownDelay = libBufferGet_uint32(data,&ind);// 4
|
||||
modCommandsGeneralConfig->humidityICType = libBufferGet_uint8(data,&ind); // 1
|
||||
|
||||
modCommandsGeneralConfig->chargeBatteryOutputChecked = libBufferGet_uint8(data, &ind);
|
||||
modCommandsGeneralConfig->brushOrShuntOutputChecked = libBufferGet_uint8(data, &ind);
|
||||
modCommandsGeneralConfig->brushOrShuntMode = libBufferGet_uint8(data, &ind);
|
||||
modCommandsGeneralConfig->brushUsageSocThreshold = libBufferGet_uint16(data, &ind);
|
||||
modCommandsGeneralConfig->shuntChargingContactorDelay = libBufferGet_uint16(data, &ind);
|
||||
modCommandsGeneralConfig->coolingOutputChecked = libBufferGet_uint8(data, &ind);
|
||||
modCommandsGeneralConfig->coolingStartThreshold = libBufferGet_int16(data, &ind);
|
||||
modCommandsGeneralConfig->coolingStopThreshold = libBufferGet_int16(data, &ind);
|
||||
modCommandsGeneralConfig->heatingOutputChecked = libBufferGet_uint8(data, &ind);
|
||||
modCommandsGeneralConfig->heatingStartThreshold = libBufferGet_int16(data, &ind);
|
||||
modCommandsGeneralConfig->heatingStopThreshold = libBufferGet_int16(data, &ind);
|
||||
|
||||
modCommandsGeneralConfig->floatCurrentK1 = libBufferGet_float32_auto(data,&ind);
|
||||
modCommandsGeneralConfig->floatCurrentK2 = libBufferGet_float32_auto(data,&ind);
|
||||
|
||||
// RawSerialPtr = modCommandsGeneralConfig->displayTimeoutBatteryDead;
|
||||
// RawSerial = *RawSerialPtr;
|
||||
// RawSerial = RawSerial<<32;
|
||||
// RawSerialPtr = modCommandsGeneralConfig->displayTimeoutBatteryError;
|
||||
// RawSerial+=*RawSerialPtr;
|
||||
|
||||
RawSerialPtrfl = modCommandsGeneralConfig->notUsedCurrentThreshold;
|
||||
RawSerial = ceil(RawSerialPtrfl);
|
||||
modCommandsGeneralConfig->serialNumber = RawSerial;
|
||||
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = packet_id;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
|
||||
modconfigHardwareLimitsApply(modCommandsGeneralConfig);
|
||||
|
||||
break;
|
||||
case COMM_GET_MCCONF:
|
||||
case COMM_GET_MCCONF_DEFAULT:
|
||||
if(packet_id == COMM_GET_MCCONF_DEFAULT){
|
||||
modConfigLoadDefaultConfig(&modCommandsConfigStorage);
|
||||
modCommandsToBeSendConfig = &modCommandsConfigStorage;
|
||||
}else{
|
||||
modCommandsToBeSendConfig = modCommandsGeneralConfig;
|
||||
}
|
||||
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = packet_id;
|
||||
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfCellsSeries ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfCellsParallel ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfParallelModules ,&ind); // 1
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->batteryCapacity ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellHardUnderVoltage ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellHardOverVoltage ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellLCSoftUnderVoltage ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellSoftOverVoltage ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellBalanceDifferenceThreshold ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellBalanceStart ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->cellBalanceAllTime ,&ind); // 1
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellThrottleUpperStart ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellThrottleLowerStart ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellThrottleUpperMargin ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->cellThrottleLowerMargin ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->packVoltageDataSource ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->packCurrentDataSource ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->buzzerSignalSource ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->buzzerSignalPersistant ,&ind); // 1
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->shuntLCFactor ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->voltageLCFactor ,&ind); // 4
|
||||
libBufferAppend_int16( modCommandsSendBuffer,modCommandsToBeSendConfig->voltageLCOffset ,&ind); // 2
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->loadVoltageFactor ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->loadVoltageOffset ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->chargerVoltageFactor ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->chargerVoltageOffset ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->throttleChargeIncreaseRate ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->throttleDisChargeIncreaseRate ,&ind); // 1
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->cellBalanceUpdateInterval ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->maxSimultaneousDischargingCells ,&ind); // 1
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutDischargeRetry ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->hysteresisDischarge ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutChargeRetry ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->hysteresisCharge ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutChargeCompleted ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutChargingCompletedMinimalMismatch,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->maxMismatchThreshold ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->chargerEnabledThreshold ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutChargerDisconnected ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->minimalPrechargePercentage ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->timeoutLCPreCharge ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->maxAllowedCurrent ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattDischargingMax ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattDischargingMin ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattChargingMax ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattChargingMin ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattCoolingMax ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBattCoolingMin ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBMSMax ,&ind); // 4
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->allowedTempBMSMin ,&ind); // 4
|
||||
|
||||
//libBufferAppend_uint64( modCommandsSendBuffer,modCommandsToBeSendConfig->serialNumber , &ind); // 8
|
||||
RawSerial=modCommandsToBeSendConfig->serialNumber;
|
||||
// modCommandsToBeSendConfig->displayTimeoutBatteryDead = RawSerial;
|
||||
// modCommandsToBeSendConfig->displayTimeoutBatteryError = RawSerial<<32;
|
||||
|
||||
modCommandsToBeSendConfig->notUsedCurrentThreshold = (float) RawSerial;
|
||||
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->displayTimeoutBatteryDead ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->displayTimeoutBatteryError ,&ind); // 4
|
||||
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->displayTimeoutBatteryErrorPreCharge,&ind);//4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->displayTimeoutSplashScreen ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->displayStyle ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->maxUnderAndOverVoltageErrorCount,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->maxUnderAndOverTemperatureErrorCount,&ind); // 1
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->notUsedCurrentThreshold ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->notUsedTimeout ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->stateOfChargeStoreInterval ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->stateOfChargeMethod ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->CANID ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->CANIDStyle ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->canBusSpeed ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->emitStatusOverCAN ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->emitStatusProtocol ,&ind); // 1
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->tempEnableMaskBMS ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->tempEnableMaskBattery ,&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->tempEnableMaskExpansion ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfTempSensorPerModule ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfExpansionBoard ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->noOfTempSensorPerExpansionBoard ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->LCUseDischarge ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->LCUsePrecharge ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->allowChargingDuringDischarge ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->allowForceOn ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->pulseToggleButton ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->useCANSafetyInput ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->useCANDelayedPowerDown ,&ind); // 1
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCTopResistor[modConfigNTCGroupLTCExt],&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTC25DegResistance[modConfigNTCGroupLTCExt],&ind); // 4
|
||||
libBufferAppend_uint16( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCBetaFactor[modConfigNTCGroupLTCExt],&ind); // 2
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCTopResistor[modConfigNTCGroupMasterPCB],&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTC25DegResistance[modConfigNTCGroupMasterPCB],&ind); // 4
|
||||
libBufferAppend_uint16( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCBetaFactor[modConfigNTCGroupMasterPCB],&ind); // 2
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCTopResistor[modConfigNTCGroupExp],&ind); // 4
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->NTC25DegResistance[modConfigNTCGroupExp],&ind); // 4
|
||||
libBufferAppend_uint16( modCommandsSendBuffer,modCommandsToBeSendConfig->NTCBetaFactor[modConfigNTCGroupExp],&ind); // 2
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->cellMonitorType ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->cellMonitorICCount ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->externalEnableOperationalState ,&ind); // 1
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->chargeEnableOperationalState ,&ind); // 1
|
||||
libBufferAppend_uint32( modCommandsSendBuffer,modCommandsToBeSendConfig->powerDownDelay ,&ind); // 4
|
||||
libBufferAppend_uint8( modCommandsSendBuffer,modCommandsToBeSendConfig->humidityICType ,&ind); // 1
|
||||
//libBufferAppend_uint64( modCommandsSendBuffer,modCommandsToBeSendConfig->serialNumber , &ind); // 8
|
||||
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsToBeSendConfig->chargeBatteryOutputChecked, &ind);
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsToBeSendConfig->brushOrShuntOutputChecked, &ind);
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsToBeSendConfig->brushOrShuntMode, &ind);
|
||||
libBufferAppend_uint16(modCommandsSendBuffer, modCommandsToBeSendConfig->brushUsageSocThreshold, &ind);
|
||||
libBufferAppend_uint16(modCommandsSendBuffer, modCommandsToBeSendConfig->shuntChargingContactorDelay, &ind);
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsToBeSendConfig->coolingOutputChecked, &ind);
|
||||
libBufferAppend_int16(modCommandsSendBuffer, modCommandsToBeSendConfig->coolingStartThreshold, &ind);
|
||||
libBufferAppend_int16(modCommandsSendBuffer, modCommandsToBeSendConfig->coolingStopThreshold, &ind);
|
||||
libBufferAppend_uint8(modCommandsSendBuffer, modCommandsToBeSendConfig->heatingOutputChecked, &ind);
|
||||
libBufferAppend_int16(modCommandsSendBuffer, modCommandsToBeSendConfig->heatingStartThreshold, &ind);
|
||||
libBufferAppend_int16(modCommandsSendBuffer, modCommandsToBeSendConfig->heatingStopThreshold, &ind);
|
||||
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->floatCurrentK1 ,&ind);
|
||||
libBufferAppend_float32_auto( modCommandsSendBuffer,modCommandsToBeSendConfig->floatCurrentK2 ,&ind);
|
||||
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
|
||||
case COMM_GET_GSM_DATA:
|
||||
case COMM_GET_GSM_DEFAULT_DATA:
|
||||
if(packet_id == COMM_GET_GSM_DEFAULT_DATA){
|
||||
modConfigLoadDefaultConfig(&modCommandsConfigStorage);
|
||||
modCommandsToBeSendConfig = &modCommandsConfigStorage;
|
||||
}else{
|
||||
modCommandsToBeSendConfig = modCommandsGeneralConfig;
|
||||
}
|
||||
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = packet_id;
|
||||
|
||||
i=0;
|
||||
while (i<250){
|
||||
libBufferAppend_uint8(modCommandsSendBuffer,modCommandsToBeSendConfig->Domain_URL[i],&ind);
|
||||
i++;
|
||||
}
|
||||
i=0;
|
||||
while (i<250){
|
||||
libBufferAppend_uint8(modCommandsSendBuffer,modCommandsToBeSendConfig->Domain_URL_Event[i],&ind);
|
||||
i++;
|
||||
}
|
||||
i=0;
|
||||
while (i<50){
|
||||
libBufferAppend_uint8(modCommandsSendBuffer,modCommandsToBeSendConfig->GSM_APN[i],&ind);
|
||||
i++;
|
||||
}
|
||||
i=0;
|
||||
while (i<50){
|
||||
libBufferAppend_uint8(modCommandsSendBuffer,modCommandsToBeSendConfig->GSM_USER[i],&ind);
|
||||
i++;
|
||||
}
|
||||
i=0;
|
||||
while (i<50){
|
||||
libBufferAppend_uint8(modCommandsSendBuffer,modCommandsToBeSendConfig->GSM_PWD[i],&ind);
|
||||
i++;
|
||||
}
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
|
||||
break;
|
||||
case COMM_SET_GSM_DATA:
|
||||
ind = 0;
|
||||
for (i=0;i<250;i++){
|
||||
modCommandsGeneralConfig->Domain_URL[i] = libBufferGet_uint8(data,&ind); // 250
|
||||
}
|
||||
for (i=0;i<250;i++){
|
||||
modCommandsGeneralConfig->Domain_URL_Event[i] = libBufferGet_uint8(data,&ind); // 250
|
||||
}
|
||||
for (i=0;i<50;i++){
|
||||
modCommandsGeneralConfig->GSM_APN[i] = libBufferGet_uint8(data,&ind); // 50
|
||||
}
|
||||
for (i=0;i<50;i++){
|
||||
modCommandsGeneralConfig->GSM_USER[i] = libBufferGet_uint8(data,&ind); // 50
|
||||
}
|
||||
for (i=0;i<50;i++){
|
||||
modCommandsGeneralConfig->GSM_PWD[i] = libBufferGet_uint8(data,&ind); // 50
|
||||
}
|
||||
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = packet_id;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
UpdateGSMParamsFromConfig();
|
||||
//SetParametersFromConfig
|
||||
|
||||
break;
|
||||
case COMM_TERMINAL_CMD:
|
||||
data[len] = '\0';
|
||||
modTerminalProcessString((char*)data);
|
||||
break;
|
||||
case COMM_REBOOT:
|
||||
modCommandsJumpToMainApplication();
|
||||
break;
|
||||
case COMM_ALIVE:
|
||||
break;
|
||||
case COMM_FORWARD_CAN:
|
||||
//ni modCANSendBuffer(data[0], data + 1, len - 1, false);
|
||||
break;
|
||||
case COMM_STORE_BMS_CONF:
|
||||
modConfigStoreConfig();
|
||||
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = packet_id;
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
break;
|
||||
case COMM_GET_FAULT_STATE:
|
||||
ind = 0;
|
||||
modCommandsSendBuffer[ind++] = COMM_GET_FAULT_STATE;
|
||||
libBufferAppend_uint16(modCommandsSendBuffer, (uint16_t)modCommandsGeneralState->faultState, &ind);
|
||||
modCommandsSendPacket(modCommandsSendBuffer, ind);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(modDelayTick1ms(&delayTick,1000) && jumpBootloaderTrue) jumpToBootLoader();
|
||||
}
|
||||
|
||||
void modCommandsPrintf(const char* format, ...) {
|
||||
va_list arg;
|
||||
va_start (arg, format);
|
||||
int len;
|
||||
static char print_buffer[255];
|
||||
|
||||
print_buffer[0] = COMM_PRINT;
|
||||
len = vsnprintf(print_buffer+1, 254, format, arg);
|
||||
va_end (arg);
|
||||
|
||||
if(len > 0) {
|
||||
modCommandsSendPacket((unsigned char*)print_buffer, (len<254)? len+1: 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void modCommandsJumpToMainApplication(void) {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
//void BufferCharStringSend(char *modCommandsSource, uint8_t NumberOfBytes){
|
||||
// char SourceBuf[NumberOfBytes];
|
||||
//
|
||||
// *SourceBuf = modCommandsSource;
|
||||
//
|
||||
// while (Number0fBytes>0){
|
||||
// libBufferAppend_uint8(modCommandsSendBuffer,SourceBuf[Number0fBytes],&ind);
|
||||
// }
|
||||
//}
|
||||
576
firmware/Core/Src/modConfig.c
Normal file
576
firmware/Core/Src/modConfig.c
Normal file
@@ -0,0 +1,576 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "modConfig.h"
|
||||
|
||||
modConfigGeneralConfigStructTypedef modConfigGeneralConfig;
|
||||
|
||||
modConfigGeneralConfigStructTypedef* modConfigInit(void) {
|
||||
driverSWStorageManagerConfigStructSize = (sizeof(modConfigGeneralConfigStructTypedef)/sizeof(uint16_t)); // Calculate the space needed for the config struct in EEPROM
|
||||
return &modConfigGeneralConfig;
|
||||
};
|
||||
|
||||
bool modConfigStoreAndLoadDefaultConfig(void) {
|
||||
bool returnVal = false;
|
||||
if(driverSWStorageManagerConfigEmpty) {
|
||||
returnVal = modConfigStoreDefaultConfig();
|
||||
}
|
||||
|
||||
modConfigLoadConfig();
|
||||
return returnVal;
|
||||
};
|
||||
|
||||
bool modConfigStoreConfig(void) {
|
||||
return driverSWStorageManagerStoreStruct(&modConfigGeneralConfig,STORAGE_CONFIG);
|
||||
// TODO_EEPROM
|
||||
};
|
||||
|
||||
bool modConfigLoadConfig(void) {
|
||||
return driverSWStorageManagerGetStruct(&modConfigGeneralConfig,STORAGE_CONFIG);
|
||||
};
|
||||
|
||||
bool modConfigStoreDefaultConfig(void) {
|
||||
// VALUES WILL ONLY AUTIMATICALLY UPDATE AFTER FLASH ERASE!
|
||||
modConfigGeneralConfigStructTypedef defaultConfig;
|
||||
modConfigLoadDefaultConfig(&defaultConfig);
|
||||
|
||||
driverSWStorageManagerConfigEmpty = false;
|
||||
return driverSWStorageManagerStoreStruct(&defaultConfig,STORAGE_CONFIG);
|
||||
}
|
||||
|
||||
void modconfigHardwareLimitsApply(modConfigGeneralConfigStructTypedef *configLocation) {
|
||||
configLocation->maxSimultaneousDischargingCells = MIN(configLocation->maxSimultaneousDischargingCells,HW_LIM_CELL_BALANCE_MAX_SIMULTANEOUS_DISCHARGE);
|
||||
configLocation->cellMonitorICCount = MIN(configLocation->cellMonitorICCount ,HW_LIM_CELL_MONITOR_IC_COUNT);
|
||||
configLocation->lastICMask = 0;
|
||||
|
||||
if(configLocation->notUsedTimeout)
|
||||
configLocation->notUsedTimeout = MAX(configLocation->notUsedTimeout ,HW_LIM_MIN_NOT_USED_DELAY);
|
||||
|
||||
// Check for feasable parameters
|
||||
if((configLocation->cellMonitorICCount % configLocation->noOfParallelModules) == 0){ // Check if feasable configuration
|
||||
if(configLocation->noOfCellsSeries % (configLocation->cellMonitorICCount / configLocation->noOfParallelModules) == 0){
|
||||
configLocation->noOfCellsPerModule = configLocation->noOfCellsSeries/(configLocation->cellMonitorICCount / configLocation->noOfParallelModules);
|
||||
configLocation->lastICNoOfCells = configLocation->noOfCellsPerModule;
|
||||
|
||||
for(int bitPointer = 0; bitPointer < configLocation->lastICNoOfCells ; bitPointer++){
|
||||
configLocation->lastICMask = (configLocation->lastICMask << 1)| 1 ; // This contains the last cells mask used for enabling UV & OV flag in the last serie IC
|
||||
}
|
||||
}else{ //Odd number of cells in series
|
||||
configLocation->noOfCellsPerModule = (configLocation->noOfCellsSeries / (configLocation->cellMonitorICCount / configLocation->noOfParallelModules))+1;
|
||||
|
||||
configLocation->lastICNoOfCells = configLocation->noOfCellsSeries % configLocation->noOfCellsPerModule; // This contains the last cells number monitored by the last serie IC
|
||||
|
||||
for(int bitPointer = 0; bitPointer < configLocation->lastICNoOfCells ; bitPointer++){
|
||||
configLocation->lastICMask = (configLocation->lastICMask << 1)| 1 ; // This contains the last cells mask used for enabling UV & OV flag in the last serie IC
|
||||
}
|
||||
};
|
||||
}else{
|
||||
configLocation->noOfCellsSeries = 8;
|
||||
configLocation->cellMonitorICCount = 1;
|
||||
configLocation->noOfCellsPerModule = 1;
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
};
|
||||
|
||||
if (configLocation->noOfCellsPerModule <= 4){
|
||||
configLocation->noOfCellsSeries = 8;
|
||||
configLocation->cellMonitorICCount = 1;
|
||||
configLocation->noOfCellsPerModule = 1;
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void modConfigLoadDefaultConfig(modConfigGeneralConfigStructTypedef *configLocation) {
|
||||
char* ptr;
|
||||
|
||||
#if ENNOID_LV
|
||||
//configLocation->serialNumber = 20000054;
|
||||
configLocation->noOfCellsSeries = 8; // Total number of cells in series in the battery pack
|
||||
configLocation->noOfCellsParallel = 2; // Number of cells in parallel
|
||||
configLocation->noOfParallelModules = 1; // Number of parallel modules
|
||||
configLocation->batteryCapacity = 144.00f; // XXAh battery
|
||||
configLocation->cellHardUnderVoltage = 2.50f; // Worst case X.XXV as lowest cell voltage
|
||||
configLocation->cellHardOverVoltage = 3.65f; // Worst case X.XXV as highest cell voltage
|
||||
configLocation->cellLCSoftUnderVoltage = 2.70f; // Lowest cell voltage X.XXV.
|
||||
configLocation->cellSoftOverVoltage = 4.10f; // Normal highest cell voltage X.XXV.
|
||||
configLocation->cellBalanceDifferenceThreshold = 0.005f; // Start balancing @ XmV difference, stop if below.
|
||||
configLocation->cellBalanceStart = 3.4f; // Start balancing above X.XXV.
|
||||
configLocation->cellBalanceAllTime = false; // Enable balancing under all opstate
|
||||
configLocation->cellThrottleUpperStart = 0.03f; // Upper range of cell voltage for charge throttling.
|
||||
configLocation->cellThrottleLowerStart = 0.20f; // Lower range of cell voltage for discharge throttling.
|
||||
configLocation->cellThrottleUpperMargin = 0.01f; // Margin of throttle from upper soft limits.
|
||||
configLocation->cellThrottleLowerMargin = 0.50f; // Margin of throttle from lower soft limits.
|
||||
configLocation->packVoltageDataSource = sourcePackVoltageSumOfIndividualCellVoltages; // Packvoltage source.
|
||||
configLocation->packCurrentDataSource = sourcePackCurrentLowCurrentShunt; // The pack current is the same as the current through the low current shunt
|
||||
configLocation->buzzerSignalSource = buzzerSourceOn; // Stores what source shoud be taken to trigger
|
||||
configLocation->buzzerSignalPersistant = false; // Stores whether the buzzer should stay on after triggering
|
||||
configLocation->shuntLCFactor = -0.051f; // Shunt factor low current
|
||||
configLocation->voltageLCFactor = 3.50f; // Pack voltage factor
|
||||
configLocation->voltageLCOffset = 0; // Pack voltage offset
|
||||
configLocation->loadVoltageFactor = 49.2f; // Load voltage factor
|
||||
configLocation->loadVoltageOffset = 0.0f; // Load voltage offset
|
||||
configLocation->chargerVoltageFactor = 49.2f; // Charger voltage factor
|
||||
configLocation->chargerVoltageOffset = 0.0f; // Charger voltage offset
|
||||
configLocation->throttleChargeIncreaseRate = 1; // Percentage charge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->throttleDisChargeIncreaseRate = 2; // Percentage discharge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->cellBalanceUpdateInterval = 4*1000; // Keep calculated resistors enabled for this amount of time in miliseconds.
|
||||
configLocation->maxSimultaneousDischargingCells = 5; // Allow a maximum of X cells simultinous discharging trough bleeding resistors.
|
||||
configLocation->timeoutDischargeRetry = 10*1000; // Wait for X seconds before retrying to enable load.
|
||||
configLocation->hysteresisDischarge = 0.02f; // Lowest cell should rise XXmV before output is re enabled.
|
||||
configLocation->timeoutChargeRetry = 100*1000; // Wait for XX seconds before retrying to enable charger.
|
||||
configLocation->hysteresisCharge = 0.01f; // Highest cell should lower XXmV before charger is re enabled.
|
||||
configLocation->timeoutChargeCompleted = 30*60*1000; // Wait for XX minutes before setting charge state to charged.
|
||||
configLocation->timeoutChargingCompletedMinimalMismatch = 6*1000; // If cell mismatch is under threshold and (charging is not allowed) wait this delay time to set "charged" state.
|
||||
configLocation->maxMismatchThreshold = 0.010f; // If mismatch is under this threshold for timeoutChargingCompletedMinimalMismatch determin fully charged.
|
||||
configLocation->chargerEnabledThreshold = 0.5f; // If charge current > X.XA stay in charging mode and dont power off.
|
||||
configLocation->timeoutChargerDisconnected = 2000; // Wait for X seconds to respond to charger disconnect.
|
||||
configLocation->minimalPrechargePercentage = 0.90f; // output should be at a minimal of 80% of input voltage.
|
||||
configLocation->timeoutLCPreCharge = 1.5*1000; // Precharge error timeout, allow 1.5 seconds pre-charge time before declaring load error.
|
||||
configLocation->maxAllowedCurrent = 1000.0f; // Allow max XXXA trough BMS.
|
||||
configLocation->allowedTempBattDischargingMax = 75.0f; // Max battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattDischargingMin = 0.0f; // Min battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattChargingMax = 50.0f; // Max battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattChargingMin = 0.0f; // Min battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattCoolingMax = 5.0f; // Max battery temperature where cooling is activated
|
||||
configLocation->allowedTempBattCoolingMin = 50.0f; // Min battery temperature where heating is activated
|
||||
configLocation->allowedTempBMSMax = 80.0f; // Max BMS operational temperature
|
||||
configLocation->allowedTempBMSMin = 0.0f; // Min BMS operational temperature
|
||||
configLocation->displayTimeoutBatteryDead = 5000; // Show battery dead symbol X seconds before going to powerdown in cell voltage error state.
|
||||
configLocation->displayTimeoutBatteryError = 5000; // Show error symbol for X seconds before going to powerdown in general error state.
|
||||
configLocation->displayTimeoutBatteryErrorPreCharge = 10000; // Show pre charge error for XX seconds.
|
||||
configLocation->displayTimeoutSplashScreen = 3000; // Display / INIT splash screen time.
|
||||
configLocation->displayStyle = advanced; // Display style used for showing the SSD1306 data
|
||||
configLocation->maxUnderAndOverVoltageErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->maxUnderAndOverTemperatureErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->notUsedCurrentThreshold = 1.0f; // If abs(packcurrent) < X.XA consider pack as not used.
|
||||
configLocation->notUsedTimeout = 20*60*1000; // If pack is not used for longer than XX minutes disable bms.
|
||||
configLocation->stateOfChargeStoreInterval = 60*1000; // Interval in ms to store state of charge information.
|
||||
configLocation->stateOfChargeMethod = socCoulomb; // Use coulomb counting for SoC calculation
|
||||
configLocation->CANID = 10; // CAN ID for CAN communication.
|
||||
configLocation->CANIDStyle = CANIDStyleVESC; // CAN ID default Style.
|
||||
configLocation->emitStatusOverCAN = false; // Send status over can.
|
||||
configLocation->canBusSpeed = canSpeedBaud500k; // 500k CAN baud
|
||||
configLocation->emitStatusProtocol = canEmitProtocolDieBieEngineering; // Can emit protocol set to MG style for backwards compatibility
|
||||
configLocation->tempEnableMaskBMS = 0x0001; // Bitwise select what sensor to enable for the BMS (internal sensors).
|
||||
configLocation->tempEnableMaskBattery = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->tempEnableMaskExpansion = 0xFFFF; // Bitwise select what sensor to enable for the expansion boards(external sensors).
|
||||
configLocation->noOfTempSensorPerModule = 4; // Number of temperature sensors monitored per LTC68XX
|
||||
configLocation->noOfExpansionBoard = 0; // Number of expansion board
|
||||
configLocation->noOfTempSensorPerExpansionBoard = 0; // Number of temperature sensors monitored per expansion board
|
||||
configLocation->LCUseDischarge = enabled; // Enable or disable the solid state output
|
||||
configLocation->LCUsePrecharge = enabled; // Use precharge before enabling main output
|
||||
configLocation->allowChargingDuringDischarge = true; // Allow the battery to be charged in normal mode
|
||||
configLocation->allowForceOn = false; // Allow the BMS to be forced ON by long actuation of the power button
|
||||
configLocation->pulseToggleButton = true; // Select either pulse or toggle power button
|
||||
configLocation->useCANSafetyInput = false; // Use the safety input status from CAN
|
||||
configLocation->useCANDelayedPowerDown = false; // Use delayed power down
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupLTCExt] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupMasterPCB] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupExp] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupLTCExt] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupMasterPCB] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupExp] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupLTCExt] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupMasterPCB] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupExp] = 4250; // NTC Beta factor
|
||||
configLocation->cellMonitorType = CELL_MON_LTC6811_1; // Use the new cell voltage monitor
|
||||
configLocation->cellMonitorICCount = 1; // Only one slave IC
|
||||
configLocation->externalEnableOperationalState = opStateExtNormal; // Go to normal enable mode
|
||||
configLocation->chargeEnableOperationalState = opStateChargingModeCharging;// Go to charging mode when a charger is connected
|
||||
configLocation->powerDownDelay = 3000; // Wait only minimal to turn off
|
||||
|
||||
configLocation->noOfCellsPerModule = 8; // Number of cell levels monitored per LTC68XX
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
configLocation->humidityICType = 0;
|
||||
|
||||
configLocation->serialNumber=__DEFAULT_BATTERY_SERIAL;
|
||||
|
||||
ptr = &configLocation->Domain_URL[0];
|
||||
strcpy(ptr,"http://battery.cscw.ru/api/v1/battery");
|
||||
|
||||
ptr = &configLocation->Domain_URL_Event[0];
|
||||
strcpy(ptr,"http://battery.cscw.ru/api/v1/events");
|
||||
|
||||
ptr = &configLocation->GSM_APN[0];
|
||||
strcpy(ptr,"internet.beeline.ru");
|
||||
|
||||
ptr = &configLocation->GSM_USER[0];
|
||||
strcpy(ptr,"Beeline");
|
||||
|
||||
ptr = &configLocation->GSM_PWD[0];
|
||||
strcpy(ptr,"Beeline");
|
||||
|
||||
configLocation->PC_Time=0;
|
||||
|
||||
configLocation->chargeBatteryOutputChecked = false;
|
||||
configLocation->brushOrShuntOutputChecked = false;
|
||||
configLocation->brushOrShuntMode = false;
|
||||
configLocation->brushUsageSocThreshold = 10;
|
||||
configLocation->shuntChargingContactorDelay = 5;
|
||||
configLocation->coolingOutputChecked = false;
|
||||
configLocation->coolingStartThreshold = 50;
|
||||
configLocation->coolingStopThreshold = 40;
|
||||
configLocation->heatingOutputChecked = false;
|
||||
configLocation->heatingStartThreshold = 0;
|
||||
configLocation->heatingStopThreshold = 20;
|
||||
|
||||
configLocation->floatCurrentK1 = 0.0f; // First factor of current calculation
|
||||
configLocation->floatCurrentK2 = 0.777f; // Second factor of current calculation
|
||||
|
||||
float currentTable[9][11] = {
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
|
||||
{0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12},
|
||||
{0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.20, 0.20},
|
||||
{0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.40, 0.40},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 0.80, 0.80},
|
||||
{0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.50, 0.40, 0.40},
|
||||
{0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.30, 0.20, 0.20},
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
float unitTable[9][11] = {
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9; ++i)
|
||||
{
|
||||
for (int j = 0; j < 11; ++j)
|
||||
{
|
||||
configLocation->externalChargeCurrentTable[i][j] = currentTable[i][j];
|
||||
configLocation->externalChargeUnitTable[i][j] = unitTable[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
#elif ENNOID_HV
|
||||
configLocation->noOfCellsSeries = 8; // Total number of cells in series in the battery pack
|
||||
configLocation->noOfCellsParallel = 10; // Number of cells in parallel
|
||||
configLocation->noOfParallelModules = 1; // Number of parallel modules
|
||||
configLocation->batteryCapacity = 22.00f; // XXAh battery
|
||||
configLocation->cellHardUnderVoltage = 2.30f; // Worst case X.XXV as lowest cell voltage
|
||||
configLocation->cellHardOverVoltage = 4.20f; // Worst case X.XXV as highest cell voltage
|
||||
configLocation->cellLCSoftUnderVoltage = 2.70f; // Lowest cell voltage X.XXV.
|
||||
configLocation->cellSoftOverVoltage = 4.15f; // Normal highest cell voltage X.XXV.
|
||||
configLocation->cellBalanceDifferenceThreshold = 0.01f; // Start balancing @ XmV difference, stop if below.
|
||||
configLocation->cellBalanceStart = 4.1f; // Start balancing above X.XXV.
|
||||
configLocation->cellBalanceAllTime = false; // Enable balancing under all opstate
|
||||
configLocation->cellThrottleUpperStart = 0.03f; // Upper range of cell voltage for charge throttling.
|
||||
configLocation->cellThrottleLowerStart = 0.20f; // Lower range of cell voltage for discharge throttling.
|
||||
configLocation->cellThrottleUpperMargin = 0.01f; // Margin of throttle from upper soft limits.
|
||||
configLocation->cellThrottleLowerMargin = 0.50f; // Margin of throttle from lower soft limits.
|
||||
configLocation->packVoltageDataSource = sourcePackVoltageISL28022_2_BatteryIn; // Packvoltage source.
|
||||
configLocation->packCurrentDataSource = sourcePackCurrentLowCurrentShunt; // The pack current is the same as the current through the low current shunt
|
||||
configLocation->buzzerSignalSource = buzzerSourceOn; // Stores what source shoud be taken to trigger
|
||||
configLocation->buzzerSignalPersistant = false; // Stores whether the buzzer should stay on after triggering
|
||||
configLocation->shuntLCFactor = -0.07f; // Shunt factor low current
|
||||
configLocation->voltageLCFactor = 47.5f; // Pack voltage factor
|
||||
configLocation->voltageLCOffset = 0; // Pack voltage offset
|
||||
configLocation->loadVoltageFactor = 190.0f; // Load voltage factor
|
||||
configLocation->loadVoltageOffset = 9.0f; // Load voltage offset
|
||||
configLocation->chargerVoltageFactor = 49.2f; // Charger voltage factor
|
||||
configLocation->chargerVoltageOffset = 0.0f; // Charger voltage offset
|
||||
configLocation->throttleChargeIncreaseRate = 1; // Percentage charge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->throttleDisChargeIncreaseRate = 2; // Percentage discharge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->cellBalanceUpdateInterval = 4*1000; // Keep calculated resistors enabled for this amount of time in miliseconds.
|
||||
configLocation->maxSimultaneousDischargingCells = 5; // Allow a maximum of X cells simultinous discharging trough bleeding resistors.
|
||||
configLocation->timeoutDischargeRetry = 10*1000; // Wait for X seconds before retrying to enable load.
|
||||
configLocation->hysteresisDischarge = 0.02f; // Lowest cell should rise XXmV before output is re enabled.
|
||||
configLocation->timeoutChargeRetry = 30*1000; // Wait for XX seconds before retrying to enable charger.
|
||||
configLocation->hysteresisCharge = 0.01f; // Highest cell should lower XXmV before charger is re enabled.
|
||||
configLocation->timeoutChargeCompleted = 30*60*1000; // Wait for XX minutes before setting charge state to charged.
|
||||
configLocation->timeoutChargingCompletedMinimalMismatch = 6*1000; // If cell mismatch is under threshold and (charging is not allowed) wait this delay time to set "charged" state.
|
||||
configLocation->maxMismatchThreshold = 0.010f; // If mismatch is under this threshold for timeoutChargingCompletedMinimalMismatch determin fully charged.
|
||||
configLocation->chargerEnabledThreshold = 0.5f; // If charge current > X.XA stay in charging mode and dont power off.
|
||||
configLocation->timeoutChargerDisconnected = 2000; // Wait for X seconds to respond to charger disconnect.
|
||||
configLocation->minimalPrechargePercentage = 0.90f; // output should be at a minimal of 80% of input voltage.
|
||||
configLocation->timeoutLCPreCharge = 1.5*1000; // Precharge error timeout, allow 1.5 seconds pre-charge time before declaring load error.
|
||||
configLocation->maxAllowedCurrent = 1000.0f; // Allow max XXXA trough BMS.
|
||||
configLocation->allowedTempBattDischargingMax = 75.0f; // Max battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattDischargingMin = 0.0f; // Min battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattChargingMax = 50.0f; // Max battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattChargingMin = 0.0f; // Min battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattCoolingMax = 5.0f; // Max battery temperature where cooling is activated
|
||||
configLocation->allowedTempBattCoolingMin = 50.0f; // Min battery temperature where heating is activated
|
||||
configLocation->allowedTempBMSMax = 80.0f; // Max BMS operational temperature
|
||||
configLocation->allowedTempBMSMin = 0.0f; // Min BMS operational temperature
|
||||
configLocation->displayTimeoutBatteryDead = 5000; // Show battery dead symbol X seconds before going to powerdown in cell voltage error state.
|
||||
configLocation->displayTimeoutBatteryError = 5000; // Show error symbol for X seconds before going to powerdown in general error state.
|
||||
configLocation->displayTimeoutBatteryErrorPreCharge = 10000; // Show pre charge error for XX seconds.
|
||||
configLocation->displayTimeoutSplashScreen = 3000; // Display / INIT splash screen time.
|
||||
configLocation->displayStyle = advanced; // Display style used for showing the SSD1306 data
|
||||
configLocation->maxUnderAndOverVoltageErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->maxUnderAndOverTemperatureErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->notUsedCurrentThreshold = 1.0f; // If abs(packcurrent) < X.XA consider pack as not used.
|
||||
configLocation->notUsedTimeout = 20*60*1000; // If pack is not used for longer than XX minutes disable bms.
|
||||
configLocation->stateOfChargeStoreInterval = 60*1000; // Interval in ms to store state of charge information.
|
||||
configLocation->stateOfChargeMethod = socCoulomb; // Use coulomb counting for SoC calculation
|
||||
configLocation->CANID = 10; // CAN ID for CAN communication.
|
||||
configLocation->CANIDStyle = CANIDStyleVESC; // CAN ID default Style.
|
||||
configLocation->canBusSpeed = canSpeedBaud500k; // 500k CAN baud
|
||||
configLocation->emitStatusOverCAN = false; // Send status over can.
|
||||
configLocation->emitStatusProtocol = canEmitProtocolDieBieEngineering; // Can emit protocol set to MG style for backwards compatibility
|
||||
configLocation->tempEnableMaskBMS = 0x0001; // Bitwise select what sensor to enable for the BMS (internal sensors).
|
||||
configLocation->tempEnableMaskBattery = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->tempEnableMaskExpansion = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->noOfTempSensorPerModule = 1; // Number of temperature sensors monitored per LTC68XX
|
||||
configLocation->noOfExpansionBoard = 0; // Number of expansion board
|
||||
configLocation->noOfTempSensorPerExpansionBoard = 0; // Number of temperature sensors monitored per expansion board
|
||||
configLocation->LCUseDischarge = enabled; // Enable or disable the solid state output
|
||||
configLocation->LCUsePrecharge = enabled; // Use precharge before enabling main output
|
||||
configLocation->allowChargingDuringDischarge = true; // Allow the battery to be charged in normal mode
|
||||
configLocation->allowForceOn = false; // Allow the BMS to be forced ON by long actuation of the power button
|
||||
configLocation->pulseToggleButton = true; // Select either pulse or toggle power button
|
||||
configLocation->useCANSafetyInput = false; // Use the safety input status from CAN
|
||||
configLocation->useCANDelayedPowerDown = false; // Use delayed power down
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupLTCExt] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupMasterPCB] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupExp] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupLTCExt] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupMasterPCB] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupExp] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupLTCExt] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupMasterPCB] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupExp] = 4250; // NTC Beta factor
|
||||
configLocation->cellMonitorType = CELL_MON_LTC6811_1; // Use the new cell voltage monitor
|
||||
configLocation->cellMonitorICCount = 1; // Only one slave IC
|
||||
configLocation->externalEnableOperationalState = opStateExtNormal; // Go to normal enable mode
|
||||
configLocation->chargeEnableOperationalState = opStateChargingModeCharging;// Go to charging mode when a charger is connected
|
||||
configLocation->powerDownDelay = 3000; // Wait only minimal to turn off
|
||||
|
||||
configLocation->noOfCellsPerModule = 8; // Number of cell levels monitored per LTC68XX
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
configLocation->humidityICType = 0;
|
||||
|
||||
|
||||
#elif ENNOID_SS
|
||||
configLocation->noOfCellsSeries = 8; // Total number of cells in series in the battery pack
|
||||
configLocation->noOfCellsParallel = 10; // Number of cells in parallel
|
||||
configLocation->noOfParallelModules = 1; // Number of parallel modules
|
||||
configLocation->batteryCapacity = 22.00f; // XXAh battery
|
||||
configLocation->cellHardUnderVoltage = 2.30f; // Worst case X.XXV as lowest cell voltage
|
||||
configLocation->cellHardOverVoltage = 4.20f; // Worst case X.XXV as highest cell voltage
|
||||
configLocation->cellLCSoftUnderVoltage = 2.70f; // Lowest cell voltage X.XXV.
|
||||
configLocation->cellSoftOverVoltage = 4.15f; // Normal highest cell voltage X.XXV.
|
||||
configLocation->cellBalanceDifferenceThreshold = 0.01f; // Start balancing @ XmV difference, stop if below.
|
||||
configLocation->cellBalanceStart = 4.1f; // Start balancing above X.XXV.
|
||||
configLocation->cellBalanceAllTime = false; // Enable balancing under all opstate
|
||||
configLocation->cellThrottleUpperStart = 0.03f; // Upper range of cell voltage for charge throttling.
|
||||
configLocation->cellThrottleLowerStart = 0.20f; // Lower range of cell voltage for discharge throttling.
|
||||
configLocation->cellThrottleUpperMargin = 0.01f; // Margin of throttle from upper soft limits.
|
||||
configLocation->cellThrottleLowerMargin = 0.50f; // Margin of throttle from lower soft limits.
|
||||
configLocation->packVoltageDataSource = sourcePackVoltageISL28022_2_BatteryIn; // Packvoltage source.
|
||||
configLocation->packCurrentDataSource = sourcePackCurrentLowCurrentShunt; // The pack current is the same as the current through the low current shunt
|
||||
configLocation->buzzerSignalSource = buzzerSourceOn; // Stores what source shoud be taken to trigger
|
||||
configLocation->buzzerSignalPersistant = false; // Stores whether the buzzer should stay on after triggering
|
||||
configLocation->shuntLCFactor = -0.0052f; // Shunt factor low current
|
||||
configLocation->voltageLCFactor = 1.35f; // Pack voltage factor
|
||||
configLocation->voltageLCOffset = 0; // Pack voltage offset
|
||||
configLocation->loadVoltageFactor = 29.8f; // Load voltage factor
|
||||
configLocation->loadVoltageOffset = 0.0f; // Load voltage offset
|
||||
configLocation->chargerVoltageFactor = 29.8f; // Charger voltage factor
|
||||
configLocation->chargerVoltageOffset = 0.0f; // Charger voltage offset
|
||||
configLocation->throttleChargeIncreaseRate = 1; // Percentage charge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->throttleDisChargeIncreaseRate = 2; // Percentage discharge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->cellBalanceUpdateInterval = 4*1000; // Keep calculated resistors enabled for this amount of time in miliseconds.
|
||||
configLocation->maxSimultaneousDischargingCells = 5; // Allow a maximum of X cells simultinous discharging trough bleeding resistors.
|
||||
configLocation->timeoutDischargeRetry = 10*1000; // Wait for X seconds before retrying to enable load.
|
||||
configLocation->hysteresisDischarge = 0.02f; // Lowest cell should rise XXmV before output is re enabled.
|
||||
configLocation->timeoutChargeRetry = 30*1000; // Wait for XX seconds before retrying to enable charger.
|
||||
configLocation->hysteresisCharge = 0.01f; // Highest cell should lower XXmV before charger is re enabled.
|
||||
configLocation->timeoutChargeCompleted = 30*60*1000; // Wait for XX minutes before setting charge state to charged.
|
||||
configLocation->timeoutChargingCompletedMinimalMismatch = 6*1000; // If cell mismatch is under threshold and (charging is not allowed) wait this delay time to set "charged" state.
|
||||
configLocation->maxMismatchThreshold = 0.010f; // If mismatch is under this threshold for timeoutChargingCompletedMinimalMismatch determin fully charged.
|
||||
configLocation->chargerEnabledThreshold = 0.5f; // If charge current > X.XA stay in charging mode and dont power off.
|
||||
configLocation->timeoutChargerDisconnected = 2000; // Wait for X seconds to respond to charger disconnect.
|
||||
configLocation->minimalPrechargePercentage = 0.90f; // output should be at a minimal of 80% of input voltage.
|
||||
configLocation->timeoutLCPreCharge = 1.5*1000; // Precharge error timeout, allow 1.5 seconds pre-charge time before declaring load error.
|
||||
configLocation->maxAllowedCurrent = 1000.0f; // Allow max XXXA trough BMS.
|
||||
configLocation->allowedTempBattDischargingMax = 105.0f; // Max battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattDischargingMin = 0.0f; // Min battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattChargingMax = 105.0f; // Max battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattChargingMin = 0.0f; // Min battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattCoolingMax = 5.0f; // Max battery temperature where cooling is activated
|
||||
configLocation->allowedTempBattCoolingMin = 50.0f; // Min battery temperature where heating is activated
|
||||
configLocation->allowedTempBMSMax = 80.0f; // Max BMS operational temperature
|
||||
configLocation->allowedTempBMSMin = 0.0f; // Min BMS operational temperature
|
||||
configLocation->displayTimeoutBatteryDead = 5000; // Show battery dead symbol X seconds before going to powerdown in cell voltage error state.
|
||||
configLocation->displayTimeoutBatteryError = 5000; // Show error symbol for X seconds before going to powerdown in general error state.
|
||||
configLocation->displayTimeoutBatteryErrorPreCharge = 10000; // Show pre charge error for XX seconds.
|
||||
configLocation->displayTimeoutSplashScreen = 3000; // Display / INIT splash screen time.
|
||||
configLocation->displayStyle = advanced; // Display style used for showing the SSD1306 data
|
||||
configLocation->maxUnderAndOverVoltageErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->maxUnderAndOverTemperatureErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->notUsedCurrentThreshold = 1.0f; // If abs(packcurrent) < X.XA consider pack as not used.
|
||||
configLocation->notUsedTimeout = 20*60*1000; // If pack is not used for longer than XX minutes disable bms.
|
||||
configLocation->stateOfChargeStoreInterval = 60*1000; // Interval in ms to store state of charge information.
|
||||
configLocation->stateOfChargeMethod = socCoulomb; // Use coulomb counting for SoC calculation
|
||||
configLocation->CANID = 10; // CAN ID for CAN communication.
|
||||
configLocation->CANIDStyle = CANIDStyleVESC; // CAN ID default Style.
|
||||
configLocation->canBusSpeed = canSpeedBaud500k; // 500k CAN baud
|
||||
configLocation->emitStatusOverCAN = false; // Send status over can.
|
||||
configLocation->emitStatusProtocol = canEmitProtocolDieBieEngineering; // Can emit protocol set to MG style for backwards compatibility
|
||||
configLocation->tempEnableMaskBMS = 0x0001; // Bitwise select what sensor to enable for the BMS (internal sensors).
|
||||
configLocation->tempEnableMaskBattery = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->tempEnableMaskExpansion = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->noOfTempSensorPerModule = 0; // Number of temperature sensors monitored per LTC68XX
|
||||
configLocation->noOfExpansionBoard = 0; // Number of expansion board
|
||||
configLocation->noOfTempSensorPerExpansionBoard = 0; // Number of temperature sensors monitored per expansion board
|
||||
configLocation->LCUseDischarge = enabled; // Enable or disable the solid state output
|
||||
configLocation->LCUsePrecharge = enabled; // Use precharge before enabling main output
|
||||
configLocation->allowChargingDuringDischarge = false; // Allow the battery to be charged in normal mode
|
||||
configLocation->allowForceOn = false; // Allow the BMS to be forced ON by long actuation of the power button
|
||||
configLocation->pulseToggleButton = true; // Select either pulse or toggle power button
|
||||
configLocation->useCANSafetyInput = false; // Use the safety input status from CAN
|
||||
configLocation->useCANDelayedPowerDown = false; // Use delayed power down
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupLTCExt] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupMasterPCB] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupExp] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupLTCExt] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupMasterPCB] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupExp] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupLTCExt] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupMasterPCB] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupExp] = 4250; // NTC Beta factor
|
||||
configLocation->cellMonitorType = CELL_MON_LTC6813_1; // Use the new cell voltage monitor
|
||||
configLocation->cellMonitorICCount = 1; // Only one slave IC
|
||||
configLocation->externalEnableOperationalState = opStateExtNormal; // Go to normal enable mode
|
||||
configLocation->chargeEnableOperationalState = opStateChargingModeCharging;// Go to charging mode when a charger is connected
|
||||
configLocation->powerDownDelay = 3000; // Wait only minimal to turn off
|
||||
|
||||
configLocation->noOfCellsPerModule = 18; // Number of cell levels monitored per LTC68XX
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
configLocation->humidityICType = 2;
|
||||
|
||||
#elif ENNOID_SS_LITE
|
||||
configLocation->noOfCellsSeries = 18; // Total number of cells in series in the battery pack
|
||||
configLocation->noOfCellsParallel = 10; // Number of cells in parallel
|
||||
configLocation->noOfParallelModules = 1; // Number of parallel modules
|
||||
configLocation->batteryCapacity = 22.00f; // XXAh battery
|
||||
configLocation->cellHardUnderVoltage = 2.30f; // Worst case X.XXV as lowest cell voltage
|
||||
configLocation->cellHardOverVoltage = 4.20f; // Worst case X.XXV as highest cell voltage
|
||||
configLocation->cellLCSoftUnderVoltage = 2.70f; // Lowest cell voltage X.XXV.
|
||||
configLocation->cellSoftOverVoltage = 4.15f; // Normal highest cell voltage X.XXV.
|
||||
configLocation->cellBalanceDifferenceThreshold = 0.01f; // Start balancing @ XmV difference, stop if below.
|
||||
configLocation->cellBalanceStart = 4.1f; // Start balancing above X.XXV.
|
||||
configLocation->cellBalanceAllTime = false; // Enable balancing under all opstate
|
||||
configLocation->cellThrottleUpperStart = 0.03f; // Upper range of cell voltage for charge throttling.
|
||||
configLocation->cellThrottleLowerStart = 0.20f; // Lower range of cell voltage for discharge throttling.
|
||||
configLocation->cellThrottleUpperMargin = 0.01f; // Margin of throttle from upper soft limits.
|
||||
configLocation->cellThrottleLowerMargin = 0.50f; // Margin of throttle from lower soft limits.
|
||||
configLocation->packVoltageDataSource = sourcePackVoltageISL28022_2_BatteryIn; // Packvoltage source.
|
||||
configLocation->packCurrentDataSource = sourcePackCurrentLowCurrentShunt; // The pack current is the same as the current through the low current shunt
|
||||
configLocation->buzzerSignalSource = buzzerSourceOn; // Stores what source shoud be taken to trigger
|
||||
configLocation->buzzerSignalPersistant = false; // Stores whether the buzzer should stay on after triggering
|
||||
configLocation->shuntLCFactor = -0.0052f; // Shunt factor low current
|
||||
configLocation->voltageLCFactor = 1.35f; // Pack voltage factor
|
||||
configLocation->voltageLCOffset = 0; // Pack voltage offset
|
||||
configLocation->loadVoltageFactor = 29.8f; // Load voltage factor
|
||||
configLocation->loadVoltageOffset = 0.0f; // Load voltage offset
|
||||
configLocation->chargerVoltageFactor = 29.8f; // Charger voltage factor
|
||||
configLocation->chargerVoltageOffset = 0.0f; // Charger voltage offset
|
||||
configLocation->throttleChargeIncreaseRate = 1; // Percentage charge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->throttleDisChargeIncreaseRate = 2; // Percentage discharge throttle increase rate per 100ms (cell voltage loop time)
|
||||
configLocation->cellBalanceUpdateInterval = 4*1000; // Keep calculated resistors enabled for this amount of time in miliseconds.
|
||||
configLocation->maxSimultaneousDischargingCells = 5; // Allow a maximum of X cells simultinous discharging trough bleeding resistors.
|
||||
configLocation->timeoutDischargeRetry = 10*1000; // Wait for X seconds before retrying to enable load.
|
||||
configLocation->hysteresisDischarge = 0.02f; // Lowest cell should rise XXmV before output is re enabled.
|
||||
configLocation->timeoutChargeRetry = 30*1000; // Wait for XX seconds before retrying to enable charger.
|
||||
configLocation->hysteresisCharge = 0.01f; // Highest cell should lower XXmV before charger is re enabled.
|
||||
configLocation->timeoutChargeCompleted = 30*60*1000; // Wait for XX minutes before setting charge state to charged.
|
||||
configLocation->timeoutChargingCompletedMinimalMismatch = 6*1000; // If cell mismatch is under threshold and (charging is not allowed) wait this delay time to set "charged" state.
|
||||
configLocation->maxMismatchThreshold = 0.010f; // If mismatch is under this threshold for timeoutChargingCompletedMinimalMismatch determin fully charged.
|
||||
configLocation->chargerEnabledThreshold = 0.5f; // If charge current > X.XA stay in charging mode and dont power off.
|
||||
configLocation->timeoutChargerDisconnected = 2000; // Wait for X seconds to respond to charger disconnect.
|
||||
configLocation->minimalPrechargePercentage = 0.90f; // output should be at a minimal of 80% of input voltage.
|
||||
configLocation->timeoutLCPreCharge = 1.5*1000; // Precharge error timeout, allow 1.5 seconds pre-charge time before declaring load error.
|
||||
configLocation->maxAllowedCurrent = 1000.0f; // Allow max XXXA trough BMS.
|
||||
configLocation->allowedTempBattDischargingMax = 105.0f; // Max battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattDischargingMin = 0.0f; // Min battery temperature where discharging is still allowed
|
||||
configLocation->allowedTempBattChargingMax = 105.0f; // Max battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattChargingMin = 0.0f; // Min battery temperature where charging is still allowed
|
||||
configLocation->allowedTempBattCoolingMax = 5.0f; // Max battery temperature where cooling is activated
|
||||
configLocation->allowedTempBattCoolingMin = 50.0f; // Min battery temperature where heating is activated
|
||||
configLocation->allowedTempBMSMax = 80.0f; // Max BMS operational temperature
|
||||
configLocation->allowedTempBMSMin = 0.0f; // Min BMS operational temperature
|
||||
configLocation->displayTimeoutBatteryDead = 5000; // Show battery dead symbol X seconds before going to powerdown in cell voltage error state.
|
||||
configLocation->displayTimeoutBatteryError = 5000; // Show error symbol for X seconds before going to powerdown in general error state.
|
||||
configLocation->displayTimeoutBatteryErrorPreCharge = 10000; // Show pre charge error for XX seconds.
|
||||
configLocation->displayTimeoutSplashScreen = 3000; // Display / INIT splash screen time.
|
||||
configLocation->displayStyle = advanced; // Display style used for showing the SSD1306 data
|
||||
configLocation->maxUnderAndOverVoltageErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->maxUnderAndOverTemperatureErrorCount = 5; // Max count of hard cell voltage errors.
|
||||
configLocation->notUsedCurrentThreshold = 1.0f; // If abs(packcurrent) < X.XA consider pack as not used.
|
||||
configLocation->notUsedTimeout = 20*60*1000; // If pack is not used for longer than XX minutes disable bms.
|
||||
configLocation->stateOfChargeStoreInterval = 60*1000; // Interval in ms to store state of charge information.
|
||||
configLocation->stateOfChargeMethod = socCoulomb; // Use coulomb counting for SoC calculation
|
||||
configLocation->CANID = 10; // CAN ID for CAN communication.
|
||||
configLocation->CANIDStyle = CANIDStyleVESC; // CAN ID default Style.
|
||||
configLocation->canBusSpeed = canSpeedBaud500k; // 500k CAN baud
|
||||
configLocation->emitStatusOverCAN = false; // Send status over can.
|
||||
configLocation->emitStatusProtocol = canEmitProtocolDieBieEngineering; // Can emit protocol set to MG style for backwards compatibility
|
||||
configLocation->tempEnableMaskBMS = 0x0001; // Bitwise select what sensor to enable for the BMS (internal sensors).
|
||||
configLocation->tempEnableMaskBattery = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->tempEnableMaskExpansion = 0xFFFF; // Bitwise select what sensor to enable for the battery (external sensors).
|
||||
configLocation->noOfTempSensorPerModule = 0; // Number of temperature sensors monitored per LTC68XX
|
||||
configLocation->noOfExpansionBoard = 0; // Number of expansion board
|
||||
configLocation->noOfTempSensorPerExpansionBoard = 0; // Number of temperature sensors monitored per expansion board
|
||||
configLocation->LCUseDischarge = disabled; // Enable or disable the solid state output
|
||||
configLocation->LCUsePrecharge = disabled; // Use precharge before enabling main output
|
||||
configLocation->allowChargingDuringDischarge = false; // Allow the battery to be charged in normal mode
|
||||
configLocation->allowForceOn = false; // Allow the BMS to be forced ON by long actuation of the power button
|
||||
configLocation->pulseToggleButton = true; // Select either pulse or toggle power button
|
||||
configLocation->useCANSafetyInput = false; // Use the safety input status from CAN
|
||||
configLocation->useCANDelayedPowerDown = false; // Use delayed power down
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupLTCExt] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupMasterPCB] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTCTopResistor[modConfigNTCGroupExp] = 100000; // NTC Pullup resistor value
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupLTCExt] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupMasterPCB] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTC25DegResistance[modConfigNTCGroupExp] = 100000; // NTC resistance at 25 degree
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupLTCExt] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupMasterPCB] = 4250; // NTC Beta factor
|
||||
configLocation->NTCBetaFactor[modConfigNTCGroupExp] = 4250; // NTC Beta factor
|
||||
configLocation->cellMonitorType = CELL_MON_LTC6813_1; // Use the new cell voltage monitor
|
||||
configLocation->cellMonitorICCount = 1; // Only one slave IC
|
||||
configLocation->externalEnableOperationalState = opStateExtNormal; // Go to normal enable mode
|
||||
configLocation->chargeEnableOperationalState = opStateChargingModeCharging;// Go to charging mode when a charger is connected
|
||||
configLocation->powerDownDelay = 3000; // Wait only minimal to turn off
|
||||
|
||||
configLocation->noOfCellsPerModule = 18; // Number of cell levels monitored per LTC68XX
|
||||
configLocation->lastICNoOfCells = 0;
|
||||
configLocation->lastICMask = 0;
|
||||
configLocation->humidityICType = 2;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
61
firmware/Core/Src/modDelay.c
Normal file
61
firmware/Core/Src/modDelay.c
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "modDelay.h"
|
||||
|
||||
static uint32_t hmsCnt = 0;
|
||||
|
||||
void modDelayInit(void) {
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
//SystemCoreClock / 1000
|
||||
if(SysTick_Config(72000)){
|
||||
while(1); //Error setting SysTick.
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t modDelayTick1ms(uint32_t *last, uint32_t ticks) {
|
||||
if((uint32_t)(HAL_GetTick() - *last) >= ticks)
|
||||
{
|
||||
*last = HAL_GetTick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t modDelayTick100ms(uint32_t *last, uint32_t ticks) {
|
||||
static uint32_t msTicks = 0;
|
||||
|
||||
if(modDelayTick1ms(&msTicks,99))
|
||||
hmsCnt++;
|
||||
|
||||
if((uint32_t)(hmsCnt - *last) >= ticks)
|
||||
{
|
||||
*last = hmsCnt;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t modDelayTick1msNoRST(uint32_t *last, uint32_t ticks) {
|
||||
if((uint32_t)(HAL_GetTick() - *last) >= ticks)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t modDelayTick100msNoRST(uint32_t *last, uint32_t ticks) {
|
||||
static uint32_t msTicks = 0;
|
||||
|
||||
if(modDelayTick1msNoRST(&msTicks,99))
|
||||
hmsCnt++;
|
||||
|
||||
if((uint32_t)(hmsCnt - *last) >= ticks)
|
||||
{
|
||||
*last = hmsCnt;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
383
firmware/Core/Src/modFlash.c
Normal file
383
firmware/Core/Src/modFlash.c
Normal file
@@ -0,0 +1,383 @@
|
||||
#include "modFlash.h"
|
||||
|
||||
static const uint32_t flash_addr[FLASH_PAGES] = {
|
||||
ADDR_FLASH_PAGE_0,
|
||||
ADDR_FLASH_PAGE_1,
|
||||
ADDR_FLASH_PAGE_2,
|
||||
ADDR_FLASH_PAGE_3,
|
||||
ADDR_FLASH_PAGE_4,
|
||||
ADDR_FLASH_PAGE_5,
|
||||
ADDR_FLASH_PAGE_6,
|
||||
ADDR_FLASH_PAGE_7,
|
||||
ADDR_FLASH_PAGE_8,
|
||||
ADDR_FLASH_PAGE_9,
|
||||
ADDR_FLASH_PAGE_10,
|
||||
ADDR_FLASH_PAGE_11,
|
||||
ADDR_FLASH_PAGE_12,
|
||||
ADDR_FLASH_PAGE_13,
|
||||
ADDR_FLASH_PAGE_14,
|
||||
ADDR_FLASH_PAGE_15,
|
||||
ADDR_FLASH_PAGE_16,
|
||||
ADDR_FLASH_PAGE_17,
|
||||
ADDR_FLASH_PAGE_18,
|
||||
ADDR_FLASH_PAGE_19,
|
||||
ADDR_FLASH_PAGE_20,
|
||||
ADDR_FLASH_PAGE_21,
|
||||
ADDR_FLASH_PAGE_22,
|
||||
ADDR_FLASH_PAGE_23,
|
||||
ADDR_FLASH_PAGE_24,
|
||||
ADDR_FLASH_PAGE_25,
|
||||
ADDR_FLASH_PAGE_26,
|
||||
ADDR_FLASH_PAGE_27,
|
||||
ADDR_FLASH_PAGE_28,
|
||||
ADDR_FLASH_PAGE_29,
|
||||
ADDR_FLASH_PAGE_30,
|
||||
ADDR_FLASH_PAGE_31,
|
||||
ADDR_FLASH_PAGE_32,
|
||||
ADDR_FLASH_PAGE_33,
|
||||
ADDR_FLASH_PAGE_34,
|
||||
ADDR_FLASH_PAGE_35,
|
||||
ADDR_FLASH_PAGE_36,
|
||||
ADDR_FLASH_PAGE_37,
|
||||
ADDR_FLASH_PAGE_38,
|
||||
ADDR_FLASH_PAGE_39,
|
||||
ADDR_FLASH_PAGE_40,
|
||||
ADDR_FLASH_PAGE_41,
|
||||
ADDR_FLASH_PAGE_42,
|
||||
ADDR_FLASH_PAGE_43,
|
||||
ADDR_FLASH_PAGE_44,
|
||||
ADDR_FLASH_PAGE_45,
|
||||
ADDR_FLASH_PAGE_46,
|
||||
ADDR_FLASH_PAGE_47,
|
||||
ADDR_FLASH_PAGE_48,
|
||||
ADDR_FLASH_PAGE_49,
|
||||
ADDR_FLASH_PAGE_50,
|
||||
ADDR_FLASH_PAGE_51,
|
||||
ADDR_FLASH_PAGE_52,
|
||||
ADDR_FLASH_PAGE_53,
|
||||
ADDR_FLASH_PAGE_54,
|
||||
ADDR_FLASH_PAGE_55,
|
||||
ADDR_FLASH_PAGE_56,
|
||||
ADDR_FLASH_PAGE_57,
|
||||
ADDR_FLASH_PAGE_58,
|
||||
ADDR_FLASH_PAGE_59,
|
||||
ADDR_FLASH_PAGE_60,
|
||||
ADDR_FLASH_PAGE_61,
|
||||
ADDR_FLASH_PAGE_62,
|
||||
ADDR_FLASH_PAGE_63,
|
||||
ADDR_FLASH_PAGE_64,
|
||||
ADDR_FLASH_PAGE_65,
|
||||
ADDR_FLASH_PAGE_66,
|
||||
ADDR_FLASH_PAGE_67,
|
||||
ADDR_FLASH_PAGE_68,
|
||||
ADDR_FLASH_PAGE_69,
|
||||
ADDR_FLASH_PAGE_70,
|
||||
ADDR_FLASH_PAGE_71,
|
||||
ADDR_FLASH_PAGE_72,
|
||||
ADDR_FLASH_PAGE_73,
|
||||
ADDR_FLASH_PAGE_74,
|
||||
ADDR_FLASH_PAGE_75,
|
||||
ADDR_FLASH_PAGE_76,
|
||||
ADDR_FLASH_PAGE_77,
|
||||
ADDR_FLASH_PAGE_78,
|
||||
ADDR_FLASH_PAGE_79,
|
||||
ADDR_FLASH_PAGE_80,
|
||||
ADDR_FLASH_PAGE_81,
|
||||
ADDR_FLASH_PAGE_82,
|
||||
ADDR_FLASH_PAGE_83,
|
||||
ADDR_FLASH_PAGE_84,
|
||||
ADDR_FLASH_PAGE_85,
|
||||
ADDR_FLASH_PAGE_86,
|
||||
ADDR_FLASH_PAGE_87,
|
||||
ADDR_FLASH_PAGE_88,
|
||||
ADDR_FLASH_PAGE_89,
|
||||
ADDR_FLASH_PAGE_90,
|
||||
ADDR_FLASH_PAGE_91,
|
||||
ADDR_FLASH_PAGE_92,
|
||||
ADDR_FLASH_PAGE_93,
|
||||
ADDR_FLASH_PAGE_94,
|
||||
ADDR_FLASH_PAGE_95,
|
||||
ADDR_FLASH_PAGE_96,
|
||||
ADDR_FLASH_PAGE_97,
|
||||
ADDR_FLASH_PAGE_98,
|
||||
ADDR_FLASH_PAGE_99,
|
||||
ADDR_FLASH_PAGE_100,
|
||||
ADDR_FLASH_PAGE_101,
|
||||
ADDR_FLASH_PAGE_102,
|
||||
ADDR_FLASH_PAGE_103,
|
||||
ADDR_FLASH_PAGE_104,
|
||||
ADDR_FLASH_PAGE_105,
|
||||
ADDR_FLASH_PAGE_106,
|
||||
ADDR_FLASH_PAGE_107,
|
||||
ADDR_FLASH_PAGE_108,
|
||||
ADDR_FLASH_PAGE_109,
|
||||
ADDR_FLASH_PAGE_110,
|
||||
ADDR_FLASH_PAGE_111,
|
||||
ADDR_FLASH_PAGE_112,
|
||||
ADDR_FLASH_PAGE_113,
|
||||
ADDR_FLASH_PAGE_114,
|
||||
ADDR_FLASH_PAGE_115,
|
||||
ADDR_FLASH_PAGE_116,
|
||||
ADDR_FLASH_PAGE_117,
|
||||
ADDR_FLASH_PAGE_118,
|
||||
ADDR_FLASH_PAGE_119,
|
||||
ADDR_FLASH_PAGE_120,
|
||||
ADDR_FLASH_PAGE_121,
|
||||
ADDR_FLASH_PAGE_122,
|
||||
ADDR_FLASH_PAGE_123,
|
||||
ADDR_FLASH_PAGE_124,
|
||||
ADDR_FLASH_PAGE_125,
|
||||
ADDR_FLASH_PAGE_126,
|
||||
ADDR_FLASH_PAGE_127
|
||||
};
|
||||
|
||||
TIM_HandleTypeDef htim2;
|
||||
TIM_HandleTypeDef htim6;
|
||||
UART_HandleTypeDef huart2;
|
||||
|
||||
uint16_t modFlashEraseNewAppData(uint32_t new_app_size) {
|
||||
uint32_t page_error = 0;
|
||||
|
||||
new_app_size += flash_addr[NEW_APP_BASE];
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
FLASH_EraseInitTypeDef flashEraseInit;
|
||||
//flashEraseInit.NbPages = 1;
|
||||
flashEraseInit.NbPages = NEW_APP_SECTORS;
|
||||
|
||||
flashEraseInit.PageAddress = flash_addr[NEW_APP_BASE];
|
||||
flashEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
|
||||
flashEraseInit.PageAddress = flash_addr[NEW_APP_BASE];
|
||||
|
||||
uint16_t res = HAL_FLASHEx_Erase(&flashEraseInit,&page_error);
|
||||
if (res != HAL_OK) {
|
||||
return res;
|
||||
}
|
||||
HAL_FLASH_Lock();
|
||||
return HAL_OK;
|
||||
|
||||
|
||||
|
||||
// for (int i = 0;i < NEW_APP_SECTORS;i++) {
|
||||
// if (new_app_size > flash_addr[NEW_APP_BASE + i]) {
|
||||
// flashEraseInit.PageAddress = flash_addr[NEW_APP_BASE + i];
|
||||
// uint16_t res = HAL_FLASHEx_Erase(&flashEraseInit,&page_error);
|
||||
// if (res != HAL_OK) {
|
||||
// return res;
|
||||
// }
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return HAL_OK;
|
||||
}
|
||||
|
||||
uint16_t modFlashEraseMainAppData(uint32_t new_app_size) {
|
||||
uint32_t page_error = 0;
|
||||
HAL_FLASH_Unlock();
|
||||
new_app_size += flash_addr[MAIN_APP_BASE];
|
||||
|
||||
FLASH_EraseInitTypeDef flashEraseInit;
|
||||
flashEraseInit.NbPages = 1;
|
||||
flashEraseInit.PageAddress = flash_addr[MAIN_APP_BASE];
|
||||
flashEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
|
||||
for (int i = 0;i < NEW_APP_SECTORS;i++) {
|
||||
if (new_app_size > flash_addr[MAIN_APP_BASE + i]) {
|
||||
flashEraseInit.PageAddress = flash_addr[NEW_APP_BASE + i];
|
||||
uint16_t res = HAL_FLASHEx_Erase(&flashEraseInit,&page_error);
|
||||
|
||||
if (res != HAL_OK) {
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
HAL_FLASH_Lock();
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
uint16_t modFlashWriteByte(uint32_t offset, uint8_t data, bool lastByte) {
|
||||
static bool highLowByte;
|
||||
static bool newStoredData;
|
||||
static uint32_t newAddressOffset;
|
||||
static uint32_t newData;
|
||||
uint16_t returnValue = HAL_OK;
|
||||
|
||||
|
||||
|
||||
if(offset != 0){
|
||||
highLowByte = (offset & 0x01) ? true : false;
|
||||
newAddressOffset = (offset & 0xFFFFFFFE);
|
||||
|
||||
if(!highLowByte)
|
||||
newData = data;
|
||||
else
|
||||
newData |= (data << 8);
|
||||
newStoredData = true;
|
||||
}
|
||||
|
||||
if((highLowByte || lastByte) && newStoredData) {
|
||||
returnValue = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,newAddressOffset,newData);
|
||||
newStoredData = false;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
uint16_t modFlashWriteNewAppData(uint32_t offset, uint8_t *data, uint32_t len) {
|
||||
uint16_t returnVal = HAL_OK;
|
||||
HAL_FLASH_Unlock();
|
||||
for (uint32_t i = 0;i < len;i++) {
|
||||
uint16_t res = modFlashWriteByte(flash_addr[NEW_APP_BASE] + offset + i, data[i],false);
|
||||
if (res != HAL_OK) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
HAL_FLASH_Lock();
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
uint16_t modFlashCopyNewAppToMainApp(uint32_t offset, uint8_t *data, uint32_t len) {
|
||||
HAL_FLASH_Unlock();
|
||||
for (uint32_t i = 0;i < len;i++) {
|
||||
uint16_t res = modFlashWriteByte(flash_addr[NEW_APP_BASE] + offset + i, data[1],false);
|
||||
if (res != HAL_OK) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
modFlashWriteByte(0,0,true);
|
||||
HAL_FLASH_Lock();
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
//void modFlashJumpToBootloader(void) {
|
||||
//
|
||||
// typedef void (*pFunction)(void);
|
||||
//
|
||||
// modFlashWriteByte(0,0,true);
|
||||
//
|
||||
// __HAL_RCC_CAN1_FORCE_RESET();
|
||||
// HAL_Delay(5);
|
||||
// __HAL_RCC_CAN1_RELEASE_RESET();
|
||||
// HAL_Delay(5);
|
||||
//
|
||||
// __HAL_RCC_USART2_FORCE_RESET();
|
||||
// HAL_Delay(5);
|
||||
// __HAL_RCC_USART2_RELEASE_RESET();
|
||||
// HAL_Delay(5);
|
||||
//
|
||||
// HAL_RCC_DeInit();
|
||||
//
|
||||
// pFunction jump_to_bootloader;
|
||||
//
|
||||
// // Variable that will be loaded with the start address of the application
|
||||
//// volatile uint32_t* jump_address;
|
||||
//// const volatile uint32_t* bootloader_address = (volatile uint32_t*)ADDR_FLASH_PAGE_110;//ADDR_FLASH_PAGE_100;
|
||||
////
|
||||
//// // Get jump address from application vector table
|
||||
//// jump_address = (volatile uint32_t*) bootloader_address[1];
|
||||
//
|
||||
// uint32_t JumpAddress;
|
||||
// JumpAddress = (uint32_t) *((__IO uint32_t*)ADDR_FLASH_PAGE_110);
|
||||
// jump_to_bootloader = (pFunction)(*(volatile uint32_t*) (ADDR_FLASH_PAGE_110+4u));
|
||||
//
|
||||
//
|
||||
//// // Load this address into function pointer
|
||||
//// jump_to_bootloader = (pFunction) jump_address;
|
||||
//
|
||||
// // Clear pending interrupts
|
||||
// SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk;
|
||||
//
|
||||
// // Disable all interrupts
|
||||
// for(int i = 0;i < 8;i++) {
|
||||
// NVIC->ICER[i] = NVIC->IABR[i];
|
||||
// }
|
||||
//
|
||||
// SCB->VTOR = JumpAddress;
|
||||
// // Set stack pointer
|
||||
// //__set_MSP((uint32_t) (bootloader_address[0]));
|
||||
// __set_MSP(JumpAddress);
|
||||
//
|
||||
// // Jump to the bootloader
|
||||
// jump_to_bootloader();
|
||||
//}
|
||||
|
||||
//
|
||||
//typedef void (*pFunction)(void);
|
||||
//pFunction Jump_To_Application;
|
||||
|
||||
|
||||
//void modFlashJumpToBootloader(void)
|
||||
//{
|
||||
// uint32_t JumpAddress;
|
||||
//
|
||||
// HAL_DeInit();
|
||||
// HAL_RCC_DeInit();
|
||||
//
|
||||
// __disable_irq();
|
||||
//
|
||||
// JumpAddress = *( uint32_t*) (ADDR_FLASH_PAGE_110 + 4);
|
||||
// JumpAddress = 0x08037004;
|
||||
// Jump_To_Application = (pFunction)JumpAddress;
|
||||
// /* Initialize user application's Stack Pointer */
|
||||
// __set_MSP(*(__IO uint32_t*) ADDR_FLASH_PAGE_110);
|
||||
//
|
||||
// Jump_To_Application();
|
||||
|
||||
// uint32_t JumpAddress;
|
||||
// JumpAddress = (uint32_t) *((__IO uint32_t*)ADDR_FLASH_PAGE_110);
|
||||
// Jump_To_Application = (pFunction)(*(volatile uint32_t*) (0x08037000+4u));
|
||||
// __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
|
||||
//
|
||||
// for(int i = 0;i < 8;i++) {
|
||||
// NVIC->ICER[i] = NVIC->IABR[i];
|
||||
// }
|
||||
//
|
||||
// SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk;
|
||||
// SCB->VTOR = 0x08037000;
|
||||
// __set_MSP(0x08037000);
|
||||
//
|
||||
// Jump_To_Application();
|
||||
//}
|
||||
|
||||
void deinitEverything()
|
||||
{
|
||||
//-- reset peripherals to guarantee flawless start of user application
|
||||
HAL_TIM_Base_Stop_IT(&htim2);
|
||||
HAL_TIM_Base_Stop_IT(&htim6);
|
||||
MX_USB_DEVICE_DeInit();
|
||||
MX_FATFS_DeInit();
|
||||
HAL_UART_DeInit(&huart2);
|
||||
|
||||
HAL_RCC_DeInit();
|
||||
HAL_DeInit();
|
||||
SysTick->CTRL = 0;
|
||||
SysTick->LOAD = 0;
|
||||
SysTick->VAL = 0;
|
||||
}
|
||||
|
||||
void jumpToBootLoader(void)
|
||||
{
|
||||
uint32_t adr=ADDR_FLASH_PAGE_104;
|
||||
const JumpStruct* vector_p = (JumpStruct*)adr;
|
||||
|
||||
//Total_DeInit();
|
||||
deinitEverything();
|
||||
|
||||
/* let's do The Jump! */
|
||||
/* Jump, used asm to avoid stack optimization */
|
||||
asm("msr msp, %0; bx %1;" : : "r"(vector_p->stack_addr), "r"(vector_p->func_p));
|
||||
}
|
||||
|
||||
void modFlashJumpToMainApplication(void) {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
537
firmware/Core/Src/modOperationalState.c
Normal file
537
firmware/Core/Src/modOperationalState.c
Normal file
@@ -0,0 +1,537 @@
|
||||
///*
|
||||
// Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
// Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
//
|
||||
// This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
//
|
||||
// The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// */
|
||||
//
|
||||
//#include "modOperationalState.h"
|
||||
//
|
||||
//OperationalStateTypedef modOperationalStateLastState;
|
||||
//OperationalStateTypedef modOperationalStateCurrentState;
|
||||
//OperationalStateTypedef modOperationalStateNewState;
|
||||
//bms_fault_state modOperationalStateLastFaultState;
|
||||
//bms_fault_state modOperationalStateCurrentFaultState;
|
||||
//bms_fault_state modOperationalStateNewFaultState;
|
||||
//modPowerElectronicsPackOperationalCellStatesTypedef packOperationalCellStateLastErrorState;
|
||||
//modPowerElectronicsPackStateTypedef *modOperationalStatePackStatehandle;
|
||||
//modConfigGeneralConfigStructTypedef *modOperationalStateGeneralConfigHandle;
|
||||
//modStateOfChargeStructTypeDef *modOperationalStateGeneralStateOfCharge;
|
||||
////nc modDisplayDataTypedef modOperationalStateDisplayData;
|
||||
//uint32_t modOperationalStateChargerTimeout;
|
||||
//uint32_t modOperationalStateChargedTimeout;
|
||||
//uint32_t modOperationalStatePreChargeTimeout;
|
||||
//uint32_t modOperationalStateStartupDelay;
|
||||
//uint32_t modOperationalStateChargerDisconnectDetectDelay;
|
||||
//uint32_t modOperationalStateBatteryDeadDisplayTime;
|
||||
//uint32_t modOperationalStateErrorDisplayTime;
|
||||
//uint32_t modOperationalStateNotUsedResetDelay;
|
||||
//uint32_t modOperationalStateNotUsedTime;
|
||||
//uint32_t modOperationalStatePSPDisableDelay;
|
||||
//uint32_t modOperationalStateWatchDogCountdownLastTick;
|
||||
//bool modOperationalStateForceOn;
|
||||
//
|
||||
//void modOperationalStateInit(modPowerElectronicsPackStateTypedef *packState, modConfigGeneralConfigStructTypedef *generalConfigPointer, modStateOfChargeStructTypeDef *generalStateOfCharge) {
|
||||
// modOperationalStatePackStatehandle = packState;
|
||||
// modOperationalStateGeneralConfigHandle = generalConfigPointer;
|
||||
// modOperationalStateGeneralStateOfCharge = generalStateOfCharge;
|
||||
// modOperationalStateSetAllStates(OP_STATE_INIT);
|
||||
// modOperationalStateStartupDelay = HAL_GetTick();
|
||||
// modOperationalStateChargerDisconnectDetectDelay = HAL_GetTick();
|
||||
// packOperationalCellStateLastErrorState = PACK_STATE_NORMAL;
|
||||
// modOperationalStateForceOn = false;
|
||||
// //nc modDisplayInit();
|
||||
//
|
||||
// //Init Expansion temperature modules
|
||||
// //nc driverSWADC128D818Init(modOperationalStateGeneralConfigHandle->noOfExpansionBoard, 8);
|
||||
//
|
||||
// modOperationalStateNotUsedTime = HAL_GetTick();
|
||||
// modOperationalStateNotUsedResetDelay = HAL_GetTick();
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateTask(void) {
|
||||
// switch(modOperationalStateCurrentState) {
|
||||
// case OP_STATE_INIT:
|
||||
// if(modPowerStateChargerDetected()) { // Check to detect charger
|
||||
// switch(modOperationalStateGeneralConfigHandle->chargeEnableOperationalState){
|
||||
// case opStateChargingModeCharging:
|
||||
// modOperationalStateSetNewState(OP_STATE_CHARGING); // Go to charge state
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_FLASH); // Flash power LED when charging
|
||||
// modOperationalStateChargerDisconnectDetectDelay = HAL_GetTick();
|
||||
// break;
|
||||
// case opStateChargingModeNormal:
|
||||
// default:
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE); // Prepare to goto operational state
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_SET); // Turn LED on in normal operation
|
||||
// break;
|
||||
// }
|
||||
// }else if(modPowerStateButtonPressedOnTurnon()) { // Check if button was pressen on turn-on
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE); // Prepare to goto operational state
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_SET); // Turn LED on in normal operation
|
||||
// }else if(modOperationalStateNewState == OP_STATE_INIT){ // USB or CAN origin of turn-on
|
||||
// switch(modOperationalStateGeneralConfigHandle->externalEnableOperationalState){
|
||||
// case opStateExtNormal:
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE); // Prepare to goto normal operational state
|
||||
// break;
|
||||
// case opStateExternal:
|
||||
// default:
|
||||
// modOperationalStateSetNewState(OP_STATE_EXTERNAL); // Serve external control
|
||||
// break;
|
||||
// }
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_SET); // Turn LED on in normal operation
|
||||
// }
|
||||
//
|
||||
// if(modDelayTick1ms(&modOperationalStateStartupDelay,modOperationalStateGeneralConfigHandle->displayTimeoutSplashScreen)) {// Wait for a bit than update state. Also check voltage after main fuse? followed by going to error state if blown?
|
||||
// if(!modOperationalStatePackStatehandle->disChargeLCAllowed && !modPowerStateChargerDetected()) { // If discharge is not allowed
|
||||
// modOperationalStateSetNewState(OP_STATE_ERROR); // Then the battery is dead
|
||||
// modOperationalStateBatteryDeadDisplayTime = HAL_GetTick();
|
||||
// }
|
||||
// modOperationalStateUpdateStates(); // Sync states
|
||||
// };
|
||||
//
|
||||
// //nc modDisplayShowInfo(DISP_MODE_SPLASH,modOperationalStateDisplayData);
|
||||
// break;
|
||||
// case OP_STATE_CHARGING:
|
||||
// // If chargeAllowed = false -> operational state balancing
|
||||
// if(modOperationalStatePackStatehandle->balanceActive){
|
||||
// modOperationalStateSetNewState(OP_STATE_BALANCING);
|
||||
// }
|
||||
// modOperationalStateHandleChargerDisconnect(OP_STATE_POWER_DOWN);
|
||||
// modPowerElectronicsSetCharge(true);
|
||||
// if(modOperationalStatePackStatehandle->packCurrent >= 0.5f || modOperationalStatePackStatehandle->packCurrent >= modOperationalStateGeneralConfigHandle->chargerEnabledThreshold){
|
||||
// modPowerElectronicsSetChargePFET(true);
|
||||
// }else{
|
||||
// modPowerElectronicsSetChargePFET(false);
|
||||
// };
|
||||
// #if (ENNOID_HV || ENNOID_LV)
|
||||
// //Allow main contactors to close if load voltage is above pack voltage & below max allowed voltage, that means that the charger is connected to the load
|
||||
// if(modOperationalStatePackStatehandle->packVoltage-modOperationalStatePackStatehandle->loCurrentLoadVoltage < (modOperationalStatePackStatehandle->packVoltage*0.1f) && modOperationalStatePackStatehandle->loCurrentLoadVoltage < (modOperationalStateGeneralConfigHandle->noOfCellsSeries*modOperationalStateGeneralConfigHandle->cellHardOverVoltage+10)){
|
||||
// modPowerElectronicsSetDisCharge(true);
|
||||
// if(modOperationalStateGeneralConfigHandle->LCUsePrecharge==forced){
|
||||
// modPowerElectronicsSetPreCharge(true);
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// //Cooling/Heating
|
||||
// if(modOperationalStatePackStatehandle->coolingAllowed )
|
||||
// modPowerElectronicsSetCooling(true);
|
||||
// else{
|
||||
// modPowerElectronicsSetCooling(false);
|
||||
// }
|
||||
//
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modOperationalStateDisplayData.StateOfCharge = modOperationalStateGeneralStateOfCharge->generalStateOfCharge;
|
||||
// //nc modOperationalStateDisplayData.Current = fabs(modOperationalStatePackStatehandle->packCurrent);
|
||||
// //nc modOperationalStateDisplayData.ChargerVoltage = fabs(modOperationalStatePackStatehandle->chargerVoltage);
|
||||
// //nc modDisplayShowInfo(DISP_MODE_CHARGE,modOperationalStateDisplayData);
|
||||
// break;
|
||||
// case OP_STATE_PRE_CHARGE:
|
||||
// // in case of timeout: disable pre charge & go to error state
|
||||
// if(modOperationalStateLastState != modOperationalStateCurrentState) { // If discharge is not allowed pre-charge will not be enabled, therefore reset timeout every task call. Also reset on first entry
|
||||
// modOperationalStatePreChargeTimeout = HAL_GetTick(); // Reset timeout
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// }
|
||||
//
|
||||
// if(modOperationalStatePackStatehandle->disChargeLCAllowed || modOperationalStateForceOn)
|
||||
// modPowerElectronicsSetPreCharge(true);
|
||||
// else{
|
||||
// modPowerElectronicsSetPreCharge(false);
|
||||
// modOperationalStatePreChargeTimeout = HAL_GetTick();
|
||||
// // if(modOperationalStateGeneralConfigHandle->buzzerSignalSource)
|
||||
// //nc modEffectChangeStateError(STAT_BUZZER,STAT_ERROR,modOperationalStatePackStatehandle->faultState);
|
||||
// // }
|
||||
//
|
||||
// if((modOperationalStatePackStatehandle->loCurrentLoadVoltage > modOperationalStatePackStatehandle->packVoltage*modOperationalStateGeneralConfigHandle->minimalPrechargePercentage) && (modOperationalStatePackStatehandle->disChargeLCAllowed || modOperationalStateForceOn)) {
|
||||
// if(modOperationalStateForceOn) {
|
||||
// modOperationalStateSetNewState(OP_STATE_FORCEON); // Goto force on
|
||||
// }else{
|
||||
// modOperationalStateSetNewState(OP_STATE_LOAD_ENABLED); // Goto normal load enabled operation
|
||||
// }
|
||||
// }else if(modDelayTick1ms(&modOperationalStatePreChargeTimeout,modOperationalStateGeneralConfigHandle->timeoutLCPreCharge)){
|
||||
// if(modOperationalStateGeneralConfigHandle->LCUsePrecharge>=1){
|
||||
// modOperationalStateSetNewState(OP_STATE_ERROR_PRECHARGE); // An error occured during pre charge
|
||||
// modOperationalStatePackStatehandle->faultState = FAULT_CODE_PRECHARGE_TIMEOUT;
|
||||
// }else
|
||||
// modOperationalStateSetNewState(OP_STATE_LOAD_ENABLED); // Goto normal load enabled operation
|
||||
// }
|
||||
//
|
||||
// modOperationalStateUpdateStates();
|
||||
// break;
|
||||
// case OP_STATE_LOAD_ENABLED:
|
||||
// if(modPowerElectronicsSetDisCharge(true)) {
|
||||
//
|
||||
// if(modOperationalStateGeneralConfigHandle->LCUsePrecharge==forced){
|
||||
// #if ENNOID_HV
|
||||
// modPowerElectronicsSetPreCharge(true);
|
||||
// #endif
|
||||
// }else{
|
||||
// modPowerElectronicsSetPreCharge(false);
|
||||
// }
|
||||
// if(modPowerStateChargerDetected()){
|
||||
// modPowerElectronicsSetCharge(modOperationalStateGeneralConfigHandle->allowChargingDuringDischarge);
|
||||
// if(modOperationalStatePackStatehandle->packCurrent >= 0.5f || modOperationalStatePackStatehandle->packCurrent >= modOperationalStateGeneralConfigHandle->chargerEnabledThreshold){
|
||||
// modPowerElectronicsSetChargePFET(true);
|
||||
// }
|
||||
// }else{
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// modPowerElectronicsSetChargePFET(false);
|
||||
// }
|
||||
// }else{
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// modPowerElectronicsSetChargePFET(false);
|
||||
// }
|
||||
//
|
||||
// //nc modEffectChangeState(STAT_BUZZER,STAT_RESET);
|
||||
//
|
||||
// //Cooling/Heating
|
||||
// if(modOperationalStatePackStatehandle->coolingAllowed )
|
||||
// modPowerElectronicsSetCooling(true);
|
||||
// else{
|
||||
// modPowerElectronicsSetCooling(false);
|
||||
// }
|
||||
// //Charger detect
|
||||
// if(modPowerStateChargerDetected() && !modOperationalStateGeneralConfigHandle->allowChargingDuringDischarge) {
|
||||
// modOperationalStateSetNewState(OP_STATE_INIT);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// };
|
||||
//
|
||||
//
|
||||
// // Battery is empty or battery temp is out of range?
|
||||
// if(!modOperationalStatePackStatehandle->disChargeLCAllowed) {
|
||||
// //modOperationalStateSetNewState(OP_STATE_ERROR);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// modOperationalStatePackStatehandle->faultState = FAULT_CODE_DISCHARGE_RETRY;
|
||||
// //nc if(modOperationalStateGeneralConfigHandle->buzzerSignalSource)
|
||||
// //nc modEffectChangeStateError(STAT_BUZZER,STAT_ERROR,modOperationalStatePackStatehandle->faultState);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// if(fabs(modOperationalStatePackStatehandle->packCurrent) >= modOperationalStateGeneralConfigHandle->notUsedCurrentThreshold) {
|
||||
// if(modDelayTick1ms(&modOperationalStateNotUsedResetDelay,1000))
|
||||
// modOperationalStateNotUsedTime = HAL_GetTick();
|
||||
// }else{
|
||||
// modOperationalStateNotUsedResetDelay = HAL_GetTick();
|
||||
// }
|
||||
//
|
||||
// if(modOperationalStatePowerDownDelayCheck()) {
|
||||
// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
// }
|
||||
//
|
||||
// if(modOperationalStatePackStatehandle->balanceActive) {
|
||||
// if(!modOperationalStatePackStatehandle->chargeAllowed && (modOperationalStatePackStatehandle->cellVoltageMisMatch < modOperationalStateGeneralConfigHandle->maxMismatchThreshold)){
|
||||
// if(modDelayTick1ms(&modOperationalStateChargedTimeout,modOperationalStateGeneralConfigHandle->timeoutChargingCompletedMinimalMismatch)) {
|
||||
// modStateOfChargeVoltageEvent(EVENT_FULL);
|
||||
// modOperationalStateChargedTimeout = HAL_GetTick();
|
||||
// }
|
||||
// }else{
|
||||
// modOperationalStateChargedTimeout = HAL_GetTick();
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// modOperationalStateUpdateStates();
|
||||
//
|
||||
// //nc modOperationalStateDisplayData.StateOfCharge = modOperationalStateGeneralStateOfCharge->generalStateOfCharge;
|
||||
// //nc modOperationalStateDisplayData.Current = fabs(modOperationalStatePackStatehandle->packCurrent);
|
||||
// //nc modOperationalStateDisplayData.PackVoltage = fabs(modOperationalStatePackStatehandle->packVoltage);
|
||||
// //nc modOperationalStateDisplayData.HighestTemp = fabs(modOperationalStatePackStatehandle->tempBatteryHigh);
|
||||
// //nc modOperationalStateDisplayData.AverageTemp = fabs(modOperationalStatePackStatehandle->tempBatteryAverage);
|
||||
// //nc modOperationalStateDisplayData.LowestTemp = fabs(modOperationalStatePackStatehandle->tempBatteryLow);
|
||||
// //nc modOperationalStateDisplayData.Humidity = fabs(modOperationalStatePackStatehandle->humidity);
|
||||
// //nc modOperationalStateDisplayData.LowestCellVoltage = fabs(modOperationalStatePackStatehandle->cellVoltageLow);
|
||||
// //nc modOperationalStateDisplayData.HighestCellVoltage = fabs(modOperationalStatePackStatehandle->cellVoltageHigh);
|
||||
// //nc modOperationalStateDisplayData.DisplayStyle = modOperationalStateGeneralConfigHandle->displayStyle;
|
||||
//
|
||||
// //nc modDisplayShowInfo(DISP_MODE_LOAD,modOperationalStateDisplayData);
|
||||
// break;
|
||||
// case OP_STATE_BATTERY_DEAD:
|
||||
// //nc modDisplayShowInfo(DISP_MODE_BATTERY_DEAD,modOperationalStateDisplayData);
|
||||
//// if(modDelayTick1ms(&modOperationalStateBatteryDeadDisplayTime,modOperationalStateGeneralConfigHandle->displayTimeoutBatteryDead)){
|
||||
//// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
//// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
//// modOperationalStatePackStatehandle->faultState = FAULT_CODE_PACK_UNDER_VOLTAGE;
|
||||
//// }
|
||||
// modOperationalStateUpdateStates();
|
||||
// break;
|
||||
// case OP_STATE_POWER_DOWN:
|
||||
// if(modOperationalStateLastState != modOperationalStateCurrentState) {
|
||||
// modOperationalStatePSPDisableDelay = HAL_GetTick();
|
||||
// }
|
||||
// modPowerElectronicsDisableAll(); // Disable all power paths
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_RESET); // Turn off power LED
|
||||
// //nc modEffectChangeState(STAT_LED_DEBUG,STAT_RESET);
|
||||
// //nc if(!modOperationalStateGeneralConfigHandle->buzzerSignalPersistant)
|
||||
// //nc modEffectChangeState(STAT_BUZZER,STAT_RESET);
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modDisplayShowInfo(DISP_MODE_POWEROFF,modOperationalStateDisplayData);
|
||||
// if(modDelayTick1ms(&modOperationalStatePSPDisableDelay,modOperationalStateGeneralConfigHandle->powerDownDelay)) { // Wait for the power down delay time to pass
|
||||
// modOperationalStateTerminateOperation(); // Disable powersupply and store SoC
|
||||
// }
|
||||
// break;
|
||||
// case OP_STATE_EXTERNAL: // BMS is turned on by external force IE CAN or USB
|
||||
// if(modOperationalStateLastState != modOperationalStateCurrentState) {
|
||||
// modPowerElectronicsSetPreCharge(false);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// }
|
||||
//
|
||||
// modOperationalStateTerminateOperation(); // Disable power and store SoC
|
||||
// //nc modDisplayShowInfo(DISP_MODE_EXTERNAL,modOperationalStateDisplayData);
|
||||
//
|
||||
// break;
|
||||
// case OP_STATE_ERROR:
|
||||
// // Go to save state and in the future -> try to handle error situation
|
||||
// if(modOperationalStateLastState != modOperationalStateCurrentState)
|
||||
// modOperationalStateErrorDisplayTime = HAL_GetTick();
|
||||
//
|
||||
// if(modDelayTick1ms(&modOperationalStateErrorDisplayTime,modOperationalStateGeneralConfigHandle->displayTimeoutBatteryError)) {
|
||||
// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
// }
|
||||
//
|
||||
// //nc modEffectChangeStateError(STAT_LED_DEBUG,STAT_ERROR,modOperationalStatePackStatehandle->faultState); // Turn flash fast on debug and power LED
|
||||
// //nc modEffectChangeStateError(STAT_LED_POWER,STAT_ERROR,modOperationalStatePackStatehandle->faultState);
|
||||
// if(modOperationalStateGeneralConfigHandle->buzzerSignalSource)
|
||||
// //nc modEffectChangeStateError(STAT_BUZZER,STAT_ERROR,modOperationalStatePackStatehandle->faultState); // Turn flash fast on debug and power LED
|
||||
// modPowerElectronicsDisableAll();
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modOperationalStateDisplayData.FaultCode = modOperationalStatePackStatehandle->faultState;
|
||||
// //nc modDisplayShowInfo(DISP_MODE_ERROR,modOperationalStateDisplayData);
|
||||
//
|
||||
// break;
|
||||
// case OP_STATE_ERROR_PRECHARGE:
|
||||
// // Go to save state and in the future -> try to handle error situation
|
||||
// if(modOperationalStateLastState != modOperationalStateCurrentState)
|
||||
// modOperationalStateErrorDisplayTime = HAL_GetTick();
|
||||
//
|
||||
// if(modDelayTick1ms(&modOperationalStateErrorDisplayTime,modOperationalStateGeneralConfigHandle->displayTimeoutBatteryErrorPreCharge)) {
|
||||
// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
// }
|
||||
//
|
||||
// //nc modEffectChangeState(STAT_LED_DEBUG,STAT_FLASH_FAST); // Turn flash fast on debug and power LED
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_FLASH_FAST); // Turn flash fast on debug and power LED
|
||||
// //nc if(modOperationalStateGeneralConfigHandle->buzzerSignalSource)
|
||||
// //nc modEffectChangeStateError(STAT_BUZZER,STAT_ERROR,modOperationalStatePackStatehandle->faultState);
|
||||
// modPowerElectronicsDisableAll();
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modDisplayShowInfo(DISP_MODE_ERROR_PRECHARGE,modOperationalStateDisplayData);
|
||||
// break;
|
||||
// case OP_STATE_BALANCING:
|
||||
// // update timeout time for balancing and use charging manager for enable state charge input
|
||||
// if(modOperationalStatePackStatehandle->packCurrent < modOperationalStateGeneralConfigHandle->chargerEnabledThreshold && modOperationalStatePackStatehandle->chargeAllowed){
|
||||
// if(modDelayTick1ms(&modOperationalStateChargerTimeout,modOperationalStateGeneralConfigHandle->timeoutChargeCompleted)) {
|
||||
// modOperationalStateSetAllStates(OP_STATE_CHARGED);
|
||||
// modStateOfChargeVoltageEvent(EVENT_FULL);
|
||||
// }
|
||||
// }else{
|
||||
// modOperationalStateChargerTimeout = HAL_GetTick();
|
||||
// };
|
||||
//
|
||||
// if(!modOperationalStatePackStatehandle->chargeAllowed && (modOperationalStatePackStatehandle->cellVoltageMisMatch < modOperationalStateGeneralConfigHandle->maxMismatchThreshold)){
|
||||
// if(modDelayTick1ms(&modOperationalStateChargedTimeout,modOperationalStateGeneralConfigHandle->timeoutChargingCompletedMinimalMismatch)) {
|
||||
// modOperationalStateSetAllStates(OP_STATE_CHARGED);
|
||||
// modStateOfChargeVoltageEvent(EVENT_FULL);
|
||||
// }
|
||||
// }else{
|
||||
// modOperationalStateChargedTimeout = HAL_GetTick();
|
||||
// };
|
||||
//
|
||||
// modOperationalStateHandleChargerDisconnect(OP_STATE_POWER_DOWN);
|
||||
// if(modOperationalStatePackStatehandle->chargeAllowed){
|
||||
// modPowerElectronicsSetCharge(true);
|
||||
// if(modOperationalStatePackStatehandle->packCurrent >= 0.5f || modOperationalStatePackStatehandle->packCurrent >= modOperationalStateGeneralConfigHandle->chargerEnabledThreshold){
|
||||
// modPowerElectronicsSetChargePFET(true);
|
||||
// }
|
||||
//
|
||||
// #if (ENNOID_HV || ENNOID_LV)
|
||||
// if(modOperationalStatePackStatehandle->packVoltage-modOperationalStatePackStatehandle->loCurrentLoadVoltage < (modOperationalStatePackStatehandle->packVoltage*0.1f) && modOperationalStatePackStatehandle->loCurrentLoadVoltage < (modOperationalStateGeneralConfigHandle->noOfCellsSeries*modOperationalStateGeneralConfigHandle->cellHardOverVoltage+10.0f)){
|
||||
// modPowerElectronicsSetDisCharge(true);
|
||||
// if(modOperationalStateGeneralConfigHandle->LCUsePrecharge==forced){
|
||||
// modPowerElectronicsSetPreCharge(true);
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }else{
|
||||
// modPowerElectronicsSetChargePFET(false);
|
||||
// modPowerElectronicsSetCharge(false);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// modPowerElectronicsSetPreCharge(false);
|
||||
// modOperationalStatePackStatehandle->faultState = FAULT_CODE_CHARGE_RETRY;
|
||||
// };
|
||||
//
|
||||
// //Cooling/Heating
|
||||
// if(modOperationalStatePackStatehandle->coolingAllowed )
|
||||
// modPowerElectronicsSetCooling(true);
|
||||
// else{
|
||||
// modPowerElectronicsSetCooling(false);
|
||||
// }
|
||||
//
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modOperationalStateDisplayData.StateOfCharge = modOperationalStateGeneralStateOfCharge->generalStateOfCharge;
|
||||
// //nc modOperationalStateDisplayData.CellMismatch = fabs(modOperationalStatePackStatehandle->cellVoltageMisMatch);
|
||||
// //nc modOperationalStateDisplayData.AverageCellVoltage = fabs(modOperationalStatePackStatehandle->cellVoltageAverage);
|
||||
// //nc modDisplayShowInfo(DISP_MODE_BALANCING,modOperationalStateDisplayData);
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_BLINKSHORTLONG_100_20); // Indicate balancing
|
||||
// break;
|
||||
// case OP_STATE_CHARGED:
|
||||
// modOperationalStateHandleChargerDisconnect(OP_STATE_POWER_DOWN);
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_BLINKSHORTLONG_1000_4); // Indicate Charged
|
||||
// modOperationalStateUpdateStates();
|
||||
// //nc modDisplayShowInfo(DISP_MODE_CHARGED,modOperationalStateDisplayData);
|
||||
// break;
|
||||
// case OP_STATE_FORCEON:
|
||||
// if(modPowerElectronicsSetDisCharge(true))
|
||||
// modPowerElectronicsSetPreCharge(false);
|
||||
// else {
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE);
|
||||
// modPowerElectronicsSetDisCharge(false);
|
||||
// }
|
||||
//
|
||||
// if(fabs(modOperationalStatePackStatehandle->packCurrent) >= modOperationalStateGeneralConfigHandle->notUsedCurrentThreshold) {
|
||||
// if(modDelayTick1ms(&modOperationalStateNotUsedResetDelay,1000))
|
||||
// modOperationalStateNotUsedTime = HAL_GetTick();
|
||||
// }else{
|
||||
// modOperationalStateNotUsedResetDelay = HAL_GetTick();
|
||||
// }
|
||||
//
|
||||
// if(modOperationalStatePowerDownDelayCheck()) {
|
||||
// modOperationalStateSetNewFaultState(FAULT_CODE_NOT_USED_TIMEOUT);
|
||||
// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
// }
|
||||
//
|
||||
// //nc modDisplayShowInfo(DISP_MODE_FORCED_ON,modOperationalStateDisplayData);
|
||||
// //nc modEffectChangeState(STAT_LED_POWER,STAT_BLINKSHORTLONG_1000_4); // Turn flash fast on debug and power LED
|
||||
// modOperationalStateUpdateStates();
|
||||
// break;
|
||||
// default:
|
||||
// modOperationalStateSetAllStates(OP_STATE_ERROR);
|
||||
// break;
|
||||
// };
|
||||
//
|
||||
// if(modPowerStateForceOnRequest()){
|
||||
// modOperationalStateForceOn = true;
|
||||
// modPowerElectronicsAllowForcedOn(true);
|
||||
// modOperationalStateSetNewState(OP_STATE_PRE_CHARGE);
|
||||
// driverSWStorageManagerEraseData();
|
||||
// };
|
||||
//
|
||||
// // Check for power button longpress -> if so power down BMS
|
||||
// if(modPowerStatePowerdownRequest()) {
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
//
|
||||
// if(modOperationalStateDelayedDisable(modOperationalStateGeneralConfigHandle->useCANDelayedPowerDown)) {
|
||||
// modOperationalStateSetNewFaultState(FAULT_CODE_CAN_DELAYED_POWER_DOWN);
|
||||
// modOperationalStateSetNewState(OP_STATE_POWER_DOWN);
|
||||
// //nc modDisplayShowInfo(DISP_MODE_POWEROFF,modOperationalStateDisplayData);
|
||||
// modOperationalStateUpdateFaultStates();
|
||||
//
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // In case of extreme cellvoltages or temperatures goto error state
|
||||
// if((modOperationalStatePackStatehandle->packOperationalCellState == PACK_STATE_ERROR_HARD_CELLVOLTAGE || modOperationalStatePackStatehandle->packOperationalCellState == PACK_STATE_ERROR_TEMPERATURE) && (modOperationalStatePackStatehandle->packOperationalCellState != packOperationalCellStateLastErrorState) && !modOperationalStateForceOn){
|
||||
// packOperationalCellStateLastErrorState = modOperationalStatePackStatehandle->packOperationalCellState; // Meganism to make error situation only trigger once
|
||||
// modOperationalStateSetNewState(OP_STATE_ERROR);
|
||||
// modOperationalStateUpdateStates();
|
||||
// }
|
||||
//
|
||||
// // In case of extreme currents goto error state
|
||||
// if((modOperationalStatePackStatehandle->packOperationalCellState == PACK_STATE_ERROR_OVER_CURRENT) && (modOperationalStatePackStatehandle->packOperationalCellState != packOperationalCellStateLastErrorState)){
|
||||
// packOperationalCellStateLastErrorState = modOperationalStatePackStatehandle->packOperationalCellState; // Meganism to make error situation only trigger once
|
||||
// modOperationalStatePackStatehandle->faultState = FAULT_CODE_OVER_CURRENT;
|
||||
// modOperationalStateSetNewState(OP_STATE_ERROR);
|
||||
// modOperationalStateUpdateStates();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// // Move the button pressed state to the status struct
|
||||
// modOperationalStatePackStatehandle->powerOnLongButtonPress = modPowerStateGetLongButtonPressState();
|
||||
//
|
||||
// // Handle subtask-display to update display content
|
||||
// //nc modDisplayTask();
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void modOperationalStateUpdateStates(void) {
|
||||
// modOperationalStateLastState = modOperationalStateCurrentState;
|
||||
// modOperationalStatePackStatehandle->operationalState = modOperationalStateCurrentState = modOperationalStateNewState;
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateSetAllStates(OperationalStateTypedef newState) {
|
||||
// modOperationalStatePackStatehandle->operationalState = modOperationalStateLastState = modOperationalStateCurrentState = modOperationalStateNewState = newState;
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateSetNewState(OperationalStateTypedef newState) {
|
||||
// modOperationalStateNewState = newState;
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateHandleChargerDisconnect(OperationalStateTypedef newState) {
|
||||
// if(modPowerStateChargerDetected() && !((modOperationalStatePackStatehandle->packCurrent < modOperationalStateGeneralConfigHandle->chargerEnabledThreshold ) && modOperationalStatePackStatehandle->chargeDesired && modOperationalStatePackStatehandle->chargeAllowed)) {
|
||||
// modOperationalStateChargerDisconnectDetectDelay = HAL_GetTick();
|
||||
// }else{
|
||||
// if(modDelayTick1ms(&modOperationalStateChargerDisconnectDetectDelay,modOperationalStateGeneralConfigHandle->timeoutChargerDisconnected)){
|
||||
// modOperationalStateSetAllStates(newState);
|
||||
// modOperationalStatePackStatehandle->powerDownDesired = true;
|
||||
// }
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateTerminateOperation(void) {
|
||||
// // Store the state of charge data
|
||||
// modStateOfChargePowerDownSave(); // Store the SoC data
|
||||
//
|
||||
// // Disable the power supply
|
||||
// modPowerStateSetState(P_STAT_RESET); // Turn off the power
|
||||
//}
|
||||
//
|
||||
//bool modOperationalStateDelayedDisable(bool delayedPowerDownDesired) {
|
||||
// if(delayedPowerDownDesired){
|
||||
// if(modOperationalStatePackStatehandle->watchDogTime){
|
||||
// if(modDelayTick1ms(&modOperationalStateWatchDogCountdownLastTick,1000))
|
||||
// modOperationalStatePackStatehandle->watchDogTime--;
|
||||
//
|
||||
// return false;
|
||||
// }else{
|
||||
// return true;
|
||||
// }
|
||||
// }else{
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//bool modOperationalStatePowerDownDelayCheck(void){
|
||||
// return modDelayTick1ms(&modOperationalStateNotUsedTime,modOperationalStateGeneralConfigHandle->notUsedTimeout) && modOperationalStateGeneralConfigHandle->notUsedTimeout;
|
||||
//}
|
||||
//
|
||||
//void modOperationalStateUpdateFaultStates(void) {
|
||||
// modOperationalStateLastFaultState = modOperationalStateCurrentFaultState;
|
||||
// modOperationalStatePackStatehandle->faultState = modOperationalStateCurrentFaultState = modOperationalStateNewFaultState;
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateSetAllFaultStates(bms_fault_state newFaultState) {
|
||||
// modOperationalStatePackStatehandle->faultState = modOperationalStateLastFaultState = modOperationalStateCurrentFaultState = modOperationalStateNewFaultState = newFaultState;
|
||||
//};
|
||||
//
|
||||
//void modOperationalStateSetNewFaultState(bms_fault_state newFaultState) {
|
||||
// modOperationalStateNewFaultState = newFaultState;
|
||||
//};
|
||||
1374
firmware/Core/Src/modPowerElectronics.c
Normal file
1374
firmware/Core/Src/modPowerElectronics.c
Normal file
File diff suppressed because it is too large
Load Diff
160
firmware/Core/Src/modPowerState.c
Normal file
160
firmware/Core/Src/modPowerState.c
Normal file
@@ -0,0 +1,160 @@
|
||||
///*
|
||||
// Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
// Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
//
|
||||
// This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
//
|
||||
// The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// */
|
||||
//
|
||||
//#include "modPowerState.h"
|
||||
//
|
||||
//modConfigGeneralConfigStructTypedef *modPowerStateGeneralConfigHandle;
|
||||
//
|
||||
//bool modPowerStatePulsePowerDownDesired;
|
||||
//bool modPowerStateForceOnDesired;
|
||||
//bool modPowerStateButtonPressedVar;
|
||||
//bool modPowerStateLastButtonPressedVar;
|
||||
//bool modPowerStateLastButtonFirstPress;
|
||||
//bool modPowerStateButtonActuated;
|
||||
//bool modPowerStateButtonPulsToggleMode;
|
||||
//bool modPowerStatePowerModeDirectHCDelay;
|
||||
//bool modPowerStateLongStartupButtonPress;
|
||||
//uint32_t modPowerStateButtonPressedDuration;
|
||||
//uint32_t modPowerStateButtonPressedTimeStamp;
|
||||
//uint32_t modPowerStateStartupDelay;
|
||||
//uint32_t modPowerStatePowerDownTimeout;
|
||||
//
|
||||
//bool tempButtonPressed;
|
||||
//
|
||||
//void modPowerStateInit(PowerStateStateTypedef desiredPowerState) {
|
||||
// uint32_t startupDelay = HAL_GetTick();
|
||||
// modPowerStateStartupDelay = HAL_GetTick();
|
||||
// modPowerStatePowerDownTimeout = HAL_GetTick();
|
||||
// modPowerStatePulsePowerDownDesired = false;
|
||||
// modPowerStateForceOnDesired = false;
|
||||
// modPowerStateButtonPressedVar = true;
|
||||
// modPowerStateLongStartupButtonPress = false;
|
||||
// modPowerStateButtonPulsToggleMode = true;
|
||||
// modPowerStateButtonPressedDuration = 0;
|
||||
// modPowerStateButtonPressedTimeStamp = 0;
|
||||
// modPowerStateButtonActuated = false;
|
||||
//
|
||||
// driverHWPowerStateInit();
|
||||
//
|
||||
// while(!modDelayTick1ms(&modPowerStateStartupDelay,20)); // Needed for power button signal to reach uC
|
||||
// modPowerStateLastButtonFirstPress = modPowerStateLastButtonPressedVar = driverHWPowerStateReadInput(P_STAT_BUTTON_INPUT);
|
||||
//
|
||||
// if(!modPowerStateLastButtonFirstPress) {
|
||||
// while(!modDelayTick1ms(&modPowerStateStartupDelay,100));
|
||||
// }
|
||||
//
|
||||
// modPowerStateSetState(desiredPowerState);
|
||||
//};
|
||||
//
|
||||
//
|
||||
//
|
||||
//void modPowerStateSetConfigHandle(modConfigGeneralConfigStructTypedef *generalConfigPointer) {
|
||||
// modPowerStateGeneralConfigHandle = generalConfigPointer;
|
||||
//
|
||||
// modPowerStateButtonPulsToggleMode = modPowerStateGeneralConfigHandle->pulseToggleButton;
|
||||
// modPowerStatePowerModeDirectHCDelay = modPowerStateGeneralConfigHandle->togglePowerModeDirectHCDelay;
|
||||
//}
|
||||
//
|
||||
//void modPowerStateTask(void) {
|
||||
// //bool tempButtonPressed = driverHWPowerStateReadInput(P_STAT_BUTTON_INPUT);
|
||||
// tempButtonPressed = driverHWPowerStateReadInput(P_STAT_BUTTON_INPUT);
|
||||
//
|
||||
// if(modPowerStateLastButtonPressedVar != tempButtonPressed) {
|
||||
// if(modPowerStateLastButtonPressedVar){ // If is was high and now low (actuated)
|
||||
// modPowerStateLastButtonFirstPress = false;
|
||||
// modPowerStateButtonActuated = true;
|
||||
// }else{ // If is was low and now high (non actuated)
|
||||
// modPowerStateButtonPressedTimeStamp = HAL_GetTick();
|
||||
// modPowerStateButtonActuated = false;
|
||||
// }
|
||||
// modPowerStateLastButtonPressedVar = tempButtonPressed;
|
||||
// }
|
||||
//
|
||||
// if(tempButtonPressed) {
|
||||
// modPowerStateButtonPressedDuration = HAL_GetTick() - modPowerStateButtonPressedTimeStamp;
|
||||
//
|
||||
// if((modPowerStateButtonPressedDuration > POWERBUTTON_DEBOUNCE_TIME) && (modPowerStateLastButtonFirstPress == false))
|
||||
// modPowerStateButtonPressedVar = true;
|
||||
//
|
||||
// if((modPowerStateButtonPressedDuration >= POWERBUTTON_POWERDOWN_THRESHOLD_TIME) && (modPowerStateLastButtonFirstPress == false) && modPowerStateGeneralConfigHandle->pulseToggleButton) {
|
||||
// modPowerStatePulsePowerDownDesired = true;
|
||||
// modPowerStateButtonPressedDuration = 0;
|
||||
// }
|
||||
//
|
||||
// if((modPowerStateButtonPressedDuration >= POWERBUTTON_FORCEON_THRESHOLD_TIME) && (modPowerStateLastButtonFirstPress == true) && modPowerStateGeneralConfigHandle->pulseToggleButton) {
|
||||
// if(modPowerStateGeneralConfigHandle->allowForceOn) {
|
||||
// modPowerStateForceOnDesired = true;
|
||||
// }
|
||||
//
|
||||
// modPowerStateLongStartupButtonPress = true;
|
||||
// modPowerStateButtonPressedDuration = 0;
|
||||
// }
|
||||
//
|
||||
// modPowerStatePowerDownTimeout = HAL_GetTick();
|
||||
// }else{
|
||||
// if(modDelayTick1ms(&modPowerStatePowerDownTimeout,500) && modPowerStateButtonActuated)
|
||||
// modPowerStateButtonPressedVar = false;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//bool modPowerStateGetButtonPressedState(void) {
|
||||
// return modPowerStateButtonPressedVar;
|
||||
//};
|
||||
//
|
||||
//bool modPowerStateChargerDetected(void) {
|
||||
// static bool chargeDetect = false;
|
||||
// chargeDetect = driverHWPowerStateReadInput(P_STAT_CHARGE_DETECT);
|
||||
// return chargeDetect;
|
||||
//};
|
||||
//
|
||||
//bool modPowerStatePowerdownRequest(void) {
|
||||
// bool returnValue = false;
|
||||
//
|
||||
// if(modPowerStateGeneralConfigHandle->pulseToggleButton){
|
||||
// returnValue = modPowerStatePulsePowerDownDesired;
|
||||
// }else{
|
||||
// returnValue = !modPowerStateButtonPressedVar;
|
||||
// }
|
||||
// return returnValue;
|
||||
//};
|
||||
//
|
||||
//bool modPowerStateForceOnRequest(void) {
|
||||
// static bool firstTrigger = true;
|
||||
//
|
||||
// if(modPowerStateForceOnDesired && firstTrigger){
|
||||
// modPowerStateForceOnDesired = false;
|
||||
// firstTrigger = false;
|
||||
// return true;
|
||||
// }else{
|
||||
// return false;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//void modPowerStateSetState(PowerStateStateTypedef newState) {
|
||||
// driverHWPowerStateSetOutput(P_STAT_POWER_ENABLE,newState);
|
||||
//};
|
||||
//
|
||||
//bool modPowerStateButtonPressedOnTurnon(void) {
|
||||
// return modPowerStateLastButtonFirstPress;
|
||||
//};
|
||||
//
|
||||
//bool modPowerStateGetLongButtonPressState(void) {
|
||||
// return modPowerStateLongStartupButtonPress;
|
||||
//}
|
||||
226
firmware/Core/Src/modStateOfCharge.c
Normal file
226
firmware/Core/Src/modStateOfCharge.c
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "modStateOfCharge.h"
|
||||
#include "main.h"
|
||||
|
||||
modStateOfChargeStructTypeDef modStateOfChargeGeneralStateOfCharge;
|
||||
modPowerElectronicsPackStateTypedef *modStateOfChargePackStatehandle;
|
||||
modConfigGeneralConfigStructTypedef *modStateOfChargeGeneralConfigHandle;
|
||||
uint32_t modStateOfChargeLargeCoulombTick;
|
||||
uint32_t modStateOfChargeStoreSoCTick;
|
||||
|
||||
bool modStateOfChargePowerDownSavedFlag = false;
|
||||
|
||||
modStateOfChargeStructTypeDef* modStateOfChargeInit(modPowerElectronicsPackStateTypedef *packState, modConfigGeneralConfigStructTypedef *generalConfigPointer){
|
||||
modStateOfChargePackStatehandle = packState;
|
||||
modStateOfChargeGeneralConfigHandle = generalConfigPointer;
|
||||
driverSWStorageManagerStateOfChargeStructSize = (sizeof(modStateOfChargeStructTypeDef)/sizeof(uint16_t)); // Calculate the space needed for the config struct in EEPROM
|
||||
|
||||
modStateOfChargeLargeCoulombTick = HAL_GetTick();
|
||||
modStateOfChargeStoreSoCTick = HAL_GetTick();
|
||||
|
||||
return &modStateOfChargeGeneralStateOfCharge;
|
||||
};
|
||||
|
||||
float real_capacity = 0;
|
||||
float previous_capacity = 0;
|
||||
float previous_SoC = 0;
|
||||
//static float current_SoC = 0;
|
||||
float soc_diff = 0;
|
||||
float capacity_diff = 0;
|
||||
uint8_t SoC_Save_Flag = 0;
|
||||
|
||||
void modStateOfChargeProcess(void){
|
||||
// Calculate accumulated energy
|
||||
uint32_t dt = HAL_GetTick() - modStateOfChargeLargeCoulombTick;
|
||||
|
||||
static float lastsaved_remainingCapacityAh = 0;
|
||||
modStateOfChargeStructTypeDef lastGeneralStateOfCharge;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
* <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD>
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*
|
||||
* soc = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> * 100
|
||||
*
|
||||
* <20> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 1% (<28><>)
|
||||
* b - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> 5% (<28><>) ( x amp - 5%
|
||||
* y amp - 100%; y = 100x/5
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> = ( 100 * <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> ) / <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*
|
||||
* 100 * 2 /1 = 200
|
||||
*
|
||||
* *
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,4<><34><EFBFBD>
|
||||
* <20><> = (100 * 1.4) / 1 = 140 <20><><EFBFBD>
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2,8<><38><EFBFBD>
|
||||
* (100 * 2,8) /1 = 280 <20><><EFBFBD>
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2%, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,4
|
||||
* (100 * 1.4) /2 70 <20><><EFBFBD>
|
||||
*
|
||||
*
|
||||
*
|
||||
* soh
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 150, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 1,5, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 99%
|
||||
*
|
||||
*
|
||||
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>) <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*
|
||||
* soh = <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*
|
||||
* soc =
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
lastGeneralStateOfCharge = modStateOfChargeGeneralStateOfCharge;
|
||||
|
||||
modStateOfChargeLargeCoulombTick = HAL_GetTick();
|
||||
// calc in Ahmps how much we put or take
|
||||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh += dt*modStateOfChargePackStatehandle->packCurrent/(3600*1000);// (miliseconds * amps)/(3600*1000) accumulatedCharge in AmpHour.
|
||||
|
||||
// Cap the max stored energy to the configured battery capacity.
|
||||
// if we put more than battery is, set maximum
|
||||
if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh > modStateOfChargeGeneralConfigHandle->batteryCapacity)
|
||||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||||
|
||||
// if we take more than battery, set zero
|
||||
if(modStateOfChargeGeneralStateOfCharge.remainingCapacityAh < 0.0f)
|
||||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = 0.0f;
|
||||
|
||||
// Calculate state of charge
|
||||
// calc percent of we put/take to battery capacity
|
||||
modStateOfChargeGeneralStateOfCharge.generalStateOfCharge = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh / modStateOfChargeGeneralConfigHandle->batteryCapacity * 100.0f;
|
||||
|
||||
if(SoC_Save_Flag == 0) {
|
||||
previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||||
previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||||
|
||||
SoC_Save_Flag = 1;
|
||||
}
|
||||
|
||||
if(previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge > 1) {
|
||||
soc_diff = previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||||
//
|
||||
if(soc_diff == 0) soc_diff = 1;
|
||||
capacity_diff = previous_capacity - modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||||
real_capacity = (100 * capacity_diff) / soc_diff;
|
||||
|
||||
export_real_capacity = real_capacity;
|
||||
|
||||
previous_SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||||
previous_capacity = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||||
|
||||
//SoC_Save_Flag = 0;
|
||||
|
||||
} //else if (previous_SoC - modStateOfChargeGeneralStateOfCharge.generalStateOfCharge < -1) {
|
||||
// SoC_Save_Flag = 0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
// if we have more than 100% it is 100%
|
||||
if(modStateOfChargeGeneralStateOfCharge.generalStateOfCharge >= 100.0f)
|
||||
modStateOfChargeGeneralStateOfCharge.generalStateOfCharge = 100.0f;
|
||||
|
||||
// save soc and amps
|
||||
modStateOfChargePackStatehandle->SoC = modStateOfChargeGeneralStateOfCharge.generalStateOfCharge;
|
||||
modStateOfChargePackStatehandle->SoCCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||||
|
||||
// Store SoC every 'stateOfChargeStoreInterval'
|
||||
|
||||
modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval = 10000;
|
||||
|
||||
|
||||
|
||||
if(modDelayTick1ms(&modStateOfChargeStoreSoCTick,modStateOfChargeGeneralConfigHandle->stateOfChargeStoreInterval) &&
|
||||
(lastsaved_remainingCapacityAh != modStateOfChargeGeneralStateOfCharge.remainingCapacityAh)) {
|
||||
lastsaved_remainingCapacityAh = modStateOfChargeGeneralStateOfCharge.remainingCapacityAh;
|
||||
modStateOfChargeStoreStateOfCharge();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
bool modStateOfChargeStoreAndLoadDefaultStateOfCharge(void){
|
||||
bool returnVal = false;
|
||||
if(driverSWStorageManagerStateOfChargeEmpty){
|
||||
// TODO: SoC manager is empy -> Determin SoC from voltage when voltages are available.
|
||||
modStateOfChargeStructTypeDef defaultStateOfCharge;
|
||||
defaultStateOfCharge.generalStateOfCharge = 100.0f;
|
||||
defaultStateOfCharge.generalStateOfHealth = 100.0f;
|
||||
defaultStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||||
defaultStateOfCharge.remainingCapacityWh = 0.0f;
|
||||
|
||||
driverSWStorageManagerStateOfChargeEmpty = false;
|
||||
driverSWStorageManagerStoreStruct(&defaultStateOfCharge,STORAGE_STATEOFCHARGE);
|
||||
// TODO_EEPROM
|
||||
}
|
||||
|
||||
modStateOfChargeStructTypeDef tempStateOfCharge;
|
||||
driverSWStorageManagerGetStruct(&tempStateOfCharge,STORAGE_STATEOFCHARGE);
|
||||
|
||||
modStateOfChargeLoadStateOfCharge();
|
||||
return returnVal;
|
||||
};
|
||||
|
||||
bool modStateOfChargeStoreStateOfCharge(void){
|
||||
HAL_GPIO_TogglePin(HL2_GPIO_Port, HL2_Pin);
|
||||
return driverSWStorageManagerStoreStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
|
||||
};
|
||||
|
||||
bool modStateOfChargeLoadStateOfCharge(void){
|
||||
return driverSWStorageManagerGetStruct(&modStateOfChargeGeneralStateOfCharge,STORAGE_STATEOFCHARGE);
|
||||
};
|
||||
|
||||
bool modStateOfChargePowerDownSave(void) {
|
||||
// if(!modStateOfChargePowerDownSavedFlag) {
|
||||
// modStateOfChargePowerDownSavedFlag = true;
|
||||
// modStateOfChargeStoreStateOfCharge();
|
||||
// // TODO_EEPROM
|
||||
// return true;
|
||||
// }else
|
||||
// return false;
|
||||
};
|
||||
|
||||
void modStateOfChargeVoltageEvent(modStateOfChargeVoltageEventTypeDef eventType) {
|
||||
switch(eventType) {
|
||||
case EVENT_EMPTY:
|
||||
break;
|
||||
case EVENT_FULL:
|
||||
modStateOfChargeGeneralStateOfCharge.remainingCapacityAh = modStateOfChargeGeneralConfigHandle->batteryCapacity;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
587
firmware/Core/Src/modTerminal.c
Normal file
587
firmware/Core/Src/modTerminal.c
Normal file
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
Copyright 2016 Benjamin Vedder benjamin@vedder.se
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the VESC/DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The VESC/DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The VESC/DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "modTerminal.h"
|
||||
#include "main.h"
|
||||
#include "time.h"
|
||||
#include "rtc.h"
|
||||
|
||||
#include "modStateOfCharge.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Private types
|
||||
typedef struct _terminal_callback_struct {
|
||||
const char *command;
|
||||
const char *help;
|
||||
const char *arg_names;
|
||||
void(*cbf)(int argc, const char **argv);
|
||||
} terminal_callback_struct;
|
||||
|
||||
// Private variables
|
||||
static terminal_callback_struct callbacks[CALLBACK_LEN];
|
||||
static int callback_write = 0;
|
||||
|
||||
extern modConfigGeneralConfigStructTypedef *generalConfig;
|
||||
extern modStateOfChargeStructTypeDef *generalStateOfCharge;
|
||||
extern modPowerElectronicsPackStateTypedef packState;
|
||||
extern OperationalStateTypedef modOperationalStateCurrentState;
|
||||
|
||||
extern SIM800_Global_Struct SIM800_Struct;
|
||||
|
||||
extern bool jumpBootloaderTrue;
|
||||
|
||||
void modTerminalProcessString(char *str) {
|
||||
|
||||
struct tm tm_PC_Time = {0};
|
||||
Time_Struct PC_time;
|
||||
uint64_t NewSerial;
|
||||
|
||||
enum { kMaxArgs = 64 };
|
||||
int argc = 0;
|
||||
char *argv[kMaxArgs];
|
||||
|
||||
char* ptr;
|
||||
|
||||
char *p2 = strtok(str, " ");
|
||||
while (p2 && argc < kMaxArgs) {
|
||||
argv[argc++] = p2;
|
||||
p2 = strtok(0, " ");
|
||||
}
|
||||
|
||||
if (argc == 0) {
|
||||
modCommandsPrintf("No command received\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "ping") == 0) {
|
||||
modCommandsPrintf("pong\n");
|
||||
} else if (strcmp(argv[0], "status") == 0) {
|
||||
bool disChargeEnabled = packState.disChargeDesired && packState.disChargeLCAllowed;
|
||||
bool chargeEnabled = packState.chargeDesired && packState.chargeAllowed;
|
||||
|
||||
|
||||
/*
|
||||
static float real_capacity = 0;
|
||||
static float previous_capacity = 0;
|
||||
static float previous_SoC = 0;
|
||||
//static float current_SoC = 0;
|
||||
static float soc_diff = 0;
|
||||
static float capacity_diff = 0;
|
||||
static uint8_t SoC_Save_Flag = 0;
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
uint8_t Pilot_Status = 0;
|
||||
uint8_t Maximum_Charge_Current_Status = 0;
|
||||
uint8_t Maximum_Voltage_Status = 0;
|
||||
uint8_t Maximum_Temp_Status = 0;
|
||||
uint8_t Maximum_Load_Current_Status = 0;
|
||||
uint8_t Minimum_Voltage_Status = 0;
|
||||
*/
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("-----Battery Pack Status-----");
|
||||
|
||||
//modPowerElectronicsPackStateHandle->cellModuleBalanceResistorEnableMask
|
||||
|
||||
|
||||
modCommandsPrintf("Balance mask : 0x%x ",packState.cellModuleBalanceResistorEnableMask[0]);
|
||||
modCommandsPrintf("Pack voltage Direct : %.2fV",packState.packVoltage);
|
||||
modCommandsPrintf("Pack voltage CVAverage: %.2fV",packState.cellVoltageAverage*generalConfig->noOfCellsSeries);
|
||||
modCommandsPrintf("Pack current : %.2fA",packState.packCurrent);
|
||||
//modCommandsPrintf("LC Load voltage : %.2fV",packState.loCurrentLoadVoltage);
|
||||
//modCommandsPrintf("Low current : %.2fA",packState.loCurrentLoadCurrent);
|
||||
modCommandsPrintf("State of charge : %.1f%%",generalStateOfCharge->generalStateOfCharge);
|
||||
modCommandsPrintf("Remaining capacity : %.2fAh",generalStateOfCharge->remainingCapacityAh);
|
||||
modCommandsPrintf("Real calculated capacity : %fAh",export_real_capacity);
|
||||
|
||||
//modCommandsPrintf("previous_capacity : %.2fAh",previous_capacity);
|
||||
// modCommandsPrintf("previous_SoC : %.2fAh",previous_SoC);
|
||||
// modCommandsPrintf("soc_diff : %.2fAh",soc_diff);
|
||||
// modCommandsPrintf("capacity_diff : %.2fAh",capacity_diff);
|
||||
// modCommandsPrintf("SoC_Save_Flag : %.2fAh",SoC_Save_Flag);
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("Pilot_Status: %s",Pilot_Status ? "Charging" : "No charging");
|
||||
modCommandsPrintf("Maximum_Charge_Current_Status: %s",Maximum_Charge_Current_Status ? "Good" : "Too high charge current!");
|
||||
modCommandsPrintf("Maximum_Voltage_Status: %s",Maximum_Voltage_Status ? "Good" : "Too high voltage!");
|
||||
modCommandsPrintf("Maximum_Temp_Status: %s",Maximum_Temp_Status ? "Good" : "Too high temperature!");
|
||||
modCommandsPrintf("Maximum_Load_Current_Status: %s",Maximum_Load_Current_Status ? "Good" : "Too high load current!");
|
||||
modCommandsPrintf("Minimum_Voltage_Status: %s",Minimum_Voltage_Status ? "Good" : "Too low voltage!");
|
||||
modCommandsPrintf("Deep_Discharge_Status: %s",Deep_Discharge_Status ? "Good" : "Deep discharge!");
|
||||
modCommandsPrintf("ADC_Current: %d",export_adc_average_res);
|
||||
modCommandsPrintf("Current Zero Value: %f",generalConfig->shuntLCFactor);
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("Charge Switch State: %s",charge_switch_state ? "ON" : "OFF");
|
||||
modCommandsPrintf("Load Switch State: %s",load_switch_state ? "ON" : "OFF");
|
||||
//generalConfig->shuntLCFactor
|
||||
//export_adc_average_res
|
||||
|
||||
//export_real_capacity
|
||||
|
||||
// switch(modOperationalStateCurrentState) {
|
||||
// case OP_STATE_CHARGING:
|
||||
// modCommandsPrintf("Operational state : %s","Charging");
|
||||
// break;
|
||||
// case OP_STATE_LOAD_ENABLED:
|
||||
// modCommandsPrintf("Operational state : %s","Load enabled");
|
||||
// break;
|
||||
// case OP_STATE_CHARGED:
|
||||
// modCommandsPrintf("Operational state : %s","Charged");
|
||||
// break;
|
||||
// case OP_STATE_BALANCING:
|
||||
// modCommandsPrintf("Operational state : %s","Balancing");
|
||||
// break;
|
||||
// case OP_STATE_ERROR_PRECHARGE:
|
||||
// modCommandsPrintf("Operational state : %s","Pre charge error");
|
||||
// break;
|
||||
// case OP_STATE_ERROR:
|
||||
// modCommandsPrintf("Operational state : %s","Error");
|
||||
// break;
|
||||
// case OP_STATE_FORCEON:
|
||||
// modCommandsPrintf("Operational state : %s","Forced on");
|
||||
// break;
|
||||
// case OP_STATE_POWER_DOWN:
|
||||
// modCommandsPrintf("Operational state : %s","Power down");
|
||||
// break;
|
||||
// case OP_STATE_EXTERNAL:
|
||||
// modCommandsPrintf("Operational state : %s","External (USB or CAN)");
|
||||
// break;
|
||||
// default:
|
||||
// modCommandsPrintf("Operational state : %s","Unknown");
|
||||
// break;
|
||||
// }
|
||||
// modCommandsPrintf("Cell voltage high : %.3fV",packState.cellVoltageHigh);
|
||||
// modCommandsPrintf("Cell voltage low : %.3fV",packState.cellVoltageLow);
|
||||
// modCommandsPrintf("Cell voltage average : %.3fV",packState.cellVoltageAverage);
|
||||
// modCommandsPrintf("Cell voltage mismatch : %.3fV",packState.cellVoltageMisMatch);
|
||||
// modCommandsPrintf("Discharge enabled : %s",disChargeEnabled ? "True" : "False");
|
||||
// modCommandsPrintf("Charge enabled : %s",chargeEnabled ? "True" : "False");
|
||||
//ni modCommandsPrintf("Power button pressed : %s",packState.powerButtonActuated ? "True" : "False");
|
||||
//ni modCommandsPrintf("CAN safety state : %s",packState.safetyOverCANHCSafeNSafe ? "True" : "False");
|
||||
|
||||
|
||||
//ni modCommandsPrintf("---End Battery Pack Status---");
|
||||
//ni modCommandsPrintf(" ");
|
||||
/*
|
||||
uint8_t cellVoltageLow_Minimum = 0;
|
||||
uint8_t cellVoltageLow_Minimum_Hyst = 0;
|
||||
uint8_t cellVoltageHigh_Maximum = 0;
|
||||
uint8_t cellVoltageHigh_Maximum_Hyst = 0;
|
||||
uint8_t maxChargeCurrent = 0;
|
||||
uint8_t maxLoadCurrent = 0;
|
||||
|
||||
*/
|
||||
} else if (strcmp(argv[0], "setZeroCurrent") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- setZeroCurrent -----");
|
||||
|
||||
// print temperatures
|
||||
modCommandsPrintf("ADC Value: %.3f V",export_adc_average_res);
|
||||
generalConfig->shuntLCFactor = export_adc_average_res;
|
||||
modCommandsPrintf("Config Zero Value in EEPROM: %.3f V",generalConfig->shuntLCFactor);
|
||||
modCommandsPrintf("Config Zero Value in RAM: %.3f V",currentZero_config);
|
||||
|
||||
modCommandsPrintf("Current Zero Value Updated! Remember to save EEPROM!");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
/*
|
||||
*
|
||||
Brush_Minimum_SoC = generalConfig->minimalPrechargePercentage;
|
||||
Brush_Default_State = generalConfig->timeoutLCPreCharge;
|
||||
*/
|
||||
|
||||
} else if (strcmp(argv[0], "Outputs") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- Outputs -----");
|
||||
|
||||
// print temperatures
|
||||
modCommandsPrintf("Output 2 minimum SoC: %.3f",Brush_Minimum_SoC);
|
||||
modCommandsPrintf("Output 2 default state: %d",Brush_Default_State);
|
||||
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
}else if (strcmp(argv[0], "limits") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- Limits -----");
|
||||
|
||||
// print temperatures
|
||||
modCommandsPrintf("Minimum Cell Voltage: %.3f V",cellVoltageLow_Minimum);
|
||||
modCommandsPrintf("Minimum Cell Voltage Hyst: %.3f V",cellVoltageLow_Minimum_Hyst);
|
||||
modCommandsPrintf("Maximum Cell Voltage: %.3f V",cellVoltageHigh_Maximum);
|
||||
modCommandsPrintf("Maximum Cell Voltage Hyst: %.3f V",cellVoltageHigh_Maximum_Hyst);
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("Maximum Charge Current: %.3f A",maxChargeCurrent);
|
||||
modCommandsPrintf("Maximum Load Current: %.3f A",maxLoadCurrent);
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("Maximum Temperature: %.3f C",maxTemperature);
|
||||
modCommandsPrintf("Maximum Temperature Hyst: %.3f C",maxTemperature_Hyst);
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "sens") == 0) {
|
||||
modCommandsPrintf("----- Sensors -----");
|
||||
|
||||
// print temperatures
|
||||
modCommandsPrintf("Sensor[0] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[0]);
|
||||
modCommandsPrintf("Sensor[1] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[1]);
|
||||
modCommandsPrintf("Sensor[2] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[2]);
|
||||
modCommandsPrintf("Sensor[3] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[3]);
|
||||
modCommandsPrintf("Sensor[4] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[4]);
|
||||
modCommandsPrintf("Sensor[5] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[5]);
|
||||
modCommandsPrintf("Sensor[6] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[6]);
|
||||
modCommandsPrintf("Sensor[7] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[7]);
|
||||
modCommandsPrintf("Sensor[8] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[8]);
|
||||
modCommandsPrintf("Sensor[9] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[9]);
|
||||
modCommandsPrintf("Sensor[10] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[10]);
|
||||
modCommandsPrintf("Sensor[11] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[11]);
|
||||
modCommandsPrintf("Sensor[12] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[12]);
|
||||
|
||||
modCommandsPrintf("Sensor[2] : % 3.1f C - I - 'LTC Internal'",packState.temperatures[2]);
|
||||
modCommandsPrintf("Sensor[3] : % 3.1f C - I - 'STM NTC'",packState.temperatures[3]);
|
||||
modCommandsPrintf("----- End sensors -----");
|
||||
modCommandsPrintf("----- E=External I=Internal -----");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "cells") == 0) {
|
||||
uint8_t cellPointer = 0;
|
||||
|
||||
modCommandsPrintf("----- Cell voltages -----");
|
||||
modCommandsPrintf("Cell in series : %d ",generalConfig->noOfCellsSeries);
|
||||
modCommandsPrintf("Number of ICs : %d ",generalConfig->cellMonitorICCount);
|
||||
modCommandsPrintf("Cells per IC : %d ",generalConfig->noOfCellsPerModule);
|
||||
|
||||
for(cellPointer = 0 ; cellPointer < generalConfig->noOfCellsSeries ; cellPointer++) {
|
||||
// test 01.11.2021 //
|
||||
//for(cellPointer = 0 ; cellPointer < 20 ; cellPointer++) {
|
||||
modCommandsPrintf("Cell voltage%3d : %.3f V",cellPointer,packState.cellVoltagesIndividual[cellPointer].cellVoltage);
|
||||
}
|
||||
modCommandsPrintf("Cell voltage high : %.3f V",packState.cellVoltageHigh);
|
||||
modCommandsPrintf("Cell voltage low : %.3f V",packState.cellVoltageLow);
|
||||
modCommandsPrintf("Cell voltage average : %.3f V",packState.cellVoltageAverage);
|
||||
modCommandsPrintf("Cell voltage mismatch : %.3f V",packState.cellVoltageMisMatch);
|
||||
modCommandsPrintf("----- End Cell voltages -----");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "config") == 0) {
|
||||
modCommandsPrintf("--- BMS Configuration ---");
|
||||
//modCommandsPrintf("serialNumber : %u",generalConfig->serialNumber);
|
||||
modCommandsPrintf("NoOfCells : %u",generalConfig->noOfCellsSeries);
|
||||
modCommandsPrintf("batteryCapacity : %.2fAh",generalConfig->batteryCapacity);
|
||||
modCommandsPrintf("cellHardUnderVoltage : %.3fV",generalConfig->cellHardUnderVoltage);
|
||||
modCommandsPrintf("cellHardOverVoltage : %.3fV",generalConfig->cellHardOverVoltage);
|
||||
modCommandsPrintf("cellLCSoftUnderVoltage : %.3fV",generalConfig->cellLCSoftUnderVoltage);
|
||||
modCommandsPrintf("cellSoftOverVoltage : %.3fV",generalConfig->cellSoftOverVoltage);
|
||||
modCommandsPrintf("cellBalanceStart : %.3fV",generalConfig->cellBalanceStart);
|
||||
//modCommandsPrintf("cellBalanceDiffThreshold : %.3fV",generalConfig->cellBalanceDifferenceThreshold);
|
||||
modCommandsPrintf("CAN ID : %u",generalConfig->CANID);
|
||||
modCommandsPrintf("--- End BMS Configuration ---");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "config_default") == 0) {
|
||||
modCommandsPrintf("--Restoring default config--");
|
||||
if(modConfigStoreDefaultConfig())
|
||||
modCommandsPrintf("Succesfully restored config, new config wil be used on powercycle (or use config_read to apply it now).");
|
||||
else
|
||||
modCommandsPrintf("Error restored config.");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "config_write") == 0) {
|
||||
modCommandsPrintf("--- Writing config ---");
|
||||
if(modConfigStoreConfig())
|
||||
modCommandsPrintf("Succesfully written config.");
|
||||
else
|
||||
modCommandsPrintf("Error writing config.");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "config_read") == 0) {
|
||||
modCommandsPrintf("--- Reading config ---");
|
||||
if(modConfigLoadConfig())
|
||||
modCommandsPrintf("Succesfully read config.");
|
||||
else
|
||||
modCommandsPrintf("Error reading config.");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "config_set_cells") == 0) {
|
||||
modCommandsPrintf("---Setting new cell count---");
|
||||
if (argc == 2) {
|
||||
uint32_t newNumberOfCells = 0;
|
||||
sscanf(argv[1], "%u", &newNumberOfCells);
|
||||
if(newNumberOfCells < 13 && newNumberOfCells > 2) {
|
||||
modCommandsPrintf("Number of cells is set to: %u.",newNumberOfCells);
|
||||
generalConfig->noOfCellsSeries = newNumberOfCells;
|
||||
} else {
|
||||
modCommandsPrintf("Invalid number of cells (should be anything from 3 to 12).");
|
||||
}
|
||||
} else {
|
||||
modCommandsPrintf("This command requires one argument.");
|
||||
}
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "hwinfo") == 0) {
|
||||
modCommandsPrintf("------- BMS Info -------");
|
||||
modCommandsPrintf("Firmware: %s", FW_REAL_VERSION);
|
||||
modCommandsPrintf("Name : %s", HW_NAME);
|
||||
modCommandsPrintf("UUID: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
STM32_UUID_8[0], STM32_UUID_8[1], STM32_UUID_8[2], STM32_UUID_8[3],
|
||||
STM32_UUID_8[4], STM32_UUID_8[5], STM32_UUID_8[6], STM32_UUID_8[7],
|
||||
STM32_UUID_8[8], STM32_UUID_8[9], STM32_UUID_8[10], STM32_UUID_8[11]);
|
||||
modCommandsPrintf("------- End BMS Info -------");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
} else if (strcmp(argv[0], "reboot") == 0) {
|
||||
modCommandsPrintf("------ Rebooting BMS ------");
|
||||
NVIC_SystemReset();
|
||||
|
||||
} else if (strcmp(argv[0], "bootloader_erase") == 0) {
|
||||
modCommandsPrintf("------ erasing new app space ------");
|
||||
//ni if(modFlashEraseNewAppData(0x00002000) == HAL_OK)
|
||||
if(1)
|
||||
modCommandsPrintf("--Erase done.");
|
||||
else
|
||||
modCommandsPrintf("--Erase error.");
|
||||
|
||||
} else if (strcmp(argv[0], "bootloader_jump") == 0) {
|
||||
//ni modFlashJumpToBootloader();
|
||||
|
||||
} else if (strcmp(argv[0], "help") == 0) {
|
||||
modCommandsPrintf("------- Start of help -------");
|
||||
modCommandsPrintf("Valid commands for ENNOID-BMS are:");
|
||||
modCommandsPrintf("help");
|
||||
modCommandsPrintf(" Show this help.");
|
||||
modCommandsPrintf("setZeroCurrent");
|
||||
modCommandsPrintf(" Set Zero for current sensor");
|
||||
modCommandsPrintf("ping");
|
||||
modCommandsPrintf(" Print pong here to see if the reply works.");
|
||||
modCommandsPrintf("slave_scan");
|
||||
modCommandsPrintf(" Scan the I2C devices on the slave.");
|
||||
modCommandsPrintf("status");
|
||||
modCommandsPrintf(" Print battery measurements summary.");
|
||||
modCommandsPrintf("sens");
|
||||
modCommandsPrintf(" Print all sensor values.");
|
||||
modCommandsPrintf("cells");
|
||||
modCommandsPrintf(" Print cell voltage measurements.");
|
||||
modCommandsPrintf("config");
|
||||
modCommandsPrintf(" Print BMS configuration.");
|
||||
modCommandsPrintf("config_default");
|
||||
modCommandsPrintf(" Load default BMS configuration.");
|
||||
modCommandsPrintf("config_write");
|
||||
modCommandsPrintf(" Store current BMS configuration to EEPROM.");
|
||||
modCommandsPrintf("config_read");
|
||||
modCommandsPrintf(" Read BMS configuration from EEPROM.");
|
||||
modCommandsPrintf("hwinfo");
|
||||
modCommandsPrintf(" Print some hardware information.");
|
||||
modCommandsPrintf("GSM");
|
||||
modCommandsPrintf(" Print some GSM information.");
|
||||
modCommandsPrintf("setUnixTime [Value]");
|
||||
modCommandsPrintf(" Set RTC Time from TimeStamp. [Value] - uint64 unixtime value ");
|
||||
modCommandsPrintf("checkUnixTime");
|
||||
modCommandsPrintf(" Check actual RTC time ");
|
||||
|
||||
modCommandsPrintf("setSerialNumber [Value]");
|
||||
modCommandsPrintf(" Set Serial [Value] - uint64 value ");
|
||||
modCommandsPrintf("checkSerialNumber");
|
||||
modCommandsPrintf(" Check actual Serial ");
|
||||
|
||||
modCommandsPrintf("SDcard");
|
||||
modCommandsPrintf(" Switch to SD storage");
|
||||
|
||||
|
||||
|
||||
for (int i = 0;i < callback_write;i++) {
|
||||
if (callbacks[i].arg_names) {
|
||||
modCommandsPrintf("%s %s", callbacks[i].command, callbacks[i].arg_names);
|
||||
} else {
|
||||
modCommandsPrintf(callbacks[i].command);
|
||||
}
|
||||
|
||||
if (callbacks[i].help) {
|
||||
modCommandsPrintf(" %s", callbacks[i].help);
|
||||
} else {
|
||||
modCommandsPrintf(" There is no help available for this command.");
|
||||
}
|
||||
}
|
||||
|
||||
modCommandsPrintf(" ");
|
||||
} else if (strcmp(argv[0], "GSM") == 0) {
|
||||
uint8_t cellPointer = 0;
|
||||
|
||||
modCommandsPrintf("----- GSM STATE -----");
|
||||
modCommandsPrintf("GPRS Connected : %d ", SIM800_Struct.Sim_Main_States.GPRS_Established);
|
||||
ptr = &SIM800_Struct.Sim_Answer.SIM_answer[0];
|
||||
modCommandsPrintf("Last received msg : %s ", ptr);
|
||||
modCommandsPrintf("----- End GSM STATE -----");
|
||||
modCommandsPrintf(" ");
|
||||
|
||||
}else if (strcmp(argv[0], "setUnixTime") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- set Unix Time -----");
|
||||
|
||||
time_t Time_rcvd;
|
||||
Time_rcvd = strtol(argv[1], NULL, 16);
|
||||
tm_PC_Time = *(localtime(&Time_rcvd));
|
||||
|
||||
if(Time_rcvd < 0x386D4380){
|
||||
PC_time.year = 0;
|
||||
PC_time.month = 1;
|
||||
PC_time.day = 1;
|
||||
PC_time.hour = 0;
|
||||
PC_time.minute = 0;
|
||||
PC_time.second = 0;
|
||||
|
||||
} else {
|
||||
|
||||
PC_time.year = tm_PC_Time.tm_year+1900-2000;
|
||||
PC_time.month = tm_PC_Time.tm_mon+1;
|
||||
PC_time.day = tm_PC_Time.tm_mday;
|
||||
PC_time.hour = tm_PC_Time.tm_hour;
|
||||
PC_time.minute = tm_PC_Time.tm_min;
|
||||
PC_time.second = tm_PC_Time.tm_sec;
|
||||
}
|
||||
|
||||
RTC_Set_Values(&PC_time);
|
||||
// print temperatures
|
||||
|
||||
modCommandsPrintf("RTC Updated!");
|
||||
modCommandsPrintf("Actual RTC:");
|
||||
modCommandsPrintf("Year : %d", PC_time.year);
|
||||
modCommandsPrintf("Month : %d", PC_time.month);
|
||||
modCommandsPrintf("Day : %d", PC_time.day);
|
||||
modCommandsPrintf("Hours : %d", PC_time.hour);
|
||||
modCommandsPrintf("Minutes : %d", PC_time.minute);
|
||||
modCommandsPrintf("Seconds : %d", PC_time.second);
|
||||
|
||||
|
||||
modCommandsPrintf(" ");
|
||||
}else if (strcmp(argv[0], "checkUnixTime") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- check Unix Time -----");
|
||||
|
||||
RTC_Get_Values(&PC_time);
|
||||
|
||||
modCommandsPrintf("Actual RTC:");
|
||||
modCommandsPrintf("Year : %d", PC_time.year);
|
||||
modCommandsPrintf("Month : %d", PC_time.month);
|
||||
modCommandsPrintf("Day : %d", PC_time.day);
|
||||
modCommandsPrintf("Hours : %d", PC_time.hour);
|
||||
modCommandsPrintf("Minutes : %d", PC_time.minute);
|
||||
modCommandsPrintf("Seconds : %d", PC_time.second);
|
||||
|
||||
modCommandsPrintf("----- end Unix Time -----");
|
||||
modCommandsPrintf(" ");
|
||||
}
|
||||
else if (strcmp(argv[0], "checkSerialNumber") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- check Serial -----");
|
||||
|
||||
modCommandsPrintf("Actual Serial:");
|
||||
modCommandsPrintf("Serial : %lu %lu", generalConfig->serialNumber);
|
||||
modCommandsPrintf("Serial : %.8f", generalConfig->notUsedCurrentThreshold);
|
||||
modCommandsPrintf("----- end Serial -----");
|
||||
modCommandsPrintf(" ");
|
||||
}
|
||||
else if (strcmp(argv[0], "setSerialNumber") == 0) {
|
||||
modCommandsPrintf(" ");
|
||||
modCommandsPrintf("----- Set Serial -----");
|
||||
|
||||
NewSerial = strtol(argv[1], NULL, 10);
|
||||
generalConfig->serialNumber = NewSerial;
|
||||
modCommandsPrintf("New Serial : %lu %lu", NewSerial);
|
||||
modCommandsPrintf("----- end Serial -----");
|
||||
modCommandsPrintf(" ");
|
||||
}
|
||||
else if (strcmp(argv[0], "SDcard") == 0) {
|
||||
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR11, 1);
|
||||
jumpBootloaderTrue = 1;
|
||||
}
|
||||
else {
|
||||
bool found = false;
|
||||
for (int i = 0;i < callback_write;i++) {
|
||||
if (strcmp(argv[0], callbacks[i].command) == 0) {
|
||||
callbacks[i].cbf(argc, (const char**)argv);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
modCommandsPrintf("Invalid command: %s\n type help to list all available commands\n", argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom command callback to the terminal. If the command
|
||||
* is already registered the old command callback will be replaced.
|
||||
*
|
||||
* @param command
|
||||
* The command name.
|
||||
*
|
||||
* @param help
|
||||
* A help text for the command. Can be NULL.
|
||||
*
|
||||
* @param arg_names
|
||||
* The argument names for the command, e.g. [arg_a] [arg_b]
|
||||
* Can be NULL.
|
||||
*
|
||||
* @param cbf
|
||||
* The callback function for the command.
|
||||
*/
|
||||
void modTerminalRegisterCommandCallBack(
|
||||
const char* command,
|
||||
const char *help,
|
||||
const char *arg_names,
|
||||
void(*cbf)(int argc, const char **argv)) {
|
||||
|
||||
int callback_num = callback_write;
|
||||
|
||||
for (int i = 0;i < callback_write;i++) {
|
||||
// First check the address in case the same callback is registered more than once.
|
||||
if (callbacks[i].command == command) {
|
||||
callback_num = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check by string comparison.
|
||||
if (strcmp(callbacks[i].command, command) == 0) {
|
||||
callback_num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
callbacks[callback_num].command = command;
|
||||
callbacks[callback_num].help = help;
|
||||
callbacks[callback_num].arg_names = arg_names;
|
||||
callbacks[callback_num].cbf = cbf;
|
||||
|
||||
if (callback_num == callback_write) {
|
||||
callback_write++;
|
||||
if (callback_write >= CALLBACK_LEN) {
|
||||
callback_write = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
defaultConfig.cellBalanceDifferenceThreshold = 0.01f; // Start balancing @ 5mV difference, stop if below
|
||||
*/
|
||||
55
firmware/Core/Src/modUART.c
Normal file
55
firmware/Core/Src/modUART.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2017 - 2018 Danny Bokma danny@diebie.nl
|
||||
Copyright 2019 - 2020 Kevin Dionne kevin.dionne@ennoid.me
|
||||
|
||||
This file is part of the DieBieMS/ENNOID-BMS firmware.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The DieBieMS/ENNOID-BMS firmware is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "modUART.h"
|
||||
|
||||
uint32_t consoleStatusLastTick;
|
||||
|
||||
void modUARTInit(void) {
|
||||
libPacketInit(modUARTSendPacket, modUARTProcessPacket, PACKET_HANDLER_UART);
|
||||
|
||||
driverSWUART2Init(115200); // Configure the UART driver
|
||||
};
|
||||
|
||||
void modUARTTask(void) {
|
||||
char inputChar;
|
||||
|
||||
while(driverSWUART2Task()){};
|
||||
|
||||
if(driverHWUART2GetChar(&inputChar))
|
||||
libPacketProcessByte(inputChar,PACKET_HANDLER_UART);
|
||||
};
|
||||
|
||||
void modUARTSendPacketWrapper(unsigned char *data, unsigned int len) {
|
||||
libPacketSendPacket(data, len, PACKET_HANDLER_UART);
|
||||
}
|
||||
|
||||
void modUARTProcessPacket(unsigned char *data, unsigned int len) {
|
||||
modCommandsSetSendFunction(modUARTSendPacketWrapper);
|
||||
modCommandsProcessPacket(data, len);
|
||||
}
|
||||
|
||||
void modUARTSendPacket(unsigned char *data, unsigned int len) {
|
||||
uint32_t outputCharPointer;
|
||||
|
||||
for(outputCharPointer = 0; outputCharPointer < len; outputCharPointer++) {
|
||||
driverHWUART2SendChar(data[outputCharPointer]);
|
||||
}
|
||||
}
|
||||
167
firmware/Core/Src/rtc.c
Normal file
167
firmware/Core/Src/rtc.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.c
|
||||
* @brief This file provides code for the configuration
|
||||
* of the RTC instances.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "rtc.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
//extern Time_Struct Global_RTC_Time;
|
||||
/* USER CODE END 0 */
|
||||
|
||||
RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* RTC init function */
|
||||
void MX_RTC_Init(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 0 */
|
||||
|
||||
/* USER CODE END RTC_Init 0 */
|
||||
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef DateToUpdate = {0};
|
||||
|
||||
/* USER CODE BEGIN RTC_Init 1 */
|
||||
|
||||
/* USER CODE END RTC_Init 1 */
|
||||
/** Initialize RTC Only
|
||||
*/
|
||||
hrtc.Instance = RTC;
|
||||
hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
|
||||
hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;
|
||||
if (HAL_RTC_Init(&hrtc) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Check_RTC_BKUP */
|
||||
|
||||
/* USER CODE END Check_RTC_BKUP */
|
||||
|
||||
/** Initialize RTC and set the Time and Date
|
||||
*/
|
||||
// sTime.Hours = 18;
|
||||
// sTime.Minutes = 25;
|
||||
// sTime.Seconds = 58;
|
||||
//
|
||||
// if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
|
||||
// {
|
||||
// Error_Handler();
|
||||
// }
|
||||
// DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
// DateToUpdate.Month = 11;
|
||||
// DateToUpdate.Date = 24;
|
||||
// DateToUpdate.Year = 21;
|
||||
//
|
||||
// if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK)
|
||||
// {
|
||||
// Error_Handler();
|
||||
// }
|
||||
/* USER CODE BEGIN RTC_Init 2 */
|
||||
|
||||
/* USER CODE END RTC_Init 2 */
|
||||
|
||||
}
|
||||
|
||||
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 0 */
|
||||
HAL_PWR_EnableBkUpAccess();
|
||||
/* Enable BKP CLK enable for backup registers */
|
||||
__HAL_RCC_BKP_CLK_ENABLE();
|
||||
/* RTC clock enable */
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
/* USER CODE BEGIN RTC_MspInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_RTC_DISABLE();
|
||||
/* USER CODE BEGIN RTC_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
void RTC_Set_Values(Time_Struct* Time_to_Set){
|
||||
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef DateToUpdate = {0};
|
||||
|
||||
sTime.Hours = Time_to_Set->hour;
|
||||
sTime.Minutes = Time_to_Set->minute;
|
||||
sTime.Seconds = Time_to_Set->second;
|
||||
|
||||
DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
DateToUpdate.Month = Time_to_Set->month;
|
||||
DateToUpdate.Date = Time_to_Set->day;
|
||||
DateToUpdate.Year = Time_to_Set->year;
|
||||
|
||||
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void RTC_Get_Values(Time_Struct* Time_to_Get){
|
||||
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef DateToUpdate = {0};
|
||||
|
||||
if (HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
Time_to_Get->hour = sTime.Hours ;
|
||||
Time_to_Get->minute = sTime.Minutes ;
|
||||
Time_to_Get->second = sTime.Seconds ;
|
||||
|
||||
Time_to_Get->month = DateToUpdate.Month ;
|
||||
Time_to_Get->day = DateToUpdate.Date ;
|
||||
Time_to_Get->year = DateToUpdate.Year ;
|
||||
}
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
625
firmware/Core/Src/stm32f1xx_hal_msp.c
Normal file
625
firmware/Core/Src/stm32f1xx_hal_msp.c
Normal file
@@ -0,0 +1,625 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f1xx_hal_msp.c
|
||||
* @brief This file provides code for the MSP Initialization
|
||||
* and de-Initialization codes.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* 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_AFIO_CLK_ENABLE();
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
|
||||
/* System interrupt init*/
|
||||
|
||||
/** ENABLE: Full SWJ (JTAG-DP + SW-DP): Reset State
|
||||
*/
|
||||
__HAL_AFIO_REMAP_SWJ_ENABLE();
|
||||
|
||||
/* USER CODE BEGIN MspInit 1 */
|
||||
|
||||
/* USER CODE END MspInit 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ADC MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param hadc: ADC handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(hadc->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_ADC2_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ADC MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param hadc: ADC handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
|
||||
{
|
||||
if(hadc->Instance==ADC2)
|
||||
{
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_ADC2_CLK_DISABLE();
|
||||
|
||||
/**ADC2 GPIO Configuration
|
||||
PC0 ------> ADC2_IN10
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0);
|
||||
|
||||
/* USER CODE BEGIN ADC2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END ADC2_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint32_t HAL_RCC_CAN1_CLK_ENABLED=0;
|
||||
|
||||
/**
|
||||
* @brief CAN MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param hcan: CAN handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(hcan->Instance==CAN1)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_MspInit 0 */
|
||||
|
||||
/* USER CODE END CAN1_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
HAL_RCC_CAN1_CLK_ENABLED++;
|
||||
if(HAL_RCC_CAN1_CLK_ENABLED==1){
|
||||
__HAL_RCC_CAN1_CLK_ENABLE();
|
||||
}
|
||||
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
/**CAN1 GPIO Configuration
|
||||
PD0 ------> CAN1_RX
|
||||
PD1 ------> CAN1_TX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_1;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
|
||||
|
||||
__HAL_AFIO_REMAP_CAN1_3();
|
||||
|
||||
/* USER CODE BEGIN CAN1_MspInit 1 */
|
||||
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
||||
/* USER CODE END CAN1_MspInit 1 */
|
||||
}
|
||||
else if(hcan->Instance==CAN2)
|
||||
{
|
||||
/* USER CODE BEGIN CAN2_MspInit 0 */
|
||||
|
||||
/* USER CODE END CAN2_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_CAN2_CLK_ENABLE();
|
||||
HAL_RCC_CAN1_CLK_ENABLED++;
|
||||
if(HAL_RCC_CAN1_CLK_ENABLED==1){
|
||||
__HAL_RCC_CAN1_CLK_ENABLE();
|
||||
}
|
||||
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
/**CAN2 GPIO Configuration
|
||||
PB12 ------> CAN2_RX
|
||||
PB13 ------> CAN2_TX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_12;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_13;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN CAN2_MspInit 1 */
|
||||
HAL_NVIC_SetPriority(CAN2_RX1_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(CAN2_RX1_IRQn);
|
||||
/* USER CODE END CAN2_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAN MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param hcan: CAN handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_CAN_MspDeInit(CAN_HandleTypeDef* hcan)
|
||||
{
|
||||
if(hcan->Instance==CAN1)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END CAN1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
HAL_RCC_CAN1_CLK_ENABLED--;
|
||||
if(HAL_RCC_CAN1_CLK_ENABLED==0){
|
||||
__HAL_RCC_CAN1_CLK_DISABLE();
|
||||
}
|
||||
|
||||
/**CAN1 GPIO Configuration
|
||||
PD0 ------> CAN1_RX
|
||||
PD1 ------> CAN1_TX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0|GPIO_PIN_1);
|
||||
|
||||
/* USER CODE BEGIN CAN1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END CAN1_MspDeInit 1 */
|
||||
}
|
||||
else if(hcan->Instance==CAN2)
|
||||
{
|
||||
/* USER CODE BEGIN CAN2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END CAN2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_CAN2_CLK_DISABLE();
|
||||
HAL_RCC_CAN1_CLK_ENABLED--;
|
||||
if(HAL_RCC_CAN1_CLK_ENABLED==0){
|
||||
__HAL_RCC_CAN1_CLK_DISABLE();
|
||||
}
|
||||
|
||||
/**CAN2 GPIO Configuration
|
||||
PB12 ------> CAN2_RX
|
||||
PB13 ------> CAN2_TX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_13);
|
||||
|
||||
/* USER CODE BEGIN CAN2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END CAN2_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DAC MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param hdac: DAC handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(hdac->Instance==DAC)
|
||||
{
|
||||
/* USER CODE BEGIN DAC_MspInit 0 */
|
||||
|
||||
/* USER CODE END DAC_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_DAC_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
/**DAC GPIO Configuration
|
||||
PA4 ------> DAC_OUT1
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_4;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN DAC_MspInit 1 */
|
||||
|
||||
/* USER CODE END DAC_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DAC MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param hdac: DAC handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_DAC_MspDeInit(DAC_HandleTypeDef* hdac)
|
||||
{
|
||||
if(hdac->Instance==DAC)
|
||||
{
|
||||
/* USER CODE BEGIN DAC_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END DAC_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_DAC_CLK_DISABLE();
|
||||
|
||||
/**DAC GPIO Configuration
|
||||
PA4 ------> DAC_OUT1
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);
|
||||
|
||||
/* USER CODE BEGIN DAC_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END DAC_MspDeInit 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==SPI1)
|
||||
{
|
||||
/* USER CODE BEGIN SPI1_MspInit 0 */
|
||||
|
||||
/* USER CODE END SPI1_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
/**SPI1 GPIO Configuration
|
||||
PA5 ------> SPI1_SCK
|
||||
PA6 ------> SPI1_MISO
|
||||
PA7 ------> SPI1_MOSI
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_6;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN SPI1_MspInit 1 */
|
||||
|
||||
/* USER CODE END SPI1_MspInit 1 */
|
||||
}
|
||||
else if(hspi->Instance==SPI3)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_MspInit 0 */
|
||||
|
||||
/* USER CODE END SPI3_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_SPI3_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
/**SPI3 GPIO Configuration
|
||||
PC10 ------> SPI3_SCK
|
||||
PC11 ------> SPI3_MISO
|
||||
PC12 ------> SPI3_MOSI
|
||||
*/
|
||||
|
||||
//
|
||||
// GPIO_InitStruct.Pin = LTC_SCK_Pin|LTC_MOSI_Pin;
|
||||
// GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
// GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
// GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
|
||||
// HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
//
|
||||
// GPIO_InitStruct.Pin = LTC_MISO_Pin;
|
||||
// GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
|
||||
// GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
// GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
|
||||
// HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_11;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // before input
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
__HAL_AFIO_REMAP_SPI3_ENABLE();
|
||||
|
||||
/* USER CODE BEGIN SPI3_MspInit 1 */
|
||||
|
||||
/* USER CODE END SPI3_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==SPI1)
|
||||
{
|
||||
/* USER CODE BEGIN SPI1_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END SPI1_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_SPI1_CLK_DISABLE();
|
||||
|
||||
/**SPI1 GPIO Configuration
|
||||
PA5 ------> SPI1_SCK
|
||||
PA6 ------> SPI1_MISO
|
||||
PA7 ------> SPI1_MOSI
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
|
||||
|
||||
/* USER CODE BEGIN SPI1_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END SPI1_MspDeInit 1 */
|
||||
}
|
||||
else if(hspi->Instance==SPI3)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END SPI3_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_SPI3_CLK_DISABLE();
|
||||
|
||||
/**SPI3 GPIO Configuration
|
||||
PC10 ------> SPI3_SCK
|
||||
PC11 ------> SPI3_MISO
|
||||
PC12 ------> SPI3_MOSI
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12);
|
||||
|
||||
/* USER CODE BEGIN SPI3_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END SPI3_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
|
||||
{
|
||||
if(htim_base->Instance==TIM6)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM6_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_TIM6_CLK_ENABLE();
|
||||
/* TIM6 interrupt Init */
|
||||
HAL_NVIC_SetPriority(TIM6_IRQn, 1, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM6_IRQn);
|
||||
/* USER CODE BEGIN TIM6_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM6_MspInit 1 */
|
||||
}
|
||||
if(htim_base->Instance==TIM2)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM6_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_TIM2_CLK_ENABLE();
|
||||
|
||||
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM2_IRQn);
|
||||
/* USER CODE BEGIN TIM6_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM6_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIM_Base MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param htim_base: TIM_Base handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
|
||||
{
|
||||
if(htim_base->Instance==TIM6)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM6_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM6_CLK_DISABLE();
|
||||
|
||||
/* TIM6 interrupt DeInit */
|
||||
HAL_NVIC_DisableIRQ(TIM6_IRQn);
|
||||
/* USER CODE BEGIN TIM6_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM6_MspDeInit 1 */
|
||||
}
|
||||
|
||||
if(htim_base->Instance==TIM2)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM6_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM2_CLK_DISABLE();
|
||||
|
||||
/* TIM6 interrupt DeInit */
|
||||
HAL_NVIC_DisableIRQ(TIM2_IRQn);
|
||||
/* USER CODE BEGIN TIM6_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM6_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART MSP Initialization
|
||||
* This function configures the hardware resources used in this example
|
||||
* @param huart: UART handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(huart->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspInit 0 */
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_USART2_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
/**USART2 GPIO Configuration
|
||||
PA2 ------> USART2_TX
|
||||
PA3 ------> USART2_RX
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_2;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN USART2_MspInit 1 */
|
||||
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
|
||||
HAL_NVIC_EnableIRQ(USART2_IRQn);
|
||||
/* USER CODE END USART2_MspInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART MSP De-Initialization
|
||||
* This function freeze the hardware resources used in this example
|
||||
* @param huart: UART handle pointer
|
||||
* @retval None
|
||||
*/
|
||||
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
|
||||
{
|
||||
if(huart->Instance==USART2)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_USART2_CLK_DISABLE();
|
||||
|
||||
/**USART2 GPIO Configuration
|
||||
PA2 ------> USART2_TX
|
||||
PA3 ------> USART2_RX
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
|
||||
|
||||
/* USER CODE BEGIN USART2_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END USART2_MspDeInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
292
firmware/Core/Src/stm32f1xx_it.c
Normal file
292
firmware/Core/Src/stm32f1xx_it.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f1xx_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "stm32f1xx_it.h"
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN TD */
|
||||
extern UART_HandleTypeDef huart2;
|
||||
extern CAN_HandleTypeDef hcan1;
|
||||
extern CAN_HandleTypeDef hcan2;
|
||||
|
||||
/* USER CODE END TD */
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN USART2_IRQn 0 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart2);
|
||||
/* USER CODE BEGIN USART2_IRQn 1 */
|
||||
|
||||
/* USER CODE END USART2_IRQn 1 */
|
||||
}
|
||||
/* 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 --------------------------------------------------------*/
|
||||
extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern TIM_HandleTypeDef htim6;
|
||||
/* USER CODE BEGIN EV */
|
||||
|
||||
/* USER CODE END EV */
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M3 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 */
|
||||
struct
|
||||
{
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
uint32_t r12;
|
||||
uint32_t lr;
|
||||
uint32_t pc;
|
||||
uint32_t psr;
|
||||
}*stack_ptr; //Указатель на текущее значение стека(SP)
|
||||
|
||||
|
||||
asm(
|
||||
"TST lr, #4 \n" //Тестируем 3ий бит указателя стека(побитовое И)
|
||||
"ITE EQ \n" //Значение указателя стека имеет бит 3?
|
||||
"MRSEQ %[ptr], MSP \n" //Да, сохраняем основной указатель стека
|
||||
"MRSNE %[ptr], PSP \n" //Нет, сохраняем указатель стека процесса
|
||||
: [ptr] "=r" (stack_ptr)
|
||||
);
|
||||
|
||||
/* USER CODE END HardFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||
|
||||
HAL_GPIO_WritePin(HL2_GPIO_Port, HL2_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(HL3_GPIO_Port, HL3_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(HL4_GPIO_Port, HL4_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(HL5_GPIO_Port, HL5_Pin, GPIO_PIN_SET);
|
||||
|
||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
void TIM2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_IRQn 0 */
|
||||
|
||||
/* USER CODE END TIM6_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim2);
|
||||
/* USER CODE BEGIN TIM6_IRQn 1 */
|
||||
|
||||
/* USER CODE END TIM6_IRQn 1 */
|
||||
}
|
||||
|
||||
|
||||
void TIM6_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM6_IRQn 0 */
|
||||
|
||||
/* USER CODE END TIM6_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim6);
|
||||
/* USER CODE BEGIN TIM6_IRQn 1 */
|
||||
|
||||
/* USER CODE END TIM6_IRQn 1 */
|
||||
}
|
||||
/**
|
||||
* @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 Prefetch 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 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F1xx 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_stm32f1xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief This function handles USB OTG FS global interrupt.
|
||||
*/
|
||||
void OTG_FS_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN OTG_FS_IRQn 0 */
|
||||
|
||||
/* USER CODE END OTG_FS_IRQn 0 */
|
||||
HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
|
||||
/* USER CODE BEGIN OTG_FS_IRQn 1 */
|
||||
|
||||
/* USER CODE END OTG_FS_IRQn 1 */
|
||||
}
|
||||
|
||||
void CAN1_RX0_IRQHandler(void)
|
||||
{
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
}
|
||||
|
||||
|
||||
void CAN2_RX1_IRQHandler(void)
|
||||
{
|
||||
HAL_CAN_IRQHandler(&hcan2);
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
207
firmware/Core/Src/syscalls.c
Normal file
207
firmware/Core/Src/syscalls.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
*****************************************************************************
|
||||
**
|
||||
** File : syscalls.c
|
||||
**
|
||||
** Author : Auto-generated by System workbench for STM32
|
||||
**
|
||||
** Abstract : System Workbench Minimal System calls file
|
||||
**
|
||||
** For more information about which c-functions
|
||||
** need which of these lowlevel functions
|
||||
** please consult the Newlib libc-manual
|
||||
**
|
||||
** Target : STMicroelectronics STM32
|
||||
**
|
||||
** Distribution: The file is distributed “as is,” without any warranty
|
||||
** of any kind.
|
||||
**
|
||||
*****************************************************************************
|
||||
** @attention
|
||||
**
|
||||
** <h2><center>© COPYRIGHT(c) 2019 STMicroelectronics</center></h2>
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without modification,
|
||||
** are permitted provided that the following conditions are met:
|
||||
** 1. Redistributions of source code must retain the above copyright notice,
|
||||
** this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
** this list of conditions and the following disclaimer in the documentation
|
||||
** and/or other materials provided with the distribution.
|
||||
** 3. Neither the name of STMicroelectronics nor the names of its contributors
|
||||
** may be used to endorse or promote products derived from this software
|
||||
** without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* 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 */
|
||||
//#undef errno
|
||||
extern int errno;
|
||||
extern int __io_putchar(int ch) __attribute__((weak));
|
||||
extern int __io_getchar(void) __attribute__((weak));
|
||||
|
||||
register char * stack_ptr asm("sp");
|
||||
|
||||
char *__env[1] = { 0 };
|
||||
char **environ = __env;
|
||||
|
||||
|
||||
/* Functions */
|
||||
void initialise_monitor_handles()
|
||||
{
|
||||
}
|
||||
|
||||
int _getpid(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _kill(int pid, int 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)
|
||||
{
|
||||
int DataIdx;
|
||||
|
||||
for (DataIdx = 0; DataIdx < len; DataIdx++)
|
||||
{
|
||||
*ptr++ = __io_getchar();
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int _write(int file, char *ptr, int len)
|
||||
{
|
||||
int DataIdx;
|
||||
|
||||
for (DataIdx = 0; DataIdx < len; DataIdx++)
|
||||
{
|
||||
__io_putchar(*ptr++);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
caddr_t _sbrk(int incr)
|
||||
{
|
||||
extern char end asm("end");
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0)
|
||||
heap_end = &end;
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > stack_ptr)
|
||||
{
|
||||
// write(1, "Heap and stack collision\n", 25);
|
||||
// abort();
|
||||
errno = ENOMEM;
|
||||
return (caddr_t) -1;
|
||||
}
|
||||
|
||||
heap_end += incr;
|
||||
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
int _close(int file)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int _fstat(int file, struct stat *st)
|
||||
{
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _isatty(int file)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _lseek(int file, int ptr, int dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _open(char *path, int flags, ...)
|
||||
{
|
||||
/* Pretend like we always fail */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _wait(int *status)
|
||||
{
|
||||
errno = ECHILD;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _unlink(char *name)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _times(struct tms *buf)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _stat(char *file, struct stat *st)
|
||||
{
|
||||
st->st_mode = S_IFCHR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _link(char *old, char *new)
|
||||
{
|
||||
errno = EMLINK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _fork(void)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _execve(char *name, char **argv, char **env)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
408
firmware/Core/Src/system_stm32f1xx.c
Normal file
408
firmware/Core/Src/system_stm32f1xx.c
Normal file
@@ -0,0 +1,408 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f1xx.c
|
||||
* @author MCD Application Team
|
||||
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File.
|
||||
*
|
||||
* 1. This file provides two functions and one global variable to be called from
|
||||
* user application:
|
||||
* - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
|
||||
* factors, AHB/APBx prescalers and Flash settings).
|
||||
* This function is called at startup just after reset and
|
||||
* before branch to main program. This call is made inside
|
||||
* the "startup_stm32f1xx_xx.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_stm32f1xx_xx.s" file, to
|
||||
* configure the system clock before to branch to main program.
|
||||
*
|
||||
* 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depending on
|
||||
* the product used), refer to "HSE_VALUE".
|
||||
* When HSE is used as system clock source, directly or through PLL, and you
|
||||
* are using different crystal you have to adapt the HSE value to your own
|
||||
* configuration.
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under BSD 3-Clause license,
|
||||
* the "License"; You may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at:
|
||||
* opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f1xx_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "stm32f1xx.h"
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_TypesDefinitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Defines
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined (HSE_VALUE)
|
||||
#define HSE_VALUE 8000000U /*!< 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 8000000U /*!< Default value of the Internal oscillator in Hz.
|
||||
This value can be provided and adapted by the user application. */
|
||||
#endif /* HSI_VALUE */
|
||||
|
||||
/*!< Uncomment the following line if you need to use external SRAM */
|
||||
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
|
||||
/* #define DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
|
||||
|
||||
/* 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 STM32F1xx_System_Private_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_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; then there
|
||||
is no need to call the 2 first functions listed above, since SystemCoreClock
|
||||
variable is updated automatically.
|
||||
*/
|
||||
uint32_t SystemCoreClock = 16000000;
|
||||
const uint8_t AHBPrescTable[16U] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
const uint8_t APBPrescTable[8U] = {0, 0, 0, 0, 1, 2, 3, 4};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_FunctionPrototypes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F1xx_System_Private_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Setup the microcontroller system
|
||||
* Initialize the Embedded Flash Interface, the PLL and update the
|
||||
* SystemCoreClock variable.
|
||||
* @note This function should be used only after reset.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit (void)
|
||||
{
|
||||
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
SystemInit_ExtMemCtl();
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#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 by the PLL factors.
|
||||
*
|
||||
* (*) HSI_VALUE is a constant defined in stm32f1xx.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 stm32f1xx.h file (default value
|
||||
* 8 MHz or 25 MHz, depending on the product used), 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 = 0U, pllmull = 0U, pllsource = 0U;
|
||||
|
||||
#if defined(STM32F105xC) || defined(STM32F107xC)
|
||||
uint32_t prediv1source = 0U, prediv1factor = 0U, prediv2factor = 0U, pll2mull = 0U;
|
||||
#endif /* STM32F105xC */
|
||||
|
||||
#if defined(STM32F100xB) || defined(STM32F100xE)
|
||||
uint32_t prediv1factor = 0U;
|
||||
#endif /* STM32F100xB or STM32F100xE */
|
||||
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
case 0x00U: /* HSI used as system clock */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
case 0x04U: /* HSE used as system clock */
|
||||
SystemCoreClock = HSE_VALUE;
|
||||
break;
|
||||
case 0x08U: /* PLL used as system clock */
|
||||
|
||||
/* Get PLL clock source and multiplication factor ----------------------*/
|
||||
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
|
||||
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
|
||||
|
||||
#if !defined(STM32F105xC) && !defined(STM32F107xC)
|
||||
pllmull = ( pllmull >> 18U) + 2U;
|
||||
|
||||
if (pllsource == 0x00U)
|
||||
{
|
||||
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
|
||||
SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(STM32F100xB) || defined(STM32F100xE)
|
||||
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
|
||||
#else
|
||||
/* HSE selected as PLL clock entry */
|
||||
if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
|
||||
{/* HSE oscillator clock divided by 2 */
|
||||
SystemCoreClock = (HSE_VALUE >> 1U) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemCoreClock = HSE_VALUE * pllmull;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
pllmull = pllmull >> 18U;
|
||||
|
||||
if (pllmull != 0x0DU)
|
||||
{
|
||||
pllmull += 2U;
|
||||
}
|
||||
else
|
||||
{ /* PLL multiplication factor = PLL input clock * 6.5 */
|
||||
pllmull = 13U / 2U;
|
||||
}
|
||||
|
||||
if (pllsource == 0x00U)
|
||||
{
|
||||
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
|
||||
SystemCoreClock = (HSI_VALUE >> 1U) * pllmull;
|
||||
}
|
||||
else
|
||||
{/* PREDIV1 selected as PLL clock entry */
|
||||
|
||||
/* Get PREDIV1 clock source and division factor */
|
||||
prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
|
||||
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1U;
|
||||
|
||||
if (prediv1source == 0U)
|
||||
{
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
|
||||
}
|
||||
else
|
||||
{/* PLL2 clock selected as PREDIV1 clock entry */
|
||||
|
||||
/* Get PREDIV2 division factor and PLL2 multiplication factor */
|
||||
prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4U) + 1U;
|
||||
pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8U) + 2U;
|
||||
SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;
|
||||
}
|
||||
}
|
||||
#endif /* STM32F105xC */
|
||||
break;
|
||||
|
||||
default:
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Compute HCLK clock frequency ----------------*/
|
||||
/* Get HCLK prescaler */
|
||||
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4U)];
|
||||
/* HCLK clock frequency */
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
|
||||
#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)
|
||||
/**
|
||||
* @brief Setup the external memory controller. Called in startup_stm32f1xx.s
|
||||
* before jump to __main
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
/**
|
||||
* @brief Setup the external memory controller.
|
||||
* Called in startup_stm32f1xx_xx.s/.c before jump to main.
|
||||
* This function configures the external SRAM mounted on STM3210E-EVAL
|
||||
* board (STM32 High density devices). This SRAM will be used as program
|
||||
* data memory (including heap and stack).
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
__IO uint32_t tmpreg;
|
||||
/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is
|
||||
required, then adjust the Register Addresses */
|
||||
|
||||
/* Enable FSMC clock */
|
||||
RCC->AHBENR = 0x00000114U;
|
||||
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmpreg = READ_BIT(RCC->AHBENR, RCC_AHBENR_FSMCEN);
|
||||
|
||||
/* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */
|
||||
RCC->APB2ENR = 0x000001E0U;
|
||||
|
||||
/* Delay after an RCC peripheral clock enabling */
|
||||
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPDEN);
|
||||
|
||||
(void)(tmpreg);
|
||||
|
||||
/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/
|
||||
/*---------------- SRAM Address lines configuration -------------------------*/
|
||||
/*---------------- NOE and NWE configuration --------------------------------*/
|
||||
/*---------------- NE3 configuration ----------------------------------------*/
|
||||
/*---------------- NBL0, NBL1 configuration ---------------------------------*/
|
||||
|
||||
GPIOD->CRL = 0x44BB44BBU;
|
||||
GPIOD->CRH = 0xBBBBBBBBU;
|
||||
|
||||
GPIOE->CRL = 0xB44444BBU;
|
||||
GPIOE->CRH = 0xBBBBBBBBU;
|
||||
|
||||
GPIOF->CRL = 0x44BBBBBBU;
|
||||
GPIOF->CRH = 0xBBBB4444U;
|
||||
|
||||
GPIOG->CRL = 0x44BBBBBBU;
|
||||
GPIOG->CRH = 0x444B4B44U;
|
||||
|
||||
/*---------------- FSMC Configuration ---------------------------------------*/
|
||||
/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/
|
||||
|
||||
FSMC_Bank1->BTCR[4U] = 0x00001091U;
|
||||
FSMC_Bank1->BTCR[5U] = 0x00110212U;
|
||||
}
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
Reference in New Issue
Block a user