Compare commits
9 Commits
5a6f678fbf
...
dd4d17c133
Author | SHA1 | Date | |
---|---|---|---|
dd4d17c133 | |||
0c4f066d92 | |||
56a4befaf1 | |||
04f678b91d | |||
d1c1419016 | |||
d71099a2d4 | |||
d86cc50caf | |||
b9f937d78c | |||
99dea8f442 |
2
AMS_Master_Code/.clang-format
Normal file
2
AMS_Master_Code/.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 120
|
File diff suppressed because one or more lines are too long
4
AMS_Master_Code/.vscode/launch.json
vendored
4
AMS_Master_Code/.vscode/launch.json
vendored
@ -90,8 +90,8 @@
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/build/debug/AMS_Master_Nucleo.elf",
|
||||
"cwd": "c:/Users/lenex/Desktop/ams-master/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src",
|
||||
"program": "c:/Users/lenex/Desktop/ams-master/AMS_Master_Code/Core/Lib/ADBMS6830B_Driver/Core/Src/build/Debug/outDebug",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "gdb",
|
||||
"setupCommands": [
|
||||
|
@ -1,3 +1,5 @@
|
||||
#ifndef INC_NTC_H_
|
||||
#define INC_NTC_H_
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@ -21,9 +23,10 @@
|
||||
|
||||
[[gnu::optimize("fast-math")]]
|
||||
static inline uint16_t ntc_mv_to_celsius(int16_t adc) {
|
||||
float log_ohms = logf(1 / ((VREF / adc) - 1));
|
||||
const float log_ohms = logf(1 / ((VREF / adc) - 1));
|
||||
return (uint16_t) (TEMP_CONV / (NTC_A1 + NTC_B1 * log_ohms + NTC_C1 * log_ohms * log_ohms + NTC_D1 * log_ohms * log_ohms * log_ohms) - CELSIUS_TO_KELVIN_SCALED);
|
||||
}
|
||||
#else
|
||||
// Lookup Table coming soon; not really needed but fun?
|
||||
#endif
|
||||
#endif
|
@ -6,15 +6,36 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
extern uint16_t min_voltage;
|
||||
extern uint16_t max_voltage;
|
||||
extern struct {uint16_t min; uint16_t max;} module_voltages[N_BMS];
|
||||
extern int16_t max_temp;
|
||||
extern int16_t min_temp;
|
||||
extern struct {int16_t min; int16_t max;} module_temps[N_BMS];
|
||||
extern float module_std_deviation[N_BMS];
|
||||
#define ADBMS_NO_LOGGING_DEFS
|
||||
#include "ADBMS_Driver.h"
|
||||
|
||||
extern int16_t cellTemps[N_BMS][10];
|
||||
extern struct {
|
||||
struct {
|
||||
float soc;
|
||||
uint16_t min_voltage;
|
||||
uint16_t max_voltage;
|
||||
uint16_t min_temp;
|
||||
uint16_t max_temp;
|
||||
} pack;
|
||||
struct {
|
||||
BMS_Chip * chip;
|
||||
int16_t cellTemps[10];
|
||||
struct {
|
||||
uint8_t min_v_idx : 4; uint8_t max_v_idx : 4; // cell index: 0-15
|
||||
uint8_t min_t_idx : 4; uint8_t max_t_idx : 4; // used like this: battery->module[i].chip->cellVoltages[min_v_idx]
|
||||
};
|
||||
} module[N_BMS];
|
||||
} battery;
|
||||
|
||||
//Helper for getting min/max values
|
||||
static inline struct { uint16_t min_v; uint16_t max_v; int16_t min_t; int16_t max_t; } getModuleMinMax(int i) {
|
||||
return (typeof(getModuleMinMax(0))) {
|
||||
.min_v = battery.module[i].chip->cellVoltages[battery.module[i].min_v_idx],
|
||||
.max_v = battery.module[i].chip->cellVoltages[battery.module[i].max_v_idx],
|
||||
.min_t = battery.module[i].cellTemps[battery.module[i].min_t_idx],
|
||||
.max_t = battery.module[i].cellTemps[battery.module[i].max_t_idx]
|
||||
};
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef battery_init(SPI_HandleTypeDef* hspi);
|
||||
HAL_StatusTypeDef battery_update();
|
||||
|
@ -1,23 +1,13 @@
|
||||
#pragma once
|
||||
#ifndef __CONFIG_ADBMS6830_H
|
||||
#define __CONFIG_ADBMS6830_H
|
||||
#include "main.h"
|
||||
|
||||
#define N_BMS 1
|
||||
#define N_CELLS 16
|
||||
#define ADBMS_MAX_CHIP_TEMP 110 // max temperature of ADBMS6830B (not battery) in C
|
||||
#define ADBMS_MAX_CHIP_TEMP 1100 // max temperature of ADBMS6830B (not battery) in C
|
||||
#define ADBMS_SPI_TIMEOUT 50 // Timeout in ms
|
||||
#define DEFAULT_UV 3000 // mV
|
||||
#define DEFAULT_OV 4200 // mV
|
||||
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline void mcuAdbmsCSLow() {
|
||||
HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline void mcuAdbmsCSHigh() {
|
||||
HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
#define ERROR_TIME_THRESH 150 // ms
|
||||
|
||||
#endif //__CONFIG_ADBMS6830_H
|
||||
|
@ -3,16 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern float current_soc;
|
||||
|
||||
void soc_init();
|
||||
void soc_update();
|
||||
|
||||
typedef struct {
|
||||
uint16_t ocv;
|
||||
float soc;
|
||||
} ocv_soc_pair_t;
|
||||
extern ocv_soc_pair_t OCV_SOC_PAIRS[];
|
||||
float soc_for_ocv(uint16_t ocv);
|
||||
|
||||
#endif // INC_SOC_ESTIMATION_H
|
||||
|
@ -11,6 +11,8 @@
|
||||
// Time to wait after reaching 95% of battery voltage before exiting precharge
|
||||
// Set this to 1000 in scruti to demonstrate the voltage on the multimeter
|
||||
#define PRECHARGE_95_DURATION 0 // ms
|
||||
// Minimum precharge time
|
||||
#define PRECHARGE_MIN_DURATION 1000 // ms
|
||||
// Time to wait for discharge
|
||||
#define DISCHARGE_DURATION 5000 // ms
|
||||
// Time to wait after there is no more error condition before exiting TS_ERROR
|
||||
|
@ -1,216 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: true
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ""
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: ".*"
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: "(Test)?$"
|
||||
IncludeIsMainSourceRegex: ""
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RequiresClausePosition: OwnLine
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
---
|
||||
|
@ -1,9 +0,0 @@
|
||||
/.vscode/
|
||||
/build/
|
||||
/Debug
|
||||
/.cache/
|
||||
.clangd
|
||||
compile_commands.json
|
||||
STM32Make.make
|
||||
/.metadata/
|
||||
openocd.cfg
|
File diff suppressed because it is too large
Load Diff
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* ADBMS_Abstraction.h
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_ADBMS_ABSTRACTION_H_
|
||||
#define INC_ADBMS_ABSTRACTION_H_
|
||||
|
||||
#include "ADBMS_Driver.h"
|
||||
|
||||
#define mV_from_ADBMS6830(x) (((((int16_t)(x))) * 0.150) + 1500)
|
||||
|
||||
// Macro to convert voltage in mV to the internal format for under/over voltage thresholds.
|
||||
// Calculation: internal = (mV - 1500) / (16 * 0.15) = (mV - 1500) / 2.4.
|
||||
// To perform integer arithmetic with rounding, we compute:
|
||||
// internal = ((mV - 1500) * 5 + 6) / 12
|
||||
#define mV_to_ADBMS6830(mV) ((((mV) - 1500) * 5 + 6) / 12)
|
||||
|
||||
HAL_StatusTypeDef amsReset();
|
||||
|
||||
HAL_StatusTypeDef initAMS(SPI_HandleTypeDef* hspi);
|
||||
HAL_StatusTypeDef amsWakeUp();
|
||||
|
||||
HAL_StatusTypeDef amsCellMeasurement(Cell_Module (*module)[N_BMS]);
|
||||
|
||||
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]);
|
||||
|
||||
HAL_StatusTypeDef amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle);
|
||||
HAL_StatusTypeDef amsStartBalancing();
|
||||
HAL_StatusTypeDef amsStopBalancing();
|
||||
|
||||
HAL_StatusTypeDef amsSelfTest();
|
||||
|
||||
HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); //arguments in mV
|
||||
|
||||
HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]);
|
||||
|
||||
HAL_StatusTypeDef amsClearFlag();
|
||||
HAL_StatusTypeDef amsClearAux();
|
||||
HAL_StatusTypeDef amsClearOVUV();
|
||||
|
||||
HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]);
|
||||
|
||||
#endif /* INC_ADBMS_ABSTRACTION_H_ */
|
@ -1,18 +0,0 @@
|
||||
//
|
||||
// Created by kbracher on 2/6/25.
|
||||
//
|
||||
|
||||
#ifndef AMS_MASTER_CODE_ADBMS_ERROR_H
|
||||
#define AMS_MASTER_CODE_ADBMS_ERROR_H
|
||||
|
||||
#include "ADBMS_Driver.h"
|
||||
#include <limits.h>
|
||||
|
||||
static_assert(sizeof(error_sources) * CHAR_BIT >= NUM_ERROR_KINDS,
|
||||
"error_sources is too small to hold all error sources");
|
||||
|
||||
void set_error_source(ADBMS_Status source);
|
||||
void clear_error_source(ADBMS_Status source);
|
||||
|
||||
|
||||
#endif //AMS_MASTER_CODE_ADBMS_ERROR_H
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* AMS_HighLevel.h
|
||||
*
|
||||
* Created on: 20.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_AMS_HIGHLEVEL_H_
|
||||
#define INC_AMS_HIGHLEVEL_H_
|
||||
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
AMSDEACTIVE,
|
||||
AMSIDLE,
|
||||
AMSCHARGING,
|
||||
AMSIDLEBALANCING,
|
||||
AMSDISCHARGING,
|
||||
AMSWARNING,
|
||||
AMSERROR
|
||||
} amsState;
|
||||
|
||||
extern amsState currentAMSState;
|
||||
extern Cell_Module modules[N_BMS];
|
||||
extern uint32_t balancedCells;
|
||||
extern bool BalancingActive;
|
||||
|
||||
#endif /* INC_AMS_HIGHLEVEL_H_ */
|
@ -1,17 +0,0 @@
|
||||
#include "ADBMS_Error.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
|
||||
SlaveErrorData error_data[NUM_ERROR_KINDS] = {};
|
||||
uint32_t error_sources = 0;
|
||||
|
||||
void set_error_source(ADBMS_Status source) {
|
||||
if (!(error_sources & (1 << source))) {
|
||||
error_data[source].errors_since = HAL_GetTick();
|
||||
}
|
||||
error_sources |= (1 << source);
|
||||
}
|
||||
|
||||
void clear_error_source(ADBMS_Status source) {
|
||||
error_data[source].errors_since = 0;
|
||||
error_sources &= ~(1 << source);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
#ifndef INC_ADBMS_ABSTRACTION_H_
|
||||
#define INC_ADBMS_ABSTRACTION_H_
|
||||
|
||||
#include "ADBMS_Driver.h"
|
||||
#include "ADBMS_Intern.h"
|
||||
|
||||
#define mV_from_ADBMS6830(x) (((((int16_t)(x))) * 0.150) + 1500)
|
||||
|
||||
// Macro to convert voltage in mV to the internal format for under/over voltage thresholds.
|
||||
// Calculation: internal = (mV - 1500) / (16 * 0.15) = (mV - 1500) / 2.4.
|
||||
// To perform integer arithmetic with rounding, we compute:
|
||||
// internal = ((mV - 1500) * 5 + 6) / 12
|
||||
#define mV_to_ADBMS6830(mV) ((((mV) - 1500) * 5 + 6) / 12)
|
||||
|
||||
ADBMS_Internal_Status amsReset();
|
||||
|
||||
ADBMS_Internal_Status initAMS(USER_PTR_TYPE ptr);
|
||||
ADBMS_Internal_Status amsWakeUp();
|
||||
|
||||
ADBMS_Internal_Status amsCellMeasurement(BMS_Chip (*module)[N_BMS]);
|
||||
|
||||
ADBMS_Internal_Status amsAuxAndStatusMeasurement(BMS_Chip (*module)[N_BMS]);
|
||||
|
||||
ADBMS_Internal_Status amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle);
|
||||
ADBMS_Internal_Status amsStartBalancing();
|
||||
ADBMS_Internal_Status amsStopBalancing();
|
||||
|
||||
ADBMS_Internal_Status amsSelfTest();
|
||||
|
||||
ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage); //arguments in mV
|
||||
|
||||
ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]);
|
||||
|
||||
ADBMS_Internal_Status amsClearFlag();
|
||||
ADBMS_Internal_Status amsClearAux();
|
||||
ADBMS_Internal_Status amsClearOVUV();
|
||||
|
||||
ADBMS_Internal_Status amsReadCellVoltages(BMS_Chip (*module)[N_BMS]);
|
||||
|
||||
#endif /* INC_ADBMS_ABSTRACTION_H_ */
|
@ -1,14 +1,6 @@
|
||||
/*
|
||||
* ADBMS_CMD_MAKROS.h
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef INC_ADBMS_CMD_MAKROS_H_
|
||||
#define INC_ADBMS_CMD_MAKROS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#define WRCFGA 0x0001 // Write Configuration Register Group A
|
||||
#define RDCFGA 0x0002 // Read Configuration Register Group A
|
||||
#define WRCFGB 0x0024 // Write Configuration Register Group B
|
@ -1,11 +1,10 @@
|
||||
#ifndef ADBMS_DRIVER_H
|
||||
#define ADBMS_DRIVER_H
|
||||
|
||||
#include "ADBMS_Intern.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define ERROR_TIME_THRESH 150 // ms
|
||||
|
||||
typedef enum : uint16_t {
|
||||
ADBMS_NO_ERROR = 0,
|
||||
ADBMS_OVERTEMP,
|
||||
@ -87,13 +86,11 @@ typedef struct {
|
||||
|
||||
int16_t cellVoltages[MAXIMUM_CELL_VOLTAGES];
|
||||
int16_t auxVoltages[MAXIMUM_AUX_VOLTAGES];
|
||||
} Cell_Module;
|
||||
} BMS_Chip;
|
||||
|
||||
extern uint32_t error_sources; // Bitfield of error sources
|
||||
extern SlaveErrorData error_data[NUM_ERROR_KINDS];
|
||||
extern Cell_Module modules[N_BMS];
|
||||
extern BMS_Chip bms_data[N_BMS];
|
||||
|
||||
[[gnu::nonnull]] ADBMS_DetailedStatus AMS_Init(SPI_HandleTypeDef* hspi);
|
||||
[[gnu::nonnull]] ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr);
|
||||
|
||||
ADBMS_DetailedStatus AMS_Idle_Loop();
|
||||
|
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
#ifndef __ADBMS_INTERN_H
|
||||
#define __ADBMS_INTERN_H
|
||||
#include <stdint.h>
|
||||
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
typedef enum {
|
||||
ADBMS_OK = 0,
|
||||
ADBMS_ERROR,
|
||||
ADBMS_BUSY,
|
||||
ADBMS_TIMEOUT,
|
||||
} ADBMS_Internal_Status;
|
||||
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline void mcuAdbmsCSLow() {
|
||||
HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline void mcuAdbmsCSHigh() {
|
||||
HAL_GPIO_WritePin(AMS_CS_GPIO_Port, AMS_CS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
// user_ptr is passed to AMS_Init and could be used to pass the SPI handle
|
||||
// the BMS code does not modify it in any way
|
||||
#define USER_PTR_TYPE SPI_HandleTypeDef*
|
||||
|
||||
[[maybe_unused, gnu::always_inline, gnu::access(read_only, 2, 3), gnu::nonnull(1)]]
|
||||
static inline ADBMS_Internal_Status mcuSPITransmit(USER_PTR_TYPE user_ptr, const uint8_t* buffer, uint8_t buffersize, uint32_t timeout) {
|
||||
const HAL_StatusTypeDef status = HAL_SPI_Transmit(user_ptr, buffer, buffersize, timeout);
|
||||
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
|
||||
}
|
||||
|
||||
[[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 3), gnu::nonnull(1)]]
|
||||
static inline ADBMS_Internal_Status mcuSPIReceive(USER_PTR_TYPE user_ptr, uint8_t* buffer, uint8_t buffersize, uint32_t timeout) {
|
||||
const HAL_StatusTypeDef status = HAL_SPI_Receive(user_ptr, buffer, buffersize, timeout);
|
||||
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
|
||||
}
|
||||
|
||||
[[maybe_unused, gnu::always_inline, gnu::access(read_write, 2, 4), gnu::access(read_only, 3, 4), gnu::nonnull(1, 2)]]
|
||||
static inline ADBMS_Internal_Status mcuSPITransmitReceive(USER_PTR_TYPE user_ptr, uint8_t* rxbuffer, const uint8_t* txbuffer, uint8_t buffersize, uint32_t timeout) {
|
||||
const HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(user_ptr, txbuffer, rxbuffer, buffersize, timeout);
|
||||
return (status == HAL_OK) ? ADBMS_OK : ADBMS_ERROR;
|
||||
}
|
||||
|
||||
// Delay by `delay` milliseconds
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline void mcuDelay(uint32_t delay) {
|
||||
HAL_Delay(delay);
|
||||
}
|
||||
|
||||
// Optional logging, leave as is if not needed
|
||||
|
||||
#ifndef ADBMS_NO_LOGGING_DEFS
|
||||
|
||||
#define LOG_PREFIX "[ADBMS] "
|
||||
#include "log.h"
|
||||
|
||||
enum {
|
||||
ADBMS_LOG_LEVEL_FATAL = 0,
|
||||
ADBMS_LOG_LEVEL_ERROR,
|
||||
ADBMS_LOG_LEVEL_WARNING,
|
||||
ADBMS_LOG_LEVEL_INFO,
|
||||
ADBMS_LOG_LEVEL_DEBUG,
|
||||
ADBMS_LOG_LEVEL_NOISY,
|
||||
};
|
||||
|
||||
// Returns a timestamp in milliseconds
|
||||
// Only used for logging
|
||||
[[maybe_unused, gnu::always_inline]]
|
||||
static inline uint32_t mcuGetTime() {
|
||||
return HAL_GetTick();
|
||||
}
|
||||
|
||||
#define debug_log(level, ...) log_message((log_level_t)level, __VA_ARGS__)
|
||||
#define debug_log_cont(level, ...) log_message_cont((log_level_t)level, __VA_ARGS__)
|
||||
#define DEBUG_CHANNEL_ENABLED(level) log_is_level_enabled((log_level_t)level)
|
||||
|
||||
#endif // ADBMS_NO_LOGGING_DEFS
|
||||
|
||||
#endif // __ADBMS_INTERN_H
|
@ -1,19 +1,11 @@
|
||||
/*
|
||||
* ADBMS_LL_Driver.h
|
||||
*
|
||||
* Created on: 05.06.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#ifndef ADBMS_LL_DRIVER_H_
|
||||
#define ADBMS_LL_DRIVER_H_
|
||||
|
||||
#include "config_ADBMS6830.h"
|
||||
#include "ADBMS_Intern.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi);
|
||||
|
||||
//2 command + 2 PEC + (data + 2 DPEC) per BMS
|
||||
#define CMD_BUFFER_SIZE(datalen) (4 + (N_BMS * ((datalen) + 2)))
|
||||
|
||||
@ -22,32 +14,31 @@ uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi);
|
||||
#define CMD_EMPTY_BUFFER ((uint8_t[CMD_BUFFER_SIZE(0)]){0})
|
||||
#define CMD_EMPTY_BUFFER_SIZE CMD_BUFFER_SIZE(0)
|
||||
|
||||
HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen);
|
||||
ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t arglen);
|
||||
|
||||
[[gnu::access(read_write, 2, 4), gnu::nonnull(2), gnu::always_inline]] //add dummy size variable for bounds checking, should be optimized out
|
||||
static inline HAL_StatusTypeDef __writeCMD(uint16_t command, uint8_t * args, size_t arglen, size_t) {
|
||||
static inline ADBMS_Internal_Status __writeCMD(uint16_t command, uint8_t * args, size_t arglen, size_t) {
|
||||
return ___writeCMD(command, args, arglen);
|
||||
}
|
||||
|
||||
#define writeCMD(command, args, arglen) \
|
||||
__writeCMD(command, args, arglen, CMD_BUFFER_SIZE(arglen))
|
||||
|
||||
HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen);
|
||||
ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen);
|
||||
|
||||
[[gnu::access(read_write, 2, 4), gnu::nonnull(2), gnu::always_inline]] //add dummy size variable for bounds checking, should be optimized out
|
||||
static inline HAL_StatusTypeDef __readCMD(uint16_t command, uint8_t * buffer, size_t arglen, size_t) {
|
||||
static inline ADBMS_Internal_Status __readCMD(uint16_t command, uint8_t * buffer, size_t arglen, size_t) {
|
||||
return ___readCMD(command, buffer, arglen);
|
||||
}
|
||||
|
||||
#define readCMD(command, buffer, buflen) \
|
||||
__readCMD(command, buffer, buflen, CMD_BUFFER_SIZE(buflen))
|
||||
|
||||
HAL_StatusTypeDef __pollCMD(uint16_t command, uint8_t waitTime);
|
||||
ADBMS_Internal_Status __pollCMD(uint16_t command, uint8_t waitTime);
|
||||
|
||||
#define pollCMD(command) \
|
||||
__pollCMD(command, (N_BMS * 2) + 1) //poll is only valid after 2 * N_BMS clock cycles, +1 for safety, see datasheet page 55
|
||||
|
||||
uint8_t wakeUpCmd();
|
||||
static inline void mcuDelay(uint16_t delay) { HAL_Delay(delay); };
|
||||
void initSPI(USER_PTR_TYPE ptr);
|
||||
|
||||
#endif /* ADBMS_LL_DRIVER_H_ */
|
@ -1,40 +1,32 @@
|
||||
/*
|
||||
* ADBMS_Abstraction.c
|
||||
*
|
||||
* Created on: 14.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_CMD_MAKROS.h"
|
||||
#include "ADBMS_CMD_Defines.h"
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
#include "ADBMS_Intern.h"
|
||||
#include <stddef.h>
|
||||
#include "NTC.h"
|
||||
|
||||
#define SWO_LOG_PREFIX "[ADBMS] "
|
||||
#include "swo_log.h"
|
||||
|
||||
static const char* const HAL_Statuses[] = {"HAL_OK", "HAL_ERROR", "HAL_BUSY", "HAL_TIMEOUT"};
|
||||
static const char* const ADBMS_Statuses[] = {"ADBMS_OK", "ADBMS_ERROR", "ADBMS_BUSY", "ADBMS_TIMEOUT"};
|
||||
|
||||
#define CHECK_RETURN(x) \
|
||||
do { \
|
||||
HAL_StatusTypeDef status = x; \
|
||||
ADBMS_Internal_Status status = x; \
|
||||
if (status != 0) { \
|
||||
debug_log(LOG_LEVEL_ERROR, "in %s:%d@%s: %s failed with status %d (%s)", __FILE_NAME__, __LINE__, __func__,\
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "in %s:%d@%s: %s failed with status %d (%s)", __FILE_NAME__, __LINE__, __func__,\
|
||||
#x, status, \
|
||||
(status < (sizeof(HAL_Statuses) / sizeof(HAL_Statuses[0]))) ? HAL_Statuses[status] : "Unknown"); \
|
||||
(status < (sizeof(ADBMS_Statuses) / sizeof(ADBMS_Statuses[0]))) ? ADBMS_Statuses[status] : "Unknown"); \
|
||||
return status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
HAL_StatusTypeDef amsReset() {
|
||||
ADBMS_Internal_Status amsReset() {
|
||||
amsWakeUp();
|
||||
readCMD(SRST, CMD_EMPTY_BUFFER, 0);
|
||||
|
||||
amsWakeUp();
|
||||
|
||||
uint8_t sidbuffer[CMD_BUFFER_SIZE(SID_GROUP_SIZE)] = {};
|
||||
if (readCMD(RDSID, sidbuffer, SID_GROUP_SIZE) != HAL_OK) {
|
||||
if (readCMD(RDSID, sidbuffer, SID_GROUP_SIZE) != ADBMS_OK) {
|
||||
bool nonzero = false;
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
if (sidbuffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE)] != 0) {
|
||||
@ -42,27 +34,27 @@ HAL_StatusTypeDef amsReset() {
|
||||
}
|
||||
}
|
||||
if (nonzero) {
|
||||
debug_log(LOG_LEVEL_ERROR,
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR,
|
||||
"CRC failure when reading BMS IDs, but some IDs are nonzero. --- Intermittent connection?");
|
||||
} else {
|
||||
debug_log(LOG_LEVEL_ERROR, "CRC failure when reading BMS IDs, all IDs are zero. --- No connection?");
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "CRC failure when reading BMS IDs, all IDs are zero. --- No connection?");
|
||||
}
|
||||
return HAL_ERROR;
|
||||
return ADBMS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
debug_log(LOG_LEVEL_INFO, "BMS reset complete");
|
||||
debug_log(ADBMS_LOG_LEVEL_INFO, "BMS reset complete");
|
||||
|
||||
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_INFO)) {
|
||||
debug_log(LOG_LEVEL_INFO, "Found IDs: ");
|
||||
if (DEBUG_CHANNEL_ENABLED(ADBMS_LOG_LEVEL_INFO)) {
|
||||
debug_log(ADBMS_LOG_LEVEL_INFO, "Found IDs: ");
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
uint64_t id = 0;
|
||||
for (size_t j = 0; j < SID_GROUP_SIZE; j++) {
|
||||
id |= sidbuffer[BUFFER_BMS_OFFSET(i, SID_GROUP_SIZE) + j] << (j * 8);
|
||||
}
|
||||
modules[i].bmsID = id;
|
||||
debug_log_cont(LOG_LEVEL_INFO, "0x%08lx%08lx ", (uint32_t)(id >> 32), (uint32_t)(id & 0xFFFFFFFF)); //newlib does not support %llu
|
||||
bms_data[i].bmsID = id;
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_INFO, "0x%08lx%08lx ", (uint32_t)(id >> 32), (uint32_t)(id & 0xFFFFFFFF)); //newlib does not support %llu
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,31 +71,29 @@ HAL_StatusTypeDef amsReset() {
|
||||
CHECK_RETURN(writeCMD(ADCV | ADCV_CONT | ADCV_RD, flagsbuffer, 0)); //start continuous cell voltage measurement with redundancy
|
||||
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, flagsbuffer, 0)); //start aux measurement
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef initAMS(SPI_HandleTypeDef* hspi) {
|
||||
// pull MSTR High for Microcontroller mode ADBMS6822
|
||||
HAL_GPIO_WritePin(MSTR1_GPIO_Port, MSTR1_Pin, GPIO_PIN_SET);
|
||||
adbmsDriverInit(hspi);
|
||||
ADBMS_Internal_Status initAMS(USER_PTR_TYPE ptr) {
|
||||
initSPI(ptr); // Initialize the SPI interface
|
||||
return amsReset();
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsWakeUp() {
|
||||
ADBMS_Internal_Status amsWakeUp() {
|
||||
return __pollCMD(PLADC, 100); //wake up ADBMS6830, wait for T_wake = 200 us (100 cycles at 500 kHz)
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsCellMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
ADBMS_Internal_Status amsCellMeasurement(BMS_Chip (*module)[N_BMS]) {
|
||||
#warning check conversion counter to ensure that continuous conversion has not been stopped
|
||||
#warning check for OW conditions: ADSV | ADSV_OW_0 / ADSV_OW_1
|
||||
return amsReadCellVoltages(module);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
ADBMS_Internal_Status amsAuxAndStatusMeasurement(BMS_Chip (*module)[N_BMS]) {
|
||||
uint8_t rxbuf[CMD_BUFFER_SIZE(STATUS_GROUP_C_SIZE)] = {};
|
||||
CHECK_RETURN(readCMD(RDSTATC, rxbuf, STATUS_GROUP_C_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_C_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_C_SIZE);
|
||||
(*module)[i].status.CS_FLT = rxbuf[offset + 0] | (rxbuf[offset + 1] << 8);
|
||||
(*module)[i].status.CCTS = rxbuf[offset + 2] | (rxbuf[offset + 3] << 8);
|
||||
(*module)[i].status.VA_OV = (rxbuf[offset + 4] >> 7) & 0x01;
|
||||
@ -124,8 +114,8 @@ HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
(*module)[i].status.OSCCHK = (rxbuf[offset + 5] >> 0) & 0x01;
|
||||
}
|
||||
|
||||
if (pollCMD(PLAUX) == HAL_BUSY) {
|
||||
// return HAL_BUSY;
|
||||
if (pollCMD(PLAUX) == ADBMS_BUSY) {
|
||||
// return ADBMS_BUSY;
|
||||
}
|
||||
|
||||
constexpr size_t auxGroupSizes[] = {AUX_GROUP_A_SIZE, AUX_GROUP_B_SIZE, AUX_GROUP_C_SIZE, AUX_GROUP_D_SIZE};
|
||||
@ -136,7 +126,7 @@ HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
for (size_t group = 0; group < 4; group++) {
|
||||
CHECK_RETURN(readCMD(auxCommands[group], rxbuf, auxGroupSizes[group]));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, auxGroupSizes[group]);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, auxGroupSizes[group]);
|
||||
for (size_t j = 0; j < auxVoltagesPerGroup[group]; j++) {
|
||||
(*module)[i].auxVoltages[group * 3 + j] = mV_from_ADBMS6830(rxbuf[offset + j * 2] | (rxbuf[offset + j * 2 + 1] << 8));
|
||||
}
|
||||
@ -146,13 +136,13 @@ HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATA, rxbuf, STATUS_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_A_SIZE);
|
||||
(*module)[i].internalDieTemp = (mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8)) / 7.5f) - 273; //datasheet page 72
|
||||
}
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATB, rxbuf, STATUS_GROUP_B_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_B_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_B_SIZE);
|
||||
(*module)[i].digitalSupplyVoltage = mV_from_ADBMS6830(rxbuf[offset + 0] | (rxbuf[offset + 1] << 8));
|
||||
(*module)[i].analogSupplyVoltage = mV_from_ADBMS6830(rxbuf[offset + 2] | (rxbuf[offset + 3] << 8));
|
||||
(*module)[i].refVoltage = mV_from_ADBMS6830(rxbuf[offset + 4] | (rxbuf[offset + 5] << 8));
|
||||
@ -160,12 +150,12 @@ HAL_StatusTypeDef amsAuxAndStatusMeasurement(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(writeCMD(ADAX | ADAX_CONV_ALL, rxbuf, 0)); // start aux conversion for next iteration
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle) {
|
||||
ADBMS_Internal_Status amsConfigBalancing(const uint32_t channels[static N_BMS], uint8_t dutyCycle) {
|
||||
if (dutyCycle > 0x0F) {
|
||||
return HAL_ERROR; // only 4 bits are allowed for dutyCycle
|
||||
return ADBMS_ERROR; // only 4 bits are allowed for dutyCycle
|
||||
}
|
||||
|
||||
uint8_t rxbufA[CMD_BUFFER_SIZE(PWM_GROUP_A_SIZE)] = {};
|
||||
@ -175,12 +165,12 @@ HAL_StatusTypeDef amsConfigBalancing(const uint32_t channels[static N_BMS], uint
|
||||
CHECK_RETURN(readCMD(RDPWMB, rxbufB, PWM_GROUP_B_SIZE));
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offsetA = BUFFER_BMS_OFFSET(i, PWM_GROUP_A_SIZE);
|
||||
size_t offsetB = BUFFER_BMS_OFFSET(i, PWM_GROUP_B_SIZE);
|
||||
const size_t offsetA = BUFFER_BMS_OFFSET(i, PWM_GROUP_A_SIZE);
|
||||
const size_t offsetB = BUFFER_BMS_OFFSET(i, PWM_GROUP_B_SIZE);
|
||||
|
||||
for (size_t c = 0; c < 16; c += 2) {
|
||||
uint8_t high = (channels[i] & (1 << (c + 1))) ? (dutyCycle << 4) : 0;
|
||||
uint8_t low = (channels[i] & (1 << c)) ? dutyCycle : 0;
|
||||
const uint8_t high = (channels[i] & (1 << (c + 1))) ? (dutyCycle << 4) : 0;
|
||||
const uint8_t low = (channels[i] & (1 << c)) ? dutyCycle : 0;
|
||||
|
||||
if (c < 12) {
|
||||
rxbufA[offsetA + (c / 2)] = high | low;
|
||||
@ -191,13 +181,13 @@ HAL_StatusTypeDef amsConfigBalancing(const uint32_t channels[static N_BMS], uint
|
||||
|
||||
// log the new PWM settings
|
||||
// output is: PWM - [BMS_ID]: [PWM0] ... [PWM16]
|
||||
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_DEBUG)) {
|
||||
debug_log(LOG_LEVEL_DEBUG, "PWM - %d: ", i);
|
||||
if (DEBUG_CHANNEL_ENABLED(ADBMS_LOG_LEVEL_DEBUG)) {
|
||||
debug_log(ADBMS_LOG_LEVEL_DEBUG, "PWM - %d: ", i);
|
||||
for (size_t j = 0; j < 6; j++) {
|
||||
debug_log_cont(LOG_LEVEL_DEBUG, "%x %x ", rxbufA[offsetA + j] & 0x0F, rxbufA[offsetA + j] >> 4);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_DEBUG, "%x %x ", rxbufA[offsetA + j] & 0x0F, rxbufA[offsetA + j] >> 4);
|
||||
}
|
||||
for (size_t j = 0; j < 2; j++) {
|
||||
debug_log_cont(LOG_LEVEL_DEBUG, "%x %x ", rxbufB[offsetB + j] & 0x0F, rxbufB[offsetB + j] >> 4);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_DEBUG, "%x %x ", rxbufB[offsetB + j] & 0x0F, rxbufB[offsetB + j] >> 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,19 +195,19 @@ HAL_StatusTypeDef amsConfigBalancing(const uint32_t channels[static N_BMS], uint
|
||||
CHECK_RETURN(writeCMD(WRPWMA, rxbufA, PWM_GROUP_A_SIZE));
|
||||
CHECK_RETURN(writeCMD(WRPWMB, rxbufB, PWM_GROUP_B_SIZE));
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsStartBalancing() { return writeCMD(UNMUTE, CMD_EMPTY_BUFFER, 0); }
|
||||
ADBMS_Internal_Status amsStartBalancing() { return writeCMD(UNMUTE, CMD_EMPTY_BUFFER, 0); }
|
||||
|
||||
HAL_StatusTypeDef amsStopBalancing() { return writeCMD(MUTE, CMD_EMPTY_BUFFER, 0); }
|
||||
ADBMS_Internal_Status amsStopBalancing() { return writeCMD(MUTE, CMD_EMPTY_BUFFER, 0); }
|
||||
|
||||
HAL_StatusTypeDef amsSelfTest() { return 0; }
|
||||
ADBMS_Internal_Status amsSelfTest() { return 0; }
|
||||
|
||||
HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage) {
|
||||
ADBMS_Internal_Status amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t underVoltage) {
|
||||
uint8_t buffer[CMD_BUFFER_SIZE(CFG_GROUP_B_SIZE)] = {};
|
||||
|
||||
debug_log(LOG_LEVEL_INFO, "Configuring OV/UV thresholds to %u mV (%u internal) / %u mV (%u internal)", overVoltage,
|
||||
debug_log(ADBMS_LOG_LEVEL_INFO, "Configuring OV/UV thresholds to %u mV (%u internal) / %u mV (%u internal)", overVoltage,
|
||||
mV_to_ADBMS6830(overVoltage), underVoltage, mV_to_ADBMS6830(underVoltage));
|
||||
|
||||
CHECK_RETURN(readCMD(RDCFGB, buffer, CFG_GROUP_B_SIZE));
|
||||
@ -226,12 +216,12 @@ HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t under
|
||||
underVoltage = mV_to_ADBMS6830(underVoltage);
|
||||
|
||||
if (underVoltage & 0xF000 || overVoltage & 0xF000) { // only 12 bits allowed
|
||||
debug_log(LOG_LEVEL_ERROR, "Invalid OV/UV thresholds: %u mV / %u mV", overVoltage, underVoltage);
|
||||
return HAL_ERROR;
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "Invalid OV/UV thresholds: %u mV / %u mV", overVoltage, underVoltage);
|
||||
return ADBMS_ERROR;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CFG_GROUP_B_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CFG_GROUP_B_SIZE);
|
||||
|
||||
// UV
|
||||
buffer[offset + 0] = (uint8_t)(underVoltage & 0xFF);
|
||||
@ -247,13 +237,13 @@ HAL_StatusTypeDef amsConfigOverUnderVoltage(uint16_t overVoltage, uint16_t under
|
||||
return writeCMD(WRCFGB, buffer, CFG_GROUP_B_SIZE);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]) {
|
||||
ADBMS_Internal_Status amsCheckUnderOverVoltage(BMS_Chip (*module)[N_BMS]) {
|
||||
uint8_t regbuffer[CMD_BUFFER_SIZE(STATUS_GROUP_D_SIZE)] = {};
|
||||
|
||||
CHECK_RETURN(readCMD(RDSTATD, regbuffer, STATUS_GROUP_D_SIZE));
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_D_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, STATUS_GROUP_D_SIZE);
|
||||
uint32_t ov_uv_data = 0;
|
||||
ov_uv_data = (regbuffer[offset + 0] << 0) | (regbuffer[offset + 1] << 8) | (regbuffer[offset + 2] << 16) |
|
||||
(regbuffer[offset + 3] << 24);
|
||||
@ -272,24 +262,24 @@ HAL_StatusTypeDef amsCheckUnderOverVoltage(Cell_Module (*module)[N_BMS]) {
|
||||
return writeCMD(CLOVUV, buffer, STATUS_GROUP_D_SIZE); // flags are latched, so we need to clear them
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsClearFlag() {
|
||||
ADBMS_Internal_Status amsClearFlag() {
|
||||
uint8_t buffer[CMD_BUFFER_SIZE(6)] = {[0 ... CMD_BUFFER_SIZE(6) - 1] = 0xFF};
|
||||
return writeCMD(CLRFLAG, buffer, 6);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsClearAux() { return writeCMD(CLRAUX, CMD_EMPTY_BUFFER, 0); }
|
||||
ADBMS_Internal_Status amsClearAux() { return writeCMD(CLRAUX, CMD_EMPTY_BUFFER, 0); }
|
||||
|
||||
HAL_StatusTypeDef amsClearOVUV() {
|
||||
ADBMS_Internal_Status amsClearOVUV() {
|
||||
uint8_t buffer[CMD_BUFFER_SIZE(6)] = {[0 ... CMD_BUFFER_SIZE(6) - 1] = 0xFF};
|
||||
return writeCMD(CLOVUV, buffer, 6);
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
ADBMS_Internal_Status amsReadCellVoltages(BMS_Chip (*module)[N_BMS]) {
|
||||
uint8_t rxbuffer[CMD_BUFFER_SIZE(CV_GROUP_A_SIZE)] = {};
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVA, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[0] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
(*module)[i].cellVoltages[1] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
|
||||
(*module)[i].cellVoltages[2] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
|
||||
@ -297,7 +287,7 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVB, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[3] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
(*module)[i].cellVoltages[4] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
|
||||
(*module)[i].cellVoltages[5] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
|
||||
@ -305,7 +295,7 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVC, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[6] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
(*module)[i].cellVoltages[7] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
|
||||
(*module)[i].cellVoltages[8] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
|
||||
@ -313,7 +303,7 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVD, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[9] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
(*module)[i].cellVoltages[10] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
|
||||
(*module)[i].cellVoltages[11] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
|
||||
@ -321,7 +311,7 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVE, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[12] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
(*module)[i].cellVoltages[13] = mV_from_ADBMS6830(rxbuffer[offset + 2] | (rxbuffer[offset + 3] << 8));
|
||||
(*module)[i].cellVoltages[14] = mV_from_ADBMS6830(rxbuffer[offset + 4] | (rxbuffer[offset + 5] << 8));
|
||||
@ -329,16 +319,16 @@ HAL_StatusTypeDef amsReadCellVoltages(Cell_Module (*module)[N_BMS]) {
|
||||
|
||||
CHECK_RETURN(readCMD(RDCVF, rxbuffer, CV_GROUP_A_SIZE));
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, CV_GROUP_A_SIZE);
|
||||
(*module)[i].cellVoltages[15] = mV_from_ADBMS6830(rxbuffer[offset + 0] | (rxbuffer[offset + 1] << 8));
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
// Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i]
|
||||
// bytes long
|
||||
HAL_StatusTypeDef amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS],
|
||||
ADBMS_Internal_Status amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS],
|
||||
const uint8_t datalens[static N_BMS], uint32_t bms_mask) {
|
||||
uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {};
|
||||
|
||||
@ -352,7 +342,7 @@ HAL_StatusTypeDef amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE);
|
||||
|
||||
if (!(bms_mask & (1 << i))) {
|
||||
buffer[offset + 0] = I2C_SEND_NOTRANSFER;
|
||||
@ -362,12 +352,12 @@ HAL_StatusTypeDef amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
}
|
||||
}
|
||||
|
||||
size_t packet_count =
|
||||
const size_t packet_count =
|
||||
((max_datalen + 1) / 3) + ((max_datalen + 1) % 3 != 0); // number of 3 byte packets needed to send all data
|
||||
|
||||
for (size_t i = 0; i < (packet_count * 3); i++) { //i - 1 is the number of data bytes sent so far (1 byte for the address)
|
||||
for (size_t j = 0; j < N_BMS; j++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
if (!(bms_mask & (1 << j)))
|
||||
continue; // skip BMS that are not selected
|
||||
|
||||
@ -409,12 +399,12 @@ HAL_StatusTypeDef amsSendI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
CHECK_RETURN(writeCMD(WRCOMM, buffer, COMM_GROUP_SIZE));
|
||||
__pollCMD(STCOMM, 72);
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
// Each selected BMS must have a corresponding address, and the data array for that BMS must be at least datalens[i]
|
||||
// bytes long
|
||||
HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS],
|
||||
ADBMS_Internal_Status amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* data[static N_BMS],
|
||||
const uint8_t datalens[static N_BMS], uint32_t bms_mask) {
|
||||
uint8_t buffer[CMD_BUFFER_SIZE(COMM_GROUP_SIZE)] = {};
|
||||
|
||||
@ -426,7 +416,7 @@ HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, COMM_GROUP_SIZE);
|
||||
|
||||
if (!(bms_mask & (1 << i))) {
|
||||
buffer[offset + 0] = I2C_SEND_NOTRANSFER;
|
||||
@ -436,7 +426,7 @@ HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
}
|
||||
}
|
||||
|
||||
size_t packet_count = ((max_datalen + 1) / 3) + ((max_datalen + 1) % 3 != 0);
|
||||
const size_t packet_count = ((max_datalen + 1) / 3) + ((max_datalen + 1) % 3 != 0);
|
||||
|
||||
for (size_t i = 0; i < (packet_count * 3);
|
||||
i++) { // i - 1 is the number of data bytes sent so far (1 byte for the address)
|
||||
@ -480,7 +470,7 @@ HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
CHECK_RETURN(readCMD(RDCOMM, buffer, COMM_GROUP_SIZE));
|
||||
|
||||
for (size_t j = 0; j < N_BMS; j++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
|
||||
if (!(bms_mask & (1 << j)))
|
||||
continue; // skip BMS that are not selected
|
||||
@ -504,7 +494,7 @@ HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
CHECK_RETURN(readCMD(RDCOMM, buffer, COMM_GROUP_SIZE));
|
||||
|
||||
for (size_t j = 0; j < N_BMS; j++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(j, COMM_GROUP_SIZE);
|
||||
|
||||
if (!(bms_mask & (1 << j)))
|
||||
continue; // skip BMS that are not selected
|
||||
@ -518,5 +508,5 @@ HAL_StatusTypeDef amsReadI2C(const uint8_t addresses[static N_BMS], uint8_t* dat
|
||||
}
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
@ -1,24 +1,12 @@
|
||||
/*
|
||||
* AMS_HighLevel.c
|
||||
*
|
||||
* Created on: 20.07.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "ADBMS_HighLevel.h"
|
||||
#include "ADBMS_Abstraction.h"
|
||||
#include "ADBMS_Driver.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "ADBMS_Intern.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SWO_LOG_PREFIX "[ADBMS] "
|
||||
#include "swo_log.h"
|
||||
|
||||
Cell_Module modules[N_BMS] = {};
|
||||
uint32_t balancedCells = 0;
|
||||
bool balancingActive = false;
|
||||
BMS_Chip bms_data[N_BMS] = {};
|
||||
|
||||
uint8_t packetChecksumFails = 0;
|
||||
#define MAX_PACKET_CHECKSUM_FAILS 5
|
||||
@ -35,15 +23,14 @@ struct pollingTimes pollingTimes = {0, 0};
|
||||
|
||||
static constexpr ADBMS_DetailedStatus NO_ERROR = {ADBMS_NO_ERROR};
|
||||
|
||||
ADBMS_DetailedStatus AMS_Init(SPI_HandleTypeDef* hspi) {
|
||||
debug_log(LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS,
|
||||
ADBMS_DetailedStatus AMS_Init(USER_PTR_TYPE ptr) {
|
||||
debug_log(ADBMS_LOG_LEVEL_INFO, "ADBMS6830B HAL - configured for %d controllers and %d cells per controller...", N_BMS,
|
||||
N_CELLS);
|
||||
if (initAMS(hspi) != HAL_OK) {
|
||||
debug_log(LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed");
|
||||
if (initAMS(ptr) != ADBMS_OK) {
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "ADBMS6830B HAL - initialization failed");
|
||||
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, -1};
|
||||
}
|
||||
|
||||
pollingTimes = (struct pollingTimes){HAL_GetTick(), HAL_GetTick()};
|
||||
packetChecksumFails = 0;
|
||||
deviceSleeps = 0;
|
||||
return NO_ERROR;
|
||||
@ -53,7 +40,7 @@ ADBMS_DetailedStatus AMS_Init(SPI_HandleTypeDef* hspi) {
|
||||
({ \
|
||||
int first_match = -1; \
|
||||
for (size_t __any_intern_i = 0; __any_intern_i < N_BMS; __any_intern_i++) { \
|
||||
Cell_Module module = modules[__any_intern_i]; \
|
||||
BMS_Chip module = bms_data[__any_intern_i]; \
|
||||
if ((x)) { \
|
||||
first_match = __any_intern_i; \
|
||||
break; \
|
||||
@ -68,7 +55,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
|
||||
// set_error_source(ERROR_SOURCE_INTERNAL); //so we can't tell if we timed out
|
||||
}
|
||||
|
||||
packetChecksumFails += (amsAuxAndStatusMeasurement(&modules) == HAL_ERROR);
|
||||
packetChecksumFails += (amsAuxAndStatusMeasurement(&bms_data) == ADBMS_ERROR);
|
||||
|
||||
int match = 0;
|
||||
if ((match = any(module.status.SLEEP))) {
|
||||
@ -76,7 +63,7 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
|
||||
if (deviceSleeps > MAX_DEVICE_SLEEP) {
|
||||
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_TIMEOUT, match - 1};
|
||||
} else {
|
||||
debug_log(LOG_LEVEL_WARNING, "BMS %d unexpectedly in sleep mode, resetting...", match - 1);
|
||||
debug_log(ADBMS_LOG_LEVEL_WARNING, "BMS %d unexpectedly in sleep mode, resetting...", match - 1);
|
||||
amsReset();
|
||||
}
|
||||
}
|
||||
@ -87,22 +74,22 @@ ADBMS_DetailedStatus AMS_Idle_Loop() {
|
||||
// iteration.
|
||||
amsClearFlag();
|
||||
// Log specific BMS fault details
|
||||
debug_log(LOG_LEVEL_ERROR, "Fault on BMS %d: ", match - 1);
|
||||
auto faultyModule = &modules[match - 1];
|
||||
if (faultyModule->status.CS_FLT) debug_log_cont(LOG_LEVEL_ERROR, "CS_FLT ");
|
||||
if (faultyModule->status.SPIFLT) debug_log_cont(LOG_LEVEL_ERROR, "SPIFLT ");
|
||||
if (faultyModule->status.CMED) debug_log_cont(LOG_LEVEL_ERROR, "CMED ");
|
||||
if (faultyModule->status.SMED) debug_log_cont(LOG_LEVEL_ERROR, "SMED ");
|
||||
if (faultyModule->status.VDE) debug_log_cont(LOG_LEVEL_ERROR, "VDE ");
|
||||
if (faultyModule->status.VDEL) debug_log_cont(LOG_LEVEL_ERROR, "VDEL ");
|
||||
if (faultyModule->status.OSCCHK) debug_log_cont(LOG_LEVEL_ERROR, "OSCCHK ");
|
||||
if (faultyModule->status.TMODCHK) debug_log_cont(LOG_LEVEL_ERROR, "TMODCHK ");
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "Fault on BMS %d: ", match - 1);
|
||||
auto faultyModule = &bms_data[match - 1];
|
||||
if (faultyModule->status.CS_FLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CS_FLT ");
|
||||
if (faultyModule->status.SPIFLT) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "SPIFLT ");
|
||||
if (faultyModule->status.CMED) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "CMED ");
|
||||
if (faultyModule->status.SMED) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "SMED ");
|
||||
if (faultyModule->status.VDE) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "VDE ");
|
||||
if (faultyModule->status.VDEL) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "VDEL ");
|
||||
if (faultyModule->status.OSCCHK) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "OSCCHK ");
|
||||
if (faultyModule->status.TMODCHK) debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "TMODCHK ");
|
||||
|
||||
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_FAULT, match - 1};
|
||||
}
|
||||
|
||||
packetChecksumFails += (amsCellMeasurement(&modules) == HAL_ERROR);
|
||||
packetChecksumFails += (amsCheckUnderOverVoltage(&modules) == HAL_ERROR);
|
||||
packetChecksumFails += (amsCellMeasurement(&bms_data) == ADBMS_ERROR);
|
||||
packetChecksumFails += (amsCheckUnderOverVoltage(&bms_data) == ADBMS_ERROR);
|
||||
|
||||
if (packetChecksumFails > MAX_PACKET_CHECKSUM_FAILS) {
|
||||
return (ADBMS_DetailedStatus){ADBMS_INTERNAL_BMS_CHECKSUM_FAIL, -1};
|
@ -1,18 +1,19 @@
|
||||
/*
|
||||
* ADBMS_LL_Driver.c
|
||||
*
|
||||
* Created on: 05.06.2022
|
||||
* Author: max
|
||||
*/
|
||||
|
||||
#include "ADBMS_LL_Driver.h"
|
||||
#include "config_ADBMS6830.h"
|
||||
#include "stm32h7xx_hal.h"
|
||||
#include "ADBMS_Intern.h"
|
||||
#include <stdint.h>
|
||||
#include <strings.h>
|
||||
|
||||
#define SWO_LOG_PREFIX "[ADBMS] "
|
||||
#include "swo_log.h"
|
||||
#if __has_include("stm32h7xx_hal.h")
|
||||
#include "stm32h7xx_hal.h"
|
||||
#define STM32_HAL
|
||||
#endif
|
||||
|
||||
static USER_PTR_TYPE usr_ptr; // SPI_HandleTypeDef*
|
||||
|
||||
void initSPI(USER_PTR_TYPE ptr) {
|
||||
usr_ptr = ptr; // Store the user pointer for SPI communication
|
||||
}
|
||||
|
||||
#define INITIAL_COMMAND_PEC 0x0010
|
||||
#define INITIAL_DATA_PEC 0x0010
|
||||
@ -24,31 +25,6 @@
|
||||
#define CRC10_REMAINDER_MASK 0x200
|
||||
#define CRC10_RESULT_MASK 0x3FF
|
||||
|
||||
SPI_HandleTypeDef* adbmsspi;
|
||||
|
||||
uint8_t adbmsDriverInit(SPI_HandleTypeDef* hspi) {
|
||||
mcuAdbmsCSLow();
|
||||
HAL_Delay(1);
|
||||
mcuAdbmsCSHigh();
|
||||
adbmsspi = hspi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef mcuSPITransmit(uint8_t* buffer, uint8_t buffersize) {
|
||||
HAL_StatusTypeDef status;
|
||||
status = HAL_SPI_Transmit(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
|
||||
__HAL_SPI_CLEAR_OVRFLAG(adbmsspi);
|
||||
return status;
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef mcuSPIReceive(uint8_t* buffer, uint8_t buffersize) {
|
||||
return HAL_SPI_Receive(adbmsspi, buffer, buffersize, ADBMS_SPI_TIMEOUT);
|
||||
}
|
||||
|
||||
static HAL_StatusTypeDef mcuSPITransmitReceive(uint8_t* rxbuffer, uint8_t* txbuffer, uint8_t buffersize) {
|
||||
return HAL_SPI_TransmitReceive(adbmsspi, txbuffer, rxbuffer, buffersize, ADBMS_SPI_TIMEOUT);
|
||||
}
|
||||
|
||||
//command PEC calculation
|
||||
//CRC-15
|
||||
//x^15 + x^14 + x^10 + x^8 + x^7 + x^4 + x^3 + 1
|
||||
@ -70,17 +46,17 @@ static uint16_t computeCRC15(const uint8_t* data, size_t length) {
|
||||
|
||||
static uint8_t calculateCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
if (datalen < 3) { return 1; }
|
||||
uint16_t pec = computeCRC15(data, datalen - 2);
|
||||
const uint16_t pec = computeCRC15(data, datalen - 2);
|
||||
data[datalen - 2] = (uint8_t)((pec >> 7) & 0xFF);
|
||||
data[datalen - 1] = (uint8_t)((pec << 1) & 0xFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t checkCommandPEC(uint8_t* data, uint8_t datalen) {
|
||||
static uint8_t checkCommandPEC(const uint8_t* data, uint8_t datalen) {
|
||||
if (datalen <= 3) { return 255; }
|
||||
uint16_t pec = computeCRC15(data, datalen - 2);
|
||||
uint8_t pech = (uint8_t)((pec >> 7) & 0xFF);
|
||||
uint8_t pecl = (uint8_t)((pec << 1) & 0xFF);
|
||||
const uint16_t pec = computeCRC15(data, datalen - 2);
|
||||
const uint8_t pech = (uint8_t)((pec >> 7) & 0xFF);
|
||||
const uint8_t pecl = (uint8_t)((pec << 1) & 0xFF);
|
||||
return ((pech == data[datalen - 2]) && (pecl == data[datalen - 1])) ? 0 : 1;
|
||||
}
|
||||
|
||||
@ -118,22 +94,24 @@ static uint16_t computeCRC10(const uint8_t* data, size_t length, bool rx_cmd) {
|
||||
|
||||
static uint8_t calculateDataPEC(uint8_t* data, uint8_t datalen) {
|
||||
if (datalen < 3) { return 1; }
|
||||
uint16_t crcVal = computeCRC10(data, datalen - 2, true);
|
||||
const uint16_t crcVal = computeCRC10(data, datalen - 2, true);
|
||||
data[datalen - 2] = (uint8_t)((crcVal >> 8) & 0xFF);
|
||||
data[datalen - 1] = (uint8_t)(crcVal & 0xFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t checkDataPEC(uint8_t* data, uint8_t len) {
|
||||
static uint8_t checkDataPEC(const uint8_t* data, uint8_t len) {
|
||||
if (len <= 2) { return 255; }
|
||||
// Zero remainder means a valid CRC.
|
||||
return (computeCRC10(data, len, false) == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
static const char* const HAL_Statuses[] = {"HAL_OK", "HAL_ERROR", "HAL_BUSY", "HAL_TIMEOUT"};
|
||||
static const char* const ADBMS_Statuses[] = {"ADBMS_OK", "ADBMS_ERROR", "ADBMS_BUSY", "ADBMS_TIMEOUT"};
|
||||
|
||||
#ifdef STM32_HAL // feel free to replace this with your own SPI error handling
|
||||
static void print_spi_details() {
|
||||
uint32_t spi_error = HAL_SPI_GetError(adbmsspi);
|
||||
extern SPI_HandleTypeDef * usr_ptr;
|
||||
const uint32_t spi_error = HAL_SPI_GetError(usr_ptr);
|
||||
|
||||
typedef struct {
|
||||
uint32_t mask;
|
||||
@ -162,27 +140,26 @@ static void print_spi_details() {
|
||||
constexpr size_t numErrors = sizeof(errors) / sizeof(errors[0]);
|
||||
for (size_t i = 0; i < numErrors; i++) {
|
||||
if (spi_error & errors[i].mask) {
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "%s ", errors[i].label);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "%s ", errors[i].label);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
|
||||
HAL_StatusTypeDef ret;
|
||||
|
||||
ADBMS_Internal_Status ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
|
||||
ADBMS_Internal_Status ret;
|
||||
if (arglen > 0) {
|
||||
args[0] = (command >> 8) & 0xFF;
|
||||
args[1] = (command) & 0xFF;
|
||||
|
||||
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_NOISY)) {
|
||||
debug_log(LOG_LEVEL_NOISY, "%lu W | %02X %02X ", HAL_GetTick(), args[0], args[1]);
|
||||
if (DEBUG_CHANNEL_ENABLED(ADBMS_LOG_LEVEL_NOISY)) {
|
||||
debug_log(ADBMS_LOG_LEVEL_NOISY, "%lu W | %02X %02X ", mcuGetTime(), args[0], args[1]);
|
||||
|
||||
//print out data bytes
|
||||
if (arglen > 0) {
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
debug_log_cont(LOG_LEVEL_NOISY, "%d: ", i);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_NOISY, "%d: ", i);
|
||||
for (size_t j = 0; j < arglen; j++) {
|
||||
debug_log_cont(LOG_LEVEL_NOISY, "%02X ", args[BUFFER_BMS_OFFSET(i, arglen) + j]);
|
||||
}
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_NOISY, "%02X ", args[BUFFER_BMS_OFFSET(i, arglen) + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,7 +173,7 @@ HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
|
||||
}
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
ret = mcuSPITransmit(args, CMD_BUFFER_SIZE(arglen));
|
||||
ret = mcuSPITransmit(usr_ptr, args, CMD_BUFFER_SIZE(arglen), ADBMS_SPI_TIMEOUT);
|
||||
mcuAdbmsCSHigh();
|
||||
} else {
|
||||
args[0] = (command >> 8) & 0xFF;
|
||||
@ -204,97 +181,103 @@ HAL_StatusTypeDef ___writeCMD(uint16_t command, uint8_t * args, size_t arglen) {
|
||||
calculateCommandPEC(args, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
ret = mcuSPITransmit(args, 4);
|
||||
ret = mcuSPITransmit(usr_ptr, args, 4, ADBMS_SPI_TIMEOUT);
|
||||
mcuAdbmsCSHigh();
|
||||
}
|
||||
|
||||
if (ret != HAL_OK) {
|
||||
debug_log(LOG_LEVEL_ERROR, "STM32 SPI HAL returned error %s", HAL_Statuses[ret]);
|
||||
debug_log(LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
if (ret != ADBMS_OK) {
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI HAL returned error %s", ADBMS_Statuses[ret]);
|
||||
#ifdef STM32_HAL
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
print_spi_details();
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) {
|
||||
ADBMS_Internal_Status ___readCMD(uint16_t command, uint8_t * buffer, size_t arglen) {
|
||||
buffer[0] = (command >> 8) & 0xFF;
|
||||
buffer[1] = (command)&0xFF;
|
||||
calculateCommandPEC(buffer, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, CMD_BUFFER_SIZE(arglen));
|
||||
const ADBMS_Internal_Status status = mcuSPITransmitReceive(usr_ptr, buffer, buffer, CMD_BUFFER_SIZE(arglen), ADBMS_SPI_TIMEOUT);
|
||||
mcuAdbmsCSHigh();
|
||||
|
||||
if (status != HAL_OK) {
|
||||
debug_log(LOG_LEVEL_ERROR, "STM32 SPI HAL returned error %s", HAL_Statuses[status]);
|
||||
debug_log(LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
if (status != ADBMS_OK) {
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI HAL returned error %s", ADBMS_Statuses[status]);
|
||||
#ifdef STM32_HAL
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
print_spi_details();
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
//[[maybe_unused]] uint8_t commandCounter = buffer[sizeof(buffer) - 2] & 0xFC; //command counter is bits 7-2
|
||||
//TODO: check command counter?
|
||||
|
||||
if (DEBUG_CHANNEL_ENABLED(LOG_LEVEL_NOISY)) {
|
||||
debug_log(LOG_LEVEL_NOISY, "%lu R | %02X %02X ", HAL_GetTick(), command >> 8, command & 0xFF);
|
||||
if (DEBUG_CHANNEL_ENABLED(ADBMS_LOG_LEVEL_NOISY)) {
|
||||
debug_log(ADBMS_LOG_LEVEL_NOISY, "%lu R | %02X %02X ", mcuGetTime(), command >> 8, command & 0xFF);
|
||||
|
||||
//print out data bytes
|
||||
if (arglen > 0) {
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
debug_log_cont(LOG_LEVEL_NOISY, "%d: ", i);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_NOISY, "%d: ", i);
|
||||
for (size_t j = 0; j < arglen; j++) {
|
||||
debug_log_cont(LOG_LEVEL_NOISY, "%02X ", buffer[BUFFER_BMS_OFFSET(i, arglen) + j]);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_NOISY, "%02X ", buffer[BUFFER_BMS_OFFSET(i, arglen) + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (arglen == 0) {
|
||||
return HAL_OK; //no data to check
|
||||
return ADBMS_OK; //no data to check
|
||||
}
|
||||
|
||||
//check data PEC
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
size_t offset = BUFFER_BMS_OFFSET(i, arglen);
|
||||
const size_t offset = BUFFER_BMS_OFFSET(i, arglen);
|
||||
if (checkDataPEC(&buffer[offset], arglen + 2) != 0) {
|
||||
debug_log(LOG_LEVEL_ERROR, "Invalid data PEC when reading BMS %d", i);
|
||||
debug_log(LOG_LEVEL_ERROR, "Received: ");
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "Invalid data PEC when reading BMS %d", i);
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "Received: ");
|
||||
for (size_t j = 0; j < arglen + 2; j++) {
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "%02X ", buffer[offset + j]);
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "%02X ", buffer[offset + j]);
|
||||
}
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "| %02X %02X ", buffer[offset + arglen], buffer[offset + arglen + 1]); //print out the DPEC
|
||||
debug_log(LOG_LEVEL_ERROR, " DATA ^");
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "| %02X %02X ", buffer[offset + arglen], buffer[offset + arglen + 1]); //print out the DPEC
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, " DATA ^");
|
||||
//print out spaces until start of DPEC
|
||||
for (size_t j = 0; j < arglen - 1; j++) {
|
||||
debug_log_cont(LOG_LEVEL_ERROR, (arglen < 2) ? "" : "^^^");
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, (arglen < 2) ? "" : "^^^");
|
||||
}
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "^^ ");
|
||||
debug_log_cont(LOG_LEVEL_ERROR, " PEC ^");
|
||||
return HAL_ERROR;
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, "^^ ");
|
||||
debug_log_cont(ADBMS_LOG_LEVEL_ERROR, " PEC ^");
|
||||
return ADBMS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
return ADBMS_OK;
|
||||
}
|
||||
|
||||
//check poll command - no data PEC sent back, waitTime is in SPI clock cycles
|
||||
HAL_StatusTypeDef __pollCMD(uint16_t command, uint8_t waitTime) {
|
||||
ADBMS_Internal_Status __pollCMD(uint16_t command, uint8_t waitTime) {
|
||||
uint8_t buffer[4 + (waitTime / 8) + 1] = {}; //8 cycles per byte, +1 as we round up
|
||||
buffer[0] = (command >> 8) & 0xFF;
|
||||
buffer[1] = (command) & 0xFF;
|
||||
calculateCommandPEC(buffer, 4);
|
||||
|
||||
mcuAdbmsCSLow();
|
||||
HAL_StatusTypeDef status = mcuSPITransmitReceive(buffer, buffer, sizeof buffer);
|
||||
const ADBMS_Internal_Status status = mcuSPITransmitReceive(usr_ptr, buffer, buffer, sizeof buffer, ADBMS_SPI_TIMEOUT);
|
||||
mcuAdbmsCSHigh();
|
||||
|
||||
if (status != HAL_OK) {
|
||||
debug_log(LOG_LEVEL_ERROR, "STM32 SPI HAL returned error %s", HAL_Statuses[status]);
|
||||
debug_log(LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
if (status != ADBMS_OK) {
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI HAL returned error %s", ADBMS_Statuses[status]);
|
||||
#ifdef STM32_HAL
|
||||
debug_log(ADBMS_LOG_LEVEL_ERROR, "SPI error bits: ");
|
||||
print_spi_details();
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
return ((buffer[sizeof buffer] & 0x0F) == 0x0) ? HAL_BUSY : HAL_OK; //SDO goes high when data is ready
|
||||
return ((buffer[sizeof buffer] & 0x0F) == 0x0) ? ADBMS_BUSY : ADBMS_OK; //SDO goes high when data is ready
|
||||
}
|
@ -33,8 +33,8 @@ static bool buffer_message(const log_message_t* message) {
|
||||
uint32_t* write_pos = using_buffer_2 ? &message_buffer.write_pos_2 : &message_buffer.write_pos;
|
||||
|
||||
/* Calculate buffer offset - buffer 2 starts at ISOTP_LOG_BUFFER_1_BYTES */
|
||||
uint32_t buffer_offset = using_buffer_2 ? ISOTP_LOG_BUFFER_1_BYTES : 0;
|
||||
uint32_t max_size = using_buffer_2 ? ISOTP_LOG_BUFFER_2_BYTES : ISOTP_LOG_BUFFER_1_BYTES; // Each buffer has its own size
|
||||
const uint32_t buffer_offset = using_buffer_2 ? ISOTP_LOG_BUFFER_1_BYTES : 0;
|
||||
const uint32_t max_size = using_buffer_2 ? ISOTP_LOG_BUFFER_2_BYTES : ISOTP_LOG_BUFFER_1_BYTES; // Each buffer has its own size
|
||||
|
||||
/* Check if we have enough space in the current buffer */
|
||||
if (*write_pos + message->message_length > max_size) {
|
||||
@ -54,7 +54,7 @@ static bool buffer_message(const log_message_t* message) {
|
||||
/* Swap buffers and prepare for sending */
|
||||
static bool swap_buffers_for_sending() {
|
||||
/* Don't swap if there's nothing to send */
|
||||
uint32_t* current_pos = using_buffer_2 ? &message_buffer.write_pos_2 : &message_buffer.write_pos;
|
||||
const uint32_t* current_pos = using_buffer_2 ? &message_buffer.write_pos_2 : &message_buffer.write_pos;
|
||||
if (*current_pos == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -102,7 +102,7 @@ void isotp_log_backend_init(void) {
|
||||
isotp_backend_registered = log_register_backend(&isotp_backend);
|
||||
|
||||
/* Set up ISO-TP connection */
|
||||
int status = isotp_add_connection(ISOTP_LOG_FC_CAN_ID, ISOTP_LOG_CAN_ID, ISOTP_FLAGS_NONE);
|
||||
const int status = isotp_add_connection(ISOTP_LOG_FC_CAN_ID, ISOTP_LOG_CAN_ID, ISOTP_FLAGS_NONE);
|
||||
if (status < 0) {
|
||||
log_error("Failed to add ISO-TP connection: %s", isotp_status_to_string((isotp_status_t)status));
|
||||
return;
|
||||
@ -145,8 +145,10 @@ static void isotp_backend_write(const log_message_t *message) {
|
||||
|
||||
/* Process buffered log messages and send them via ISO-TP */
|
||||
void isotp_log_process(void) {
|
||||
/* Process ISO-TP updates to send any pending messages */
|
||||
isotp_update();
|
||||
/* Check if we have data to send */
|
||||
if (message_buffer.write_pos > 0 || message_buffer.write_pos_2 > 0) {
|
||||
isotp_backend_flush();
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush the ISO-TP backend */
|
||||
@ -154,12 +156,12 @@ static void isotp_backend_flush(void) {
|
||||
/* Swap buffers if we have data to send and we're ready to send */
|
||||
if (streaming_enabled) {
|
||||
/* Get the buffer that is currently being written to */
|
||||
uint32_t buffer_offset = !using_buffer_2 ? 0 : ISOTP_LOG_BUFFER_1_BYTES;
|
||||
uint32_t buffer_size = !using_buffer_2 ? message_buffer.write_pos : message_buffer.write_pos_2;
|
||||
const uint32_t buffer_offset = !using_buffer_2 ? 0 : ISOTP_LOG_BUFFER_1_BYTES;
|
||||
const uint32_t buffer_size = !using_buffer_2 ? message_buffer.write_pos : message_buffer.write_pos_2;
|
||||
|
||||
/* Only send if we have data and a previous send is not in progress */
|
||||
if (buffer_size > 0) {
|
||||
isotp_status_t status = isotp_add_message(
|
||||
const isotp_status_t status = isotp_add_message(
|
||||
isotp_connection_id,
|
||||
message_buffer.buffer + buffer_offset,
|
||||
buffer_size
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "stm32h7xx_hal.h"
|
||||
|
||||
/* Backend management */
|
||||
static const log_backend_t* registered_backends[MAX_LOG_BACKENDS] = {0};
|
||||
static const log_backend_t* registered_backends[MAX_LOG_BACKENDS] = {};
|
||||
static uint8_t backend_count = 0;
|
||||
|
||||
/* Register a new logging backend */
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/* Configuration */
|
||||
#define MAX_MESSAGE_LENGTH 384
|
||||
#define USE_ANSI_ESCAPE_CODES true // if true, log messages will be colored according to their log level
|
||||
#define USE_ANSI_ESCAPE_CODES false // if true, log messages will be colored according to their log level
|
||||
#define PRINT_TIMESTAMP false // if true, timestamp (from HAL_GetTick) is printed before each log message
|
||||
|
||||
/* Maximum number of backends that can be registered */
|
||||
@ -72,6 +72,8 @@ void log_message(log_level_t level, const char *msg, ...);
|
||||
|
||||
#ifdef LOG_PREFIX
|
||||
#define log_message(level, fmt, ...) \
|
||||
static_assert(__builtin_constant_p(fmt), "Format string must be a compile-time constant if using LOG_PREFIX"); \
|
||||
static_assert(__builtin_constant_p(LOG_PREFIX), "LOG_PREFIX must be a compile-time constant"); \
|
||||
log_message(level, LOG_PREFIX fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "battery.h"
|
||||
#define ADBMS_NO_LOGGING_DEFS // fix conflicting defines
|
||||
#include "ADBMS_Driver.h"
|
||||
#include "NTC.h"
|
||||
#include "can.h"
|
||||
@ -6,6 +7,7 @@
|
||||
#include "ts_state_machine.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "main.h"
|
||||
|
||||
#define SWO_LOG_PREFIX "[BATTERY] "
|
||||
#include "swo_log.h"
|
||||
@ -15,15 +17,7 @@
|
||||
|
||||
#define MAX_TEMP 60 // max temperature in C
|
||||
|
||||
uint16_t min_voltage = 0xFFFF;
|
||||
uint16_t max_voltage = 0;
|
||||
typeof(module_voltages) module_voltages = {[0 ... N_BMS - 1] = {0xFFFF, 0}};
|
||||
int16_t min_temp = INT16_MAX;
|
||||
int16_t max_temp = INT16_MIN;
|
||||
typeof(module_temps) module_temps = {[0 ... N_BMS - 1] = {INT16_MAX, INT16_MIN}};
|
||||
float module_std_deviation[N_BMS] = {};
|
||||
|
||||
int16_t cellTemps[N_BMS][10] = {};
|
||||
typeof(battery) battery = {};
|
||||
|
||||
static bool error_window[MAX_ERRORS_WINDOW_SIZE] = {};
|
||||
static size_t error_window_index = 0;
|
||||
@ -46,7 +40,9 @@ static inline void update_error_window(bool error, int id) {
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef battery_init(SPI_HandleTypeDef *hspi) {
|
||||
auto ret = AMS_Init(hspi);
|
||||
// pull MSTR High for Microcontroller mode ADBMS6822
|
||||
HAL_GPIO_WritePin(MSTR1_GPIO_Port, MSTR1_Pin, GPIO_PIN_SET);
|
||||
auto const ret = AMS_Init(hspi);
|
||||
if (ret.status != ADBMS_NO_ERROR) {
|
||||
debug_log(LOG_LEVEL_ERROR, "Failed to initialize BMS: %s",
|
||||
ADBMS_Status_ToString(ret.status));
|
||||
@ -55,13 +51,27 @@ HAL_StatusTypeDef battery_init(SPI_HandleTypeDef *hspi) {
|
||||
}
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
// Initialize battery structure with default values
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
battery.module[i].chip = &bms_data[i];
|
||||
for (size_t j = 0; j < 10; j++) {
|
||||
battery.module[i].cellTemps[j] = 0;
|
||||
}
|
||||
}
|
||||
battery.pack.soc = 0.0f;
|
||||
battery.pack.min_voltage = 0xFFFF;
|
||||
battery.pack.max_voltage = 0;
|
||||
battery.pack.min_temp = INT16_MAX;
|
||||
battery.pack.max_temp = INT16_MIN;
|
||||
|
||||
debug_log(LOG_LEVEL_INFO, "Battery initialized successfully");
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
[[gnu::optimize("no-math-errno")]]
|
||||
HAL_StatusTypeDef battery_update() {
|
||||
auto ret = AMS_Idle_Loop();
|
||||
auto const ret = AMS_Idle_Loop();
|
||||
if (ret.status != ADBMS_NO_ERROR) {
|
||||
debug_log(LOG_LEVEL_ERROR, "Error while updating battery data: %s",
|
||||
ADBMS_Status_ToString(ret.status));
|
||||
@ -72,16 +82,16 @@ HAL_StatusTypeDef battery_update() {
|
||||
if (ret.status == ADBMS_OVERVOLT || ret.status == ADBMS_UNDERVOLT) {
|
||||
if (ret.bms_id != -1 && ret.bms_id < N_BMS) {
|
||||
const char* error_type = (ret.status == ADBMS_OVERVOLT) ? "overvoltage" : "undervoltage";
|
||||
uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ?
|
||||
modules[ret.bms_id].overVoltage :
|
||||
modules[ret.bms_id].underVoltage;
|
||||
const uint32_t voltage_flags = (ret.status == ADBMS_OVERVOLT) ?
|
||||
bms_data[ret.bms_id].overVoltage :
|
||||
bms_data[ret.bms_id].underVoltage;
|
||||
|
||||
debug_log(LOG_LEVEL_ERROR, "Cell %s detected on module %d, affected cells: ",
|
||||
error_type, ret.bms_id);
|
||||
|
||||
for (size_t cell = 0; cell < N_CELLS; cell++) {
|
||||
if (voltage_flags & (1UL << cell)) {
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "%u (%d mV) ", cell, modules[ret.bms_id].cellVoltages[cell]);
|
||||
debug_log_cont(LOG_LEVEL_ERROR, "%u (%d mV) ", cell, bms_data[ret.bms_id].cellVoltages[cell]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,69 +107,60 @@ HAL_StatusTypeDef battery_update() {
|
||||
|
||||
update_error_window(false, ret.bms_id);
|
||||
|
||||
min_voltage = 0xFFFF;
|
||||
max_voltage = 0;
|
||||
min_temp = INT16_MAX;
|
||||
max_temp = INT16_MIN;
|
||||
battery.pack.min_voltage = 0xFFFF;
|
||||
battery.pack.max_voltage = 0;
|
||||
battery.pack.min_temp = INT16_MAX;
|
||||
battery.pack.max_temp = INT16_MIN;
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
// Calculate standard deviation for each module
|
||||
if (DEBUG_CHANNEL_ENABLED(DEBUG_CHANNEL)) {
|
||||
float sum = 0;
|
||||
float mean = 0;
|
||||
float variance = 0;
|
||||
// Initialize min/max indices for this module
|
||||
battery.module[i].min_v_idx = 0;
|
||||
battery.module[i].max_v_idx = 0;
|
||||
battery.module[i].min_t_idx = 0;
|
||||
battery.module[i].max_t_idx = 0;
|
||||
|
||||
// First pass: calculate mean
|
||||
// Track min/max voltages
|
||||
for (size_t j = 0; j < N_CELLS; j++) {
|
||||
sum += modules[i].cellVoltages[j];
|
||||
if (bms_data[i].cellVoltages[j] < battery.pack.min_voltage) {
|
||||
battery.pack.min_voltage = bms_data[i].cellVoltages[j];
|
||||
}
|
||||
mean = sum / N_CELLS;
|
||||
|
||||
// Second pass: calculate variance
|
||||
for (size_t j = 0; j < N_CELLS; j++) {
|
||||
float diff = modules[i].cellVoltages[j] - mean;
|
||||
variance += diff * diff;
|
||||
}
|
||||
variance /= N_CELLS;
|
||||
|
||||
// Calculate standard deviation
|
||||
module_std_deviation[i] = sqrtf(variance);
|
||||
if (bms_data[i].cellVoltages[j] > battery.pack.max_voltage) {
|
||||
battery.pack.max_voltage = bms_data[i].cellVoltages[j];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < N_CELLS; j++) {
|
||||
if (modules[i].cellVoltages[j] > min_voltage) {
|
||||
min_voltage = modules[i].cellVoltages[j];
|
||||
// Update min/max voltage indices for this module
|
||||
if (bms_data[i].cellVoltages[j] < bms_data[i].cellVoltages[battery.module[i].min_v_idx]) {
|
||||
battery.module[i].min_v_idx = j;
|
||||
}
|
||||
if (modules[i].cellVoltages[j] < max_voltage) {
|
||||
max_voltage = modules[i].cellVoltages[j];
|
||||
}
|
||||
if (modules[i].cellVoltages[j] > module_voltages[i].max) {
|
||||
module_voltages[i].max = modules[i].cellVoltages[j];
|
||||
}
|
||||
if (modules[i].cellVoltages[j] < module_voltages[i].min) {
|
||||
module_voltages[i].min = modules[i].cellVoltages[j];
|
||||
if (bms_data[i].cellVoltages[j] > bms_data[i].cellVoltages[battery.module[i].max_v_idx]) {
|
||||
battery.module[i].max_v_idx = j;
|
||||
}
|
||||
}
|
||||
|
||||
// Process temperature values
|
||||
for (size_t j = 0; j < 10; j++) { //10 GPIOs
|
||||
cellTemps[i][j] = ntc_mv_to_celsius(modules[i].auxVoltages[j]);
|
||||
battery.module[i].cellTemps[j] = ntc_mv_to_celsius(bms_data[i].auxVoltages[j]);
|
||||
|
||||
if (cellTemps[i][j] > max_temp) {
|
||||
max_temp = cellTemps[i][j];
|
||||
|
||||
// For new battery struct
|
||||
if (battery.module[i].cellTemps[j] > battery.pack.max_temp) {
|
||||
battery.pack.max_temp = battery.module[i].cellTemps[j];
|
||||
}
|
||||
if (cellTemps[i][j] < min_temp) {
|
||||
min_temp = cellTemps[i][j];
|
||||
if (battery.module[i].cellTemps[j] < battery.pack.min_temp) {
|
||||
battery.pack.min_temp = battery.module[i].cellTemps[j];
|
||||
}
|
||||
|
||||
if (cellTemps[i][j] > module_temps[i].max) {
|
||||
module_temps[i].max = cellTemps[i][j];
|
||||
// Update min/max temperature indices for this module
|
||||
if (battery.module[i].cellTemps[j] < battery.module[i].cellTemps[battery.module[i].min_t_idx]) {
|
||||
battery.module[i].min_t_idx = j;
|
||||
}
|
||||
if (cellTemps[i][j] < module_temps[i].min) {
|
||||
module_temps[i].min = cellTemps[i][j];
|
||||
if (battery.module[i].cellTemps[j] > battery.module[i].cellTemps[battery.module[i].max_t_idx]) {
|
||||
battery.module[i].max_t_idx = j;
|
||||
}
|
||||
|
||||
if (cellTemps[i][j] > (MAX_TEMP * (uint16_t)(TEMP_CONV))) {
|
||||
debug_log(LOG_LEVEL_ERROR, "Cell %u on BMS %u overtemp: %d0 mC", j, i, cellTemps[i][j]);
|
||||
// Check for overtemperature condition
|
||||
if (battery.module[i].cellTemps[j] > (MAX_TEMP * (uint16_t)(TEMP_CONV))) {
|
||||
debug_log(LOG_LEVEL_ERROR, "Cell %u on BMS %u overtemp: %d0 mC", j, i, battery.module[i].cellTemps[j]);
|
||||
can_send_error(TS_ERRORKIND_CELL_OVERTEMP, i);
|
||||
ts_sm_set_error_source(TS_ERROR_SOURCE_SLAVES, TS_ERRORKIND_CELL_OVERTEMP, true);
|
||||
} else {
|
||||
|
@ -35,7 +35,7 @@ void can_init(FDCAN_HandleTypeDef *handle) {
|
||||
ftcan_add_filter(CAN_ID_AMS_DETAILS_FC, 0xFFF);
|
||||
ftcan_add_filter(ISOTP_LOG_FC_CAN_ID, 0xFFF);
|
||||
|
||||
auto status = isotp_add_connection(CAN_ID_AMS_DETAILS_FC, CAN_ID_AMS_DETAILS, ISOTP_FLAGS_NONE);
|
||||
auto const status = isotp_add_connection(CAN_ID_AMS_DETAILS_FC, CAN_ID_AMS_DETAILS, ISOTP_FLAGS_NONE);
|
||||
if (status < 0) {
|
||||
log_warning("Failed to add ISO-TP connection: %s", isotp_status_to_string((isotp_status_t)status));
|
||||
}
|
||||
@ -49,16 +49,16 @@ void can_init(FDCAN_HandleTypeDef *handle) {
|
||||
HAL_StatusTypeDef can_send_status() {
|
||||
uint8_t data[8];
|
||||
data[0] = ts_state.current_state | (sdc_closed << 7);
|
||||
data[1] = roundf(current_soc);
|
||||
ftcan_marshal_unsigned(&data[2], min_voltage, 2);
|
||||
ftcan_marshal_signed(&data[4], max_temp, 2);
|
||||
data[1] = roundf(battery.pack.soc); // Use the battery struct now
|
||||
ftcan_marshal_unsigned(&data[2], battery.pack.min_voltage, 2); // Use the battery struct now
|
||||
ftcan_marshal_signed(&data[4], battery.pack.max_temp, 2); // Use the battery struct now
|
||||
data[6] = imd_data.state | (imd_data.ok << 7);
|
||||
if (imd_data.r_iso < 0xFFF) {
|
||||
data[7] = imd_data.r_iso >> 4;
|
||||
} else {
|
||||
data[7] = 0xFF;
|
||||
}
|
||||
HAL_StatusTypeDef ret = ftcan_transmit(CAN_ID_AMS_STATUS, data, sizeof(data));
|
||||
const HAL_StatusTypeDef ret = ftcan_transmit(CAN_ID_AMS_STATUS, data, sizeof(data));
|
||||
if (ret != HAL_OK) {
|
||||
return ret;
|
||||
}
|
||||
@ -70,8 +70,8 @@ HAL_StatusTypeDef can_send_status() {
|
||||
|
||||
HAL_StatusTypeDef can_send_details() {
|
||||
static uint8_t module_index = 0;
|
||||
static uint8_t data[103] = {}; //sizeof(Cell_Module) + 10 + 1
|
||||
auto module = &modules[module_index];
|
||||
static uint8_t data[103] = {}; //sizeof(BMS_Chip) + 10 + 1
|
||||
auto const module = &bms_data[module_index];
|
||||
auto data_ptr = &data[1];
|
||||
|
||||
isotp_status_t status = isotp_try_add_message(isotp_connection_id, data, sizeof(data));
|
||||
@ -136,7 +136,7 @@ HAL_StatusTypeDef can_send_details() {
|
||||
|
||||
// Marshal temperature data
|
||||
for (int i = 0; i < 10; i++) {
|
||||
data_ptr = ftcan_marshal_signed(data_ptr, cellTemps[module_index][i], 2);
|
||||
data_ptr = ftcan_marshal_signed(data_ptr, battery.module[module_index].cellTemps[i], 2);
|
||||
}
|
||||
|
||||
if ((status = isotp_add_message(isotp_connection_id, data, sizeof(data))) != ISOTP_OK) {
|
||||
@ -164,7 +164,7 @@ void ftcan_msg_received_cb(uint16_t id, size_t len, const uint8_t *data) {
|
||||
switch (id) {
|
||||
case ISOTP_LOG_FC_CAN_ID:
|
||||
case CAN_ID_AMS_DETAILS_FC:
|
||||
auto status = isotp_handle_incoming(id, data, len);
|
||||
auto const status = isotp_handle_incoming(id, data, len);
|
||||
if (status != ISOTP_OK) {
|
||||
log_debug("Error when handling flow control: %s", isotp_status_to_string(status));
|
||||
}
|
||||
@ -172,5 +172,7 @@ void ftcan_msg_received_cb(uint16_t id, size_t len, const uint8_t *data) {
|
||||
case CAN_ID_AMS_IN:
|
||||
ts_sm_handle_ams_in(data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *handle) {
|
||||
if (handle != htim || htim->Channel != HAL_TIM_ACTIVE_CHANNEL_1) {
|
||||
return;
|
||||
}
|
||||
uint32_t period = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
|
||||
const uint32_t period = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
|
||||
if (period == 0) {
|
||||
// First edge, ignore
|
||||
return;
|
||||
@ -40,7 +40,7 @@ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *handle) {
|
||||
imd_data.last_high = HAL_GetTick();
|
||||
|
||||
imd_data.freq = FREQ_TIMER / period;
|
||||
uint32_t high_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
|
||||
const uint32_t high_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
|
||||
imd_data.duty_cycle = (100 * high_time) / period;
|
||||
|
||||
// Check PWM frequency for state determination
|
||||
|
@ -203,7 +203,7 @@ int main(void)
|
||||
// for testing. in the final code can log streaming will be enabled by can message
|
||||
isotp_log_enable_streaming(LOG_LEVEL_INFO);
|
||||
|
||||
shunt_init();
|
||||
//shunt_init();
|
||||
ts_sm_init();
|
||||
soc_init();
|
||||
imd_init(&htim15);
|
||||
@ -217,6 +217,7 @@ int main(void)
|
||||
int error_count = 0;
|
||||
while (1)
|
||||
{
|
||||
isotp_log_process();
|
||||
isotp_update();
|
||||
//left over from slave communication test, could be nicer and in an additional function !!
|
||||
if (error_count > 25) {
|
||||
@ -242,7 +243,7 @@ int main(void)
|
||||
print_battery_info();
|
||||
print_master_status();
|
||||
}
|
||||
shunt_check();
|
||||
//shunt_check();
|
||||
ts_sm_update();
|
||||
soc_update();
|
||||
imd_update();
|
||||
@ -331,17 +332,16 @@ void PeriphCommonClock_Config(void)
|
||||
|
||||
/** Initializes the peripherals clock
|
||||
*/
|
||||
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_FDCAN;
|
||||
PeriphClkInitStruct.PLL2.PLL2M = 1;
|
||||
PeriphClkInitStruct.PLL2.PLL2N = 8;
|
||||
PeriphClkInitStruct.PLL2.PLL2P = 3;
|
||||
PeriphClkInitStruct.PLL2.PLL2Q = 3;
|
||||
PeriphClkInitStruct.PLL2.PLL2R = 2;
|
||||
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
|
||||
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
|
||||
PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
|
||||
PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL2;
|
||||
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;
|
||||
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;
|
||||
PeriphClkInitStruct.PLL3.PLL3M = 1;
|
||||
PeriphClkInitStruct.PLL3.PLL3N = 8;
|
||||
PeriphClkInitStruct.PLL3.PLL3P = 2;
|
||||
PeriphClkInitStruct.PLL3.PLL3Q = 2;
|
||||
PeriphClkInitStruct.PLL3.PLL3R = 3;
|
||||
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_3;
|
||||
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
|
||||
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
|
||||
PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL3;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
@ -370,7 +370,7 @@ static void MX_ADC1_Init(void)
|
||||
/** Common config
|
||||
*/
|
||||
hadc1.Instance = ADC1;
|
||||
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
|
||||
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
|
||||
hadc1.Init.Resolution = ADC_RESOLUTION_16B;
|
||||
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
|
||||
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
@ -437,7 +437,7 @@ static void MX_ADC2_Init(void)
|
||||
/** Common config
|
||||
*/
|
||||
hadc2.Instance = ADC2;
|
||||
hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
|
||||
hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
|
||||
hadc2.Init.Resolution = ADC_RESOLUTION_16B;
|
||||
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
|
||||
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
|
||||
@ -498,7 +498,7 @@ static void MX_FDCAN1_Init(void)
|
||||
hfdcan1.Init.ProtocolException = DISABLE;
|
||||
hfdcan1.Init.NominalPrescaler = 2;
|
||||
hfdcan1.Init.NominalSyncJumpWidth = 1;
|
||||
hfdcan1.Init.NominalTimeSeg1 = 31;
|
||||
hfdcan1.Init.NominalTimeSeg1 = 23;
|
||||
hfdcan1.Init.NominalTimeSeg2 = 8;
|
||||
hfdcan1.Init.DataPrescaler = 1;
|
||||
hfdcan1.Init.DataSyncJumpWidth = 1;
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "swo_log_backend.h"
|
||||
|
||||
void print_master_status() {
|
||||
auto backend = swo_log_get_backend();
|
||||
auto const backend = swo_log_get_backend();
|
||||
|
||||
if (!backend->is_enabled(LOG_LEVEL_INFO)) {
|
||||
return; // No need to print if the backend is not enabled for this log level
|
||||
@ -61,33 +61,26 @@ void print_master_status() {
|
||||
swo_write(" Time delta: %lu ms", HAL_GetTick() - shunt_data.last_message);
|
||||
|
||||
swo_write("\nBattery data:");
|
||||
swo_write(" Min/Max voltage: %d mV / %d mV", min_voltage, max_voltage);
|
||||
swo_write(" Min/Max temp: %d °C / %d °C", min_temp, max_temp);
|
||||
swo_write(" SoC: %.2f %%", current_soc);
|
||||
swo_write(" Module data: Min V | Max V | Std Dev | Min T | Max T");
|
||||
auto max_std_dev = 0.0f;
|
||||
swo_write(" Min/Max voltage: %d mV / %d mV", battery.pack.min_voltage, battery.pack.max_voltage);
|
||||
swo_write(" Min/Max temp: %d °C / %d °C", battery.pack.min_temp, battery.pack.max_temp);
|
||||
swo_write(" SoC: %.2f %%", battery.pack.soc);
|
||||
swo_write(" Module data: Min V | Max V | Min T | Max T");
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
if (module_std_deviation[i] > max_std_dev) {
|
||||
max_std_dev = module_std_deviation[i];
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
#if USE_ANSI_ESCAPE_CODES
|
||||
auto module_data = getModuleMinMax(i);
|
||||
/* #if USE_ANSI_ESCAPE_CODES
|
||||
#define COLOR_MIN "\033[38;5;75m" //blue for min
|
||||
#define COLOR_MAX "\033[38;5;203m" //red for max
|
||||
#define COLOR_RESET "\033[0m"
|
||||
swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%.2f mV%s | %s%3d °C%s | %s%3d °C%s", i,
|
||||
(module_voltages[i].min == min_voltage) ? COLOR_MIN : "", (module_voltages[i].min), COLOR_RESET,
|
||||
(module_voltages[i].max == max_voltage) ? COLOR_MAX : "", (module_voltages[i].max), COLOR_RESET,
|
||||
(module_std_deviation[i] > max_std_dev) ? COLOR_MAX : "", module_std_deviation[i], COLOR_RESET,
|
||||
(module_temps[i].min == min_temp) ? COLOR_MIN : "", (module_temps[i].min), COLOR_RESET,
|
||||
(module_temps[i].max == max_temp) ? COLOR_MAX : "", (module_temps[i].max), COLOR_RESET);
|
||||
swo_write(" %2zu: %s%5d mV%s | %s%5d mV%s | %s%3d °C%s | %s%3d °C%s", i,
|
||||
(module_data.min_v == battery.pack.min_voltage) ? COLOR_MIN : "", (module_data.min_v), COLOR_RESET,
|
||||
(module_data.max_v == battery.pack.max_voltage) ? COLOR_MAX : "", (module_data.max_v), COLOR_RESET,
|
||||
(module_data.min_t == battery.pack.min_temp) ? COLOR_MIN : "", (module_data.min_t), COLOR_RESET,
|
||||
(module_data.max_t == battery.pack.max_temp) ? COLOR_MAX : "", (module_data.max_t), COLOR_RESET);
|
||||
#else
|
||||
swo_write(" %2zu: %5d mV | %5d mV | %.2f mV | %3d °C | %3d °C", i,
|
||||
module_voltages[i].min, module_voltages[i].max,
|
||||
module_std_deviation[i],
|
||||
module_temps[i].min, module_temps[i].max);
|
||||
#endif
|
||||
swo_write(" %2zu: %5d mV | %5d mV | %3d °C | %3d °C", i,
|
||||
module_data.min_v, module_data.max_v,
|
||||
module_data.min_t, module_data.max_t);
|
||||
#endif */
|
||||
}
|
||||
|
||||
swo_write("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "swo_log_backend.h"
|
||||
|
||||
void print_battery_info() {
|
||||
auto backend = swo_log_get_backend();
|
||||
auto const backend = swo_log_get_backend();
|
||||
|
||||
if (!backend->is_enabled(LOG_LEVEL_INFO)) {
|
||||
return; // No need to print if the backend is not enabled for this log level
|
||||
@ -28,131 +28,131 @@ void print_battery_info() {
|
||||
|
||||
for (size_t i = 0; i < N_BMS; i++) {
|
||||
swo_write("Module %d status:", i);
|
||||
swo_write(" BMS ID: 0x%08lx%08lx", (uint32_t)(modules[i].bmsID >> 32), (uint32_t)(modules[i].bmsID & 0xFFFFFFFF));
|
||||
swo_write(" BMS ID: 0x%08lx%08lx", (uint32_t)(bms_data[i].bmsID >> 32), (uint32_t)(bms_data[i].bmsID & 0xFFFFFFFF));
|
||||
|
||||
// Print cell voltages in 4x4 format
|
||||
swo_write(" Cell voltages (mV):");
|
||||
swo_write(" C0: %4d C1: %4d C2: %4d C3: %4d",
|
||||
modules[i].cellVoltages[0], modules[i].cellVoltages[1],
|
||||
modules[i].cellVoltages[2], modules[i].cellVoltages[3]);
|
||||
bms_data[i].cellVoltages[0], bms_data[i].cellVoltages[1],
|
||||
bms_data[i].cellVoltages[2], bms_data[i].cellVoltages[3]);
|
||||
swo_write(" C4: %4d C5: %4d C6: %4d C7: %4d",
|
||||
modules[i].cellVoltages[4], modules[i].cellVoltages[5],
|
||||
modules[i].cellVoltages[6], modules[i].cellVoltages[7]);
|
||||
bms_data[i].cellVoltages[4], bms_data[i].cellVoltages[5],
|
||||
bms_data[i].cellVoltages[6], bms_data[i].cellVoltages[7]);
|
||||
swo_write(" C8: %4d C9: %4d C10: %4d C11: %4d",
|
||||
modules[i].cellVoltages[8], modules[i].cellVoltages[9],
|
||||
modules[i].cellVoltages[10], modules[i].cellVoltages[11]);
|
||||
bms_data[i].cellVoltages[8], bms_data[i].cellVoltages[9],
|
||||
bms_data[i].cellVoltages[10], bms_data[i].cellVoltages[11]);
|
||||
swo_write(" C12: %4d C13: %4d C14: %4d C15: %4d",
|
||||
modules[i].cellVoltages[12], modules[i].cellVoltages[13],
|
||||
modules[i].cellVoltages[14], modules[i].cellVoltages[15]);
|
||||
bms_data[i].cellVoltages[12], bms_data[i].cellVoltages[13],
|
||||
bms_data[i].cellVoltages[14], bms_data[i].cellVoltages[15]);
|
||||
|
||||
// Print GPIO values
|
||||
swo_write(" GPIO voltages (mV):");
|
||||
swo_write(
|
||||
" G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d",
|
||||
modules[i].auxVoltages[0], modules[i].auxVoltages[1],
|
||||
modules[i].auxVoltages[2], modules[i].auxVoltages[3],
|
||||
modules[i].auxVoltages[4]);
|
||||
bms_data[i].auxVoltages[0], bms_data[i].auxVoltages[1],
|
||||
bms_data[i].auxVoltages[2], bms_data[i].auxVoltages[3],
|
||||
bms_data[i].auxVoltages[4]);
|
||||
swo_write(
|
||||
" G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d",
|
||||
modules[i].auxVoltages[5], modules[i].auxVoltages[6],
|
||||
modules[i].auxVoltages[7], modules[i].auxVoltages[8],
|
||||
modules[i].auxVoltages[9]);
|
||||
bms_data[i].auxVoltages[5], bms_data[i].auxVoltages[6],
|
||||
bms_data[i].auxVoltages[7], bms_data[i].auxVoltages[8],
|
||||
bms_data[i].auxVoltages[9]);
|
||||
|
||||
// Print temperatures
|
||||
swo_write(" GPIO as temperatures (°C):");
|
||||
swo_write(
|
||||
" G0: %4d G1: %4d G2: %4d G3: %4d G4: %4d",
|
||||
cellTemps[i][0], cellTemps[i][1], cellTemps[i][2],
|
||||
cellTemps[i][3], cellTemps[i][4]);
|
||||
battery.module[i].cellTemps[0], battery.module[i].cellTemps[1], battery.module[i].cellTemps[2],
|
||||
battery.module[i].cellTemps[3], battery.module[i].cellTemps[4]);
|
||||
swo_write(
|
||||
" G5: %4d G6: %4d G7: %4d G8: %4d G9: %4d",
|
||||
cellTemps[i][5], cellTemps[i][6], cellTemps[i][7],
|
||||
cellTemps[i][8], cellTemps[i][9]);
|
||||
battery.module[i].cellTemps[5], battery.module[i].cellTemps[6], battery.module[i].cellTemps[7],
|
||||
battery.module[i].cellTemps[8], battery.module[i].cellTemps[9]);
|
||||
|
||||
swo_write(
|
||||
" Internal temp: %d, VAnalog: %d, VDigital: %d, VRef: %d",
|
||||
modules[i].internalDieTemp, modules[i].analogSupplyVoltage,
|
||||
modules[i].digitalSupplyVoltage, modules[i].refVoltage);
|
||||
bms_data[i].internalDieTemp, bms_data[i].analogSupplyVoltage,
|
||||
bms_data[i].digitalSupplyVoltage, bms_data[i].refVoltage);
|
||||
|
||||
// Print error flags if any are set
|
||||
bool hasFlags = false;
|
||||
char flagBuffer[128] = "";
|
||||
char *bufPos = flagBuffer;
|
||||
|
||||
if (modules[i].status.CS_FLT) {
|
||||
if (bms_data[i].status.CS_FLT) {
|
||||
bufPos = stpcpy(bufPos, "CS_FLT ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.SMED) {
|
||||
if (bms_data[i].status.SMED) {
|
||||
bufPos = stpcpy(bufPos, "SMED ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.SED) {
|
||||
if (bms_data[i].status.SED) {
|
||||
bufPos = stpcpy(bufPos, "SED ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.CMED) {
|
||||
if (bms_data[i].status.CMED) {
|
||||
bufPos = stpcpy(bufPos, "CMED ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.CED) {
|
||||
if (bms_data[i].status.CED) {
|
||||
bufPos = stpcpy(bufPos, "CED ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VD_UV) {
|
||||
if (bms_data[i].status.VD_UV) {
|
||||
bufPos = stpcpy(bufPos, "VD_UV ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VD_OV) {
|
||||
if (bms_data[i].status.VD_OV) {
|
||||
bufPos = stpcpy(bufPos, "VD_OV ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VA_UV) {
|
||||
if (bms_data[i].status.VA_UV) {
|
||||
bufPos = stpcpy(bufPos, "VA_UV ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VA_OV) {
|
||||
if (bms_data[i].status.VA_OV) {
|
||||
bufPos = stpcpy(bufPos, "VA_OV ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.THSD) {
|
||||
if (bms_data[i].status.THSD) {
|
||||
bufPos = stpcpy(bufPos, "THSD ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.SLEEP) {
|
||||
if (bms_data[i].status.SLEEP) {
|
||||
bufPos = stpcpy(bufPos, "SLEEP ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.SPIFLT) {
|
||||
if (bms_data[i].status.SPIFLT) {
|
||||
bufPos = stpcpy(bufPos, "SPIFLT ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.COMPARE) {
|
||||
if (bms_data[i].status.COMPARE) {
|
||||
bufPos = stpcpy(bufPos, "COMPARE ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VDE) {
|
||||
if (bms_data[i].status.VDE) {
|
||||
bufPos = stpcpy(bufPos, "VDE ");
|
||||
hasFlags = true;
|
||||
}
|
||||
if (modules[i].status.VDEL) {
|
||||
if (bms_data[i].status.VDEL) {
|
||||
bufPos = stpcpy(bufPos, "VDEL ");
|
||||
hasFlags = true;
|
||||
}
|
||||
|
||||
swo_write(" Status flags: %s", hasFlags ? flagBuffer : "[none]");
|
||||
|
||||
if (modules[i].status.CS_FLT) { // Print out which ADCs are faulting
|
||||
if (bms_data[i].status.CS_FLT) { // Print out which ADCs are faulting
|
||||
swo_write("Comparison fault on ADC/Cell(s): ");
|
||||
for (ssize_t j = 0; j < 16; j++) {
|
||||
if (modules[i].status.CS_FLT & (1u << j)) {
|
||||
if (bms_data[i].status.CS_FLT & (1u << j)) {
|
||||
swo_write("%d ", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
swo_write(" Conversion counter: %d",
|
||||
modules[i].status.CCTS);
|
||||
bms_data[i].status.CCTS);
|
||||
}
|
||||
swo_write("\n------ Updated at %lu ------", HAL_GetTick());
|
||||
}
|
@ -35,14 +35,14 @@ void shunt_handle_can_msg(uint16_t id, const uint8_t *data) {
|
||||
shunt_data.last_message = HAL_GetTick();
|
||||
|
||||
// All result messages contain a big-endian 6-byte integer
|
||||
uint64_t result = ftcan_unmarshal_unsigned(&data, 6);
|
||||
const uint64_t result = ftcan_unmarshal_unsigned(&data, 6);
|
||||
|
||||
switch (id) {
|
||||
case CAN_ID_SHUNT_CURRENT:
|
||||
shunt_data.current = result;
|
||||
if (shunt_data.last_current_message > 0) {
|
||||
uint32_t now = HAL_GetTick();
|
||||
float dt = (now - shunt_data.last_current_message) * 0.001f;
|
||||
const uint32_t now = HAL_GetTick();
|
||||
const float dt = (now - shunt_data.last_current_message) * 0.001f;
|
||||
shunt_data.current_counter += shunt_data.current * dt;
|
||||
}
|
||||
shunt_data.last_current_message = HAL_GetTick();
|
||||
|
@ -12,54 +12,31 @@
|
||||
#define SOC_ESTIMATION_NO_CURRENT_THRESH 200 // mA
|
||||
#define SOC_ESTIMATION_NO_CURRENT_TIME 100000 // ms
|
||||
#define SOC_ESTIMATION_BATTERY_CAPACITY 64800000 // mAs
|
||||
|
||||
typedef struct {
|
||||
uint16_t ocv;
|
||||
float soc;
|
||||
} ocv_soc_pair_t;
|
||||
|
||||
ocv_soc_pair_t OCV_SOC_PAIRS[] = {
|
||||
{2500, 0.00f}, {2990, 3.97f}, {3230, 9.36f}, {3320, 12.60f},
|
||||
{3350, 13.68f}, {3410, 20.15f}, {3530, 32.01f}, {3840, 66.53f},
|
||||
{4010, 83.79f}, {4020, 90.26f}, {4040, 94.58f}, {4100, 98.89f},
|
||||
{4200, 100.00f}};
|
||||
|
||||
float current_soc;
|
||||
|
||||
int current_was_flowing;
|
||||
uint32_t last_current_time;
|
||||
float soc_before_current;
|
||||
float mAs_before_current;
|
||||
|
||||
void soc_init() {
|
||||
current_soc = 0;
|
||||
last_current_time = 0;
|
||||
current_was_flowing = 1;
|
||||
}
|
||||
|
||||
void soc_update() {
|
||||
uint32_t now = HAL_GetTick();
|
||||
if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) {
|
||||
last_current_time = now;
|
||||
if (!current_was_flowing) {
|
||||
soc_before_current = current_soc;
|
||||
mAs_before_current = shunt_data.current_counter;
|
||||
}
|
||||
current_was_flowing = 1;
|
||||
} else {
|
||||
current_was_flowing = 0;
|
||||
}
|
||||
|
||||
if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME ||
|
||||
last_current_time == 0) {
|
||||
// Assume we're measuring OCV if there's been no current for a while (or
|
||||
// we've just turned on the battery).
|
||||
current_soc = soc_for_ocv(min_voltage);
|
||||
} else {
|
||||
// Otherwise, use the current counter to update SoC
|
||||
float as_delta = shunt_data.current_counter - mAs_before_current;
|
||||
float soc_delta = as_delta / SOC_ESTIMATION_BATTERY_CAPACITY * 100;
|
||||
current_soc = soc_before_current - soc_delta;
|
||||
}
|
||||
}
|
||||
|
||||
float soc_for_ocv(uint16_t ocv) {
|
||||
static float soc_for_ocv(uint16_t ocv) {
|
||||
size_t i = 0;
|
||||
size_t array_length = sizeof(OCV_SOC_PAIRS) / sizeof(*OCV_SOC_PAIRS);
|
||||
const size_t array_length = sizeof(OCV_SOC_PAIRS) / sizeof(*OCV_SOC_PAIRS);
|
||||
// Find the index of the first element with OCV greater than the target OCV
|
||||
while (i < array_length && OCV_SOC_PAIRS[i].ocv <= ocv) {
|
||||
i++;
|
||||
@ -78,13 +55,39 @@ float soc_for_ocv(uint16_t ocv) {
|
||||
}
|
||||
|
||||
// Perform linear interpolation
|
||||
uint16_t ocv1 = OCV_SOC_PAIRS[i - 1].ocv;
|
||||
uint16_t ocv2 = OCV_SOC_PAIRS[i].ocv;
|
||||
float soc1 = OCV_SOC_PAIRS[i - 1].soc;
|
||||
float soc2 = OCV_SOC_PAIRS[i].soc;
|
||||
const uint16_t ocv1 = OCV_SOC_PAIRS[i - 1].ocv;
|
||||
const uint16_t ocv2 = OCV_SOC_PAIRS[i].ocv;
|
||||
const float soc1 = OCV_SOC_PAIRS[i - 1].soc;
|
||||
const float soc2 = OCV_SOC_PAIRS[i].soc;
|
||||
|
||||
float slope = (soc2 - soc1) / (ocv2 - ocv1);
|
||||
float interpolated_soc = soc1 + slope * (ocv - ocv1);
|
||||
const float slope = (soc2 - soc1) / (ocv2 - ocv1);
|
||||
const float interpolated_soc = soc1 + slope * (ocv - ocv1);
|
||||
|
||||
return interpolated_soc;
|
||||
}
|
||||
|
||||
void soc_update() {
|
||||
const uint32_t now = HAL_GetTick();
|
||||
if (abs(shunt_data.current) >= SOC_ESTIMATION_NO_CURRENT_THRESH) {
|
||||
last_current_time = now;
|
||||
if (!current_was_flowing) {
|
||||
soc_before_current = battery.pack.soc;
|
||||
mAs_before_current = shunt_data.current_counter;
|
||||
}
|
||||
current_was_flowing = 1;
|
||||
} else {
|
||||
current_was_flowing = 0;
|
||||
}
|
||||
|
||||
if (now - last_current_time >= SOC_ESTIMATION_NO_CURRENT_TIME ||
|
||||
last_current_time == 0) {
|
||||
// Assume we're measuring OCV if there's been no current for a while (or
|
||||
// we've just turned on the battery).
|
||||
battery.pack.soc = soc_for_ocv(battery.pack.min_voltage);
|
||||
} else {
|
||||
// Otherwise, use the current counter to update SoC
|
||||
const float as_delta = shunt_data.current_counter - mAs_before_current;
|
||||
const float soc_delta = as_delta / SOC_ESTIMATION_BATTERY_CAPACITY * 100;
|
||||
battery.pack.soc = soc_before_current - soc_delta;
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,15 @@ typedef enum {
|
||||
|
||||
uint32_t count = 0;
|
||||
bool main_led = false;
|
||||
LedColor led_1 = (LedColor) {.red = 0, .green = 0, .blue = 0};
|
||||
LedColor led_2 = (LedColor) {.red = 0, .green = 0, .blue = 0};
|
||||
auto led_1 = (LedColor) {.red = 0, .green = 0, .blue = 0};
|
||||
auto led_2 = (LedColor) {.red = 0, .green = 0, .blue = 0};
|
||||
#define ITER_COUNT 20
|
||||
#define INTERN_ERROR_COUNT 7500
|
||||
|
||||
static void set_led_color_hw(LedColor color) {
|
||||
GPIO_PinState red = color.red ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
GPIO_PinState green = color.green ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
GPIO_PinState blue = color.blue ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
const GPIO_PinState red = color.red ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
const GPIO_PinState green = color.green ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
const GPIO_PinState blue = color.blue ? GPIO_PIN_RESET : GPIO_PIN_SET;
|
||||
|
||||
HAL_GPIO_WritePin(STATUS_LED_R_GPIO_Port, STATUS_LED_R_Pin, red);
|
||||
HAL_GPIO_WritePin(STATUS_LED_G_GPIO_Port, STATUS_LED_G_Pin, green);
|
||||
|
@ -202,11 +202,30 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
|
||||
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
|
||||
if(hfdcan->Instance==FDCAN1)
|
||||
{
|
||||
/* USER CODE BEGIN FDCAN1_MspInit 0 */
|
||||
|
||||
/* USER CODE END FDCAN1_MspInit 0 */
|
||||
|
||||
/** Initializes the peripherals clock
|
||||
*/
|
||||
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
|
||||
PeriphClkInitStruct.PLL2.PLL2M = 1;
|
||||
PeriphClkInitStruct.PLL2.PLL2N = 8;
|
||||
PeriphClkInitStruct.PLL2.PLL2P = 2;
|
||||
PeriphClkInitStruct.PLL2.PLL2Q = 4;
|
||||
PeriphClkInitStruct.PLL2.PLL2R = 2;
|
||||
PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;
|
||||
PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
|
||||
PeriphClkInitStruct.PLL2.PLL2FRACN = 0.0;
|
||||
PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL2;
|
||||
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_FDCAN_CLK_ENABLE();
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
TSStateHandle ts_state;
|
||||
|
||||
static uint32_t precharge_95_reached_timestamp = 0;
|
||||
static uint32_t precharge_start_timestamp = 0;
|
||||
static uint32_t charging_check_timestamp = 0;
|
||||
static uint32_t discharge_begin_timestamp = 0;
|
||||
static uint32_t precharge_opened_timestamp = 0;
|
||||
@ -27,7 +28,7 @@ void ts_sm_update() {
|
||||
ts_state.current_state = TS_ERROR;
|
||||
}
|
||||
|
||||
auto old_state = ts_state.current_state;
|
||||
auto const old_state = ts_state.current_state;
|
||||
|
||||
switch (ts_state.current_state) {
|
||||
case TS_INACTIVE:
|
||||
@ -104,15 +105,20 @@ TSState ts_sm_update_precharge() {
|
||||
discharge_begin_timestamp = HAL_GetTick();
|
||||
return TS_DISCHARGE;
|
||||
}
|
||||
if (precharge_start_timestamp == 0) {
|
||||
precharge_start_timestamp = HAL_GetTick();
|
||||
}
|
||||
if (shunt_data.voltage_veh > MIN_VEHICLE_SIDE_VOLTAGE &&
|
||||
shunt_data.voltage_veh > 0.95 * shunt_data.voltage_bat) {
|
||||
uint32_t now = HAL_GetTick();
|
||||
const uint32_t now = HAL_GetTick();
|
||||
if (precharge_95_reached_timestamp == 0) {
|
||||
precharge_95_reached_timestamp = now;
|
||||
} else if ((now - precharge_95_reached_timestamp) >=
|
||||
PRECHARGE_95_DURATION) {
|
||||
PRECHARGE_95_DURATION &&
|
||||
(now - precharge_start_timestamp) >= PRECHARGE_MIN_DURATION) {
|
||||
precharge_95_reached_timestamp = 0;
|
||||
precharge_opened_timestamp = 0;
|
||||
precharge_start_timestamp = 0;
|
||||
//precharge_opened = 0;
|
||||
return TS_ACTIVE;
|
||||
}
|
||||
@ -133,7 +139,7 @@ TSState ts_sm_update_discharge() {
|
||||
TSState ts_sm_update_error() {
|
||||
static uint32_t no_error_since = 0;
|
||||
if (ts_state.error_source == 0) {
|
||||
uint32_t now = HAL_GetTick();
|
||||
const uint32_t now = HAL_GetTick();
|
||||
if (no_error_since == 0) {
|
||||
no_error_since = now;
|
||||
} else if (now - no_error_since > NO_ERROR_TIME) {
|
||||
@ -205,7 +211,7 @@ void ts_sm_set_relay_position(Relay relay, int closed) {
|
||||
static int pos_closed = 0;
|
||||
static int pre_closed = 0;
|
||||
|
||||
GPIO_PinState state = closed ? GPIO_PIN_SET : GPIO_PIN_RESET;
|
||||
const GPIO_PinState state = closed ? GPIO_PIN_SET : GPIO_PIN_RESET;
|
||||
switch (relay) {
|
||||
case RELAY_NEG:
|
||||
ts_sm_check_close_wait(&neg_closed, closed);
|
||||
@ -227,7 +233,7 @@ void ts_sm_check_close_wait(int *is_closed, int should_close) {
|
||||
if (should_close != *is_closed) {
|
||||
*is_closed = should_close;
|
||||
if (should_close) {
|
||||
uint32_t dt = HAL_GetTick() - last_close_timestamp;
|
||||
const uint32_t dt = HAL_GetTick() - last_close_timestamp;
|
||||
if (dt < RELAY_CLOSE_WAIT) {
|
||||
HAL_Delay(RELAY_CLOSE_WAIT - dt);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
##########################################################################################################################
|
||||
# File automatically-generated by tool: [projectgenerator] version: [4.5.0-RC5] date: [Wed Mar 26 19:38:08 CET 2025]
|
||||
# File automatically-generated by tool: [projectgenerator] version: [4.6.0-B36] date: [Sat Apr 26 19:50:03 CEST 2025]
|
||||
##########################################################################################################################
|
||||
|
||||
# ------------------------------------------------
|
||||
@ -150,7 +150,7 @@ CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
|
||||
# LDFLAGS
|
||||
#######################################
|
||||
# link script
|
||||
LDSCRIPT = stm32h7a3ritx_flash.ld
|
||||
LDSCRIPT = STM32H7A3XX_FLASH.ld
|
||||
|
||||
# libraries
|
||||
LIBS = -lc -lm -lnosys
|
||||
|
@ -1,6 +1,7 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_10
|
||||
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,master
|
||||
ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV2
|
||||
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ClockPrescaler
|
||||
ADC1.NbrOfConversionFlag=1
|
||||
ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
|
||||
ADC1.OffsetSignedSaturation-0\#ChannelRegularConversion=DISABLE
|
||||
@ -8,7 +9,8 @@ ADC1.Rank-0\#ChannelRegularConversion=1
|
||||
ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5
|
||||
ADC1.master=1
|
||||
ADC2.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_10
|
||||
ADC2.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,SingleDiff-0\#ChannelRegularConversion
|
||||
ADC2.ClockPrescaler=ADC_CLOCK_ASYNC_DIV2
|
||||
ADC2.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,SingleDiff-0\#ChannelRegularConversion,ClockPrescaler
|
||||
ADC2.NbrOfConversionFlag=1
|
||||
ADC2.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
|
||||
ADC2.OffsetSignedSaturation-0\#ChannelRegularConversion=DISABLE
|
||||
@ -18,12 +20,12 @@ ADC2.SingleDiff-0\#ChannelRegularConversion=ADC_DIFFERENTIAL_ENDED
|
||||
CAD.formats=[]
|
||||
CAD.pinconfig=Dual
|
||||
CAD.provider=
|
||||
FDCAN1.CalculateBaudRateNominal=533333
|
||||
FDCAN1.CalculateTimeBitNominal=1875
|
||||
FDCAN1.CalculateTimeQuantumNominal=46.875
|
||||
FDCAN1.CalculateBaudRateNominal=500000
|
||||
FDCAN1.CalculateTimeBitNominal=2000
|
||||
FDCAN1.CalculateTimeQuantumNominal=62.5
|
||||
FDCAN1.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,StdFiltersNbr,NominalPrescaler,NominalTimeSeg1,NominalTimeSeg2,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr
|
||||
FDCAN1.NominalPrescaler=2
|
||||
FDCAN1.NominalTimeSeg1=31
|
||||
FDCAN1.NominalTimeSeg1=23
|
||||
FDCAN1.NominalTimeSeg2=8
|
||||
FDCAN1.RxFifo0ElmtsNbr=16
|
||||
FDCAN1.StdFiltersNbr=32
|
||||
@ -265,6 +267,7 @@ PH1-OSC_OUT.Signal=RCC_OSC_OUT
|
||||
PinOutPanel.RotationAngle=0
|
||||
ProjectManager.AskForMigrate=true
|
||||
ProjectManager.BackupPrevious=false
|
||||
ProjectManager.CompilerLinker=GCC
|
||||
ProjectManager.CompilerOptimize=6
|
||||
ProjectManager.ComputerToolchain=false
|
||||
ProjectManager.CoupleFile=false
|
||||
@ -294,6 +297,7 @@ ProjectManager.UAScriptAfterPath=
|
||||
ProjectManager.UAScriptBeforePath=
|
||||
ProjectManager.UnderRoot=false
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_FDCAN1_Init-FDCAN1-false-HAL-true,4-MX_TIM15_Init-TIM15-false-HAL-true,5-MX_SPI1_Init-SPI1-false-HAL-true,6-MX_SPI2_Init-SPI2-false-HAL-true,7-MX_ADC1_Init-ADC1-false-HAL-true,8-MX_ADC2_Init-ADC2-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
|
||||
RCC.ADCCLockSelection=RCC_ADCCLKSOURCE_PLL3
|
||||
RCC.ADCFreq_Value=42666666.666666664
|
||||
RCC.AHB12Freq_Value=64000000
|
||||
RCC.AHB4Freq_Value=64000000
|
||||
@ -315,21 +319,23 @@ RCC.DFSDMACLkFreq_Value=64000000
|
||||
RCC.DFSDMFreq_Value=64000000
|
||||
RCC.DIVM1=1
|
||||
RCC.DIVM2=1
|
||||
RCC.DIVM3=1
|
||||
RCC.DIVN1=8
|
||||
RCC.DIVN2=8
|
||||
RCC.DIVN3=8
|
||||
RCC.DIVP1Freq_Value=64000000
|
||||
RCC.DIVP2=3
|
||||
RCC.DIVP2Freq_Value=42666666.666666664
|
||||
RCC.DIVP3Freq_Value=32250000
|
||||
RCC.DIVP2Freq_Value=64000000
|
||||
RCC.DIVP3Freq_Value=64000000
|
||||
RCC.DIVQ1Freq_Value=64000000
|
||||
RCC.DIVQ2=3
|
||||
RCC.DIVQ2Freq_Value=42666666.666666664
|
||||
RCC.DIVQ3Freq_Value=32250000
|
||||
RCC.DIVQ2=4
|
||||
RCC.DIVQ2Freq_Value=32000000
|
||||
RCC.DIVQ3Freq_Value=64000000
|
||||
RCC.DIVR1Freq_Value=64000000
|
||||
RCC.DIVR2Freq_Value=64000000
|
||||
RCC.DIVR3Freq_Value=32250000
|
||||
RCC.DIVR3=3
|
||||
RCC.DIVR3Freq_Value=42666666.666666664
|
||||
RCC.FDCANCLockSelection=RCC_FDCANCLKSOURCE_PLL2
|
||||
RCC.FDCANFreq_Value=42666666.666666664
|
||||
RCC.FDCANFreq_Value=32000000
|
||||
RCC.FMCFreq_Value=64000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLK3ClockFreq_Value=64000000
|
||||
@ -338,15 +344,16 @@ RCC.HSE_VALUE=16000000
|
||||
RCC.I2C123CLockSelection=RCC_I2C123CLKSOURCE_CSI
|
||||
RCC.I2C123Freq_Value=4000000
|
||||
RCC.I2C4Freq_Value=64000000
|
||||
RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CDCPREFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,DAC1Freq_Value,DAC2Freq_Value,DFSDM2ACLkFreq_Value,DFSDM2Freq_Value,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1Freq_Value,DIVP2,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1Freq_Value,DIVQ2,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,FDCANCLockSelection,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HSE_VALUE,I2C123CLockSelection,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLLFRACN,PLLSourceVirtual,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI2AFreq_Value,SAI2BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value
|
||||
RCC.IPParameters=ADCCLockSelection,ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CDCPREFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,DAC1Freq_Value,DAC2Freq_Value,DFSDM2ACLkFreq_Value,DFSDM2Freq_Value,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVM3,DIVN1,DIVN2,DIVN3,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1Freq_Value,DIVQ2,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3,DIVR3Freq_Value,FDCANCLockSelection,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HSE_VALUE,I2C123CLockSelection,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLL3FRACN,PLLFRACN,PLLSourceVirtual,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI2AFreq_Value,SAI2BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value
|
||||
RCC.LPTIM1Freq_Value=64000000
|
||||
RCC.LPTIM2Freq_Value=64000000
|
||||
RCC.LPTIM345Freq_Value=64000000
|
||||
RCC.LPUART1Freq_Value=64000000
|
||||
RCC.LTDCFreq_Value=32250000
|
||||
RCC.LTDCFreq_Value=42666666.666666664
|
||||
RCC.MCO1PinFreq_Value=64000000
|
||||
RCC.MCO2PinFreq_Value=64000000
|
||||
RCC.PLL2FRACN=0
|
||||
RCC.PLL3FRACN=0
|
||||
RCC.PLLFRACN=0
|
||||
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
|
||||
RCC.QSPIFreq_Value=64000000
|
||||
@ -371,10 +378,10 @@ RCC.USART234578Freq_Value=64000000
|
||||
RCC.USBFreq_Value=64000000
|
||||
RCC.VCO1OutputFreq_Value=128000000
|
||||
RCC.VCO2OutputFreq_Value=128000000
|
||||
RCC.VCO3OutputFreq_Value=64500000
|
||||
RCC.VCO3OutputFreq_Value=128000000
|
||||
RCC.VCOInput1Freq_Value=16000000
|
||||
RCC.VCOInput2Freq_Value=16000000
|
||||
RCC.VCOInput3Freq_Value=500000
|
||||
RCC.VCOInput3Freq_Value=16000000
|
||||
SH.ADCx_INP10.0=ADC1_INP10,IN10-Single-Ended
|
||||
SH.ADCx_INP10.1=ADC2_INP10,IN10-Differential
|
||||
SH.ADCx_INP10.ConfNb=2
|
||||
|
209
AMS_Master_Code/STM32H7A3XX_FLASH.ld
Normal file
209
AMS_Master_Code/STM32H7A3XX_FLASH.ld
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
******************************************************************************
|
||||
**
|
||||
|
||||
** File : LinkerScript.ld
|
||||
**
|
||||
** Author : STM32CubeMX
|
||||
**
|
||||
** Abstract : Linker script for STM32H7A3RITx series
|
||||
** 2048Kbytes FLASH and 1216Kbytes RAM
|
||||
**
|
||||
** Set heap size, stack size and stack location according
|
||||
** to application requirements.
|
||||
**
|
||||
** Set memory bank area and size if external memory is used.
|
||||
**
|
||||
** Target : STMicroelectronics STM32
|
||||
**
|
||||
** Distribution: The file is distributed “as is,” without any warranty
|
||||
** of any kind.
|
||||
**
|
||||
*****************************************************************************
|
||||
** @attention
|
||||
**
|
||||
** <h2><center>© COPYRIGHT(c) 2025 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.
|
||||
**
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
/* Entry Point */
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
/* Highest address of the user mode stack */
|
||||
_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM); /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x200; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 1024K
|
||||
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
/* The startup code goes first into FLASH */
|
||||
.isr_vector :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
/* The program code and other data goes into FLASH */
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.glue_7) /* glue arm to thumb code */
|
||||
*(.glue_7t) /* glue thumb to arm code */
|
||||
*(.eh_frame)
|
||||
|
||||
KEEP (*(.init))
|
||||
KEEP (*(.fini))
|
||||
|
||||
. = ALIGN(4);
|
||||
_etext = .; /* define a global symbols at end of code */
|
||||
} >FLASH
|
||||
|
||||
/* Constant data goes into FLASH */
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP (*(.preinit_array*))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT(.init_array.*)))
|
||||
KEEP (*(.init_array*))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
.fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
|
||||
{
|
||||
. = ALIGN(4);
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP (*(SORT(.fini_array.*)))
|
||||
KEEP (*(.fini_array*))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
. = ALIGN(4);
|
||||
} >FLASH
|
||||
|
||||
/* used by the startup to initialize data */
|
||||
_sidata = LOADADDR(.data);
|
||||
|
||||
/* Initialized data sections goes into RAM, load LMA copy after code */
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .; /* create a global symbol at data start */
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.RamFunc) /* .RamFunc sections */
|
||||
*(.RamFunc*) /* .RamFunc* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
_edata = .; /* define a global symbol at data end */
|
||||
} >DTCMRAM AT> FLASH
|
||||
|
||||
|
||||
/* Uninitialized data section */
|
||||
. = ALIGN(4);
|
||||
.bss :
|
||||
{
|
||||
/* This is used by the startup in order to initialize the .bss secion */
|
||||
_sbss = .; /* define a global symbol at bss start */
|
||||
__bss_start__ = _sbss;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .; /* define a global symbol at bss end */
|
||||
__bss_end__ = _ebss;
|
||||
} >DTCMRAM
|
||||
|
||||
/* User_heap_stack section, used to check that there is enough RAM left */
|
||||
._user_heap_stack :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
PROVIDE ( end = . );
|
||||
PROVIDE ( _end = . );
|
||||
. = . + _Min_Heap_Size;
|
||||
. = . + _Min_Stack_Size;
|
||||
. = ALIGN(8);
|
||||
} >DTCMRAM
|
||||
|
||||
|
||||
|
||||
/* Remove information from the standard libraries */
|
||||
/DISCARD/ :
|
||||
{
|
||||
libc.a ( * )
|
||||
libm.a ( * )
|
||||
libgcc.a ( * )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
745
AMS_Master_Code/startup_stm32h7a3xx.s
Normal file
745
AMS_Master_Code/startup_stm32h7a3xx.s
Normal file
@ -0,0 +1,745 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file startup_stm32h7a3xx.s
|
||||
* @author MCD Application Team
|
||||
* @brief STM32H7B3xx Devices vector table for GCC based toolchain.
|
||||
* This module performs:
|
||||
* - Set the initial SP
|
||||
* - Set the initial PC == Reset_Handler,
|
||||
* - Set the vector table entries with the exceptions ISR address
|
||||
* - Branches to main in the C library (which eventually
|
||||
* calls main()).
|
||||
* After Reset the Cortex-M processor is in Thread mode,
|
||||
* priority is Privileged, and the Stack is set to Main.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m7
|
||||
.fpu softvfp
|
||||
.thumb
|
||||
|
||||
.global g_pfnVectors
|
||||
.global Default_Handler
|
||||
|
||||
/* start address for the initialization values of the .data section.
|
||||
defined in linker script */
|
||||
.word _sidata
|
||||
/* start address for the .data section. defined in linker script */
|
||||
.word _sdata
|
||||
/* end address for the .data section. defined in linker script */
|
||||
.word _edata
|
||||
/* start address for the .bss section. defined in linker script */
|
||||
.word _sbss
|
||||
/* end address for the .bss section. defined in linker script */
|
||||
.word _ebss
|
||||
/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
|
||||
|
||||
/**
|
||||
* @brief This is the code that gets called when the processor first
|
||||
* starts execution following a reset event. Only the absolutely
|
||||
* necessary set is performed, after which the application
|
||||
* supplied main() routine is called.
|
||||
* @param None
|
||||
* @retval : None
|
||||
*/
|
||||
|
||||
.section .text.Reset_Handler
|
||||
.weak Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
ldr sp, =_estack /* set stack pointer */
|
||||
|
||||
/* Call the ExitRun0Mode function to configure the power supply */
|
||||
bl ExitRun0Mode
|
||||
/* Call the clock system initialization function.*/
|
||||
bl SystemInit
|
||||
|
||||
/* Copy the data segment initializers from flash to SRAM */
|
||||
ldr r0, =_sdata
|
||||
ldr r1, =_edata
|
||||
ldr r2, =_sidata
|
||||
movs r3, #0
|
||||
b LoopCopyDataInit
|
||||
|
||||
CopyDataInit:
|
||||
ldr r4, [r2, r3]
|
||||
str r4, [r0, r3]
|
||||
adds r3, r3, #4
|
||||
|
||||
LoopCopyDataInit:
|
||||
adds r4, r0, r3
|
||||
cmp r4, r1
|
||||
bcc CopyDataInit
|
||||
/* Zero fill the bss segment. */
|
||||
ldr r2, =_sbss
|
||||
ldr r4, =_ebss
|
||||
movs r3, #0
|
||||
b LoopFillZerobss
|
||||
|
||||
FillZerobss:
|
||||
str r3, [r2]
|
||||
adds r2, r2, #4
|
||||
|
||||
LoopFillZerobss:
|
||||
cmp r2, r4
|
||||
bcc FillZerobss
|
||||
|
||||
/* Call static constructors */
|
||||
bl __libc_init_array
|
||||
/* Call the application's entry point.*/
|
||||
bl main
|
||||
bx lr
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
/**
|
||||
* @brief This is the code that gets called when the processor receives an
|
||||
* unexpected interrupt. This simply enters an infinite loop, preserving
|
||||
* the system state for examination by a debugger.
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
.section .text.Default_Handler,"ax",%progbits
|
||||
Default_Handler:
|
||||
Infinite_Loop:
|
||||
b Infinite_Loop
|
||||
.size Default_Handler, .-Default_Handler
|
||||
/******************************************************************************
|
||||
*
|
||||
* The minimal vector table for a Cortex M. Note that the proper constructs
|
||||
* must be placed on this to ensure that it ends up at physical address
|
||||
* 0x0000.0000.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.section .isr_vector,"a",%progbits
|
||||
.type g_pfnVectors, %object
|
||||
|
||||
|
||||
g_pfnVectors:
|
||||
.word _estack
|
||||
.word Reset_Handler
|
||||
|
||||
.word NMI_Handler
|
||||
.word HardFault_Handler
|
||||
.word MemManage_Handler
|
||||
.word BusFault_Handler
|
||||
.word UsageFault_Handler
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word SVC_Handler
|
||||
.word DebugMon_Handler
|
||||
.word 0
|
||||
.word PendSV_Handler
|
||||
.word SysTick_Handler
|
||||
|
||||
/* External Interrupts */
|
||||
.word WWDG_IRQHandler /* Window WatchDog */
|
||||
.word PVD_PVM_IRQHandler /* PVD/PVM through EXTI Line detection */
|
||||
.word RTC_TAMP_STAMP_CSS_LSE_IRQHandler /* Tamper and TimeStamps through the EXTI line */
|
||||
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
|
||||
.word FLASH_IRQHandler /* FLASH */
|
||||
.word RCC_IRQHandler /* RCC */
|
||||
.word EXTI0_IRQHandler /* EXTI Line0 */
|
||||
.word EXTI1_IRQHandler /* EXTI Line1 */
|
||||
.word EXTI2_IRQHandler /* EXTI Line2 */
|
||||
.word EXTI3_IRQHandler /* EXTI Line3 */
|
||||
.word EXTI4_IRQHandler /* EXTI Line4 */
|
||||
.word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
|
||||
.word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
|
||||
.word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
|
||||
.word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
|
||||
.word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
|
||||
.word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
|
||||
.word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
|
||||
.word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
|
||||
.word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */
|
||||
.word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */
|
||||
.word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */
|
||||
.word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */
|
||||
.word EXTI9_5_IRQHandler /* External Line[9:5]s */
|
||||
.word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */
|
||||
.word TIM1_UP_IRQHandler /* TIM1 Update interrupt */
|
||||
.word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */
|
||||
.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
|
||||
.word TIM2_IRQHandler /* TIM2 */
|
||||
.word TIM3_IRQHandler /* TIM3 */
|
||||
.word TIM4_IRQHandler /* TIM4 */
|
||||
.word I2C1_EV_IRQHandler /* I2C1 Event */
|
||||
.word I2C1_ER_IRQHandler /* I2C1 Error */
|
||||
.word I2C2_EV_IRQHandler /* I2C2 Event */
|
||||
.word I2C2_ER_IRQHandler /* I2C2 Error */
|
||||
.word SPI1_IRQHandler /* SPI1 */
|
||||
.word SPI2_IRQHandler /* SPI2 */
|
||||
.word USART1_IRQHandler /* USART1 */
|
||||
.word USART2_IRQHandler /* USART2 */
|
||||
.word USART3_IRQHandler /* USART3 */
|
||||
.word EXTI15_10_IRQHandler /* External Line[15:10]s */
|
||||
.word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
|
||||
.word DFSDM2_IRQHandler /* DFSDM2 Interrupt */
|
||||
.word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
|
||||
.word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
|
||||
.word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
|
||||
.word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
|
||||
.word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
|
||||
.word FMC_IRQHandler /* FMC */
|
||||
.word SDMMC1_IRQHandler /* SDMMC1 */
|
||||
.word TIM5_IRQHandler /* TIM5 */
|
||||
.word SPI3_IRQHandler /* SPI3 */
|
||||
.word UART4_IRQHandler /* UART4 */
|
||||
.word UART5_IRQHandler /* UART5 */
|
||||
.word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
|
||||
.word TIM7_IRQHandler /* TIM7 */
|
||||
.word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
|
||||
.word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
|
||||
.word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
|
||||
.word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
|
||||
.word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/
|
||||
.word DFSDM1_FLT4_IRQHandler /* DFSDM Filter4 Interrupt */
|
||||
.word DFSDM1_FLT5_IRQHandler /* DFSDM Filter5 Interrupt */
|
||||
.word DFSDM1_FLT6_IRQHandler /* DFSDM Filter6 Interrupt */
|
||||
.word DFSDM1_FLT7_IRQHandler /* DFSDM Filter7 Interrupt */
|
||||
.word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
|
||||
.word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
|
||||
.word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
|
||||
.word USART6_IRQHandler /* USART6 */
|
||||
.word I2C3_EV_IRQHandler /* I2C3 event */
|
||||
.word I2C3_ER_IRQHandler /* I2C3 error */
|
||||
.word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
|
||||
.word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
|
||||
.word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
|
||||
.word OTG_HS_IRQHandler /* USB OTG HS */
|
||||
.word DCMI_PSSI_IRQHandler /* DCMI, PSSI */
|
||||
.word 0 /* Reserved */
|
||||
.word RNG_IRQHandler /* RNG */
|
||||
.word FPU_IRQHandler /* FPU */
|
||||
.word UART7_IRQHandler /* UART7 */
|
||||
.word UART8_IRQHandler /* UART8 */
|
||||
.word SPI4_IRQHandler /* SPI4 */
|
||||
.word SPI5_IRQHandler /* SPI5 */
|
||||
.word SPI6_IRQHandler /* SPI6 */
|
||||
.word SAI1_IRQHandler /* SAI1 */
|
||||
.word LTDC_IRQHandler /* LTDC */
|
||||
.word LTDC_ER_IRQHandler /* LTDC error */
|
||||
.word DMA2D_IRQHandler /* DMA2D */
|
||||
.word SAI2_IRQHandler /* SAI2 */
|
||||
.word OCTOSPI1_IRQHandler /* OCTOSPI1 */
|
||||
.word LPTIM1_IRQHandler /* LPTIM1 */
|
||||
.word CEC_IRQHandler /* HDMI_CEC */
|
||||
.word I2C4_EV_IRQHandler /* I2C4 Event */
|
||||
.word I2C4_ER_IRQHandler /* I2C4 Error */
|
||||
.word SPDIF_RX_IRQHandler /* SPDIF_RX */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */
|
||||
.word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */
|
||||
.word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */
|
||||
.word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */
|
||||
.word TIM15_IRQHandler /* TIM15 global Interrupt */
|
||||
.word TIM16_IRQHandler /* TIM16 global Interrupt */
|
||||
.word TIM17_IRQHandler /* TIM17 global Interrupt */
|
||||
.word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */
|
||||
.word MDIOS_IRQHandler /* MDIOS global Interrupt */
|
||||
.word JPEG_IRQHandler /* JPEG global Interrupt */
|
||||
.word MDMA_IRQHandler /* MDMA global Interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */
|
||||
.word HSEM1_IRQHandler /* HSEM1 global Interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word DAC2_IRQHandler /* DAC2 global Interrupt */
|
||||
.word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */
|
||||
.word BDMA2_Channel0_IRQHandler /* BDMA2 Channel 0 global Interrupt */
|
||||
.word BDMA2_Channel1_IRQHandler /* BDMA2 Channel 1 global Interrupt */
|
||||
.word BDMA2_Channel2_IRQHandler /* BDMA2 Channel 2 global Interrupt */
|
||||
.word BDMA2_Channel3_IRQHandler /* BDMA2 Channel 3 global Interrupt */
|
||||
.word BDMA2_Channel4_IRQHandler /* BDMA2 Channel 4 global Interrupt */
|
||||
.word BDMA2_Channel5_IRQHandler /* BDMA2 Channel 5 global Interrupt */
|
||||
.word BDMA2_Channel6_IRQHandler /* BDMA2 Channel 6 global Interrupt */
|
||||
.word BDMA2_Channel7_IRQHandler /* BDMA2 Channel 7 global Interrupt */
|
||||
.word COMP_IRQHandler /* COMP global Interrupt */
|
||||
.word LPTIM2_IRQHandler /* LP TIM2 global interrupt */
|
||||
.word LPTIM3_IRQHandler /* LP TIM3 global interrupt */
|
||||
.word UART9_IRQHandler /* UART9 global interrupt */
|
||||
.word USART10_IRQHandler /* USART10 global interrupt */
|
||||
.word LPUART1_IRQHandler /* LP UART1 interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word CRS_IRQHandler /* Clock Recovery Global Interrupt */
|
||||
.word ECC_IRQHandler /* ECC diagnostic Global Interrupt */
|
||||
.word 0 /* Reserved */
|
||||
.word DTS_IRQHandler /* DTS */
|
||||
.word 0 /* Reserved */
|
||||
.word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */
|
||||
.word OCTOSPI2_IRQHandler /* OCTOSPI2 */
|
||||
.word 0 /* Reserved */
|
||||
.word 0 /* Reserved */
|
||||
.word GFXMMU_IRQHandler /* GFXMMU */
|
||||
.word BDMA1_IRQHandler /* BDMA1 */
|
||||
|
||||
.size g_pfnVectors, .-g_pfnVectors
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Provide weak aliases for each Exception handler to the Default_Handler.
|
||||
* As they are weak aliases, any function with the same name will override
|
||||
* this definition.
|
||||
*
|
||||
*******************************************************************************/
|
||||
.weak NMI_Handler
|
||||
.thumb_set NMI_Handler,Default_Handler
|
||||
|
||||
.weak HardFault_Handler
|
||||
.thumb_set HardFault_Handler,Default_Handler
|
||||
|
||||
.weak MemManage_Handler
|
||||
.thumb_set MemManage_Handler,Default_Handler
|
||||
|
||||
.weak BusFault_Handler
|
||||
.thumb_set BusFault_Handler,Default_Handler
|
||||
|
||||
.weak UsageFault_Handler
|
||||
.thumb_set UsageFault_Handler,Default_Handler
|
||||
|
||||
.weak SVC_Handler
|
||||
.thumb_set SVC_Handler,Default_Handler
|
||||
|
||||
.weak DebugMon_Handler
|
||||
.thumb_set DebugMon_Handler,Default_Handler
|
||||
|
||||
.weak PendSV_Handler
|
||||
.thumb_set PendSV_Handler,Default_Handler
|
||||
|
||||
.weak SysTick_Handler
|
||||
.thumb_set SysTick_Handler,Default_Handler
|
||||
|
||||
.weak WWDG_IRQHandler
|
||||
.thumb_set WWDG_IRQHandler,Default_Handler
|
||||
|
||||
.weak PVD_PVM_IRQHandler
|
||||
.thumb_set PVD_PVM_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_TAMP_STAMP_CSS_LSE_IRQHandler
|
||||
.thumb_set RTC_TAMP_STAMP_CSS_LSE_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_WKUP_IRQHandler
|
||||
.thumb_set RTC_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak FLASH_IRQHandler
|
||||
.thumb_set FLASH_IRQHandler,Default_Handler
|
||||
|
||||
.weak RCC_IRQHandler
|
||||
.thumb_set RCC_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI0_IRQHandler
|
||||
.thumb_set EXTI0_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI1_IRQHandler
|
||||
.thumb_set EXTI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI2_IRQHandler
|
||||
.thumb_set EXTI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI3_IRQHandler
|
||||
.thumb_set EXTI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI4_IRQHandler
|
||||
.thumb_set EXTI4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream0_IRQHandler
|
||||
.thumb_set DMA1_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream1_IRQHandler
|
||||
.thumb_set DMA1_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream2_IRQHandler
|
||||
.thumb_set DMA1_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream3_IRQHandler
|
||||
.thumb_set DMA1_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream4_IRQHandler
|
||||
.thumb_set DMA1_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream5_IRQHandler
|
||||
.thumb_set DMA1_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream6_IRQHandler
|
||||
.thumb_set DMA1_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak ADC_IRQHandler
|
||||
.thumb_set ADC_IRQHandler,Default_Handler
|
||||
|
||||
.weak FDCAN1_IT0_IRQHandler
|
||||
.thumb_set FDCAN1_IT0_IRQHandler,Default_Handler
|
||||
|
||||
.weak FDCAN2_IT0_IRQHandler
|
||||
.thumb_set FDCAN2_IT0_IRQHandler,Default_Handler
|
||||
|
||||
.weak FDCAN1_IT1_IRQHandler
|
||||
.thumb_set FDCAN1_IT1_IRQHandler,Default_Handler
|
||||
|
||||
.weak FDCAN2_IT1_IRQHandler
|
||||
.thumb_set FDCAN2_IT1_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI9_5_IRQHandler
|
||||
.thumb_set EXTI9_5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_BRK_IRQHandler
|
||||
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_UP_IRQHandler
|
||||
.thumb_set TIM1_UP_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_TRG_COM_IRQHandler
|
||||
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM1_CC_IRQHandler
|
||||
.thumb_set TIM1_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM2_IRQHandler
|
||||
.thumb_set TIM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM3_IRQHandler
|
||||
.thumb_set TIM3_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM4_IRQHandler
|
||||
.thumb_set TIM4_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_EV_IRQHandler
|
||||
.thumb_set I2C1_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C1_ER_IRQHandler
|
||||
.thumb_set I2C1_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_EV_IRQHandler
|
||||
.thumb_set I2C2_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C2_ER_IRQHandler
|
||||
.thumb_set I2C2_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI1_IRQHandler
|
||||
.thumb_set SPI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI2_IRQHandler
|
||||
.thumb_set SPI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART1_IRQHandler
|
||||
.thumb_set USART1_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART2_IRQHandler
|
||||
.thumb_set USART2_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART3_IRQHandler
|
||||
.thumb_set USART3_IRQHandler,Default_Handler
|
||||
|
||||
.weak EXTI15_10_IRQHandler
|
||||
.thumb_set EXTI15_10_IRQHandler,Default_Handler
|
||||
|
||||
.weak RTC_Alarm_IRQHandler
|
||||
.thumb_set RTC_Alarm_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM2_IRQHandler
|
||||
.thumb_set DFSDM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_BRK_TIM12_IRQHandler
|
||||
.thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_UP_TIM13_IRQHandler
|
||||
.thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_TRG_COM_TIM14_IRQHandler
|
||||
.thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM8_CC_IRQHandler
|
||||
.thumb_set TIM8_CC_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA1_Stream7_IRQHandler
|
||||
.thumb_set DMA1_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak FMC_IRQHandler
|
||||
.thumb_set FMC_IRQHandler,Default_Handler
|
||||
|
||||
.weak SDMMC1_IRQHandler
|
||||
.thumb_set SDMMC1_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM5_IRQHandler
|
||||
.thumb_set TIM5_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI3_IRQHandler
|
||||
.thumb_set SPI3_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART4_IRQHandler
|
||||
.thumb_set UART4_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART5_IRQHandler
|
||||
.thumb_set UART5_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM6_DAC_IRQHandler
|
||||
.thumb_set TIM6_DAC_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM7_IRQHandler
|
||||
.thumb_set TIM7_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream0_IRQHandler
|
||||
.thumb_set DMA2_Stream0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream1_IRQHandler
|
||||
.thumb_set DMA2_Stream1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream2_IRQHandler
|
||||
.thumb_set DMA2_Stream2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream3_IRQHandler
|
||||
.thumb_set DMA2_Stream3_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream4_IRQHandler
|
||||
.thumb_set DMA2_Stream4_IRQHandler,Default_Handler
|
||||
|
||||
.weak FDCAN_CAL_IRQHandler
|
||||
.thumb_set FDCAN_CAL_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT4_IRQHandler
|
||||
.thumb_set DFSDM1_FLT4_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT5_IRQHandler
|
||||
.thumb_set DFSDM1_FLT5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT6_IRQHandler
|
||||
.thumb_set DFSDM1_FLT6_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT7_IRQHandler
|
||||
.thumb_set DFSDM1_FLT7_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream5_IRQHandler
|
||||
.thumb_set DMA2_Stream5_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream6_IRQHandler
|
||||
.thumb_set DMA2_Stream6_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2_Stream7_IRQHandler
|
||||
.thumb_set DMA2_Stream7_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART6_IRQHandler
|
||||
.thumb_set USART6_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_EV_IRQHandler
|
||||
.thumb_set I2C3_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C3_ER_IRQHandler
|
||||
.thumb_set I2C3_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_OUT_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_EP1_IN_IRQHandler
|
||||
.thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_WKUP_IRQHandler
|
||||
.thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak OTG_HS_IRQHandler
|
||||
.thumb_set OTG_HS_IRQHandler,Default_Handler
|
||||
|
||||
.weak DCMI_PSSI_IRQHandler
|
||||
.thumb_set DCMI_PSSI_IRQHandler,Default_Handler
|
||||
|
||||
.weak RNG_IRQHandler
|
||||
.thumb_set RNG_IRQHandler,Default_Handler
|
||||
|
||||
.weak FPU_IRQHandler
|
||||
.thumb_set FPU_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART7_IRQHandler
|
||||
.thumb_set UART7_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART8_IRQHandler
|
||||
.thumb_set UART8_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI4_IRQHandler
|
||||
.thumb_set SPI4_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI5_IRQHandler
|
||||
.thumb_set SPI5_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPI6_IRQHandler
|
||||
.thumb_set SPI6_IRQHandler,Default_Handler
|
||||
|
||||
.weak SAI1_IRQHandler
|
||||
.thumb_set SAI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak LTDC_IRQHandler
|
||||
.thumb_set LTDC_IRQHandler,Default_Handler
|
||||
|
||||
.weak LTDC_ER_IRQHandler
|
||||
.thumb_set LTDC_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMA2D_IRQHandler
|
||||
.thumb_set DMA2D_IRQHandler,Default_Handler
|
||||
|
||||
.weak SAI2_IRQHandler
|
||||
.thumb_set SAI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak OCTOSPI1_IRQHandler
|
||||
.thumb_set OCTOSPI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPTIM1_IRQHandler
|
||||
.thumb_set LPTIM1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CEC_IRQHandler
|
||||
.thumb_set CEC_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C4_EV_IRQHandler
|
||||
.thumb_set I2C4_EV_IRQHandler,Default_Handler
|
||||
|
||||
.weak I2C4_ER_IRQHandler
|
||||
.thumb_set I2C4_ER_IRQHandler,Default_Handler
|
||||
|
||||
.weak SPDIF_RX_IRQHandler
|
||||
.thumb_set SPDIF_RX_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMAMUX1_OVR_IRQHandler
|
||||
.thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT0_IRQHandler
|
||||
.thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT1_IRQHandler
|
||||
.thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT2_IRQHandler
|
||||
.thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DFSDM1_FLT3_IRQHandler
|
||||
.thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler
|
||||
|
||||
.weak SWPMI1_IRQHandler
|
||||
.thumb_set SWPMI1_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM15_IRQHandler
|
||||
.thumb_set TIM15_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM16_IRQHandler
|
||||
.thumb_set TIM16_IRQHandler,Default_Handler
|
||||
|
||||
.weak TIM17_IRQHandler
|
||||
.thumb_set TIM17_IRQHandler,Default_Handler
|
||||
|
||||
.weak MDIOS_WKUP_IRQHandler
|
||||
.thumb_set MDIOS_WKUP_IRQHandler,Default_Handler
|
||||
|
||||
.weak MDIOS_IRQHandler
|
||||
.thumb_set MDIOS_IRQHandler,Default_Handler
|
||||
|
||||
.weak JPEG_IRQHandler
|
||||
.thumb_set JPEG_IRQHandler,Default_Handler
|
||||
|
||||
.weak MDMA_IRQHandler
|
||||
.thumb_set MDMA_IRQHandler,Default_Handler
|
||||
|
||||
.weak SDMMC2_IRQHandler
|
||||
.thumb_set SDMMC2_IRQHandler,Default_Handler
|
||||
|
||||
.weak HSEM1_IRQHandler
|
||||
.thumb_set HSEM1_IRQHandler,Default_Handler
|
||||
|
||||
.weak DAC2_IRQHandler
|
||||
.thumb_set DAC2_IRQHandler,Default_Handler
|
||||
|
||||
.weak DMAMUX2_OVR_IRQHandler
|
||||
.thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel0_IRQHandler
|
||||
.thumb_set BDMA2_Channel0_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel1_IRQHandler
|
||||
.thumb_set BDMA2_Channel1_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel2_IRQHandler
|
||||
.thumb_set BDMA2_Channel2_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel3_IRQHandler
|
||||
.thumb_set BDMA2_Channel3_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel4_IRQHandler
|
||||
.thumb_set BDMA2_Channel4_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel5_IRQHandler
|
||||
.thumb_set BDMA2_Channel5_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel6_IRQHandler
|
||||
.thumb_set BDMA2_Channel6_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA2_Channel7_IRQHandler
|
||||
.thumb_set BDMA2_Channel7_IRQHandler,Default_Handler
|
||||
|
||||
.weak COMP_IRQHandler
|
||||
.thumb_set COMP_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPTIM2_IRQHandler
|
||||
.thumb_set LPTIM2_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPTIM3_IRQHandler
|
||||
.thumb_set LPTIM3_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPTIM4_IRQHandler
|
||||
.thumb_set LPTIM4_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPTIM5_IRQHandler
|
||||
.thumb_set LPTIM5_IRQHandler,Default_Handler
|
||||
|
||||
.weak UART9_IRQHandler
|
||||
.thumb_set UART9_IRQHandler,Default_Handler
|
||||
|
||||
.weak USART10_IRQHandler
|
||||
.thumb_set USART10_IRQHandler,Default_Handler
|
||||
|
||||
.weak LPUART1_IRQHandler
|
||||
.thumb_set LPUART1_IRQHandler,Default_Handler
|
||||
|
||||
.weak CRS_IRQHandler
|
||||
.thumb_set CRS_IRQHandler,Default_Handler
|
||||
|
||||
.weak ECC_IRQHandler
|
||||
.thumb_set ECC_IRQHandler,Default_Handler
|
||||
|
||||
.weak DTS_IRQHandler
|
||||
.thumb_set DTS_IRQHandler,Default_Handler
|
||||
|
||||
.weak WAKEUP_PIN_IRQHandler
|
||||
.thumb_set WAKEUP_PIN_IRQHandler,Default_Handler
|
||||
|
||||
.weak OCTOSPI2_IRQHandler
|
||||
.thumb_set OCTOSPI2_IRQHandler,Default_Handler
|
||||
|
||||
.weak GFXMMU_IRQHandler
|
||||
.thumb_set GFXMMU_IRQHandler,Default_Handler
|
||||
|
||||
.weak BDMA1_IRQHandler
|
||||
.thumb_set BDMA1_IRQHandler,Default_Handler
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user