feat: KT mBMS 펌웨어 3종(HW1/2/3) 및 통합 빌드 환경 초기 커밋 (V4.0.0.1)

This commit is contained in:
2026-11-05 14:31:31 +09:00
commit c52dc2f348
10803 changed files with 4642514 additions and 0 deletions

View File

@@ -0,0 +1,803 @@
/*! ADBMS1818: Multicell Battery Monitors
*
*@verbatim
*The ADBMS1818 is multi-cell battery stack monitor that measures up to 18 series
*connected battery cells with a total measurement error of less than 2.2mV.
*The cell measurement range of 0V to 5V makes the ADBMS1818 suitable for most
*battery chemistries. All 18 cell voltages can be captured in 290uS, and lower
*data acquisition rates can be selected for high noise reduction.
*Using the ADBMS1818, multiple devices are connected in a daisy-chain with one
*host processor connection for all devices, permitting simultaneous cell monitoring
*of long, high voltage battery strings.
*@endverbatim
*
* https://www.analog.com/en/products/ADBMS1818.html /TBD
* https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/EVAL-ADBMS1818.html /TBD
*
*********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
//! @ingroup BMS
//! @{
//! @defgroup ADBMS1818 ADBMS1818: Multicell Battery Monitor
//! @}
/*! @file
@ingroup ADBMS1818
Library for ADBMS1818 Multicell Battery Monitor
*/
#include "stdint.h"
#include "ADBMS181x.h"
#include "ADBMS1818.h"
/* Helper function to initialize register limits. */
void ADBMS1818_init_reg_limits(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
for(uint8_t cic=0; cic<total_ic; cic++)
{
ic[cic].ic_reg.cell_channels = 18;
ic[cic].ic_reg.stat_channels = 4;
ic[cic].ic_reg.aux_channels = 9;
ic[cic].ic_reg.num_cv_reg = 6;
ic[cic].ic_reg.num_gpio_reg = 4;
ic[cic].ic_reg.num_stat_reg = 2;
}
}
/*
This command will write the configuration registers of the ADBMS1818s
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void ADBMS1818_wrcfg(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
ADBMS181x_wrcfg(total_ic,ic);
}
/*
This command will write the configuration b registers of the ADBMS1818s
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void ADBMS1818_wrcfgb(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
ADBMS181x_wrcfgb(total_ic,ic);
}
/* Reads configuration registers of a ADBMS1818 daisy chain */
int8_t ADBMS1818_rdcfg(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
int8_t pec_error = 0;
pec_error = ADBMS181x_rdcfg(total_ic,ic);
return(pec_error);
}
/* Reads configuration b registers of a ADBMS1818 daisy chain */
int8_t ADBMS1818_rdcfgb(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
int8_t pec_error = 0;
pec_error = ADBMS181x_rdcfgb(total_ic,ic);
return(pec_error);
}
/* Starts cell voltage conversion */
void ADBMS1818_adcv(uint8_t MD, //ADC Mode
uint8_t DCP, //Discharge Permit
uint8_t CH //Cell Channels to be measured
)
{
ADBMS181x_adcv(MD,DCP,CH);
}
/* Start a GPIO and Vref2 Conversion */
void ADBMS1818_adax(uint8_t MD, //ADC Mode
uint8_t CHG //GPIO Channels to be measured)
)
{
ADBMS181x_adax(MD,CHG);
}
/* Start a Status ADC Conversion */
void ADBMS1818_adstat(uint8_t MD, //ADC Mode
uint8_t CHST //Stat Channels to be measured
)
{
ADBMS181x_adstat(MD,CHST);
}
/* Starts cell voltage and GPIO 1&2 conversion */
void ADBMS1818_adcvax(uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
ADBMS181x_adcvax(MD,DCP);
}
/* Starts cell voltage and SOC conversion */
void ADBMS1818_adcvsc( uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
ADBMS181x_adcvsc(MD,DCP);
}
/* Reads and parses the ADBMS1818 cell voltage registers */
uint8_t ADBMS1818_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
uint8_t total_ic, // The number of ICs in the system
cell_asic *ic // Array of the parsed cell codes
)
{
int8_t pec_error = 0;
pec_error = ADBMS181x_rdcv(reg,total_ic,ic);
return(pec_error);
}
/*
The function is used
to read the parsed GPIO codes of the ADBMS1818. This function will send the requested
read commands parse the data and store the gpio voltages in aux_codes variable
*/
int8_t ADBMS1818_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
uint8_t total_ic,//The number of ICs in the system
cell_asic *ic//A two dimensional array of the gpio voltage codes.
)
{
int8_t pec_error = 0;
ADBMS181x_rdaux(reg,total_ic,ic);
return (pec_error);
}
/*
Reads and parses the ADBMS1818 stat registers.
The function is used
to read the parsed stat codes of the ADBMS1818. This function will send the requested
read commands parse the data and store the stat voltages in stat_codes variable
*/
int8_t ADBMS1818_rdstat(uint8_t reg, //Determines which Stat register is read back.
uint8_t total_ic,//The number of ICs in the system
cell_asic *ic //A two dimensional array of the stat codes.
)
{
int8_t pec_error = 0;
pec_error = ADBMS181x_rdstat(reg,total_ic,ic);
return (pec_error);
}
/* Sends the poll ADC command */
uint8_t ADBMS1818_pladc()
{
return(ADBMS181x_pladc());
}
/* This function will block operation until the ADC has finished it's conversion */
uint32_t ADBMS1818_pollAdc()
{
return(ADBMS181x_pollAdc());
}
/*
The command clears the cell voltage registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void ADBMS1818_clrcell()
{
ADBMS181x_clrcell();
}
/*
The command clears the Auxiliary registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void ADBMS1818_clraux()
{
ADBMS181x_clraux();
}
/*
The command clears the Stat registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void ADBMS1818_clrstat()
{
ADBMS181x_clrstat();
}
/* Starts the Mux Decoder diagnostic self test */
void ADBMS1818_diagn()
{
ADBMS181x_diagn();
}
/* Starts cell voltage self test conversion */
void ADBMS1818_cvst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
ADBMS181x_cvst(MD,ST);
}
/* Start an Auxiliary Register Self Test Conversion */
void ADBMS1818_axst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
ADBMS181x_axst(MD,ST);
}
/* Start a Status Register Self Test Conversion */
void ADBMS1818_statst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
ADBMS181x_statst(MD,ST);
}
/* Starts cell voltage overlap conversion */
void ADBMS1818_adol(uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
ADBMS181x_adol(MD,DCP);
}
/* Start an GPIO Redundancy test */
void ADBMS1818_adaxd(uint8_t MD, //ADC Mode
uint8_t CHG //GPIO Channels to be measured
)
{
ADBMS181x_adaxd(MD,CHG);
}
/* Start a Status register redundancy test Conversion */
void ADBMS1818_adstatd(uint8_t MD, //ADC Mode
uint8_t CHST //Stat Channels to be measured
)
{
ADBMS181x_adstatd(MD,CHST);
}
/* Runs the Digital Filter Self Test */
int16_t ADBMS1818_run_cell_adc_st(uint8_t adc_reg, // Type of register
uint8_t total_ic, // Number of ICs in the system
cell_asic *ic, // A two dimensional array that will store the data
uint8_t md, //ADC Mode
bool adcopt // The adcopt bit in the configuration register
)
{
int16_t error = 0;
error = ADBMS181x_run_cell_adc_st(adc_reg,total_ic,ic,md,adcopt);
return(error);
}
/* Runs the ADC overlap test for the IC */
uint16_t ADBMS1818_run_adc_overlap(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
uint16_t error = 0;
int32_t measure_delta =0;
int16_t failure_pos_limit = 20;
int16_t failure_neg_limit = -20;
uint32_t conv_time=0;
wakeup_idle(total_ic);
ADBMS181x_adol(MD_7KHZ_3KHZ,DCP_DISABLED);
conv_time = ADBMS181x_pollAdc();
wakeup_idle(total_ic);
error = ADBMS181x_rdcv(0, total_ic,ic);
for (int cic = 0; cic<total_ic; cic++)
{
measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
{
error = error | (1<<(cic-1));
}
measure_delta = (int32_t)ic[cic].cells.c_codes[12]-(int32_t)ic[cic].cells.c_codes[13];
if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
{
error = error | (1<<(cic-1));
}
}
/* Keeping here, Unused variables to retain Lib API as is */
(void)conv_time;
return(error);
}
/* Runs the redundancy self test */
int16_t ADBMS1818_run_adc_redundancy_st(uint8_t adc_mode, //ADC Mode
uint8_t adc_reg, // Type of register
uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
int16_t error = 0;
ADBMS181x_run_adc_redundancy_st(adc_mode,adc_reg,total_ic,ic);
return(error);
}
/* Start an open wire Conversion */
void ADBMS1818_adow(uint8_t MD, //ADC Mode
uint8_t PUP, //Pull up/Pull down current
uint8_t CH, //Sets which Cell channels are converted
uint8_t DCP //Discharge Permit
)
{
ADBMS181x_adow(MD,PUP,CH,DCP);
}
/* Start GPIOs open wire ADC conversion */
void ADBMS1818_axow(uint8_t MD, //ADC Mode
uint8_t PUP //Pull up/Pull down current
)
{
ADBMS181x_axow(MD, PUP);
}
/* Runs the data sheet algorithm for open wire for single cell detection */
void ADBMS1818_run_openwire_single(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_run_openwire_single(total_ic, ic);
}
/* Runs the data sheet algorithm for open wire for multiple cell and two consecutive cells detection */
void ADBMS1818_run_openwire_multi(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_run_openwire_multi( total_ic, ic);
}
/* Runs open wire for GPIOs */
void ADBMS1818_run_gpio_openwire(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_run_gpio_openwire(total_ic, ic);
}
/* Helper function to set discharge bit in CFG register */
void ADBMS1818_set_discharge(int Cell, // Cell to be discharged
uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
for (int i=0; i<total_ic; i++)
{
if (Cell==0)
{
ic[i].configb.tx_data[1] = ic[i].configb.tx_data[1] |(0x04);
}
else if (Cell<9)
{
ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (1<<(Cell-1));
}
else if (Cell < 13)
{
ic[i].config.tx_data[5] = ic[i].config.tx_data[5] | (1<<(Cell-9));
}
else if (Cell<17)
{
ic[i].configb.tx_data[0] = ic[i].configb.tx_data[0] | (1<<(Cell-9));
}
else if (Cell<19)
{
ic[i].configb.tx_data[1] = ic[i].configb.tx_data[1] | (1<<(Cell-17));
}
else
{
break;
}
}
}
/* Clears all of the DCC bits in the configuration registers */
void ADBMS1818_clear_discharge(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_clear_discharge(total_ic,ic);
}
/* Writes the pwm registers of a ADBMS1818 daisy chain */
void ADBMS1818_wrpwm(uint8_t total_ic, // Number of ICs in the system
uint8_t pwmReg, // PWM Register A or B
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
ADBMS181x_wrpwm(total_ic,pwmReg,ic);
}
/* Reads pwm registers of a ADBMS1818 daisy chain */
int8_t ADBMS1818_rdpwm(uint8_t total_ic, //Number of ICs in the system
uint8_t pwmReg, // PWM Register A or B
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
int8_t pec_error =0;
pec_error = ADBMS181x_rdpwm(total_ic,pwmReg,ic);
return(pec_error);
}
/* Writes data in S control register the ADBMS1818 connected in a daisy chain stack */
void ADBMS1818_wrsctrl(uint8_t total_ic, // number of ICs in the daisy chain
uint8_t sctrl_reg, // SCTRL Register A or B
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_wrsctrl(total_ic, sctrl_reg, ic);
}
/* Reads sctrl registers of a ADBMS1818 daisy chain */
int8_t ADBMS1818_rdsctrl(uint8_t total_ic, // number of ICs in the daisy chain
uint8_t sctrl_reg, // SCTRL Register A or B
cell_asic *ic //< a two dimensional array that the function stores the read data
)
{
return ADBMS181x_rdsctrl( total_ic, sctrl_reg,ic );
}
/*
Start Sctrl data communication
This command will start the sctrl pulse communication over the spins
*/
void ADBMS1818_stsctrl()
{
ADBMS181x_stsctrl();
}
/*
The command clears the Sctrl registers and initializes
all values to 0. The register will read back hexadecimal 0x00
after the command is sent.
*/
void ADBMS1818_clrsctrl()
{
ADBMS181x_clrsctrl();
}
/* Write the 6813 PWM/Sctrl Register B */
void ADBMS1818_wrpsb(uint8_t total_ic, // Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
uint8_t cmd[2];
uint8_t write_buffer[256];
uint8_t c_ic = 0;
cmd[0] = 0x00;
cmd[1] = 0x1C;
for(uint8_t current_ic = 0; current_ic<total_ic;current_ic++)
{
/*
* isospi_reverse
* if true then taking current_ic as c_ic from ,
* but in other functions it seems to be different
* where if false they are taking current_ic as c_ic
* so changing to it false to be in sync with other code
*/
//if(ic->isospi_reverse == true){c_ic = current_ic;}
if(ic->isospi_reverse == false){c_ic = current_ic;}
else{c_ic = total_ic - current_ic - 1;}
write_buffer[ (current_ic*6) + 0] = ic[c_ic].pwmb.tx_data[0];
write_buffer[ (current_ic*6) + 1] = ic[c_ic].pwmb.tx_data[1];
write_buffer[ (current_ic*6) + 2]= ic[c_ic].pwmb.tx_data[2];
write_buffer[ (current_ic*6) + 3] = ic[c_ic].sctrlb.tx_data[3];
write_buffer[ (current_ic*6) + 4] = ic[c_ic].sctrlb.tx_data[4];
write_buffer[ (current_ic*6) + 5]= ic[c_ic].sctrlb.tx_data[5];
#if 0
write_buffer[0] = ic[c_ic].pwmb.tx_data[0];
write_buffer[1] = ic[c_ic].pwmb.tx_data[1];
write_buffer[2]= ic[c_ic].pwmb.tx_data[2];
write_buffer[3] = ic[c_ic].sctrlb.tx_data[3];
write_buffer[4] = ic[c_ic].sctrlb.tx_data[4];
write_buffer[5]= ic[c_ic].sctrlb.tx_data[5];
#endif
}
write_68(total_ic, cmd, write_buffer);
}
/* Reading the 6813 PWM/Sctrl Register B */
uint8_t ADBMS1818_rdpsb(uint8_t total_ic, //< number of ICs in the daisy chain
cell_asic *ic //< a two dimensional array that the function stores the read data
)
{
uint8_t cmd[4];
uint8_t read_buffer[256];
int8_t pec_error = 0;
uint16_t data_pec;
uint16_t calc_pec;
uint8_t c_ic = 0;
cmd[0] = 0x00;
cmd[1] = 0x1E;
pec_error = read_68(total_ic, cmd, read_buffer);
for(uint8_t current_ic =0; current_ic<total_ic; current_ic++)
{
if(ic->isospi_reverse == false){c_ic = current_ic;}
else{c_ic = total_ic - current_ic - 1;}
for(int byte=0; byte<3;byte++)
{
ic[c_ic].pwmb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
for(int byte=3; byte<6;byte++)
{
ic[c_ic].sctrlb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
for(int byte=6; byte<8;byte++)
{
ic[c_ic].pwmb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
ic[c_ic].sctrlb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
if(calc_pec != data_pec )
{
ic[c_ic].pwmb.rx_pec_match = 1;
ic[c_ic].sctrlb.rx_pec_match = 1;
}
else
{
ic[c_ic].pwmb.rx_pec_match = 0;
ic[c_ic].sctrlb.rx_pec_match = 0;
}
}
return(pec_error);
}
/* Writes the COMM registers of a ADBMS1818 daisy chain */
void ADBMS1818_wrcomm(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the comm data that will be written
)
{
ADBMS181x_wrcomm(total_ic,ic);
}
/* Reads COMM registers of a ADBMS1818 daisy chain */
int8_t ADBMS1818_rdcomm(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read data.
)
{
int8_t pec_error = 0;
ADBMS181x_rdcomm(total_ic, ic);
return(pec_error);
}
/* Shifts data in COMM register out over ADBMS1818 SPI/I2C port */
void ADBMS1818_stcomm(uint8_t len) //Length of data to be transmitted
{
ADBMS181x_stcomm(len);
}
/* Mutes the ADBMS1818 discharge transistors */
void ADBMS1818_mute()
{
uint8_t cmd[2];
cmd[0] = 0x00;
cmd[1] = 0x28;
cmd_68(cmd);
}
/* Clears the ADBMS1818 Mute Discharge */
void ADBMS1818_unmute()
{
uint8_t cmd[2];
cmd[0] = 0x00;
cmd[1] = 0x29;
cmd_68(cmd);
}
/* Helper function that increments PEC counters */
void ADBMS1818_check_pec(uint8_t total_ic,//Number of ICs in the system
uint8_t reg, // Type of register
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_check_pec(total_ic,reg,ic);
}
/* Helper Function to reset PEC counters */
void ADBMS1818_reset_crc_count(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic // A two dimensional array that will store the data
)
{
ADBMS181x_reset_crc_count(total_ic,ic);
}
/* Helper function to initialize CFG variables */
void ADBMS1818_init_cfg(uint8_t total_ic, cell_asic *ic)
{
ADBMS181x_init_cfg(total_ic,ic);
}
/* Helper function to set CFGR variable */
void ADBMS1818_set_cfgr(uint8_t nIC, cell_asic *ic, bool refon, bool adcopt, bool gpio[5],bool dcc[12],bool dcto[4], uint16_t uv, uint16_t ov)
{
ADBMS181x_set_cfgr_refon (nIC, ic, refon);
ADBMS181x_set_cfgr_adcopt(nIC, ic, adcopt);
ADBMS181x_set_cfgr_gpio (nIC, ic, gpio);
ADBMS181x_set_cfgr_dis (nIC, ic, dcc);
ADBMS181x_set_cfgr_dcto (nIC, ic, dcto);
ADBMS181x_set_cfgr_uv (nIC, ic, uv);
ADBMS181x_set_cfgr_ov (nIC, ic, ov);
}
/* Helper function to set the REFON bit */
void ADBMS1818_set_cfgr_refon(uint8_t nIC, cell_asic *ic, bool refon)
{
ADBMS181x_set_cfgr_refon(nIC,ic,refon);
}
/* Helper function to set the adcopt bit */
void ADBMS1818_set_cfgr_adcopt(uint8_t nIC, cell_asic *ic, bool adcopt)
{
ADBMS181x_set_cfgr_adcopt(nIC,ic,adcopt);
}
/* Helper function to set GPIO bits */
void ADBMS1818_set_cfgr_gpio(uint8_t nIC, cell_asic *ic,bool gpio[5])
{
ADBMS181x_set_cfgr_gpio(nIC,ic,gpio);
}
/* Helper function to control discharge */
void ADBMS1818_set_cfgr_dis(uint8_t nIC, cell_asic *ic,bool dcc[12])
{
ADBMS181x_set_cfgr_dis(nIC,ic,dcc);
}
/* Helper Function to set uv value in CFG register */
void ADBMS1818_set_cfgr_uv(uint8_t nIC, cell_asic *ic,uint16_t uv)
{
ADBMS181x_set_cfgr_uv(nIC, ic, uv);
}
/* Helper Function to set dcto value in CFG register */
void ADBMS1818_set_cfgr_dcto(uint8_t nIC, cell_asic *ic,bool dcto[4])
{
ADBMS181x_set_cfgr_dcto(nIC, ic, dcto);
}
/* Helper function to set OV value in CFG register */
void ADBMS1818_set_cfgr_ov(uint8_t nIC, cell_asic *ic,uint16_t ov)
{
ADBMS181x_set_cfgr_ov( nIC, ic, ov);
}
/* Helper Function to initialize the CFGRB data structures */
void ADBMS1818_init_cfgb(uint8_t total_ic,cell_asic *ic)
{
for (uint8_t current_ic = 0; current_ic<total_ic;current_ic++)
{
for(int j =0; j<6;j++)
{
ic[current_ic].configb.tx_data[j] = 0;
}
}
}
/* Helper Function to set the configuration register B */
void ADBMS1818_set_cfgrb(uint8_t nIC, cell_asic *ic,bool fdrf,bool dtmen,bool ps[2],bool gpiobits[4],bool dccbits[7])
{
ADBMS1818_set_cfgrb_fdrf (nIC, ic, fdrf);
ADBMS1818_set_cfgrb_dtmen (nIC, ic, dtmen);
ADBMS1818_set_cfgrb_ps (nIC, ic, ps);
ADBMS1818_set_cfgrb_gpio_b(nIC, ic, gpiobits);
ADBMS1818_set_cfgrb_dcc_b (nIC, ic, dccbits);
}
/* Helper function to set the FDRF bit */
void ADBMS1818_set_cfgrb_fdrf(uint8_t nIC, cell_asic *ic, bool fdrf)
{
if(fdrf) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|0x40;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&0xBF;
}
/* Helper function to set the DTMEN bit */
void ADBMS1818_set_cfgrb_dtmen(uint8_t nIC, cell_asic *ic, bool dtmen)
{
if(dtmen) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|0x08;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&0xF7;
}
/* Helper function to set the PATH SELECT bit */
void ADBMS1818_set_cfgrb_ps(uint8_t nIC, cell_asic *ic, bool ps[])
{
for(int i =0;i<2;i++)
{
if(ps[i])ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|(0x01<<(i+4));
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&(~(0x01<<(i+4)));
}
}
/* Helper function to set the gpio bits in configb b register */
void ADBMS1818_set_cfgrb_gpio_b(uint8_t nIC, cell_asic *ic, bool gpiobits[])
{
for(int i =0;i<4;i++)
{
if(gpiobits[i])ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0]|(0x01<<i);
else ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0]&(~(0x01<<i));
}
}
/* Helper function to set the dcc bits in configb b register */
void ADBMS1818_set_cfgrb_dcc_b(uint8_t nIC, cell_asic *ic, bool dccbits[])
{
for(int i =0;i<7;i++)
{
if(i==0)
{
if(dccbits[i])ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|0x04;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&0xFB;
}
if(i>0 && i<5)
{
if(dccbits[i])ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0]|(0x01<<(i+3));
else ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0]&(~(0x01<<(i+3)));
}
if(i>4 && i<7)
{
if(dccbits[i])ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|(0x01<<(i-5));
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&(~(0x01<<(i-5)));
}
}
}

View File

@@ -0,0 +1,637 @@
/*! ADBMS1818: Multicell Battery Monitors
*
*@verbatim
*The ADBMS1818 is multi-cell battery stack monitor that measures up to 18 series
*connected battery cells with a total measurement error of less than 2.2mV.
*The cell measurement range of 0V to 5V makes the ADBMS1818 suitable for most
*battery chemistries. All 18 cell voltages can be captured in 290uS, and lower
*data acquisition rates can be selected for high noise reduction.
*Using the ADBMS1818, multiple devices are connected in a daisy-chain with one
*host processor connection for all devices, permitting simultaneous cell monitoring
*of long, high voltage battery strings.
*@endverbatim
*
* https://www.analog.com/en/products/ADBMS1818.html /TBD
* https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/EVAL-ADBMS1818.html /TBD
*
*********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
/*! @file
@ingroup ADBMS1818
Header for ADBMS1818 Multicell Battery Monitor
*/
#ifndef ADBMS1818_H
#define ADBMS1818_H
#include "stdint.h"
#include "ADBMS181x.h"
#define CELL 1
#define AUX 2
#define STAT 3
/*!
Helper function to initialize register limits
@return void
*/
void ADBMS1818_init_reg_limits(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Write the ADBMS1818 configuration register A
@return void
*/
void ADBMS1818_wrcfg(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array of the configuration data that will be written
);
/*!
Write the ADBMS1818 configuration register B
@return void
*/
void ADBMS1818_wrcfgb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array of the configuration data that will be written
);
/*!
Reads configuration register A of a ADBMS1818 daisy chain
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS1818_rdcfg(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that the function stores the read configuration data
);
/*!
Reads configuration register B of a ADBMS1818 daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS1818_rdcfgb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that the function stores the read configuration data
);
/*!
Starts cell voltage conversion
@return void
*/
void ADBMS1818_adcv(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP, //!< Controls if Discharge is permitted during conversion
uint8_t CH //!< Sets which Cell channels are converted
);
/*!
Start a GPIO and Vref2 Conversion
@return void
*/
void ADBMS1818_adax(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*!
Start a Status ADC Conversion
@return void
*/
void ADBMS1818_adstat( uint8_t MD, //!< ADC Conversion Mode
uint8_t CHST //!< Sets which Stat channels are converted
);
/*!
Starts cell voltage and GPIO 1 & 2 conversion
@return void
*/
void ADBMS1818_adcvax(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*! Starts cell voltage and Sum of cells conversion
@return void
*/
void ADBMS1818_adcvsc(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*!
Reads and parses the ADBMS1818 cell voltage registers.
@return uint8_t, pec_error PEC Status.
0: No PEC error detected
-1: PEC error detected, retry read
*/
uint8_t ADBMS1818_rdcv(uint8_t reg, //!< Controls which cell voltage register is read back.
uint8_t total_ic, //!< The number of ICs in the daisy chain
cell_asic *ic //!< Array of the parsed cell codes from lowest to highest.
);
/*! Reads and parses the ADBMS1818 auxiliary registers.
@return int8_t, pec_error PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t ADBMS1818_rdaux(uint8_t reg, //!< Controls which GPIO voltage register is read back
uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array of the parsed gpio voltage codes
);
/*!
Reads and parses the ADBMS1818 stat registers.
@return int8_t, pec_error PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t ADBMS1818_rdstat(uint8_t reg, //!< Determines which Stat register is read back.
uint8_t total_ic,//!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Sends the poll ADC command
@returns 1 byte read back after a pladc command. If the byte is not 0xFF ADC conversion has completed
*/
uint8_t ADBMS1818_pladc(void);
/*!
This function will block operation until the ADC has finished it's conversion
@returns uint32_t, counter The approximate time it took for the ADC function to complete.
*/
uint32_t ADBMS1818_pollAdc(void);
/*!
Clears the ADBMS1818 cell voltage registers
@return void
*/
void ADBMS1818_clrcell(void);
/*!
Clears the ADBMS1818 Auxiliary registers
@return void
*/
void ADBMS1818_clraux(void);
/*!
Clears the ADBMS1818 Stat registers
@return void
*/
void ADBMS1818_clrstat(void);
/*!
Starts the Mux Decoder diagnostic self test
Running this command will start the Mux Decoder Diagnostic Self Test
This test takes roughly 1mS to complete. The MUXFAIL bit will be updated,
the bit will be set to 1 for a failure and 0 if the test has been passed.
@return void
*/
void ADBMS1818_diagn(void);
/*!
Starts cell voltage self test conversion
@return void
*/
void ADBMS1818_cvst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Self Test Mode
);
/*!
Start an Auxiliary Register Self Test Conversion
@return void
*/
void ADBMS1818_axst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*!
Start a Status Register Self Test Conversion
@return void
*/
void ADBMS1818_statst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*!
Starts cell voltage overlap conversion
@return void
*/
void ADBMS1818_adol(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Discharge permitted during conversion
);
/*!
Start an GPIO Redundancy test
@return void
*/
void ADBMS1818_adaxd(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*!
Start a Status register redundancy test Conversion
@return void
*/
void ADBMS1818_adstatd(uint8_t MD, //!< ADC Mode
uint8_t CHST //!< Sets which Status channels are converted
);
/*!
Helper function that runs the ADC Self Tests
@return int16_t, error Number of errors detected.
*/
int16_t ADBMS1818_run_cell_adc_st(uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t md, //!< ADC Mode
bool adcopt //!< The adcopt bit in the configuration register
);
/*!
Helper Function that runs the ADC Overlap test
@return uint16_t, error
0: Pass
-1: False, Error detected
*/
uint16_t ADBMS1818_run_adc_overlap(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function that runs the ADC Digital Redundancy commands and checks output for errors
@return int16_t, error Number of errors detected.
*/
int16_t ADBMS1818_run_adc_redundancy_st(uint8_t adc_mode, //!< ADC Mode
uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Start an open wire Conversion
@return void
*/
void ADBMS1818_adow(uint8_t MD, //!< ADC Conversion Mode
uint8_t PUP,//!< Pull up/Pull down current
uint8_t CH, //!< Sets which Cell channels are converted
uint8_t DCP //!< Discharge permitted during conversion
);
/*!
Start GPIOs open wire ADC conversion
@return void
*/
void ADBMS1818_axow(uint8_t MD, //!< ADC Mode
uint8_t PUP //!< Pull up/Pull down current
);
/*!
Helper function that runs the data sheet algorithm for open wire for single cell detection
@return void
*/
void ADBMS1818_run_openwire_single(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function that runs open wire for multiple cell and two consecutive cells detection
@return void
*/
void ADBMS1818_run_openwire_multi(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Runs open wire for GPIOs
@return void
*/
void ADBMS1818_run_gpio_openwire(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function to Set DCC bits in the CFGR Registers
@return void
*/
void ADBMS1818_set_discharge(int Cell, //!< The cell to be discharged
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function to clear DCC bits in the CFGR Registers
@return void
*/
void ADBMS1818_clear_discharge(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Write the ADBMS1818 PWM register
@return void
*/
void ADBMS1818_wrpwm(uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t pwmReg, //!< PWM Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Reads pwm registers of a ADBMS1818 daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS1818_rdpwm(uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t pwmReg, //!< PWM Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Write the ADBMS1818 Sctrl register
@return void
*/
void ADBMS1818_wrsctrl(uint8_t nIC, //!< Number of ICs in the daisy chain
uint8_t sctrl_reg,//! SCTRL Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Reads sctrl registers of a ADBMS1818 daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS1818_rdsctrl(uint8_t nIC, //!< Number of ICs in the daisy chain
uint8_t sctrl_reg,//!< SCTRL Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Start Sctrl data communication
This command will start the sctrl pulse communication over the spins
@return void
*/
void ADBMS1818_stsctrl(void);
/*!
Clears the ADBMS1818 Sctrl registers
@return void
*/
void ADBMS1818_clrsctrl(void);
/*!
Write the 6813 PWM/Sctrl Register B
@return void
*/
void ADBMS1818_wrpsb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Reading pwm/s control register B
@return uint8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
uint8_t ADBMS1818_rdpsb(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that the function stores the read data
);
/*!
Write the ADBMS1818 COMM register
@return void
*/
void ADBMS1818_wrcomm(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array of the comm data that will be written
);
/*!
Reads comm registers of a ADBMS1818 daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS1818_rdcomm(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< Two dimensional array that the function stores the read comm data.
);
/*!
Issues a stcomm command and clocks data out of the COMM register
@return void
*/
void ADBMS1818_stcomm(uint8_t len //!< Length of data to be transmitted
);
/*!
Mutes the ADBMS1818 discharge transistors
@return void
*/
void ADBMS1818_mute(void);
/*!
Clears the ADBMS1818 Mute Discharge
@return void
*/
void ADBMS1818_unmute(void);
/*!
Helper Function that counts overall PEC errors and register/IC PEC errors
@return void
*/
void ADBMS1818_check_pec(uint8_t total_ic, //!< Number of ICs in the system
uint8_t reg, //!< Type of register
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function that resets the PEC error counters
@return void
*/
void ADBMS1818_reset_crc_count(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function to initialize the CFGR data structures
@return void
*/
void ADBMS1818_init_cfg(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function to set appropriate bits in CFGR register based on bit function
@return void
*/
void ADBMS1818_set_cfgr(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon, //!< The REFON bit
bool adcopt, //!< The ADCOPT bit
bool gpio[5], //!< The GPIO bits
bool dcc[12], //!< The DCC bits
bool dcto[4], //!< The Dcto bits
uint16_t uv, //!< The UV value
uint16_t ov //!< The OV value
);
/*!
Helper function to turn the REFON bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgr_refon(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon //!< The REFON bit
);
/*!
Helper function to turn the ADCOPT bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgr_adcopt(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool adcopt //!< The ADCOPT bit
);
/*!
Helper function to turn the GPIO bits HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgr_gpio(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool gpio[] //!< The GPIO bits
);
/*!
Helper function to turn the DCC bits HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgr_dis(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool dcc[] //!< The DCC bits
);
/*!
Helper function to set UV field in CFGRA register
@return void
*/
void ADBMS1818_set_cfgr_uv(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t uv //!< The UV value
);
/*!
Helper function to set DCTO field in CFGRA register
@return void
*/
void ADBMS1818_set_cfgr_dcto(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool dcto[4] //!< The Dcto bits
);
/*!
Helper function to set OV field in CFGRA register
@return void
*/
void ADBMS1818_set_cfgr_ov(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t ov //!< The OV value
);
/*!
Helper Function to initialize the CFGR B data structures
@return void
*/
void ADBMS1818_init_cfgb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function to set appropriate bits in CFGR register based on bit function
@return void
*/
void ADBMS1818_set_cfgrb(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool fdrf, //!< The FDRF bit
bool dtmen, //!< The DTMEN bit
bool ps[2], //!< Path selection bits
bool gpiobits[4], //!< The GPIO bits
bool dccbits[7] //!< The DCC bits
);
/*!
Helper function to turn the FDRF bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgrb_fdrf(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool fdrf //!< The FDRF bit
);
/*!
Helper function to turn the DTMEN bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgrb_dtmen(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool dtmen //!< The DTMEN bit
);
/*!
Helper function to turn the Path Select bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgrb_ps(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool ps[] //!< Path selection bits
);
/*!
Helper function to turn the GPIO bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgrb_gpio_b(uint8_t nIC, //!< The number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool gpiobits[] //!< The GPIO bits
);
/*!
Helper function to turn the DCC bit HIGH or LOW
@return void
*/
void ADBMS1818_set_cfgrb_dcc_b(uint8_t nIC, //!< The number of ICs in The daisy chain
cell_asic *ic, //!< A two dimensional array that will store The data
bool dccbits[] //!< The DCC bits
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,768 @@
/*! General BMS Library
*******************************************************************************
* @file ADBMS181x.h
* @author BMS (bms.support@analog.com)
********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
/*! @file
Library for ADBMS181x Multi-cell Battery Monitor
*/
#ifndef ADBMS181x_h
#define ADBMS181x_h
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "hc32_ddl.h"
#ifndef bool
#define bool uint8_t
#endif
#define IC_ADBMS1818
#define MD_422HZ_1KHZ 0
#define MD_27KHZ_14KHZ 1
#define MD_7KHZ_3KHZ 2
#define MD_26HZ_2KHZ 3
#define ADC_OPT_ENABLED 1
#define ADC_OPT_DISABLED 0
#define CELL_CH_ALL 0
#define CELL_CH_1and7 1
#define CELL_CH_2and8 2
#define CELL_CH_3and9 3
#define CELL_CH_4and10 4
#define CELL_CH_5and11 5
#define CELL_CH_6and12 6
#define SELFTEST_1 1
#define SELFTEST_2 2
#define AUX_CH_ALL 0
#define AUX_CH_GPIO1 1
#define AUX_CH_GPIO2 2
#define AUX_CH_GPIO3 3
#define AUX_CH_GPIO4 4
#define AUX_CH_GPIO5 5
#define AUX_CH_VREF2 6
#define STAT_CH_ALL 0
#define STAT_CH_SOC 1
#define STAT_CH_ITEMP 2
#define STAT_CH_VREGA 3
#define STAT_CH_VREGD 4
#define REG_ALL 0
#define REG_1 1
#define REG_2 2
#define REG_3 3
#define REG_4 4
#define REG_5 5
#define REG_6 6
#define DCP_DISABLED 0
#define DCP_ENABLED 1
#define PULL_UP_CURRENT 1
#define PULL_DOWN_CURRENT 0
#define NUM_RX_BYT 8
#define CELL 1
#define AUX 2
#define STAT 3
#define CFGR 0
#define CFGRB 4
#define CS_PIN_HIGH SPI1_NSS_HIGH
#define CS_PIN_LOW SPI1_NSS_LOW
/*! Cell Voltage data structure. */
typedef struct
{
uint16_t c_codes[18]; //!< Cell Voltage Codes
uint8_t pec_match[6]; //!< If a PEC error was detected during most recent read cmd
} cv;
/*! AUX Reg Voltage Data structure */
typedef struct
{
uint16_t a_codes[12]; //!< Aux Voltage Codes
uint8_t pec_match[4]; //!< If a PEC error was detected during most recent read cmd
} ax;
/*! Status Reg data structure. */
typedef struct
{
uint16_t stat_codes[4]; //!< Status codes.
uint8_t flags[3]; //!< Byte array that contains the uv/ov flag data
uint8_t mux_fail[1]; //!< Mux self test status flag
uint8_t thsd[1]; //!< Thermal shutdown status
uint8_t pec_match[2]; //!< If a PEC error was detected during most recent read cmd
} st;
/*! IC register structure. */
typedef struct
{
uint8_t tx_data[6]; //!< Stores data to be transmitted
uint8_t rx_data[8]; //!< Stores received data
uint8_t rx_pec_match; //!< If a PEC error was detected during most recent read cmd
} ic_register;
/*! PEC error counter structure. */
typedef struct
{
uint16_t pec_count; //!< Overall PEC error count
uint16_t cfgr_pec; //!< Configuration register data PEC error count
uint16_t cell_pec[6]; //!< Cell voltage register data PEC error count
uint16_t aux_pec[4]; //!< Aux register data PEC error count
uint16_t stat_pec[2]; //!< Status register data PEC error count
} pec_counter;
/*! Register configuration structure */
typedef struct
{
uint8_t cell_channels; //!< Number of Cell channels
uint8_t stat_channels; //!< Number of Stat channels
uint8_t aux_channels; //!< Number of Aux channels
uint8_t num_cv_reg; //!< Number of Cell voltage register
uint8_t num_gpio_reg; //!< Number of Aux register
uint8_t num_stat_reg; //!< Number of Status register
} register_cfg;
/*! Cell variable structure */
typedef struct
{
ic_register config;
ic_register configb;
cv cells;
ax aux;
st stat;
ic_register com;
ic_register pwm;
ic_register pwmb;
ic_register sctrl;
ic_register sctrlb;
uint8_t sid[6];
bool isospi_reverse;
pec_counter crc_count;
register_cfg ic_reg;
long system_open_wire;
} cell_asic;
/*!
Wake isoSPI up from IDlE state and enters the READY state
@return void
*/
void wakeup_idle(uint8_t total_ic);//!< Number of ICs in the daisy chain
/*!
Wake the ADBMS181x from the sleep state
@return void
*/
void wakeup_sleep(uint8_t total_ic); //!< Number of ICs in the daisy chain
/*!
Sends a command to the BMS IC. This code will calculate the PEC code for the transmitted command
@return void
*/
void cmd_68(uint8_t tx_cmd[2]); //!< 2 byte array containing the BMS command to be sent
/*!
Writes an array of data to the daisy chain
@return void
*/
void write_68(uint8_t total_ic , //!< Number of ICs in the daisy chain
uint8_t tx_cmd[2], //!< 2 byte array containing the BMS command to be sent
uint8_t data[] //!< Array containing the data to be written to the BMS ICs
);
/*!
Issues a command onto the daisy chain and reads back 6*total_ic data in the rx_data array
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t read_68( uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t tx_cmd[2], //!< 2 byte array containing the BMS command to be sent
uint8_t *rx_data); //!< Array that the read back data will be stored in.
/*!
Calculates and returns the CRC15
@returns The calculated pec15 as an unsigned int
*/
uint16_t pec15_calc(uint8_t len, //!< The length of the data array being passed to the function
uint8_t *data //!< The array of data that the PEC will be generated from
);
/*!
Write the ADBMS181x CFGRA register
This command will write the configuration registers of the ADBMS181xs connected in a daisy chain stack.
The configuration is written in descending order so the last device's configuration is written first.
@return void
*/
void ADBMS181x_wrcfg(uint8_t total_ic, //!< The number of ICs being written to
cell_asic *ic //!< A two dimensional array of the configuration data that will be written
);
/*!
Write the ADBMS181x CFGRB register
This command will write the configuration registers of the ADBMS181xs connected in a daisy chain stack.
The configuration is written in descending order so the last device's configuration is written first.
@return void
*/
void ADBMS181x_wrcfgb(uint8_t total_ic, //!< The number of ICs being written to
cell_asic *ic //!< A two dimensional array of the configuration data that will be written
);
/*!
Reads the ADBMS181x CFGRA register
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS181x_rdcfg(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that the function stores the read configuration data.
);
/*!
Reads the ADBMS181x CFGRB register
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS181x_rdcfgb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that the function stores the read configuration data.
);
/*!
Starts cell voltage conversion
Starts ADC conversions of the ADBMS181x Cpin inputs.
The type of ADC conversion executed can be changed by setting the following parameters:
@return void
*/
void ADBMS181x_adcv(uint8_t MD, //!< ADC conversion Mode
uint8_t DCP, //!< Controls if Discharge is permitted during conversion
uint8_t CH //!< Sets which Cell channels are converted
);
/*!
Start a GPIO and Vref2 Conversion
@return void
*/
void ADBMS181x_adax( uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*!
Start a Status ADC Conversion
@return void
*/
void ADBMS181x_adstat(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHST //!< Sets which Stat channels are converted
);
/*!
Starts cell voltage and GPIO 1&2 conversion
@return void
*/
void ADBMS181x_adcvax( uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*!
Starts cell voltage and SOC conversion
@return void
*/
void ADBMS181x_adcvsc(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*!
Reads and parses the ADBMS181x cell voltage registers.
The function is used to read the cell codes of the ADBMS181x.
This function will send the requested read commands parse the data and store the cell voltages in the cell_asic structure.
@return uint8_t, PEC Status.
0: No PEC error detected
-1: PEC error detected, retry read
*/
uint8_t ADBMS181x_rdcv(uint8_t reg, //!< Controls which cell voltage register is read back.
uint8_t total_ic, //!< The number of ICs in the system
cell_asic *ic //!< Array of the parsed cell codes
);
/*!
Reads and parses the ADBMS181x auxiliary registers.
The function is used to read the parsed GPIO codes of the ADBMS181x.
This function will send the requested read commands parse the data and store the gpio voltages in the cell_asic structure.
@return int8_t, PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t ADBMS181x_rdaux(uint8_t reg, //!< Determines which GPIO voltage register is read back.
uint8_t total_ic,//!< the number of ICs in the system
cell_asic *ic//!< Array of the parsed aux codes
);
/*!
Reads and parses the ADBMS181x stat registers.
The function is used to read the parsed status codes of the ADBMS181x.
This function will send the requested read commands parse the data and store the status voltages in the cell_asic structure
@return int8_t, PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t ADBMS181x_rdstat(uint8_t reg, //!< Determines which Stat register is read back.
uint8_t total_ic,//!< The number of ICs in the system
cell_asic *ic//!< Array of the parsed stat codes
);
/*!
Reads the raw cell voltage register data
@return void
*/
void ADBMS181x_rdcv_reg(uint8_t reg, //!< Determines which cell voltage register is read back
uint8_t total_ic, //!< The number of ICs in the
uint8_t *data //!< An array of the unparsed cell codes
);
/*!
Read the raw data from the ADBMS181x auxiliary register
The function reads a single GPIO voltage register and stores the read data in the *data point as a byte array.
This function is rarely used outside of the ADBMS181x_rdaux() command.
@return void
*/
void ADBMS181x_rdaux_reg( uint8_t reg, //!< Determines which GPIO voltage register is read back
uint8_t total_ic, //!< The number of ICs in the system
uint8_t *data //!< Array of the unparsed auxiliary codes
);
/*!
Read the raw data from the ADBMS181x stat register
The function reads a single Status register and stores the read data in the *data point as a byte array.
This function is rarely used outside of the ADBMS181x_rdstat() command.
@return void
*/
void ADBMS181x_rdstat_reg(uint8_t reg, //!< Determines which stat register is read back
uint8_t total_ic, //!< The number of ICs in the system
uint8_t *data //!< Array of the unparsed stat codes
);
/*!
Helper function that parses voltage measurement registers
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t parse_cells(uint8_t current_ic, //!< Current IC
uint8_t cell_reg, //!< Type of register
uint8_t cell_data[], //!< Unparsed data
uint16_t *cell_codes, //!< Parsed data
uint8_t *ic_pec //!< PEC error
);
/*!
Sends the poll ADC command
@returns uint8_t adc_state 1 byte read back after a pladc command. If the byte is not 0xFF ADC conversion has completed
*/
uint8_t ADBMS181x_pladc(void);
/*!
This function will block operation until the ADC has finished it's conversion
@returns uint32_t counter The approximate time it took for the ADC function to complete.
*/
uint32_t ADBMS181x_pollAdc(void);
/*!
Clears the ADBMS181x Cell voltage registers
The command clears the cell voltage registers and initializes all values to 1.
The register will read back hexadecimal 0xFF after the command is sent.
@return void
*/
void ADBMS181x_clrcell(void);
/*!
Clears the ADBMS181x Auxiliary registers
The command clears the Auxiliary registers and initializes all values to 1.
The register will read back hexadecimal 0xFF after the command is sent.
@return void
*/
void ADBMS181x_clraux(void);
/*!
Clears the ADBMS181x Stat registers
The command clears the Stat registers and initializes all values to 1.
The register will read back hexadecimal 0xFF after the command is sent.
@return void
*/
void ADBMS181x_clrstat(void);
/*!
Starts the Mux Decoder diagnostic self test
Running this command will start the Mux Decoder Diagnostic Self Test
This test takes roughly 1ms to complete. The MUXFAIL bit will be updated,
the bit will be set to 1 for a failure and 0 if the test has been passed.
@return void
*/
void ADBMS181x_diagn(void);
/*!
Starts cell voltage self test conversion
@return void
*/
void ADBMS181x_cvst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*!
Start an Auxiliary Register Self Test Conversion
@return void
*/
void ADBMS181x_axst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*!
Start a Status Register Self Test Conversion
@return void
*/
void ADBMS181x_statst( uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*!
Starts cell voltage overlap conversion
@return void
*/
void ADBMS181x_adol(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Discharge permitted during conversion
);
/*!
Start an GPIO Redundancy test
@return void
*/
void ADBMS181x_adaxd(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*!
Start a Status register redundancy test Conversion
@return void
*/
void ADBMS181x_adstatd(uint8_t MD, //!< ADC Mode
uint8_t CHST //!< Sets which Status channels are converted
);
/*!
Helper function that runs the ADC Self Tests
@return int16_t, error Number of errors detected.
*/
int16_t ADBMS181x_run_cell_adc_st(uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t md, //!< ADC Mode
bool adcopt //!< ADCOPT bit in the configuration register
);
/*!
Self Test Helper Function
@return uint16_t test_pattern returns the register data pattern for a given ADC MD and Self test
*/
uint16_t ADBMS181x_st_lookup( uint8_t MD, //!< ADC Mode
uint8_t ST, //!< Self Test
bool adcopt //!< ADCOPT bit in the configuration register
);
/*!
Helper Function that runs the ADC Overlap test
@return uint16_t, error
0: Pass
-1: False, Error detected
*/
uint16_t ADBMS181x_run_adc_overlap(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function that runs the ADC Digital Redundancy commands and checks output for errors
@return int16_t, error Number of errors detected.
*/
int16_t ADBMS181x_run_adc_redundancy_st(uint8_t adc_mode, //!< ADC Mode
uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Start an open wire Conversion
@return void
*/
void ADBMS181x_adow(uint8_t MD, //!< ADC Conversion Mode
uint8_t PUP, //!< Pull up/Pull down current
uint8_t CH, //!< Channels
uint8_t DCP//!< Discharge Permit
);
/*!
Start GPIOs open wire ADC conversion
@return void
*/
void ADBMS181x_axow(uint8_t MD, //!< ADC Mode
uint8_t PUP //!<Pull up/Pull down current
);
/*!
Helper function that runs the data sheet algorithm for open wire for single cell detection
@return void
*/
void ADBMS181x_run_openwire_single(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function that runs open wire for multiple cell and two consecutive cells detection
@return void
*/
void ADBMS181x_run_openwire_multi(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Runs open wire for GPIOs
@return void
*/
void ADBMS181x_run_gpio_openwire(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function to clear DCC bits in the CFGR Registers
@return void
*/
void ADBMS181x_clear_discharge(uint8_t total_ic,//!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Write the ADBMS181x PWM register
This command will write the pwm registers of the ADBMS181x connected in a daisy chain stack.
The pwm is written in descending order so the last device's pwm is written first.
@return void
*/
void ADBMS181x_wrpwm(uint8_t total_ic, //!< The number of ICs being written to
uint8_t pwmReg, //!< The PWM Register to be written
cell_asic *ic //!< A two dimensional array that will store the data to be written
);
/*!
Reads pwm registers of a ADBMS181x daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS181x_rdpwm(uint8_t total_ic, //!< Number of ICs in the system
uint8_t pwmReg, //!< The PWM Register to be written A or B
cell_asic *ic //!< A two dimensional array that will store the read data
);
/*!
Write the ADBMS181x Sctrl register
@return void
*/
void ADBMS181x_wrsctrl(uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t sctrl_reg, //!< The Sctrl Register to be written A or B
cell_asic *ic //!< A two dimensional array that will store the data to be written
);
/*!
Reads sctrl registers of a ADBMS181x daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS181x_rdsctrl(uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t sctrl_reg, //!< The Sctrl Register to be written A or B
cell_asic *ic //!< A two dimensional array that the function stores the read data
);
/*!
Start Sctrl data communication
This command will start the sctrl pulse communication over the spins
@return void
*/
void ADBMS181x_stsctrl(void);
/*!
Clears the ADBMS181x SCTRL registers
The command clears the SCTRL registers and initializes all values to 0.
The register will read back hexadecimal 0x00 after the command is sent.
@return void
*/
void ADBMS181x_clrsctrl(void);
/*!
Write the ADBMS181x COMM register
This command will write the comm registers of the ADBMS181x connected in a daisy chain stack.
The comm is written in descending order so the last device's configuration is written first.
@return void
*/
void ADBMS181x_wrcomm(uint8_t total_ic, //!< The number of ICs being written to
cell_asic *ic //!< A two dimensional array that will store the data to be written
);
/*!
Reads comm registers of a ADBMS181x daisy chain
@return int8_t, pec_error PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t ADBMS181x_rdcomm(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that the function stores the read data
);
/*!
Issues a stcomm command and clocks data out of the COMM register
@return void
*/
void ADBMS181x_stcomm(uint8_t len //!< Length of data to be transmitted
);
/*!
Helper Function that counts overall PEC errors and register/IC PEC errors
@return void
*/
void ADBMS181x_check_pec(uint8_t total_ic, //!< Number of ICs in the daisy chain
uint8_t reg, //!< Type of register
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function that resets the PEC error counters
@return void
*/
void ADBMS181x_reset_crc_count(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper Function to initialize the CFGR data structures
@return void
*/
void ADBMS181x_init_cfg(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array that will store the data
);
/*!
Helper function to set appropriate bits in CFGR register based on bit function
@return void
*/
void ADBMS181x_set_cfgr(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon, //!< The REFON bit
bool adcopt, //!< The ADCOPT bit
bool gpio[5],//!< The GPIO bits
bool dcc[12],//!< The DCC bits
bool dcto[4],//!< The Dcto bits
uint16_t uv, //!< The UV value
uint16_t ov //!< The OV value
);
/*!
Helper function to turn the REFON bit HIGH or LOW
@return void
*/
void ADBMS181x_set_cfgr_refon(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon //!< The REFON bit
);
/*!
Helper function to turn the ADCOPT bit HIGH or LOW
@return void
*/
void ADBMS181x_set_cfgr_adcopt(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool adcopt //!< The ADCOPT bit
);
/*!
Helper function to turn the GPIO bits HIGH or LOW
@return void
*/
void ADBMS181x_set_cfgr_gpio(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool gpio[] //!< The GPIO bits
);
/*!
Helper function to turn the DCC bits HIGH or LOW
@return void
*/
void ADBMS181x_set_cfgr_dis(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool dcc[] //!< The DCC bits
);
/*!
Helper function to control discharge time value
@return void
*/
void ADBMS181x_set_cfgr_dcto(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
bool dcto[] //!< The Dcto bits
);
/*!
Helper function to set uv field in CFGRA register
@return void
*/
void ADBMS181x_set_cfgr_uv(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t uv //!< The UV value
);
/*!
Helper function to set ov field in CFGRA register
@return void
*/
void ADBMS181x_set_cfgr_ov(uint8_t nIC, //!< Current IC
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t ov //!< The OV value
);
#endif

View File

@@ -0,0 +1,496 @@
/**
******************************************************************************
* @file adc.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of adc control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include <includes.h>
#include "adc.h"
#include "delay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/*
* If you remap the mapping between the channel and the pin with the function
* ADC_ChannelRemap, define ADC_CH_REMAP as non-zero, otherwise define as 0.
*/
#define ADC_CH_REMAP (0u)
/* ADC clock selection definition. */
#define ADC_CLK_PCLK (1u)
#define ADC_CLK_MPLLQ (2u)
#define ADC_CLK_UPLLR (3u)
/* ADC1 channel definition for this example. */
#define ADC1_SA_NORMAL_CHANNEL (ADC1_CH0 | ADC1_CH1 | ADC1_CH2 | ADC1_CH3 | ADC1_CH4 | ADC1_CH5 | ADC1_CH6 | ADC1_CH7)
#define ADC1_SA_CHANNEL (ADC1_SA_NORMAL_CHANNEL)
#define ADC1_SA_CHANNEL_COUNT (8u)
#define ADC1_CHANNEL (ADC1_SA_CHANNEL)
/* ADC1 channel sampling time. ADC1_CH0 ADC1_CH1 ADC1_CH2 ADC1_CH3 ADC1_CH4 ADC1_CH5 ADC1_CH6 ADC1_CH7 */
#define ADC1_SA_CHANNEL_SAMPLE_TIME { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }
/* ADC2 channel definition for this example. */
#define ADC2_SA_NORMAL_CHANNEL (ADC2_CH6 | ADC2_CH7)
#define ADC2_SA_CHANNEL (ADC2_SA_NORMAL_CHANNEL)
#define ADC2_SA_CHANNEL_COUNT (2u)
/* ADC2 channel sampling time. ADC2_CH6(AD_10), ADC2_CH7(AD_11) */
#define ADC2_SA_CHANNEL_SAMPLE_TIME { 0x30, 0x30 }
#define ADC2_CHANNEL (ADC2_SA_CHANNEL)
/* DMA definition for ADC1. */
#define ADC1_SA_DMA_UNIT (M4_DMA1)
#define ADC1_SA_DMA_CH (DmaCh0)
#define ADC1_SA_DMA_PWC (PWC_FCG0_PERIPH_DMA1)
#define ADC1_SA_DMA_TRGSRC (EVT_ADC1_EOCA)
#define ADC1_SA_DMA_IRQ_NUM (INT_DMA1_TC0)
#define ADC1_SA_DMA_INT_CB (Dma1Btc0_IrqHandler)
#define ADC1_DMA_IRQ_NVIC_NUM (Int030_IRQn)
/* DMA definition for ADC2. */
#define ADC2_SA_DMA_UNIT (M4_DMA1)
#define ADC2_SA_DMA_CH (DmaCh2)
#define ADC2_SA_DMA_PWC (PWC_FCG0_PERIPH_DMA1)
#define ADC2_SA_DMA_TRGSRC (EVT_ADC2_EOCA)
#define ADC2_SA_DMA_IRQ_NUM (INT_DMA1_TC2)
#define ADC2_SA_DMA_INT_CB (Dma1Btc2_IrqHandler)
#define ADC2_DMA_IRQ_NVIC_NUM (Int031_IRQn)
#define ADC1_SA_DMA_BUFFER_MAX (1024 / ADC1_SA_CHANNEL_COUNT)
#define ADC2_SA_DMA_BUFFER_MAX (1024 / ADC2_SA_CHANNEL_COUNT)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
// DMA Buffer
uint16_t Adc1DmaSaBuff[ADC1_SA_DMA_BUFFER_MAX][ADC1_SA_CHANNEL_COUNT];
uint16_t Adc2DmaSaBuff[ADC2_SA_DMA_BUFFER_MAX][ADC2_SA_CHANNEL_COUNT];
uint8_t m_u8Adc1DmaIrqFlag = 0u;
uint8_t m_u8Adc2DmaIrqFlag = 0u;
/* Private function prototypes -----------------------------------------------*/
void AdcConfig(void);
void AdcInitConfig(void);
void AdcChannelConfig(void);
void AdcTriggerConfig(void);
void DmaConfig(void);
void DmaIrqConfig(void);
void DmaIrqRegister(stc_irq_regi_conf_t *pstcCfg, uint32_t u32Priority);
void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,
uint32_t u32Channel,
en_pin_mode_t enMode);
/* Private functions ---------------------------------------------------------*/
/**
*******************************************************************************
** \brief ADC configuration, including clock configuration, initial configuration,
** channel configuration and trigger source configuration.
**
** \param None.
**
** \retval None.
**
******************************************************************************/
void AdcConfig(void)
{
// stc_port_init_t stcPortInit;
// /* configuration structure initialization */
// MEM_ZERO_STRUCT(stcPortInit);
// stcPortInit.enPinMode = Pin_Mode_Out;
// stcPortInit.enExInt = Disable;
// stcPortInit.enPullUp = Disable;
// /* Test Port/Pin initialization */
// PORT_Init(PortE, Pin00, &stcPortInit);
AdcInitConfig();
AdcChannelConfig();
AdcTriggerConfig();
memset(Adc1DmaSaBuff, 0xAA, sizeof(Adc1DmaSaBuff));
memset(Adc2DmaSaBuff, 0xBB, sizeof(Adc2DmaSaBuff));
}
/**
*******************************************************************************
** \brief ADC initial configuration.
**
******************************************************************************/
void AdcInitConfig(void)
{
stc_adc_init_t stcAdcInit;
MEM_ZERO_STRUCT(stcAdcInit);
stcAdcInit.enResolution = AdcResolution_12Bit;
stcAdcInit.enDataAlign = AdcDataAlign_Right;
stcAdcInit.enAutoClear = AdcClren_Enable;
stcAdcInit.enScanMode = AdcMode_SAContinuous;
stcAdcInit.enRschsel = AdcRschsel_Restart;
/* 1. Enable ADC1. */
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
/* 2. Initialize ADC1. */
ADC_Init(M4_ADC1, &stcAdcInit);
/* 1. Enable ADC2. */
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC2, Enable);
/* 2. Initialize ADC2. */
ADC_Init(M4_ADC2, &stcAdcInit);
}
/**
*******************************************************************************
** \brief ADC channel configuration.
**
******************************************************************************/
void AdcChannelConfig(void)
{
uint8_t au8Adc1SaSampTime[ADC1_SA_CHANNEL_COUNT] = ADC1_SA_CHANNEL_SAMPLE_TIME;
uint8_t au8Adc2SaSampTime[ADC2_SA_CHANNEL_COUNT] = ADC2_SA_CHANNEL_SAMPLE_TIME;
stc_adc_ch_cfg_t stcChCfg;
MEM_ZERO_STRUCT(stcChCfg);
/**************************** Add ADC1 channels ****************************/
/* 1. Set the ADC pin to analog mode. */
AdcSetChannelPinMode(M4_ADC1, ADC1_CHANNEL, Pin_Mode_Ana);
stcChCfg.u32Channel = ADC1_SA_CHANNEL;
stcChCfg.u8Sequence = ADC_SEQ_A;
stcChCfg.pu8SampTime = au8Adc1SaSampTime;
/* 2. Add ADC channel. */
ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
/**************************** Add ADC2 channels ****************************/
/* 1. Set the ADC pin to analog mode. */
AdcSetChannelPinMode(M4_ADC2, ADC2_CHANNEL, Pin_Mode_Ana);
stcChCfg.u32Channel = ADC2_SA_CHANNEL;
stcChCfg.u8Sequence = ADC_SEQ_A;
stcChCfg.pu8SampTime = au8Adc2SaSampTime;
/* 2. Add ADC channel. */
ADC_AddAdcChannel(M4_ADC2, &stcChCfg);
}
/**
*******************************************************************************
** \brief ADC trigger source configuration.
**
******************************************************************************/
void AdcTriggerConfig(void)
{
stc_adc_trg_cfg_t stcTrgCfg;
MEM_ZERO_STRUCT(stcTrgCfg);
/*
* If select an event(@ref en_event_src_t) to trigger ADC,
* AOS must be enabled first.
*/
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
/* Trigger ADC1 sequence A. */
stcTrgCfg.u8Sequence = ADC_SEQ_A;
stcTrgCfg.enTrgSel = AdcTrgsel_TRGX0;
stcTrgCfg.enInTrg0 = EVT_ADC1_EOCA;
ADC_ConfigTriggerSrc(M4_ADC1, &stcTrgCfg);
// ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Enable);
/* ADC1 sequence A will be started by software. */
ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Disable);
/* Trigger ADC2 sequence A. */
stcTrgCfg.u8Sequence = ADC_SEQ_A;
stcTrgCfg.enTrgSel = AdcTrgsel_TRGX0;
stcTrgCfg.enInTrg0 = EVT_ADC2_EOCA;
ADC_ConfigTriggerSrc(M4_ADC2, &stcTrgCfg);
/* ADC2 sequence A will be started by software. */
ADC_TriggerSrcCmd(M4_ADC2, ADC_SEQ_A, Disable);
}
/**
*******************************************************************************
** \brief DMA configuration for ADC1 and ADC2, including initial configuration
** and interrupt configuration.
**
******************************************************************************/
void DmaConfig(void)
{
DmaInitConfig();
DmaIrqConfig();
}
/**
*******************************************************************************
** \brief DMA initial configuration.
**
******************************************************************************/
void DmaInitConfig(void)
{
stc_dma_config_t stcDmaCfg;
MEM_ZERO_STRUCT(stcDmaCfg);
stcDmaCfg.u16BlockSize = ADC1_SA_CHANNEL_COUNT;
stcDmaCfg.u16TransferCnt = ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT;
stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC1->DR0);
stcDmaCfg.u32DesAddr = (uint32_t)(&Adc1DmaSaBuff[0][0]);
stcDmaCfg.u16DesRptSize = ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT;
stcDmaCfg.u16SrcRptSize = ADC1_SA_CHANNEL_COUNT;
stcDmaCfg.u32DmaLlp = 0u;
stcDmaCfg.stcSrcNseqCfg.u16Cnt = 0u;
stcDmaCfg.stcSrcNseqCfg.u32Offset = 0u;
stcDmaCfg.stcDesNseqCfg.u16Cnt = 0u;
stcDmaCfg.stcDesNseqCfg.u32Offset = 0u;
stcDmaCfg.stcDmaChCfg.enSrcInc = AddressIncrease;
stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease;
stcDmaCfg.stcDmaChCfg.enSrcRptEn = Enable;
stcDmaCfg.stcDmaChCfg.enDesRptEn = Enable;
stcDmaCfg.stcDmaChCfg.enSrcNseqEn = Disable;
stcDmaCfg.stcDmaChCfg.enDesNseqEn = Disable;
stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma16Bit;
stcDmaCfg.stcDmaChCfg.enLlpEn = Disable;
/* Enable DMA interrupt. */
stcDmaCfg.stcDmaChCfg.enIntEn = Enable;
PWC_Fcg0PeriphClockCmd(ADC1_SA_DMA_PWC, Enable);
DMA_InitChannel(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, &stcDmaCfg);
DMA_Cmd(ADC1_SA_DMA_UNIT, Enable);
DMA_ChannelCmd(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, Enable);
DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, TrnCpltIrq);
/* AOS must be enabled to use DMA */
/* AOS enabled at first. */
/* If you have enabled AOS before, then the following statement is not needed. */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
DMA_SetTriggerSrc(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_DMA_TRGSRC);
// DMA ADC2 SA
stcDmaCfg.u16BlockSize = ADC2_SA_CHANNEL_COUNT;
stcDmaCfg.u16TransferCnt = ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT; //
stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC2->DR6);
stcDmaCfg.u32DesAddr = (uint32_t)(&Adc2DmaSaBuff[0][0]);
stcDmaCfg.u16DesRptSize = ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT;
stcDmaCfg.u16SrcRptSize = ADC2_SA_CHANNEL_COUNT;
PWC_Fcg0PeriphClockCmd(ADC2_SA_DMA_PWC, Enable);
DMA_InitChannel(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, &stcDmaCfg);
DMA_Cmd(ADC2_SA_DMA_UNIT, Enable);
DMA_ChannelCmd(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, Enable);
DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, TrnCpltIrq);
DMA_SetTriggerSrc(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_DMA_TRGSRC);
}
/**
*******************************************************************************
** \brief DMA initial configuration.
**
******************************************************************************/
void DmaReloadConfig(uint8_t nAdc)
{
if (nAdc == 0) {
DMA_SetBlockSize(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_CHANNEL_COUNT);
DMA_SetTransferCnt(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_DMA_BUFFER_MAX * ADC1_SA_CHANNEL_COUNT);
DMA_Cmd(ADC1_SA_DMA_UNIT, Enable);
DMA_ChannelCmd(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, Enable);
} else {
DMA_SetBlockSize(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_CHANNEL_COUNT);
DMA_SetTransferCnt(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, ADC2_SA_DMA_BUFFER_MAX * ADC2_SA_CHANNEL_COUNT);
DMA_Cmd(ADC2_SA_DMA_UNIT, Enable);
DMA_ChannelCmd(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, Enable);
}
}
/**
*******************************************************************************
** \brief DMA interrupt configuration.
**
** \note DMA NVIC number: [Int030_IRQn, Int031_IRQn]
**
******************************************************************************/
void DmaIrqConfig(void)
{
stc_irq_regi_conf_t stcAdcIrqCfg;
stcAdcIrqCfg.enIntSrc = ADC1_SA_DMA_IRQ_NUM;
stcAdcIrqCfg.enIRQn = ADC1_DMA_IRQ_NVIC_NUM;
stcAdcIrqCfg.pfnCallback = &ADC1_SA_DMA_INT_CB;
DmaIrqRegister(&stcAdcIrqCfg, DDL_IRQ_PRIORITY_DEFAULT);
stcAdcIrqCfg.enIntSrc = ADC2_SA_DMA_IRQ_NUM;
stcAdcIrqCfg.enIRQn = ADC2_DMA_IRQ_NVIC_NUM;
stcAdcIrqCfg.pfnCallback = &ADC2_SA_DMA_INT_CB;
DmaIrqRegister(&stcAdcIrqCfg, DDL_IRQ_PRIORITY_DEFAULT);
}
/**
*******************************************************************************
** \brief DMA IRQ register function.
**
******************************************************************************/
void DmaIrqRegister(stc_irq_regi_conf_t *pstcCfg, uint32_t u32Priority)
{
int16_t s16Vnum = pstcCfg->enIRQn;
if ((s16Vnum == ADC1_DMA_IRQ_NVIC_NUM) || (s16Vnum == ADC2_DMA_IRQ_NVIC_NUM)) {
if (Ok != enIrqRegistration(pstcCfg)) return;
} else {
return;
}
NVIC_ClearPendingIRQ(pstcCfg->enIRQn);
NVIC_SetPriority(pstcCfg->enIRQn, u32Priority);
NVIC_EnableIRQ(pstcCfg->enIRQn);
}
/**
*******************************************************************************
** \brief Config the pin which is mapping the channel to analog or digit mode.
**
******************************************************************************/
void AdcSetChannelPinMode(const M4_ADC_TypeDef *ADCx,
uint32_t u32Channel,
en_pin_mode_t enMode)
{
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = enMode;
stcPortInit.enPullUp = Disable;
if (M4_ADC1 == ADCx) {
PORT_Init(PortA, Pin00, &stcPortInit);
PORT_Init(PortA, Pin01, &stcPortInit);
PORT_Init(PortA, Pin02, &stcPortInit);
PORT_Init(PortA, Pin03, &stcPortInit);
PORT_Init(PortA, Pin04, &stcPortInit);
PORT_Init(PortA, Pin05, &stcPortInit);
PORT_Init(PortA, Pin06, &stcPortInit);
PORT_Init(PortA, Pin07, &stcPortInit);
} else if (M4_ADC2 == ADCx) {
PORT_Init(PortC, Pin00, &stcPortInit);
PORT_Init(PortC, Pin01, &stcPortInit);
}
}
/**
*******************************************************************************
** \brief DMA IRQ callbacks.
**
******************************************************************************/
void Dma1Btc0_IrqHandler(void)
{
DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, BlkTrnCpltIrq);
DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, TrnCpltIrq);
m_u8Adc1DmaIrqFlag = true;
// PORT_ResetBits(PortE, Pin00);
NVIC_ClearPendingIRQ(ADC1_DMA_IRQ_NVIC_NUM);
}
void Dma1Btc2_IrqHandler(void)
{
DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, BlkTrnCpltIrq);
DMA_ClearIrqFlag(ADC2_SA_DMA_UNIT, ADC2_SA_DMA_CH, TrnCpltIrq);
m_u8Adc2DmaIrqFlag = true;
// PORT_ResetBits(PortE, Pin00);
NVIC_ClearPendingIRQ(ADC2_DMA_IRQ_NVIC_NUM);
}
uint8_t GetAdcIrgFlag(uint8_t nAdc)
{
uint8_t result = false;
if (nAdc == 0) {
result = m_u8Adc1DmaIrqFlag;
m_u8Adc1DmaIrqFlag = false;
} else {
result = m_u8Adc2DmaIrqFlag;
m_u8Adc2DmaIrqFlag = false;
}
return result;
}
uint16_t AvgAdc1DmaValue(uint16_t ch)
{
uint32_t sum = 0;
for (int i = 0; i < ADC1_SA_DMA_BUFFER_MAX; i++)
sum += Adc1DmaSaBuff[i][ch];
return (uint16_t)(sum / ADC1_SA_DMA_BUFFER_MAX);
}
//VI(Voltage and Current) port Initialize
void ADC_Port_Init(void)
{
/* Config ADCs. */
AdcConfig();
/* Config DMA. */
DmaConfig();
}
uint16_t AvgAdc2DmaValue(uint16_t ch)
{
__IO uint32_t sum = 0;
for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) {
sum += Adc2DmaSaBuff[i][ch];
}
return (uint32_t)(sum / ADC2_SA_DMA_BUFFER_MAX);
}
uint32_t CheckAdc2DmaValue(uint16_t ch)
{
__IO uint32_t sum = 0;
for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) {
if (sum < Adc2DmaSaBuff[i][ch])
sum = Adc2DmaSaBuff[i][ch];
}
return sum;
}
#ifdef CONSOLE_DEBUG
void DisplayAdc2DmaBufferValue(uint8_t ch)
{
for (int i = 0; i < ADC2_SA_DMA_BUFFER_MAX; i++) {
printf("(%3d), %04X\r\n", i, Adc2DmaSaBuff[i][ch]);
delay_os_ms(1);
}
}
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,58 @@
/**
******************************************************************************
* @file adc.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of adc control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _ADC_H
#define _ADC_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
#define ADC_VBASE 3300 // 3.3V
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void DmaInitConfig(void);
void DmaReloadConfig(uint8_t nAdc);
void ADC_Port_Init(void);
uint8_t GetAdcIrgFlag(uint8_t nAdc);
/****** ADC1 for Temperature **************************************************/
uint16_t AvgAdc1DmaValue(uint16_t ch);
uint16_t GetAdc1DmaBufferValue(uint16_t ch, uint16_t no);
void DisplayAdc1DmaBufferValue(void);
/****** ADC2 for VI ***********************************************************/
uint16_t AvgAdc2DmaValue(uint16_t ch);
uint16_t GetAdc2DmaBufferValue(uint16_t ch, uint16_t no);
void DisplayAdc2DmaBufferValue(uint8_t ch);
uint32_t CheckAdc2DmaValue(uint16_t ch);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,62 @@
/**
******************************************************************************
* @file buck.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of buck control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "buck.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Buck on/off Port/Pin definition */
#define BUCK_ONOFF_PORT (PortA)
#define BUCK_ONOFF_PIN (Pin11)
// Relay port definitions
#define BUCK_ON PORT_ResetBits(BUCK_ONOFF_PORT, BUCK_ONOFF_PIN);
#define BUCK_OFF PORT_SetBits(BUCK_ONOFF_PORT, BUCK_ONOFF_PIN);
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
// Relay IO Initialize
void Buck_ctrl_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enPinOType = Pin_OType_Od;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* Relay Control Port/Pin initialization */
PORT_Init(BUCK_ONOFF_PORT, BUCK_ONOFF_PIN, &stcPortInit);
BUCK_ON;
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,39 @@
/**
******************************************************************************
* @file buck.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of buck control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _BUCK_H
#define _BUCK_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void Buck_ctrl_Init(void); // Initialize
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,65 @@
/**
******************************************************************************
* @file buzzer.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of buzzer control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "buzzer.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Define port and pin for device address */
#define BUZZER_PORT (PortE)
#define BUZZER_PIN (Pin02)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//Relay IO Initialize
void Buzzer_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* LED Port/Pin initialization */
PORT_Init(BUZZER_PORT, BUZZER_PIN, &stcPortInit);
PORT_ResetBits(BUZZER_PORT, BUZZER_PIN);
}
void Buzzer(uint8_t onoff)
{
if (onoff) PORT_SetBits(BUZZER_PORT, BUZZER_PIN);
else PORT_ResetBits(BUZZER_PORT, BUZZER_PIN);
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* @file buzzer.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of buzzer control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _BUZZER_H
#define _BUZZER_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void Buzzer_Init(void); //Initialize
void Buzzer(uint8_t onoff);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,239 @@
/**
******************************************************************************
* @file can.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of CAN communication functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "can.h"
#include "string.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* CAN channel definition */
/* CAN baudrate definition */
#define CAN_BAUDRATE (250000ul)
/* CAN RX Port/Pin definition */
#define CAN_RX_PORT (PortE)
#define CAN_RX_PIN (Pin01)
#define CAN_RX_FUNC (Func_Can1_Rx)
/* CAN TX Port/Pin definition */
#define CAN_TX_PORT (PortE)
#define CAN_TX_PIN (Pin00)
#define CAN_TX_FUNC (Func_Can1_Tx)
#define TX_BUFFER_SIZE 10
#define RX_BUFFER_SIZE 320
/* Private macro -------------------------------------------------------------*/
typedef struct {
volatile uint16_t RxInPos, RxOutPos;
volatile uint32_t RxOverflowCount;
uint16_t TxInPos, TxOutPos;
stc_can_rxframe_t RxBuf[RX_BUFFER_SIZE];
stc_can_txframe_t TxBuf[TX_BUFFER_SIZE];
} CAN_Info;
/* Private variables ---------------------------------------------------------*/
CAN_Info Can;
/* Private function prototypes -----------------------------------------------*/
void CAN_RxIrqCallBack(void);
/* Private functions ---------------------------------------------------------*/
// Initializes CAN Port
void can_init(uint32_t CAN_Baud_Rate)
{
stc_can_init_config_t stcCanInitCfg;
stc_can_filter_t stcFilter;
stc_irq_regi_conf_t stcIrqRegiConf;
stc_port_init_t stcPortInit;
MEM_ZERO_STRUCT(stcCanInitCfg);
MEM_ZERO_STRUCT(stcFilter);
MEM_ZERO_STRUCT(stcIrqRegiConf);
MEM_ZERO_STRUCT(stcPortInit);
MEM_ZERO_STRUCT(Can);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Enable;
/* SPI Port/Pin initialization */
PORT_Init(CAN_TX_PORT, CAN_TX_PIN, &stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
PORT_Init(CAN_RX_PORT, CAN_RX_PIN, &stcPortInit);
// PORT_Init(PortB, Pin03, &stcPortInit);
PORT_Init(PortB, Pin04, &stcPortInit);
//<<Enable can peripheral clock and buffer(ram)
PWC_RamOpMdConfig(HighSpeedMd);
PWC_RamPwrdownCmd(PWC_RAMPWRDOWN_CAN, Enable);
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_CAN, Enable);
//<<CAN GPIO config
PORT_SetFunc(CAN_RX_PORT, CAN_RX_PIN, CAN_RX_FUNC, Disable);
PORT_SetFunc(CAN_TX_PORT, CAN_TX_PIN, CAN_TX_FUNC, Disable);
//<<Can bit time config
// stcCanInitCfg.stcCanBt.PRESC = 4u-1u;//???,??????????
switch(CAN_Baud_Rate) {
case 1000: // 1000K
stcCanInitCfg.stcCanBt.PRESC = 2u-1u;
break;
case 500: // 500K
stcCanInitCfg.stcCanBt.PRESC = 4u-1u;
break;
case 250: // 125K
stcCanInitCfg.stcCanBt.PRESC = 8u-1u;
break;
case 125: // 100K
stcCanInitCfg.stcCanBt.PRESC = 16u-1u;
break;
default:
stcCanInitCfg.stcCanBt.PRESC = 2u-1u;
break;
}
// stcCanInitCfg.stcCanBt.PRESC = 1u-1u;
stcCanInitCfg.stcCanBt.SEG_1 = 5u-2u;
stcCanInitCfg.stcCanBt.SEG_2 = 3u-1u;
stcCanInitCfg.stcCanBt.SJW = 3u-1u;
stcCanInitCfg.stcWarningLimit.CanErrorWarningLimitVal = 10u;
stcCanInitCfg.stcWarningLimit.CanWarningLimitVal = 16u-1u;
stcCanInitCfg.enCanRxBufAll = CanRxNormal;
stcCanInitCfg.enCanRxBufMode = CanRxBufNotStored;
stcCanInitCfg.enCanSAck = CanSelfAckDisable; //CanSelfAckEnable;
stcCanInitCfg.enCanSTBMode = CanSTBFifoMode;
CAN_Init(&stcCanInitCfg);
//<<Can filter config
stcFilter.enAcfFormat = CanAllFrames;
stcFilter.enFilterSel = CanFilterSel1;
stcFilter.u32CODE = 0x00000000u;
stcFilter.u32MASK = 0x1FFFFFFFu;
CAN_FilterConfig(&stcFilter, Enable);
//<<Can Irq Enable
CAN_IrqCmd(CanRxIrqEn, Enable);
CAN_IrqCmd(CanTxPrimaryIrqEn, Enable);
stcIrqRegiConf.enIRQn = Int005_IRQn;
stcIrqRegiConf.enIntSrc = INT_CAN_INT;
stcIrqRegiConf.pfnCallback = &CAN_RxIrqCallBack;
enIrqRegistration(&stcIrqRegiConf);
NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}
void CAN_RxIrqCallBack(void)
{
if (true == CAN_IrqFlgGet(CanRxIrqFlg)) {
CAN_IrqFlgClr(CanRxIrqFlg);
stc_can_rxframe_t received;
uint16_t next = (uint16_t)((Can.RxInPos + 1U) % RX_BUFFER_SIZE);
/* Always drain the hardware receive slot, even when the software queue is full. */
CAN_Receive(&received);
if (next == Can.RxOutPos) {
Can.RxOverflowCount++;
} else {
memcpy(&Can.RxBuf[Can.RxInPos], &received, sizeof(received));
__DMB();
Can.RxInPos = next;
}
// CAN_IrqCmd(CanRxIrqEn, Disable);
}
if (true == CAN_IrqFlgGet(CanTxPrimaryIrqFlg)) {
CAN_IrqFlgClr(CanTxPrimaryIrqFlg);
// CAN_IrqCmd(CanRxIrqEn, Enable);
}
if (true == CAN_IrqFlgGet(CanBusErrorIrqFlg)) {
CAN_IrqFlgClr(CanBusErrorIrqFlg);
}
if (true == CAN_IrqFlgGet(CanArbiLostIrqFlg)) {
CAN_IrqFlgClr(CanArbiLostIrqFlg);
}
NVIC_ClearPendingIRQ(Int005_IRQn);
}
/*******************************************************************************
* Function Name : uint8_t CAN_GetPacket(CanRxMsg *packet)
* Description : Send 1 packet data to CAN Port transmit buffer
* Parameters : none
* Return : Transmission result (0: buffer empty, 1: buffer has data)
*******************************************************************************/
uint8_t CAN_GetPacket(stc_can_rxframe_t *packet)
{
if (Can.RxInPos != Can.RxOutPos) {
memcpy(packet, &Can.RxBuf[Can.RxOutPos], sizeof(stc_can_rxframe_t));
__DMB();
Can.RxOutPos = (uint16_t)((Can.RxOutPos + 1U) % RX_BUFFER_SIZE);
return 1;
}
else
return 0;
}
void CAN_SendPacket(stc_can_txframe_t *packet)
{
uint32_t timeout = 50000;
while ((M4_CAN->TCMD_f.TPE != 0) && (--timeout > 0)) {
__NOP();
}
if (timeout == 0) {
M4_CAN->TCMD |= CanPTBTxAbortCmd;
}
CAN_SetFrame(packet);
en_can_tx_buf_status_t txSts = CAN_TransmitCmd(CanPTBTxCmd);
switch (txSts) {
case CanTxBufEmpty: // = 0, ///< TTEN=0 or TTTBM=0: STB is empty
// printf("CanTxBufEmpty \r\n");
break; ///< TTEN=1 and TTTBM=1: PTB and STB are empty
case CanTxBufnotHalfFull: // = 1, ///< TTEN=0 or TTTBM=0: STB is less than or equal to half full
// printf("CanTxBufnotHalfFull \r\n");
break; ///< TTEN=1 and TTTBM=1: PTB and STB are not empty and not full
case CanTxBufHalfFull: // = 2, ///< TTEN=0 or TTTBM=0: STB is more than half full
// printf("CanTxBufHalfFull \r\n");
break; ///< TTEN=1 and TTTBM=1: None
case CanTxBufFull: // = 3, ///< TTEN=0 or TTTBM=0: STB is full
// printf("CanTxBufFull \r\n");
break;
}
// CAN_IrqCmd(CanRxIrqEn, Enable);
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,39 @@
/**
******************************************************************************
* @file can.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the CAN communication functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __CAN_H
#define __CAN_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void can_init(uint32_t CAN_Baud_Rate);
uint8_t CAN_GetPacket(stc_can_rxframe_t *packet);
void CAN_SendPacket(stc_can_txframe_t *packet);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,126 @@
/**
******************************************************************************
* @file delay.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the code of the delay functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "delay.h"
#include "includes.h" //ucos use
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SYS_CLOCK 200
#define SYSTICK_LOAD 200000
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private prototype functions -----------------------------------------------*/
// OS is called the delay function delay
// ticks:Delay number of beats
void delay_ostimedly(uint32_t ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks,OS_OPT_TIME_PERIODIC, &err);//UCOSIII delay adoption cycle mode
#else
OSTimeDly(ticks); //UCOSII delay
#endif
}
void delay_us1(uint32_t us)
{
uint32_t udelay = us * 10;
for (int i = 0; i < udelay; i++)
{
i = i;
}
}
void delay_us(uint32_t us)
{
uint32_t usec = us * SYS_CLOCK;
uint32_t temp = CPU_REG_NVIC_ST_CURRENT;
uint32_t comp = temp + usec;
if (temp < usec)
{
comp = SYSTICK_LOAD - (usec - temp); // 200 - 100 = 100, 200000 - 100 = 199900, 200000 + 100
while ((comp < temp) || (temp < usec))
{
temp = CPU_REG_NVIC_ST_CURRENT;
}
}
else
{
comp = temp - usec;
while (comp < temp)
{
temp = CPU_REG_NVIC_ST_CURRENT;
}
}
}
void delay_ns1(uint32_t ns)
{
uint32_t nsec = ns / 1;
uint32_t temp = CPU_REG_NVIC_ST_CURRENT;
uint32_t comp = temp + nsec;
if (temp < nsec)
{
comp = SYSTICK_LOAD - (nsec - temp); // 200 - 100 = 100, 200000 - 100 = 199900, 200000 + 100
while ((comp < temp) || (temp < nsec))
{
temp = CPU_REG_NVIC_ST_CURRENT;
}
}
else
{
comp = temp - nsec;
while (comp < temp)
{
temp = CPU_REG_NVIC_ST_CURRENT;
}
}
}
void delay_ns(uint32_t ns)
{
for (uint32_t i = 0; i < ns; i++)
{
__NOP();
}
}
void delay_os_ms(uint32_t ms)
{
OS_ERR err;
OSTimeDlyHMSM(0, 0, (ms / 1000), (ms % 1000),
OS_OPT_TIME_HMSM_STRICT,
&err);
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,71 @@
/**
******************************************************************************
* @file delay.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the delay functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DELAY_H
#define __DELAY_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void delay_init(uint32_t SYSCLK);
void delay_ms(uint32_t nms);
void delay_us(uint32_t us);
void delay_ns(uint32_t ns);
void delay_os_ms(uint32_t ms);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,86 @@
/**
******************************************************************************
* @file dev_addr.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of device address functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "dev_addr.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Define port and pin for device address */
#define DEV_ADDR_0_PORT (PortB)
#define DEV_ADDR_0_PIN (Pin10)
#define DEV_ADDR_1_PORT (PortE)
#define DEV_ADDR_1_PIN (Pin15)
#define DEV_ADDR_2_PORT (PortE)
#define DEV_ADDR_2_PIN (Pin14)
#define DEV_ADDR_3_PORT (PortE)
#define DEV_ADDR_3_PIN (Pin13)
//#define DEV_ADDR_4_PORT (PortE)
//#define DEV_ADDR_4_PIN (Pin01)
//#define DEV_ADDR_5_PORT (PortE)
//#define DEV_ADDR_5_PIN (Pin01)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//Relay IO Initialize
void DevAddrInit(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Enable;
/* LED Port/Pin initialization */
PORT_Init(DEV_ADDR_0_PORT, DEV_ADDR_0_PIN, &stcPortInit);
PORT_Init(DEV_ADDR_1_PORT, DEV_ADDR_1_PIN, &stcPortInit);
PORT_Init(DEV_ADDR_2_PORT, DEV_ADDR_2_PIN, &stcPortInit);
PORT_Init(DEV_ADDR_3_PORT, DEV_ADDR_3_PIN, &stcPortInit);
}
uint8_t GetDevAddr(void)
{
uint8_t result = 0;
result |= (!PORT_GetBit(DEV_ADDR_0_PORT, DEV_ADDR_0_PIN) << 3);
result |= (!PORT_GetBit(DEV_ADDR_1_PORT, DEV_ADDR_1_PIN) << 2);
result |= (!PORT_GetBit(DEV_ADDR_2_PORT, DEV_ADDR_2_PIN) << 1);
result |= (!PORT_GetBit(DEV_ADDR_3_PORT, DEV_ADDR_3_PIN) << 0);
return result;
}

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* @file dev_addr.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of device address functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _DEV_ADDR_H
#define _DEV_ADDR_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
//Relay port definitions
void DevAddrInit(void); // Initialize
void DevAddrDeInit(void); // DeInitialize
uint8_t GetDevAddr(void);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,253 @@
/**
******************************************************************************
* @file flash_if.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the flash memory functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "flash_if.h"
#include "stdio.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
FW_INFO fwinfo;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief Unlocks Flash for write access
* @param None
* @retval None
*/
void FLASH_If_Init(void)
{
/* Unlock EFM. */
EFM_Unlock();
/* Enable flash. */
EFM_FlashCmd(Enable);
}
/**
* @brief This function does an erase of all user flash area
* @param StartSector: start of user flash area
* @retval 0: user flash area successfully erased
* 1: error occurred
*/
uint32_t FLASH_If_Erase(uint32_t StartSector, uint32_t uSize)
{
uint32_t UserStartSector, UserEndSector, i = 0;
/* Unlock EFM. */
EFM_Unlock();
/* Enable flash. */
EFM_FlashCmd(Enable);
/* Wait flash ready. */
while(Set != EFM_GetFlagStatus(EFM_FLAG_RDY))
{
;
}
/* Get the sector where start the user flash area */
UserStartSector = StartSector;
UserEndSector = (StartSector + uSize);
for(i = UserStartSector; i <= UserEndSector; i += SECTOR_SIZE)
{
/* Reload IWDG counter */
WDT_RefreshCounter();
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
if (EFM_SectorErase(i) != Ok)
{
/* Error occurred while page erase */
return (1);
}
}
/* Lock EFM. */
EFM_Lock();
return (0);
}
/**
* @brief This function does an erase of all user flash area
* @param StartSector: start of user flash area
* @retval 0: user flash area successfully erased
* 1: error occurred
*/
uint32_t FLASH_If_SingleSectorErase(uint32_t SectorAddr)
{
uint32_t result = 0;
/* Unlock EFM. */
EFM_Unlock();
/* Enable flash. */
EFM_FlashCmd(Enable);
/* Wait flash ready. */
while(Set != EFM_GetFlagStatus(EFM_FLAG_RDY))
{
;
}
/* Reload IWDG counter */
WDT_RefreshCounter();
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
if (EFM_SectorErase(SectorAddr) != Ok)
{
/* Error occurred while page erase */
result = (1);
}
/* Lock EFM. */
EFM_Lock();
return result;
}
/**
* @brief This function writes a data buffer in flash (data are 32-bit aligned).
* @note After writing data buffer, the flash content is checked.
* @param FlashAddress: start address for writing data buffer
* @param Data: pointer on data buffer
* @param DataLength: length of data buffer (unit is 32-bit word)
* @retval 0: Data successfully written to Flash memory
* 1: Error occurred while writing data in Flash memory
* 2: Written Data in flash memory is different from expected one
*/
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength)
{
uint32_t i = 0;
uint32_t result = 0;
/* Unlock EFM. */
EFM_Unlock();
/* Enable flash. */
EFM_FlashCmd(Enable);
/* Wait flash ready. */
while(Set != EFM_GetFlagStatus(EFM_FLAG_RDY))
{
;
}
for (i = 0; (i < DataLength) && (*FlashAddress <= (mBMS_FW_DN_END_ADDRESS - 4)); i++)
{
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
if (EFM_SingleProgram(*FlashAddress, *(uint32_t *)(Data + i)) == Ok)
{
/* Check the written value */
if (*(uint32_t*)*FlashAddress != *(uint32_t *)(Data + i))
{
/* Flash content doesn't match SRAM content */
result = 2;
break;
}
/* Increment FLASH destination address */
*FlashAddress += 4;
}
else
{
/* Error occurred while writing data in Flash memory */
result = 1;
break;
}
}
/* Lock EFM. */
EFM_Lock();
return result;
}
///**
// * @brief Returns the write protection status of user flash area.
// * @param None
// * @retval 0: No write protected sectors inside the user flash area
// * 1: Some sectors inside the user flash area are write protected
// */
//uint16_t FLASH_If_GetWriteProtectionStatus(void)
//{
// uint32_t UserStartSector = FLASH_Sector_1;
// /* Get the sector where start the user flash area */
// UserStartSector = GetSector(APPLICATION_ADDRESS);
// /* Check if there are write protected sectors inside the user flash area */
// if ((FLASH_OB_GetWRP() >> (UserStartSector/8)) == (0xFFF >> (UserStartSector/8)))
// { /* No write protected sectors inside the user flash area */
// return 1;
// }
// else
// { /* Some sectors inside the user flash area are write protected */
// return 0;
// }
//}
///**
// * @brief Disables the write protection of user flash area.
// * @param None
// * @retval 1: Write Protection successfully disabled
// * 2: Error: Flash write unprotection failed
// */
//uint32_t FLASH_If_DisableWriteProtection(void)
//{
// __IO uint32_t UserStartSector = FLASH_Sector_1, UserWrpSectors = OB_WRP_Sector_1;
// /* Get the sector where start the user flash area */
// UserStartSector = GetSector(APPLICATION_ADDRESS);
// /* Mark all sectors inside the user flash area as non protected */
// UserWrpSectors = 0xFFF-((1 << (UserStartSector/8))-1);
//
// /* Unlock the Option Bytes */
// FLASH_OB_Unlock();
// /* Disable the write protection for all sectors inside the user flash area */
// FLASH_OB_WRPConfig(UserWrpSectors, DISABLE);
// /* Start the Option Bytes programming process. */
// if (FLASH_OB_Launch() != FLASH_COMPLETE)
// {
// /* Error: Flash write unprotection failed */
// return (2);
// }
// /* Write Protection successfully disabled */
// return (1);
//}
/**
* @}
*/
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,103 @@
/**
******************************************************************************
* @file flash_if.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the flash memory functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __FLASH_IF_H
#define __FLASH_IF_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
typedef struct
{
uint32_t AppFileSize;
uint8_t BootVer[4];
uint8_t AppVer[4];
uint8_t FileName[30];
uint8_t BootUpdate;
uint8_t AppUpdate;
} FW_INFO;
/* Exported constants --------------------------------------------------------*/
/* Base address of the Flash sectors */
#define SECTOR_SIZE 8192 // 0X2000
#define ADDR_FLASH_SECTOR_00 ((uint32_t)0x00000000) /* Base @ of Sector 0, 8 Kbyte */
#define ADDR_FLASH_SECTOR_01 ((uint32_t)0x00002000) /* Base @ of Sector 1, 8 Kbyte */
#define ADDR_FLASH_SECTOR_02 ((uint32_t)0x00004000) /* Base @ of Sector 2, 8 Kbyte */
#define ADDR_FLASH_SECTOR_03 ((uint32_t)0x00006000) /* Base @ of Sector 3, 8 Kbyte */
#define ADDR_FLASH_SECTOR_04 ((uint32_t)0x00008000) /* Base @ of Sector 4, 8 Kbyte */
#define ADDR_FLASH_SECTOR_05 ((uint32_t)0x0000A000) /* Base @ of Sector 5, 8 Kbyte */
#define ADDR_FLASH_SECTOR_06 ((uint32_t)0x0000C000) /* Base @ of Sector 6, 8 Kbyte */
#define ADDR_FLASH_SECTOR_07 ((uint32_t)0x0000E000) /* Base @ of Sector 7, 8 Kbyte */
#define ADDR_FLASH_SECTOR_08 ((uint32_t)0x00010000) /* Base @ of Sector 8, 8 Kbyte */
#define ADDR_FLASH_SECTOR_09 ((uint32_t)0x00012000) /* Base @ of Sector 9, 8 Kbyte */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x00014000) /* Base @ of Sector 10, 8 Kbyte */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x00016000) /* Base @ of Sector 11, 8 Kbyte */
#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x00018000) /* Base @ of Sector 12, 8 Kbyte */
#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x0001A000) /* Base @ of Sector 13, 8 Kbyte */
#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x0001C000) /* Base @ of Sector 14, 8 Kbyte */
#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0001E000) /* Base @ of Sector 15, 8 Kbyte */
#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x00020000) /* Base @ of Sector 16, 8 Kbyte */
#define ADDR_FLASH_SECTOR_32 ((uint32_t)0x00040000) /* Base @ of Sector 32, 8 Kbyte */
#define ADDR_FLASH_SECTOR_48 ((uint32_t)0x00060000) /* Base @ of Sector 1, 16 Kbyte */
/* Define the address from where user application will be loaded.
Note: the 1st sector 0x00000000-0x00020000 is reserved for the IAP code */
#define mBMS_FW_RN_ADDRESS ADDR_FLASH_SECTOR_16
#define mBMS_FW_DN_ADDRESS ADDR_FLASH_SECTOR_48
/* End of the Flash address */
#define mBMS_FW_DN_END_ADDRESS ((uint32_t)0x00080000)
/* Define the user application size */
#define mBMS_FW_FLASH_SIZE (mBMS_FW_DN_END_ADDRESS - mBMS_FW_DN_ADDRESS)
#define mBMS_FW_PACKET_SIZE 0x800 // 2048
#define mBMS_SOC_BASE_ADDR ADDR_FLASH_SECTOR_11
#define mBMS_PARAM_BASE_ADDR ADDR_FLASH_SECTOR_12
#define mBMS_INV_BASE_ADDR ADDR_FLASH_SECTOR_13
#define mBMS_CALIB_BASE_ADDR ADDR_FLASH_SECTOR_14
#define mBMS_FW_INFO_BASE_ADDR ADDR_FLASH_SECTOR_15
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector, uint32_t uSize);
uint32_t FLASH_If_SingleSectorErase(uint32_t SectorAddr);
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength);
uint16_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_DisableWriteProtection(void);
extern FW_INFO fwinfo;
#endif /* __FLASH_IF_H */
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,217 @@
/**
******************************************************************************
* @file i2c.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of i2c functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "i2c.h"
#include "delay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Define I2C unit used for the example */
#define I2C_UNIT (M4_I2C1)
/* Define BQ Series device address */
#define BQ_ADDRESS (0x50u)
#define BQ_ADR_LEN (1u)
/* Define port and pin for SDA and SCL */
#define I2C_SCL_PORT (PortD)
#define I2C_SCL_PIN (Pin01)
#define I2C_SDA_PORT (PortD)
#define I2C_SDA_PIN (Pin00)
#define I2C_GPIO_SCL_FUNC (Func_I2c1_Scl)
#define I2C_GPIO_SDA_FUNC (Func_I2c1_Sda)
#define I2C_FCG_USE (PWC_FCG1_PERIPH_I2C1)
#define TIMEOUT (0x40000ul)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
******************************************************************************
** \brief I2C memory write
**
** \param u8DevAddr The slave address
** \param u8Addr The register address
** \param pu8Data Pointer to the data buffer
** \param u32Size Data size
** \param u32TimeOut Time out count
** \retval en_result_t Enumeration value:
** - Ok: Success
** - Error: Receive NACK
** - ErrorTimeout: Time out
******************************************************************************/
en_result_t I2C_Reg_Write(uint16_t u8DevAddr, uint8_t u8RegAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut)
{
en_result_t enRet;
I2C_Cmd(I2C_UNIT, Enable);
I2C_SoftwareResetCmd(I2C_UNIT, Enable);
I2C_SoftwareResetCmd(I2C_UNIT, Disable);
enRet = I2C_Start(I2C_UNIT, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_TransAddr(I2C_UNIT, u8DevAddr, I2CDirTrans, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_TransData(I2C_UNIT, (uint8_t *)&u8RegAddr, BQ_ADR_LEN, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_TransData(I2C_UNIT, pu8Data, u32Size, u32TimeOut);
}
}
}
I2C_Stop(I2C_UNIT, u32TimeOut);
I2C_Cmd(I2C_UNIT, Disable);
return enRet;
}
/**
******************************************************************************
** \brief I2C memory read
**
** \param u8DevAddr The slave address
** \param u8Addr The register address
** \param pu8Data Pointer to the data buffer
** \param u32Size Data size
** \param u32TimeOut Time out count
** \retval en_result_t Enumeration value:
** - Ok: Success
** - ErrorTimeout: Time out
******************************************************************************/
en_result_t I2C_Reg_Read(uint8_t u8DevAddr, uint8_t u8RegAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut)
{
en_result_t enRet;
I2C_Cmd(I2C_UNIT, Enable);
I2C_SoftwareResetCmd(I2C_UNIT, Enable);
I2C_SoftwareResetCmd(I2C_UNIT, Disable);
enRet = I2C_Start(I2C_UNIT, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_TransAddr(I2C_UNIT, (uint8_t)u8DevAddr, I2CDirTrans, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_TransData(I2C_UNIT, (uint8_t *)&u8RegAddr, BQ_ADR_LEN, u32TimeOut);
if(Ok == enRet)
{
enRet = I2C_Restart(I2C_UNIT, u32TimeOut);
if (Ok == enRet)
{
if (1ul == u32Size)
{
I2C_AckConfig(I2C_UNIT, I2c_NACK);
}
enRet = I2C_TransAddr(I2C_UNIT, (uint8_t)u8DevAddr, I2CDirReceive, u32TimeOut);
if (Ok == enRet)
{
enRet = I2C_MasterDataReceiveAndStop(I2C_UNIT, pu8Data, u32Size, u32TimeOut);
}
I2C_AckConfig(I2C_UNIT, I2c_ACK);
}
}
}
}
if (Ok != enRet)
{
I2C_Stop(I2C_UNIT, u32TimeOut);
}
I2C_Cmd(I2C_UNIT, Disable);
return enRet;
}
/**
******************************************************************************
** \brief Initialize the I2C peripheral for e2prom
** \param None
** \retval en_result_t Enumeration value:
** - Ok: Success
** - ErrorTimeout: Time out
******************************************************************************/
static en_result_t E2_Initialize(void)
{
stc_i2c_init_t stcI2cInit;
en_result_t enRet;
float32_t fErr;
I2C_DeInit(I2C_UNIT);
/* Initialize I2C port*/
PORT_SetFunc(I2C_SCL_PORT, I2C_SCL_PIN, I2C_GPIO_SCL_FUNC, Disable);
PORT_SetFunc(I2C_SDA_PORT, I2C_SDA_PIN, I2C_GPIO_SDA_FUNC, Disable);
/* Enable I2C Peripheral*/
PWC_Fcg1PeriphClockCmd(I2C_FCG_USE, Enable);
MEM_ZERO_STRUCT(stcI2cInit);
stcI2cInit.u32ClockDiv = I2C_CLK_DIV8;
stcI2cInit.u32Baudrate = 100000ul;
stcI2cInit.u32SclTime = 0ul;
enRet = I2C_Init(I2C_UNIT, &stcI2cInit, &fErr);
I2C_BusWaitCmd(I2C_UNIT, Enable);
return enRet;
}
void I2c_Config(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* SPI Port/Pin initialization */
PORT_Init(I2C_SCL_PORT, I2C_SCL_PIN, &stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
PORT_Init(I2C_SDA_PORT, I2C_SDA_PIN, &stcPortInit);
E2_Initialize();
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* @file i2c.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the spi communication.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __I2C_H
#define __I2C_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void I2c_Config(void);
en_result_t I2C_Reg_Write(uint16_t u8DevAddr, uint8_t u8RegAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut);
en_result_t I2C_Reg_Read(uint8_t u8DevAddr, uint8_t u8RegAddr, uint8_t *pu8Data, uint32_t u32Size, uint32_t u32TimeOut);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,45 @@
/**
******************************************************************************
* @file iwdg.c
* @author AMG Energy Solution Application Team
* @version V1.0.0
* @date 25-January-2022
* @brief Watchdog Service Routines.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "iwdg.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* WDT count cycle definition */
#define WDT_COUNT_CYCLE (16384u)
/* Reset source definition */
#define RESET_WDT_TRIGGER (0u)
#define RESET_OTHER_TRIGGER (1u)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//Initialize watch-dog
void IWDG_Init(void)
{
stc_wdt_init_t stcWdtInit;
/* configure structure initialization */
MEM_ZERO_STRUCT(stcWdtInit);
stcWdtInit.enClkDiv = WdtPclk3Div8192;
stcWdtInit.enCountCycle = WdtCountCycle16384;
stcWdtInit.enRefreshRange = WdtRefresh100Pct; //WdtRefresh0To25Pct;
stcWdtInit.enSleepModeCountEn = Disable;
stcWdtInit.enRequestType = WdtTriggerResetRequest;
WDT_Init(&stcWdtInit);
/* First refresh to start WDT */
WDT_RefreshCounter();
}

View File

@@ -0,0 +1,19 @@
#ifndef _IWDG_H
#define _IWDG_H
//////////////////////////////////////////////////////////////////////////////////
//This program is for educational purposes only, without the author's permission, may not be used for any other purpose
//ALIENTEK STM32F407 Development Board
//Independent watch-dog driver code
//Hot Atomic @ALIENTEK
//Forum: www.openedv.com
//Date created: 2015/9/1
//Version: V1.0
//All rights reserved pirated reserved.
//Copyright(C) Guangzhou wing electronic technology limited company 2014-2024
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
#include "hc32_ddl.h"
void IWDG_Init(void); //Initialize
#endif

View File

@@ -0,0 +1,161 @@
/**
******************************************************************************
* @file led.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the code of the led control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "led.h"
#include "delay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//LED port definitions
/* LED RUN(GREEN) Port/Pin definition */
#define LED_BD_PORT (PortB)
#define LED_BD_PIN (Pin08)
/* LED RUN(GREEN) Port/Pin definition */
#define LED_G_PORT (PortE)
#define LED_G_PIN (Pin08)
/* LED ALARM (RED) Port/Pin definition */
#define LED_R_PORT (PortE)
#define LED_R_PIN (Pin07)
/* LED SOC Port/Pin definition */
#define LED_SOC_3_PORT (PortE)
#define LED_SOC_3_PIN (Pin09)
#define LED_SOC_2_PORT (PortE)
#define LED_SOC_2_PIN (Pin10)
#define LED_SOC_1_PORT (PortE)
#define LED_SOC_1_PIN (Pin11)
#define LED_SOC_0_PORT (PortE)
#define LED_SOC_0_PIN (Pin12)
/* LED0~3 toggle definition */
#define LED_G_TOGGLE() (PORT_Toggle(LED_G_PORT, LED_G_PIN))
#define LED_R_TOGGLE() (PORT_Toggle(LED_R_PORT, LED_R_PIN))
#define LED_S0C_0_TOGGLE() (PORT_Toggle(LED_SOC_0_PIN, LED_SOC_0_PIN))
#define LED_S0C_1_TOGGLE() (PORT_Toggle(LED_SOC_1_PIN, LED_SOC_1_PIN))
#define LED_S0C_2_TOGGLE() (PORT_Toggle(LED_SOC_2_PIN, LED_SOC_2_PIN))
#define LED_S0C_3_TOGGLE() (PORT_Toggle(LED_SOC_3_PIN, LED_SOC_3_PIN))
#define DLY_MS (200ul)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
// LED class IO
void LED_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* LED Port/Pin initialization */
PORT_Init(LED_BD_PORT, LED_BD_PIN, &stcPortInit);
PORT_Init(LED_G_PORT, LED_G_PIN, &stcPortInit);
PORT_Init(LED_R_PORT, LED_R_PIN, &stcPortInit);
PORT_Init(LED_SOC_0_PORT, LED_SOC_0_PIN, &stcPortInit);
PORT_Init(LED_SOC_1_PORT, LED_SOC_1_PIN, &stcPortInit);
PORT_Init(LED_SOC_2_PORT, LED_SOC_2_PIN, &stcPortInit);
PORT_Init(LED_SOC_3_PORT, LED_SOC_3_PIN, &stcPortInit);
}
void LED_SelfTest(void)
{
LED_Off(LED_ALL);
delay_os_ms(DLY_MS);
for (int i = 0; i < 6; i++) {
LED_On((LED_CONTROL)i);
if (i > 0) LED_Off((LED_CONTROL)(i - 1));
delay_os_ms(DLY_MS);
}
LED_Off(LED_ALL);
delay_os_ms(DLY_MS);
LED_On(LED_G);
}
void LED_On(LED_CONTROL flag)
{
switch (flag) {
case (LED_CONTROL)0: PORT_SetBits(LED_G_PORT, LED_G_PIN); break;
case (LED_CONTROL)1: PORT_SetBits(LED_R_PORT, LED_R_PIN); break;
case (LED_CONTROL)2: PORT_SetBits(LED_SOC_0_PORT, LED_SOC_0_PIN); break;
case (LED_CONTROL)3: PORT_SetBits(LED_SOC_1_PORT, LED_SOC_1_PIN); break;
case (LED_CONTROL)4: PORT_SetBits(LED_SOC_2_PORT, LED_SOC_2_PIN); break;
case (LED_CONTROL)5: PORT_SetBits(LED_SOC_3_PORT, LED_SOC_3_PIN); break;
case (LED_CONTROL)6: PORT_ResetBits(LED_BD_PORT, LED_BD_PIN); break;
case (LED_CONTROL)7:
PORT_SetBits(LED_G_PORT, LED_G_PIN);
PORT_SetBits(LED_R_PORT, LED_R_PIN);
PORT_SetBits(LED_SOC_0_PORT, LED_SOC_0_PIN);
PORT_SetBits(LED_SOC_1_PORT, LED_SOC_1_PIN);
PORT_SetBits(LED_SOC_2_PORT, LED_SOC_2_PIN);
PORT_SetBits(LED_SOC_3_PORT, LED_SOC_3_PIN);
break;
}
}
void LED_Off(LED_CONTROL flag)
{
switch (flag) {
case (LED_CONTROL)0: PORT_ResetBits(LED_G_PORT, LED_G_PIN); break;
case (LED_CONTROL)1: PORT_ResetBits(LED_R_PORT, LED_R_PIN); break;
case (LED_CONTROL)2: PORT_ResetBits(LED_SOC_0_PORT, LED_SOC_0_PIN); break;
case (LED_CONTROL)3: PORT_ResetBits(LED_SOC_1_PORT, LED_SOC_1_PIN); break;
case (LED_CONTROL)4: PORT_ResetBits(LED_SOC_2_PORT, LED_SOC_2_PIN); break;
case (LED_CONTROL)5: PORT_ResetBits(LED_SOC_3_PORT, LED_SOC_3_PIN); break;
case (LED_CONTROL)6: PORT_SetBits(LED_BD_PORT, LED_BD_PIN); break;
case (LED_CONTROL)7:
PORT_ResetBits(LED_G_PORT, LED_G_PIN);
PORT_ResetBits(LED_R_PORT, LED_R_PIN);
PORT_ResetBits(LED_SOC_0_PORT, LED_SOC_0_PIN);
PORT_ResetBits(LED_SOC_1_PORT, LED_SOC_1_PIN);
PORT_ResetBits(LED_SOC_2_PORT, LED_SOC_2_PIN);
PORT_ResetBits(LED_SOC_3_PORT, LED_SOC_3_PIN);
break;
}
}
void BD_LED_Toggle(void)
{
PORT_Toggle(LED_BD_PORT, LED_BD_PIN);
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,58 @@
/**
******************************************************************************
* @file led.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the led control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _LED_H
#define _LED_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
typedef enum {
LED_G = 0, /* 0: GREEN LED */
LED_R, /* 1: RED LED */
LED_SOC_0, /* 2: SOC 0 LED */
LED_SOC_1, /* 3: SOC 1 LED */
LED_SOC_2, /* 4: SOC 2 LED */
LED_SOC_3, /* 5: SOC 3 LED */
LED_BD, /* 6: Board LED */
LED_ALL /* 7: All LED */
} LED_CONTROL;
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void LED_Init(void); //Initialize
void LED_SelfTest(void);
void LED_On(LED_CONTROL flag);
void LED_Off(LED_CONTROL flag);
void BD_LED_Toggle(void);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,948 @@
/*! LTC6813: Multicell Battery Monitors
*
*@verbatim
*The LTC6813 is multicell battery stack monitor that measures up to 18 series
*connected battery cells with a total measurement error of less than 2.2mV.
*The cell measurement range of 0V to 5V makes the LTC6813 suitable for most
*battery chemistries. All 18 cell voltages can be captured in 290uS, and lower
*data acquisition rates can be selected for high noise reduction.
*Using the LTC6813-1, multiple devices are connected in a daisy-chain with one
*host processor connection for all devices, permitting simultaneous cell monitoring
*of long, high voltage battery strings.
*@endverbatim
*
* https://www.analog.com/en/products/ltc6813-1.html
* https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/dc2350a-b.html
*
*********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
//! @ingroup BMS
//! @{
//! @defgroup LTC6813-1 LTC6813-1: Multicell Battery Monitor
//! @}
/*! @file
@ingroup LTC6813-1
Library for LTC6813-1 Multicell Battery Monitor
*/
#include <includes.h>
#include "stdint.h"
#include "spi.h"
#include "LTC681x.h"
#include "LTC6813.h"
#include "delay.h"
//Helper function to initialize register limits.
void LTC6813_init_reg_limits(uint8_t total_ic, cell_asic *ic)
{
for (uint8_t cic = 0; cic < total_ic; cic++)
{
ic[cic].ic_reg.cell_channels = 18;
ic[cic].ic_reg.stat_channels = 4;
ic[cic].ic_reg.aux_channels = 9;
ic[cic].ic_reg.num_cv_reg = 6;
ic[cic].ic_reg.num_gpio_reg = 4;
ic[cic].ic_reg.num_stat_reg = 2;
}
}
//Helper function to initialize CFG variables.
void LTC6813_init_cfg(uint8_t total_ic, cell_asic *ic)
{
bool REFON = true;
bool ADCOPT = false;
uint8_t gpioBits = 0x1F; // {true, true, true, true, true};
uint16_t dccBits = 0;
for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
{
for (int j =0; j < 6; j++)
{
ic[current_ic].config.tx_data[j] = 0;
ic[current_ic].configb.tx_data[j] = 0;
}
LTC6813_set_cfgr(current_ic , ic, REFON, ADCOPT, gpioBits, dccBits, 0, 0, 0);
}
}
//Helper function to set CFGR variable
void LTC6813_set_cfgr(uint8_t nIC, cell_asic *ic, bool refon, bool adcopt, uint8_t gpio, uint16_t dcc, uint8_t dcto, uint16_t uv, uint16_t ov)
{
LTC6813_set_cfgr_refon (nIC, ic, refon );
LTC6813_set_cfgr_adcopt(nIC, ic, adcopt);
LTC6813_set_cfgr_gpio (nIC, ic, gpio );
LTC6813_set_cfgr_dis (nIC, ic, dcc );
LTC6813_set_cfgr_dcto (nIC, ic, dcto );
LTC6813_set_cfgr_uv (nIC, ic, uv );
LTC6813_set_cfgr_ov (nIC, ic, ov );
}
//Helper function to set the REFON bit
void LTC6813_set_cfgr_refon(uint8_t nIC, cell_asic *ic, bool refon)
{
if (refon) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] | 0x04;
else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] & 0xFB;
}
//Helper function to set the adcopt bit
void LTC6813_set_cfgr_adcopt(uint8_t nIC, cell_asic *ic, bool adcopt)
{
if (adcopt) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] | 0x01;
else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] & 0xFE;
}
//Helper function to set GPIO bits
void LTC6813_set_cfgr_gpio(uint8_t nIC, cell_asic *ic, uint8_t gpio)
{
for (int i = 0; i < 5; i++)
{
if ((gpio >> i) & 0x01) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] | ( 0x01 << (i + 3));
else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0] & (~(0x01 << (i + 3)));
}
}
//Helper function to control discharge
void LTC6813_set_cfgr_dis(uint8_t nIC, cell_asic *ic, uint16_t dcc)
{
for (int i = 0; i < 8; i++)
{
if ((dcc >> i) & 0x0001) ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4] | (0x01 << i);
else ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4] & (~(0x01 << i));
}
for (int i = 0; i < 4; i++)
{
if ((dcc >> (8 + i)) & 0x0001) ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5] | (0x01 << i);
else ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5] & (~(0x01 << i));
}
}
//Helper Function to set dcto value in CFG register
void LTC6813_set_cfgr_dcto(uint8_t nIC, cell_asic *ic, uint8_t dcto)
{
ic[nIC].config.tx_data[5] &= 0x0F;
ic[nIC].config.tx_data[5] |= (uint8_t)((dcto << 4) & 0xF0);
}
//Helper Function to set uv value in CFG register
void LTC6813_set_cfgr_uv(uint8_t nIC, cell_asic *ic,uint16_t uv)
{
ic[nIC].config.tx_data[1] = (uint8_t)((uv >> 0) & 0xFF);
ic[nIC].config.tx_data[2] &= 0xF0;
ic[nIC].config.tx_data[2] |= (uint8_t)((uv >> 8) & 0x0F);
}
//Helper function to set OV value in CFG register
void LTC6813_set_cfgr_ov(uint8_t nIC, cell_asic *ic, uint16_t ov)
{
ic[nIC].config.tx_data[2] &= 0x0F;
ic[nIC].config.tx_data[2] |= (uint8_t)((ov << 4) & 0xF0);
ic[nIC].config.tx_data[3] = (uint8_t)((ov >> 4) & 0xFF);
}
/***************************** CFGRB *********************************/
//Helper Function to initialize the CFGRB data structures
void LTC6813_init_cfgb(uint8_t total_ic,cell_asic *ic)
{
for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
{
for(int j = 0; j < 6; j++)
{
ic[current_ic].configb.tx_data[j] = 0;
}
}
}
//Helper Function to set the configuration register B
void LTC6813_set_cfgrb(uint8_t nIC, cell_asic *ic, bool fdrf, bool dtmen, bool ps[2], uint8_t gpiobits, uint16_t dccbits)
{
LTC6813_set_cfgrb_fdrf (nIC, ic, fdrf);
LTC6813_set_cfgrb_dtmen (nIC, ic, dtmen);
LTC6813_set_cfgrb_ps (nIC, ic, ps);
LTC6813_set_cfgrb_gpio_b(nIC, ic, gpiobits);
LTC6813_set_cfgrb_dcc_b (nIC, ic, dccbits);
}
//Helper function to set the FDRF bit
void LTC6813_set_cfgrb_fdrf(uint8_t nIC, cell_asic *ic, bool fdrf)
{
if(fdrf) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|0x40;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&0xBF;
}
//Helper function to set the DTMEN bit
void LTC6813_set_cfgrb_dtmen(uint8_t nIC, cell_asic *ic, bool dtmen)
{
if(dtmen) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|0x08;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&0xF7;
}
//Helper function to set the PATH SELECT bit
void LTC6813_set_cfgrb_ps(uint8_t nIC, cell_asic *ic, bool ps[])
{
for(int i =0;i<2;i++)
{
if(ps[i])ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]|(0x01<<(i+4));
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1]&(~(0x01<<(i+4)));
}
}
// Helper function to set the gpio bits in configb b register
void LTC6813_set_cfgrb_gpio_b(uint8_t nIC, cell_asic *ic, uint8_t gpiobits)
{
for (int i = 0; i < 4; i++)
{
if ((gpiobits >> 1) & 0x01) ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0] | ( 0x01 << i);
else ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0] & (~(0x01 << i));
}
}
// Helper function to set the dcc bits in configb b register
void LTC6813_set_cfgrb_dcc_b(uint8_t nIC, cell_asic *ic, uint16_t dccbits)
{
for (int i = 0; i < 7; i++)
{
if (i < 4)
{
// DCC 13, 14, 15, 16
if ((dccbits >> i) & 0x0001) ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0] | (0x01 << (i + 4));
else ic[nIC].configb.tx_data[0] = ic[nIC].configb.tx_data[0] & (~(0x01 << (i + 4)));
}
if (i >= 4 && i < 6)
{
if ((dccbits >> i) & 0x0001) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1] | (0x01 << (i - 4));
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1] & (~(0x01 << (i - 4)));
}
if (i == 6)
{
if ((dccbits >> i) & 0x0001) ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1] | 0x04;
else ic[nIC].configb.tx_data[1] = ic[nIC].configb.tx_data[1] & (~0x04); //0xFB;
}
}
}
/*
This command will write the configuration registers of the LTC6813-1s
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void LTC6813_wrcfg(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
LTC681x_wrcfg(total_ic,ic);
}
/*
This command will write the configuration b registers of the LTC6813-1s
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void LTC6813_wrcfgb(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
LTC681x_wrcfgb(total_ic, ic);
}
// Reads configuration registers of a LTC6813 daisy chain
int8_t LTC6813_rdcfg(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
uint8_t cmd[2] = {0x00, 0x02};
uint8_t read_buffer[10];
int8_t pec_error = 0;
uint16_t data_pec;
uint16_t calc_pec;
uint8_t c_ic = 0;
pec_error = read_68(total_ic, cmd, read_buffer);
for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
{
if (ic->isospi_reverse == false)
{
c_ic = current_ic;
}
else
{
c_ic = total_ic - current_ic - 1;
}
for (int byte = 0; byte < 8; byte++)
{
ic[c_ic].config.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
if (calc_pec != data_pec )
{
ic[c_ic].config.rx_pec_match = 1;
}
else ic[c_ic].config.rx_pec_match = 0;
}
LTC681x_check_pec(total_ic,CFGR,ic);
return(pec_error);
}
//Reads configuration b registers of a LTC6813 daisy chain
int8_t LTC6813_rdcfgb(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
uint8_t cmd[2]= {0x00 , 0x26};
uint8_t read_buffer[256];
int8_t pec_error = 0;
uint16_t data_pec;
uint16_t calc_pec;
uint8_t c_ic = 0;
pec_error = read_68(total_ic, cmd, read_buffer);
for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
{
if (ic->isospi_reverse == false)
{
c_ic = current_ic;
}
else
{
c_ic = total_ic - current_ic - 1;
}
for (int byte = 0; byte < 8; byte++)
{
ic[c_ic].configb.rx_data[byte] = read_buffer[byte + (8 * current_ic)];
}
calc_pec = pec15_calc(6, &read_buffer[8 * current_ic]);
data_pec = read_buffer[7 + (8 * current_ic)] | (read_buffer[6 + (8 * current_ic)] << 8);
if (calc_pec != data_pec )
{
ic[c_ic].configb.rx_pec_match = 1;
}
else ic[c_ic].configb.rx_pec_match = 0;
}
LTC681x_check_pec(total_ic,CFGR,ic);
return(pec_error);
}
//Starts cell voltage conversion
void LTC6813_adcv(uint8_t MD, //ADC Mode
uint8_t DCP, //Discharge Permit
uint8_t CH //Cell Channels to be measured
)
{
uint8_t cmd[4];
uint8_t md_bits;
md_bits = (MD & 0x02) >> 1;
cmd[0] = md_bits + 0x02;
md_bits = (MD & 0x01) << 7;
cmd[1] = md_bits + 0x60 + (DCP << 4) + CH;
cmd_68(cmd);
}
// Reads and parses the LTC6813 cell voltage registers.
uint8_t LTC6813_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
uint8_t total_ic, // the number of ICs in the system
cell_asic *ic // Array of the parsed cell codes
)
{
int8_t pec_error = 0;
pec_error = LTC681x_rdcv(reg,total_ic,ic);
return(pec_error);
}
//Start a GPIO and Vref2 Conversion
void LTC6813_adax(uint8_t MD, //ADC Mode
uint8_t CHG //GPIO Channels to be measured)
)
{
uint8_t cmd[4];
uint8_t md_bits;
md_bits = (MD & 0x02) >> 1;
cmd[0] = md_bits + 0x04;
md_bits = (MD & 0x01) << 7;
cmd[1] = md_bits + 0x60 + CHG ;
cmd_68(cmd);
}
/*
The function is used
to read the parsed GPIO codes of the LTC6813. This function will send the requested
read commands parse the data and store the gpio voltages in aux_codes variable
*/
int8_t LTC6813_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
uint8_t total_ic,//the number of ICs in the system
cell_asic *ic//A two dimensional array of the gpio voltage codes.
)
{
uint8_t *data;
int8_t pec_error = 0;
uint8_t c_ic =0;
data = (uint8_t *) malloc((NUM_RX_BYT * total_ic) * sizeof(uint8_t));
if (reg == 0)
{
for (uint8_t gpio_reg = 1; gpio_reg < ic[0].ic_reg.num_gpio_reg + 1; gpio_reg++) //executes once for each of the LTC6813 aux voltage registers
{
LTC681x_rdaux_reg(gpio_reg, total_ic, data); //Reads the raw auxiliary register data into the data[] array
for (int current_ic = 0; current_ic < total_ic; current_ic++)
{
if (ic->isospi_reverse == false)
{
c_ic = current_ic;
}
else
{
c_ic = total_ic - current_ic - 1;
}
pec_error = parse_auxs(current_ic, gpio_reg, data,
&ic[c_ic].aux.a_codes[0],
&ic[c_ic].aux.pec_match[0]);
}
}
}
else
{
LTC681x_rdaux_reg(reg, total_ic, data);
for (int current_ic = 0; current_ic<total_ic; current_ic++)
{
if (ic->isospi_reverse == false)
{
c_ic = current_ic;
}
else
{
c_ic = total_ic - current_ic - 1;
}
pec_error = parse_cells(current_ic,reg, data,
&ic[c_ic].aux.a_codes[0],
&ic[c_ic].aux.pec_match[0]);
}
}
LTC681x_check_pec(total_ic,AUX,ic);
free(data);
return (pec_error);
}
//Start a Status ADC Conversion
void LTC6813_adstat(uint8_t MD, //ADC Mode
uint8_t CHST //GPIO Channels to be measured
)
{
LTC681x_adstat(MD,CHST);
}
/*
Reads and parses the LTC6813 stat registers.
The function is used
to read the parsed stat codes of the LTC6813. This function will send the requested
read commands parse the data and store the stat voltages in stat_codes variable
*/
int8_t LTC6813_rdstat(uint8_t reg, //Determines which Stat register is read back.
uint8_t total_ic,//the number of ICs in the system
cell_asic *ic
)
{
int8_t pec_error = 0;
pec_error = LTC681x_rdstat(reg,total_ic,ic);
return (pec_error);
}
// Starts cell voltage and GPIO 1&2 conversion
void LTC6813_adcvax(uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
// LTC681x_adcvax(MD,DCP);
}
//Starts cell voltage and SOC conversion
void LTC6813_adcvsc( uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
// LTC681x_adcvsc(MD,DCP);
}
//Starts the Mux Decoder diagnostic self test
void LTC6813_diagn()
{
LTC681x_diagn();
}
//Starts cell voltage self test conversion
void LTC6813_cvst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
LTC681x_cvst(MD,ST);
}
//Start an Auxiliary Register Self Test Conversion
void LTC6813_axst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
LTC681x_axst(MD,ST);
}
//Start a Status Register Self Test Conversion
void LTC6813_statst(uint8_t MD, //ADC Mode
uint8_t ST //Self Test
)
{
LTC681x_statst(MD,ST);
}
// Runs the Digital Filter Self Test
int16_t LTC6813_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic *ic,uint8_t md,bool adcopt)
{
int16_t error = 0;
// error = LTC681x_run_cell_adc_st(adc_reg,total_ic,ic,md,adcopt);
return(error);
}
//Starts cell voltage overlap conversion
void LTC6813_adol(uint8_t MD, //ADC Mode
uint8_t DCP //Discharge Permit
)
{
LTC681x_adol(MD,DCP);
}
// Runs the ADC overlap test for the IC
uint16_t LTC6813_run_adc_overlap(uint8_t total_ic, cell_asic *ic)
{
uint16_t error = 0;
int32_t measure_delta =0;
int16_t failure_pos_limit = 20;
int16_t failure_neg_limit = -20;
uint32_t conv_time=0;
wakeup_idle(total_ic);
LTC681x_adol(MD_7KHZ_3KHZ, DCP_DISABLED);
conv_time = LTC6813_pollAdc();
conv_time = conv_time;
wakeup_idle(total_ic);
error = LTC681x_rdcv(0, total_ic,ic);
for (int cic = 0; cic<total_ic; cic++)
{
measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
{
error = error | (1<<(cic-1));
}
measure_delta = (int32_t)ic[cic].cells.c_codes[12]-(int32_t)ic[cic].cells.c_codes[13];
if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit))
{
error = error | (1<<(cic-1));
}
}
return(error);
}
//Start GPIOs open wire ADC conversion
void LTC6813_axow(uint8_t MD, //ADC Mode
uint8_t PUP //Discharge Permit
)
{
// LTC681x_axow(MD, PUP);
}
// Start an open wire Conversion
void LTC6813_adow(uint8_t MD,uint8_t PUP,uint8_t CH,uint8_t DCP)
{
// LTC681x_adow(MD,PUP,CH,DCP);
}
//Runs open wire for GPIOs
void LTC6813_run_gpio_openwire(uint8_t total_ic,
cell_asic *ic
)
{
// LTC681x_run_gpio_openwire(total_ic, ic);
}
//Runs the data sheet algorithm for open wire for single cell detection
void LTC6813_run_openwire_single(uint8_t total_ic, cell_asic *ic)
{
// LTC681x_run_openwire_single(total_ic, ic);
}
//Runs the data sheet algorithm for open wire for multiple cell and two consecutive cells detection
void LTC6813_run_openwire_multi(uint8_t total_ic, cell_asic *ic)
{
// LTC681x_run_openwire_multi( total_ic, ic);
}
//Start an GPIO Redundancy test
void LTC6813_adaxd(uint8_t MD, //ADC Mode
uint8_t CHG //GPIO Channels to be measured)
)
{
LTC681x_adaxd(MD,CHG);
}
// Start a Status register redundancy test Conversion
void LTC6813_adstatd(uint8_t MD, //ADC Mode
uint8_t CHST //GPIO Channels to be measured
)
{
LTC681x_adstatd(MD,CHST);
}
//Runs the redundancy self test
int16_t LTC6813_run_adc_redundancy_st(uint8_t adc_mode, uint8_t adc_reg, uint8_t total_ic, cell_asic *ic)
{
int16_t error = 0;
LTC681x_run_adc_redundancy_st(adc_mode,adc_reg,total_ic,ic);
return(error);
}
//Sends the poll ADC command
uint8_t LTC6813_pladc()
{
// return(LTC681x_pladc());
return(0);
}
//This function will block operation until the ADC has finished it's conversion
uint32_t LTC6813_pollAdc()
{
uint32_t counter = 0;
uint8_t finished = 0;
uint8_t current_time = 0;
uint8_t cmd[4];
uint16_t cmd_pec;
cmd[0] = 0x07;
cmd[1] = 0x14;
cmd_pec = pec15_calc(2, cmd);
cmd[2] = (uint8_t)(cmd_pec >> 8);
cmd[3] = (uint8_t)(cmd_pec);
CS_PIN_LOW();
spi_write_array(4,cmd);
while ((counter < 200000) && (finished == 0))
{
current_time = spi_read_byte(0xff);
if (current_time > 0)
finished = 1;
else
counter = counter + 10;
delay_os_ms(1);
}
CS_PIN_HIGH();
return(counter);
}
/*
The command clears the cell voltage registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC6813_clrcell()
{
LTC681x_clrcell();
}
/*
The command clears the Auxiliary registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC6813_clraux()
{
LTC681x_clraux();
}
/*
The command clears the Stat registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC6813_clrstat()
{
LTC681x_clrstat();
}
//Writes the pwm registers of a LTC6813 daisy chain
void LTC6813_wrpwm(uint8_t total_ic,
uint8_t pwmReg, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the configuration data that will be written
)
{
// LTC681x_wrpwm(total_ic,pwmReg,ic);
}
//Reads pwm registers of a LTC6813 daisy chain
int8_t LTC6813_rdpwm(uint8_t total_ic, //Number of ICs in the system
uint8_t pwmReg,
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
int8_t pec_error =0;
// pec_error = LTC681x_rdpwm(total_ic,pwmReg,ic);
return(pec_error);
}
//Writes data in S control register the ltc6813-1 connected in a daisy chain stack.
void LTC6813_wrsctrl(uint8_t total_ic, //< number of ICs in the daisy chain
uint8_t sctrl_reg,
cell_asic *ic
)
{
// LTC681x_wrsctrl(total_ic, sctrl_reg, ic);
}
// Reads sctrl registers of a ltc6812 daisy chain
int8_t LTC6813_rdsctrl(uint8_t total_ic, //< number of ICs in the daisy chain
uint8_t sctrl_reg,
cell_asic *ic //< a two dimensional array that the function stores the read pwm data
)
{
// LTC681x_rdsctrl( total_ic, sctrl_reg,ic );
return 0;
}
/* Start Sctrl data communication
This command will start the sctrl pulse communication over the spins
*/
void LTC6813_stsctrl()
{
// LTC681x_stsctrl();
}
/*
The command clears the Sctrl registers and initializes
all values to 0. The register will read back hexadecimal 0x00
after the command is sent.
*/
void LTC6813_clrsctrl()
{
// LTC681x_clrsctrl();
}
//Writes the COMM registers of a LTC6813 daisy chain
void LTC6813_wrcomm(uint8_t total_ic, //The number of ICs being written to
cell_asic *ic //A two dimensional array of the comm data that will be written
)
{
// LTC681x_wrcomm(total_ic,ic);
}
// Reads COMM registers of a LTC6813 daisy chain
int8_t LTC6813_rdcomm(uint8_t total_ic, //Number of ICs in the system
cell_asic *ic //A two dimensional array that the function stores the read configuration data.
)
{
int8_t pec_error = 0;
// LTC681x_rdcomm(total_ic, ic);
return(pec_error);
}
// Shifts data in COMM register out over LTC6813 SPI/I2C port
void LTC6813_stcomm()
{
// LTC681x_stcomm();
}
//Helper function to set discharge bit in CFG register
void LTC6813_set_discharge(int Cell, uint8_t total_ic, cell_asic *ic)
{
for (int i=0; i<total_ic; i++)
{
if (Cell==0)
{
ic[i].configb.tx_data[1] = ic[i].configb.tx_data[1] |(0x04);
}
else if (Cell<9)
{
ic[i].config.tx_data[4] = ic[i].config.tx_data[4] | (1<<(Cell-1));
}
else if (Cell < 13)
{
ic[i].config.tx_data[5] = ic[i].config.tx_data[5] | (1<<(Cell-9));
}
else if (Cell<17)
{
ic[i].configb.tx_data[0] = ic[i].configb.tx_data[0] | (1<<(Cell-9));
}
else if (Cell<19)
{
ic[i].configb.tx_data[1] = ic[i].configb.tx_data[1] | (1<<(Cell-17));
}
else
{
break;
}
}
}
//Clears all of the DCC bits in the configuration registers
void LTC6813_clear_discharge(uint8_t total_ic,
cell_asic *ic)
{
// LTC681x_clear_discharge(total_ic,ic);
}
//Helper function that increments PEC counters
void LTC6813_check_pec(uint8_t total_ic,uint8_t reg, cell_asic *ic)
{
LTC681x_check_pec(total_ic,reg,ic);
}
//Helper Function to reset PEC counters
void LTC6813_reset_crc_count(uint8_t total_ic, cell_asic *ic)
{
LTC681x_reset_crc_count(total_ic,ic);
}
// Write the 6813 PWM/S ctrl Register B
void LTC6813_wrpsb(uint8_t total_ic,cell_asic *ic)
{
uint8_t cmd[2];
uint8_t write_buffer[256];
uint8_t c_ic = 0;
cmd[0] = 0x00;
cmd[1] = 0x1C;
for(uint8_t current_ic = 0; current_ic<total_ic;current_ic++)
{
if(ic->isospi_reverse == true){c_ic = current_ic;}
else{c_ic = total_ic - current_ic - 1;}
write_buffer[0] = ic[c_ic].pwmb.tx_data[0];
write_buffer[1] = ic[c_ic].pwmb.tx_data[1];
write_buffer[2]= ic[c_ic].pwmb.tx_data[2];
write_buffer[3] = ic[c_ic].sctrlb.tx_data[3];
write_buffer[4] = ic[c_ic].sctrlb.tx_data[4];
write_buffer[5]= ic[c_ic].sctrlb.tx_data[5];
}
write_68(total_ic, cmd, write_buffer);
}
//Reading pwm/s control register b
uint8_t LTC6813_rdpsb(uint8_t total_ic, //< number of ICs in the daisy chain
cell_asic *ic //< a two dimensional array that the function stores the read pwm data
)
{
uint8_t cmd[4];
uint8_t read_buffer[256];
int8_t pec_error = 0;
uint16_t data_pec;
uint16_t calc_pec;
uint8_t c_ic = 0;
cmd[0] = 0x00;
cmd[1] = 0x1E;
pec_error = read_68(total_ic, cmd, read_buffer);
for(uint8_t current_ic =0; current_ic<total_ic; current_ic++)
{
if(ic->isospi_reverse == false){c_ic = current_ic;}
else{c_ic = total_ic - current_ic - 1;}
for(int byte=0; byte<3;byte++)
{
ic[c_ic].pwmb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
for(int byte=3; byte<6;byte++)
{
ic[c_ic].sctrlb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
for(int byte=6; byte<8;byte++)
{
ic[c_ic].pwmb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
ic[c_ic].sctrlb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
}
calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
if(calc_pec != data_pec )
{
ic[c_ic].pwmb.rx_pec_match = 1;
ic[c_ic].sctrlb.rx_pec_match = 1;
}
else
{
ic[c_ic].pwmb.rx_pec_match = 0;
ic[c_ic].sctrlb.rx_pec_match = 0;
}
}
return(pec_error);
}
//Mutes the LTC6813 discharge transistors
void LTC6813_mute()
{
uint8_t cmd[2];
cmd[0] = 0x00;
cmd[1] = 0x28;
cmd_68(cmd);
}
//Clears the LTC6813 Mute Discharge
void LTC6813_unmute()
{
uint8_t cmd[2];
cmd[0] = 0x00;
cmd[1] = 0x29;
cmd_68(cmd);
}

View File

@@ -0,0 +1,516 @@
/*! LTC6813: Multicell Battery Monitors
*
*@verbatim
*The LTC6813 is multicell battery stack monitor that measures up to 18 series
*connected battery cells with a total measurement error of less than 2.2mV.
*The cell measurement range of 0V to 5V makes the LTC6813 suitable for most
*battery chemistries. All 18 cell voltages can be captured in 290uS, and lower
*data acquisition rates can be selected for high noise reduction.
*Using the LTC6813-1, multiple devices are connected in a daisy-chain with one
*host processor connection for all devices, permitting simultaneous cell monitoring
*of long, high voltage battery strings.
*@endverbatim
*
* https://www.analog.com/en/products/ltc6813-1.html
* https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/dc2350a-b.html
*
*********************************************************************************
* Copyright 2019(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
*******************************************************************************/
/*! @file
@ingroup LTC6813-1
Header for LTC6813-1 Multicell Battery Monitor
*/
#ifndef LTC6813_H
#define LTC6813_H
#include "stdint.h"
#include "LTC681x.h"
#define CELL 1
#define AUX 2
#define STAT 3
/*! Helper function to initialize register limits */
//!@return void
void LTC6813_init_reg_limits(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper Function to initialize the CFGR data structures*/
//!@return void
void LTC6813_init_cfg(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper function to set appropriate bits in CFGR register based on bit function*/
//!@return void
void LTC6813_set_cfgr(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon, //!< the REFON bit
bool adcopt, //!< the ADCOPT bit
uint8_t gpio, //!< the GPIO bits
uint16_t dcc, //!< the DCC bits
uint8_t dcto, //!< the Dcto bits
uint16_t uv, //!< the UV value
uint16_t ov //!< the OV value
);
/*! Helper function to turn the refon bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgr_refon(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool refon //!< the REFON bit
);
/*! Helper function to turn the ADCOPT bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgr_adcopt(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool adcopt //!< the ADCOPT bit
);
/*! Helper function to turn the GPIO bits HIGH or LOW*/
//!@return void
void LTC6813_set_cfgr_gpio(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t gpio //!< the GPIO bits
);
/*! Helper function to turn the DCC bits HIGH or LOW*/
//!@return void
void LTC6813_set_cfgr_dis(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t dcc //!< the DCC bits
);
/*! Helper function to set uv field in CFGRA register*/
//!@return void
void LTC6813_set_cfgr_uv(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t uv //!< the UV value
);
/*! Helper function to set DCTO field in CFGRA register*/
//!@return void
void LTC6813_set_cfgr_dcto(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t dcto //!< the Dcto bits
);
/*! Helper function to set ov field in CFGRA register*/
//!@return void
void LTC6813_set_cfgr_ov(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t ov //!< the OV value
);
/*! Helper Function to initialize the CFGR B data structures*/
//!@return void
void LTC6813_init_cfgb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper function to set appropriate bits in CFGR register based on bit function*/
//!@return void
void LTC6813_set_cfgrb(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool fdrf, //!< the FDRF bit
bool dtmen, //!< the DTMEN bit
bool ps[2], //!< Path selection bits
uint8_t gpiobits, //!< the GPIO bits
uint16_t dccbits //!< the DCC bits - 7bits
);
/*! Helper function to turn the fdrf bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgrb_fdrf(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool fdrf //!< the FDRF bit
);
/*! Helper function to turn the DTMEN bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgrb_dtmen(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool dtmen //!< the DTMEN bit
);
/*! Helper function to turn the Path Select bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgrb_ps(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
bool ps[] //!< Path selection bits
);
/*! Helper function to turn the GPIO bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgrb_gpio_b(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t gpiobits //!< the GPIO bits
);
/*! Helper function to turn the dcc bit HIGH or LOW*/
//!@return void
void LTC6813_set_cfgrb_dcc_b(uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic, //!< A two dimensional array that will store the data
uint16_t dccbits //!< the DCC bits - 7bits
);
/*! Write the LTC6813 configuration register A*/
//!@return void
void LTC6813_wrcfg(uint8_t nIC, //!< Number of ICs in the system
cell_asic *ic //!< a two dimensional array of the configuration data that will be written
);
/*! Write the LTC6813 configuration register B*/
//!@return void
void LTC6813_wrcfgb(uint8_t nIC, //!< Number of ICs in the system
cell_asic *ic //!< a two dimensional array of the configuration data that will be written
);
/*! Reads configuration register A of a LTC6813 daisy chain
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC */
int8_t LTC6813_rdcfg(uint8_t nIC, //!< Number of ICs in the system
cell_asic *ic //!< a two dimensional array that the function stores the read configuration data
);
/*! Reads configuration register B of a LTC6813 daisy chain
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC */
int8_t LTC6813_rdcfgb(uint8_t nIC, //!< Number of ICs in the system
cell_asic *ic //!< a two dimensional array that the function stores the read configuration data
);
/*! Starts cell voltage conversion */
//!@return void
void LTC6813_adcv(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP, //!< Controls if Discharge is permitted during conversion
uint8_t CH //!< Sets which Cell channels are converted
);
/*! Reads and parses the LTC6813 cell voltage registers.
@return uint8_t, PEC Status.
0: No PEC error detected
-1: PEC error detected, retry read
*/
uint8_t LTC6813_rdcv(uint8_t reg, //!< controls which cell voltage register is read back.
uint8_t total_ic, //!< the number of ICs in the daisy chain(-1 only)
cell_asic *ic //!< array of the parsed cell codes from lowest to highest.
);
/*! Start a GPIO and Vref2 Conversion */
//!@return void
void LTC6813_adax(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*! Reads and parses the LTC6813 auxiliary registers.
@return int8_t, PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t LTC6813_rdaux(uint8_t reg, //!< controls which GPIO voltage register is read back
uint8_t nIC, //!< the number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array of the parsed gpio voltage codes
);
/*! Start a Status ADC Conversion */
//!@return void
void LTC6813_adstat( uint8_t MD, //!< ADC Conversion Mode
uint8_t CHST //!< Sets which Stat channels are converted
);
/*! Reads and parses the LTC6813 stat registers.
@return int8_t, PEC Status
0: No PEC error detected
-1: PEC error detected, retry read
*/
int8_t LTC6813_rdstat(uint8_t reg, //!< Determines which Stat register is read back.
uint8_t total_ic,//!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Starts cell voltage and GPIO 1&2 conversion */
//!@return void
void LTC6813_adcvax(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*! Starts cell voltage and SOC conversion */
//!@return void
void LTC6813_adcvsc(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*! Starts the Mux Decoder diagnostic self test
Running this command will start the Mux Decoder Diagnostic Self Test
This test takes roughly 1mS to complete. The MUXFAIL bit will be updated,
the bit will be set to 1 for a failure and 0 if the test has been passed.
*/
//!@return void
void LTC6813_diagn(void);
/*! Starts cell voltage self test conversion */
//!@return void
void LTC6813_cvst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Self Test Mode
);
/*! Start an Auxiliary Register Self Test Conversion */
//!@return void
void LTC6813_axst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*! Start a Status Register Self Test Conversion */
//!@return void
void LTC6813_statst(uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*! Helper function that runs the ADC Self Tests*/
//!@return int16_t, error
//! Number of errors detected.
int16_t LTC6813_run_cell_adc_st(uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic, //!< A two dimensional array that will store the data
uint8_t md, //!< ADC Mode
bool adcopt //!< the adcopt bit in the configuration register
);
/*! Starts cell voltage overlap conversion */
//!@return void
void LTC6813_adol(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Discharge permitted during conversion
);
/*! Helper Function that runs the ADC Overlap test*/
//!@return uint16_t, error
//! 0: Pass
//!-1: False, Error detected
uint16_t LTC6813_run_adc_overlap(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Start an open wire Conversion
*/
//!@return void
void LTC6813_adow(uint8_t MD, //!< ADC Conversion Mode
uint8_t PUP,//!< Controls if Discharge is permitted during
uint8_t CH, //!< Sets which Cell channels are converted
uint8_t DCP //!< Discharge permitted during conversion
);
/*! start GPIOs open wire ADC conversion */
//!@return void
void LTC6813_axow(uint8_t MD, //!< ADC Mode
uint8_t PUP //!< Discharge Permit
);
/*! Runs open wire for GPIOs*/
//!@return void
void LTC6813_run_gpio_openwire(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper function that runs the data sheet algorithm for open wire for single cell detection*/
//!@return void
void LTC6813_run_openwire_single(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper function that runs open wire for multiple cell and two consecutive cells detection*/
//!@return void
void LTC6813_run_openwire_multi(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Start an GPIO Redundancy test */
//!@return void
void LTC6813_adaxd(uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*! Start a Status register redundancy test Conversion */
//!@return void
void LTC6813_adstatd(uint8_t MD, //!< ADC Mode
uint8_t CHST //!< Sets which Status channels are converted
);
/*! Helper function that runs the ADC Digital Redundancy commands and checks output for errors*/
//!@return int16_t, error
int16_t LTC6813_run_adc_redundancy_st(uint8_t adc_mode, //!< ADC Mode
uint8_t adc_reg, //!< Type of register
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
//! Sends the poll ADC command
//! @returns 1 byte read back after a pladc command. If the byte is not 0xFF ADC conversion has completed
uint8_t LTC6813_pladc(void);
//! This function will block operation until the ADC has finished it's conversion
//! @returns the approximate time it took for the ADC function to complete.
uint32_t LTC6813_pollAdc(void);
/*! Clears the LTC6813 cell voltage registers */
//!@return void
void LTC6813_clrcell(void);
/*! Clears the LTC6813 Auxiliary registers */
//!@return void
void LTC6813_clraux(void);
/*! Clears the LTC6813 Stat registers */
//!@return void
void LTC6813_clrstat(void);
/*! Write the LTC6813 PWM register */
//!@return void
void LTC6813_wrpwm(uint8_t nIC, //!< number of ICs in the daisy chain
uint8_t pwmReg, //!< PWM Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Reads pwm registers of a LTC6813 daisy chain */
//!@return int8_t, PEC Status.
//! 0: Data read back has matching PEC
//! -1: Data read back has incorrect PEC
int8_t LTC6813_rdpwm(uint8_t nIC, //!< number of ICs in the daisy chain
uint8_t pwmReg, //! PWM Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Write the LTC6813 Sctrl register */
//!@return void
void LTC6813_wrsctrl(uint8_t nIC, //!< number of ICs in the daisy chain
uint8_t sctrl_reg,//! SCTRL Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Reads sctrl registers of a LTC6813 daisy chain
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t LTC6813_rdsctrl(uint8_t nIC, //!< number of ICs in the daisy chain
uint8_t sctrl_reg,//! SCTRL Register A or B
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Start Sctrl data communication
This command will start the sctrl pulse communication over the spins
*/
//!@return void
void LTC6813_stsctrl(void);
/*! Clears the LTC6813 Sctrl registers */
//!@return void
void LTC6813_clrsctrl(void);
/*! Write the LTC6813 COMM register */
//!@return void
void LTC6813_wrcomm(uint8_t total_ic, //!< Number of ICs in the daisy chain
cell_asic *ic //!< A two dimensional array of the comm data that will be written
);
/*! Reads comm registers of a LTC6813 daisy chain
@return int8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
int8_t LTC6813_rdcomm(uint8_t total_ic, //!< number of ICs in the daisy chain
cell_asic *ic //!< Two dimensional array that the function stores the read comm data.
);
/*! Issues a stcomm command and clocks data out of the COMM register */
//!@return void
void LTC6813_stcomm(void);
/*! Helper Function to Set DCC bits in the CFGR Registers*/
//!@return void
void LTC6813_set_discharge(int Cell, //!< The cell to be discharged
uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper Function to clear DCC bits in the CFGR Registers*/
//!@return void
void LTC6813_clear_discharge(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper Function that counts overall PEC errors and register/IC PEC errors*/
//!@return void
void LTC6813_check_pec(uint8_t total_ic, //!< Number of ICs in the system
uint8_t reg, //!< Type of register
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Helper Function that resets the PEC error counters */
//!@return void
void LTC6813_reset_crc_count(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Write the 6813 PWM/Sctrl Register B */
//!@return void
void LTC6813_wrpsb(uint8_t total_ic, //!< Number of ICs in the system
cell_asic *ic //!< A two dimensional array that will store the data
);
/*! Reading pwm/s control register B
@return uint8_t, PEC Status.
0: Data read back has matching PEC
-1: Data read back has incorrect PEC
*/
uint8_t LTC6813_rdpsb(uint8_t total_ic, //!< number of ICs in the daisy chain
cell_asic *ic //!< a two dimensional array that the function stores the read pwm data
);
/*! Mutes the LTC6813 discharge transistors */
//!@return void
void LTC6813_mute(void);
/*! Clears the LTC6813 Mute Discharge */
//!@return void
void LTC6813_unmute(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,519 @@
/**
******************************************************************************
* File Name : ltc681x.h
* Description : This file provides code for the configuration
* of ltc681x driver.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2021 Amogreentech Co., Ltd.
* All rights reserved.</center></h2>
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _LTC681X_H_
#define _LTC681X_H_
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported define -----------------------------------------------------------*/
#define IC_LTC6813
#define MD_422HZ_1KHZ 0
#define MD_27KHZ_14KHZ 1
#define MD_7KHZ_3KHZ 2
#define MD_26HZ_2KHZ 3
#define ADC_OPT_ENABLED 1
#define ADC_OPT_DISABLED 0
#define CELL_CH_ALL 0
#define CELL_CH_1and7 1
#define CELL_CH_2and8 2
#define CELL_CH_3and9 3
#define CELL_CH_4and10 4
#define CELL_CH_5and11 5
#define CELL_CH_6and12 6
#define SELFTEST_1 1
#define SELFTEST_2 2
#define AUX_CH_ALL 0
#define AUX_CH_GPIO1 1
#define AUX_CH_GPIO2 2
#define AUX_CH_GPIO3 3
#define AUX_CH_GPIO4 4
#define AUX_CH_GPIO5 5
#define AUX_CH_VREF2 6
#define STAT_CH_ALL 0
#define STAT_CH_SOC 1
#define STAT_CH_ITEMP 2
#define STAT_CH_VREGA 3
#define STAT_CH_VREGD 4
#define DCP_DISABLED 0
#define DCP_ENABLED 1
#define PULL_UP_CURRENT 1
#define PULL_DOWN_CURRENT 0
#define NUM_RX_BYT 8
#define CELL 1
#define AUX 2
#define STAT 3
#define CFGR 0
#define CFGRB 4
#define CS_PIN_HIGH SPI1_NSS_HIGH
#define CS_PIN_LOW SPI1_NSS_LOW
/* Exported types ------------------------------------------------------------*/
//! Cell Voltage data structure.
typedef struct
{
uint16_t c_codes[18]; //!< Cell Voltage Codes
uint8_t pec_match[6]; //!< If a PEC error was detected during most recent read cmd
} cv;
//! AUX Reg Voltage Data
typedef struct
{
uint16_t a_codes[12]; //!< Aux Voltage Codes
uint8_t pec_match[4]; //!< If a PEC error was detected during most recent read cmd
} ax;
typedef struct
{
uint16_t stat_codes[4]; //!< A two dimensional array of the stat voltage codes.
uint8_t flags[3]; //!< byte array that contains the uv/ov flag data
uint8_t mux_fail[1]; //!< Mux self test status flag
uint8_t thsd[1]; //!< Thermal shutdown status
uint8_t pec_match[2]; //!< If a PEC error was detected during most recent read cmd
} st;
typedef struct
{
uint8_t tx_data[6];
uint8_t rx_data[8];
uint8_t rx_pec_match; //!< If a PEC error was detected during most recent read cmd
} ic_register;
typedef struct
{
uint16_t pec_count;
uint16_t cfgr_pec;
uint16_t cell_pec[6];
uint16_t aux_pec[4];
uint16_t stat_pec[2];
} pec_counter;
typedef struct
{
uint8_t cell_channels;
uint8_t stat_channels;
uint8_t aux_channels;
uint8_t num_cv_reg;
uint8_t num_gpio_reg;
uint8_t num_stat_reg;
} register_cfg;
typedef struct
{
ic_register config;
ic_register configb;
cv cells;
ax aux;
st stat;
ic_register com;
ic_register pwm;
ic_register pwmb;
ic_register sctrl;
ic_register sctrlb;
bool isospi_reverse;
pec_counter crc_count;
register_cfg ic_reg;
long system_open_wire;
} cell_asic;
/* Exported variables ------------------------------------------------------- */
/* Exported functions ------------------------------------------------------- */
/*! calculates and returns the CRC15
@returns The calculated pec15 as an unsigned int
*/
uint16_t pec15_calc(uint8_t len, //!< the length of the data array being passed to the function
uint8_t *data //!< the array of data that the PEC will be generated from
);
/*! Wake isoSPI up from idle state */
void wakeup_idle(uint8_t total_ic);//!< number of ICs in the daisy chain
/*! Wake the LTC6813 from the sleep state */
void wakeup_sleep(uint8_t total_ic); //!< number of ICs in the daisy chain
/*! Sense a command to the bms IC. This code will calculate the PEC code for the transmitted command*/
void cmd_68(uint8_t tx_cmd[2]); //!< 2 Byte array containing the BMS command to be sent
//! Writes an array of data to the daisy chain
void write_68(uint8_t total_ic , //!< number of ICs in the daisy chain
uint8_t tx_cmd[2], //!< 2 Byte array containing the BMS command to be sent
uint8_t data[] //!< Array containing the data to be written to the BMS ICs
);
//! Issues a command onto the daisy chain and reads back 6*total_ic data in the rx_data array
int8_t read_68( uint8_t total_ic, //!< number of ICs in the daisy chain
uint8_t tx_cmd[2], //!< 2 Byte array containing the BMS command to be sent
uint8_t *rx_data); //!< Array that the read back data will be stored.
/*! Starts the Mux Decoder diagnostic self test
Running this command will start the Mux Decoder Diagnostic Self Test
This test takes roughly 1mS to complete. The MUXFAIL bit will be updated,
the bit will be set to 1 for a failure and 0 if the test has been passed.
*/
void LTC681x_diagn(void);
/*! Starts cell voltage conversion
Starts ADC conversions of the LTC6811 Cpin inputs.
The type of ADC conversion executed can be changed by setting the following parameters:
*/
void LTC681x_adcv(uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP, //!< Controls if Discharge is permitted during conversion
uint8_t CH //!< Sets which Cell channels are converted
);
/*! Starts cell voltage and GPIO 1&2 conversion
*/
void LTC681x_adcvax(
uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*! Starts cell voltage self test conversion
*/
void LTC681x_cvst(
uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Self Test Mode
);
/*! Starts cell voltage and SOC conversion
*/
void LTC681x_adcvsc(
uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Controls if Discharge is permitted during conversion
);
/*! Starts cell voltage overlap conversion
*/
void LTC681x_adol(
uint8_t MD, //!< ADC Conversion Mode
uint8_t DCP //!< Discharge permitted during conversion
);
/*! Start an open wire Conversion
*/
void LTC681x_adow(
uint8_t MD, //!< ADC Conversion Mode
uint8_t PUP //!< Controls if Discharge is permitted during conversion
);
/*! Start a GPIO and Vref2 Conversion
*/
void LTC681x_adax(
uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*! Start an GPIO Redundancy test
*/
void LTC681x_adaxd(
uint8_t MD, //!< ADC Conversion Mode
uint8_t CHG //!< Sets which GPIO channels are converted
);
/*! Start an Auxiliary Register Self Test Conversion
*/
void LTC681x_axst(
uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
/*! Start a Status ADC Conversion
*/
void LTC681x_adstat(
uint8_t MD, //!< ADC Conversion Mode
uint8_t CHST //!< Sets which Stat channels are converted
);
/*! Start a Status register redundancy test Conversion
*/
void LTC681x_adstatd(
uint8_t MD, //!< ADC Mode
uint8_t CHST //!< Sets which Status channels are converted
);
/*! Start a Status Register Self Test Conversion
*/
void LTC681x_statst(
uint8_t MD, //!< ADC Conversion Mode
uint8_t ST //!< Sets if self test 1 or 2 is run
);
void LTC681x_rdcv_reg(uint8_t reg, //!<Determines which cell voltage register is read back
uint8_t total_ic, //!<the number of ICs in the
uint8_t *data //!<An array of the unparsed cell codes
);
/*! helper function that parses voltage measurement registers
*/
int8_t parse_cells(uint8_t current_ic,
uint8_t cell_reg,
uint8_t cell_data[],
uint16_t *cell_codes,
uint8_t *ic_pec);
/*! helper function that parses aux volatge measurement registers
*/
int8_t parse_auxs(uint8_t current_ic,
uint8_t aux_reg,
uint8_t aux_data[],
uint16_t *aux_codes,
uint8_t *ic_pec);
/*! Read the raw data from the LTC681x auxiliary register
The function reads a single GPIO voltage register and stores thre read data
in the *data point as a byte array. This function is rarely used outside of
the LTC681x_rdaux(void) command.
*/
void LTC681x_rdaux_reg( uint8_t reg, //Determines which GPIO voltage register is read back
uint8_t total_ic, //The number of ICs in the system
uint8_t *data //Array of the unparsed auxiliary codes
);
/*! Read the raw data from the LTC681x stat register
The function reads a single GPIO voltage register and stores thre read data
in the *data point as a byte array. This function is rarely used outside of
the LTC681x_rdstat(void) command.
*/
void LTC681x_rdstat_reg(uint8_t reg, //Determines which stat register is read back
uint8_t total_ic, //The number of ICs in the system
uint8_t *data //Array of the unparsed stat codes
);
/*! Clears the LTC681x cell voltage registers
The command clears the cell voltage registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC681x_clrcell(void);
/*! Clears the LTC681x Auxiliary registers
The command clears the Auxiliary registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC681x_clraux(void);
/*! Clears the LTC681x Stat registers
The command clears the Stat registers and initializes
all values to 1. The register will read back hexadecimal 0xFF
after the command is sent.
*/
void LTC681x_clrstat(void);
/*! Clears the LTC681x SCTRL registers
The command clears the SCTRL registers and initializes
all values to 0. The register will read back hexadecimal 0x00
after the command is sent.
*/
void LTC681x_clrsctrl(void);
/*! Starts the Mux Decoder diagnostic self test
Running this command will start the Mux Decoder Diagnostic Self Test
This test takes roughly 1mS to complete. The MUXFAIL bit will be updated,
the bit will be set to 1 for a failure and 0 if the test has been passed.
*/
void LTC681x_diagn(void);
/*! Reads and parses the LTC681x cell voltage registers.
The function is used to read the cell codes of the LTC6811.
This function will send the requested read commands parse the data
and store the cell voltages in the cell_asic structure.
*/
uint8_t LTC681x_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
uint8_t total_ic, // the number of ICs in the system
cell_asic ic[] // Array of the parsed cell codes
);
/*! Reads and parses the LTC681x auxiliary registers.
The function is used to read the parsed GPIO codes of the LTC6811. This function will send the requested
read commands parse the data and store the gpio voltages in the cell_asic structure.
*/
int8_t LTC681x_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
uint8_t total_ic,//the number of ICs in the system
cell_asic ic[]//!< Measurement Data Structure
);
/*! Reads and parses the LTC681x stat registers.
The function is used to read the parsed status codes of the LTC6811. This function will send the requested
read commands parse the data and store the status voltages in the cell_asic structure
*/
int8_t LTC681x_rdstat( uint8_t reg, //!<Determines which Stat register is read back.
uint8_t total_ic,//!<the number of ICs in the system
cell_asic ic[]//!< Measurement Data Structure
);
/*! Write the LTC681x CFGRA
This command will write the configuration registers of the LTC681xs
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void LTC681x_wrcfg(uint8_t total_ic, //The number of ICs being written to
cell_asic ic[] //A two dimensional array of the configuration data that will be written
);
/*! Write the LTC681x CFGRB
This command will write the configuration registers of the LTC681xs
connected in a daisy chain stack. The configuration is written in descending
order so the last device's configuration is written first.
*/
void LTC681x_wrcfgb(uint8_t total_ic, //The number of ICs being written to
cell_asic ic[] //A two dimensional array of the configuration data that will be written
);
/*! Reads the LTC681x CFGRA register
*/
int8_t LTC681x_rdcfg(uint8_t total_ic, //Number of ICs in the system
cell_asic ic[] //A two dimensional array that the function stores the read configuration data.
);
/*! Reads the LTC681x CFGRB register
*/
int8_t LTC681x_rdcfgb(uint8_t total_ic, //Number of ICs in the system
cell_asic ic[] //A two dimensional array that the function stores the read configuration data.
);
/*! Selft Test Helper Function*/
uint16_t LTC681x_st_lookup(
uint8_t MD, //ADC Mode
uint8_t ST //Self Test
);
/*! Helper Function to clear DCC bits in the CFGR Registers*/
void clear_discharge(uint8_t total_ic,
cell_asic ic[]);
/*! Helper function that runs the ADC Self Tests*/
int16_t LTC681x_run_cell_adc_st(uint8_t adc_reg,
uint8_t total_ic,
cell_asic ic[]);
/*! Helper function that runs the ADC Digital Redudancy commands and checks output for errors*/
int16_t LTC681x_run_adc_redundancy_st(uint8_t adc_mode,
uint8_t adc_reg,
uint8_t total_ic,
cell_asic ic[]);
/*! Helper function that runs the datasheet open wire algorithm*/
void LTC681x_run_openwire(uint8_t total_ic,
cell_asic ic[]);
/*! Helper Function that counts overall PEC errors and register/IC PEC errors*/
void LTC681x_check_pec(uint8_t total_ic,
uint8_t reg,
cell_asic ic[]);
/*! Helper Function that resets the PEC error counters */
void LTC681x_reset_crc_count(uint8_t total_ic,
cell_asic ic[]);
/*! Helper Function to initialize the CFGR data structures*/
void LTC681x_init_cfg(uint8_t total_ic,
cell_asic ic[]);
/*! Helper function to set appropriate bits in CFGR register based on bit function*/
void LTC681x_set_cfgr(uint8_t nIC,
cell_asic ic[],
bool refon,
bool adcopt,
bool gpio[5],
uint16_t dcc);
/*! Helper function to turn the refon bit HIGH or LOW*/
void LTC681x_set_cfgr_refon(uint8_t nIC,
cell_asic ic[],
bool refon);
/*! Helper function to turn the ADCOPT bit HIGH or LOW*/
void LTC681x_set_cfgr_adcopt(uint8_t nIC,
cell_asic ic[],
bool adcopt);
/*! Helper function to turn the GPIO bits HIGH or LOW*/
void LTC681x_set_cfgr_gpio(uint8_t nIC,
cell_asic ic[],
bool gpio[]);
/*! Helper function to turn the DCC bits HIGH or LOW*/
void LTC681x_set_cfgr_dis(uint8_t nIC,
cell_asic ic[],
uint16_t dcc);
/*! Helper function to turn the DCC bits HIGH or LOW*/
void LTC681x_set_cfgr_dcto(uint8_t nIC,
cell_asic ic[],
uint8_t dcto);
/*! Helper function to turn the DCC bits HIGH or LOW*/
void LTC681x_set_cfgr_uv(uint8_t nIC,
cell_asic ic[],
uint16_t UV);
//********************************** LTC6811 ******************************************//
void LTC6811_init_reg_limits(uint8_t total_ic, cell_asic ic[]);
void LTC6811_set_discharge(int Cell,
uint8_t total_ic,
cell_asic ic[]);
//********************************** SPI ******************************************//
/*
Writes an array of bytes out of the SPI port
*/
void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
uint8_t data[] //Array of bytes to be written on the SPI port
);
/*
Writes and read a set number of bytes using the SPI port.
*/
void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
uint8_t tx_len, //length of the tx data arry
uint8_t *rx_data,//Input: array that will store the data read by the SPI port
uint8_t rx_len //Option: number of bytes to be read from the SPI port
);
uint8_t spi_read_byte(uint8_t tx_dat);//name conflicts with linduino also needs to take a byte as a parameter
#endif /* _LTC681X_H_ */
/*******************(C)COPYRIGHT 2021 Amogreentech *********END OF FILE********/

View File

@@ -0,0 +1,180 @@
/**
******************************************************************************
* File Name : can_comm.c
* Description : This file provides code for the configuration
* of the CAN communication instances.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "malloc.h"
//Memory pool (4-byte alignment)
__align(4) uint8_t membase[MEM_MAX_SIZE]; // __attribute__((at(0x10000000))); //CMM within the memory pool
//Memory management tables
__align(4) uint16_t memmapbase[MEM_ALLOC_TABLE_SIZE]; // __attribute__((at(0X10000000 + MEM3_MAX_SIZE))); //Internal CCM pools MAP
//Memory management parameters
const uint32_t memtblsize = MEM_ALLOC_TABLE_SIZE; //Memory table size
const uint32_t memblksize = MEM_BLOCK_SIZE; //Memory block size
const uint32_t memsize = MEM_MAX_SIZE; //Total memory size
//Memory management controller
struct _m_mallco_dev mallco_dev =
{
mymem_init, //Memory initialization
mem_perused, //Memory usage
membase, //Memory pool
memmapbase, //Memory management tables
0, //Memory management is not ready
};
//Copy memory
//*des:Destination address
//*src:Source address
//n:Need to copy memory length (bytes)
void mymemcpy(void *des,void *src,uint32_t n)
{
uint8_t *xdes = des;
uint8_t *xsrc = src;
while(n--) *xdes++ = *xsrc++;
}
//Setting memory
//*s:Memory address
//c :The value to be set
//count:Need to set the memory size(Bytes)
void mymemset(void*s,uint8_t c,uint32_t count)
{
uint8_t *xs = s;
while(count--) *xs++=c;
}
//Memory management class
//memx:Belongs to a block of memory
void mymem_init(void)
{
mymemset(mallco_dev.memmap, 0, memtblsize * 2); // Memory status table is cleared to zero
mymemset(mallco_dev.membase, 0, memsize); // Memory pool all data to zero
mallco_dev.memrdy = 1; // Memory initialized OK
}
//Get memory usage
//memx:Belongs to a block of memory
//Return value: usage (0~100)
uint8_t mem_perused(void)
{
uint32_t used = 0;
uint32_t i;
for (i = 0; i < memtblsize; i++)
{
if (mallco_dev.memmap[i]) used++;
}
return (used * 100) / (memtblsize);
}
// Memory allocation (internal call)
// size:Amount of memory to allocate (in bytes)
// The return value:0XFFFFFFFF,To indicate an error; the other, the memory offset
uint32_t _mem_malloc(uint32_t size)
{
signed long offset = 0;
uint16_t nmemb; // Required number of memory blocks
uint16_t cmemb = 0; // Number of contiguous blocks of free memory
uint32_t i;
if (!mallco_dev.memrdy) mallco_dev.init(); // Is not initialized, perform the initialization
if (size == 0) return 0XFFFFFFFF; // Do not need to allocate
nmemb = size / memblksize; // Gets the required number of contiguous blocks of memory allocated
if (size % memblksize) nmemb++;
for (offset = memtblsize - 1; offset >= 0; offset--) // Search the entire memory control
{
if (!mallco_dev.memmap[offset]) cmemb++; // Increase the number of contiguous blocks of free memory
else cmemb = 0; // Contiguous blocks of memory to zero
if (cmemb == nmemb) // Find nmemb consecutive empty memory blocks
{
for (i = 0; i < nmemb; i++) // Mark a block of memory is not empty
{
mallco_dev.memmap[offset+i] = nmemb;
}
return (offset*memblksize); // Returns the offset address
}
}
return 0XFFFFFFFF; // Not found consistent with allocated memory block
}
//Free memory (internal call)
//offset:Memory address of offset
//Return values: 0, release success; 1, release failed;
uint8_t _mem_free(uint32_t offset)
{
int i;
if (!mallco_dev.memrdy) // Is not initialized, perform the initialization
{
mallco_dev.init();
return 1; // Not initialized
}
if (offset < memsize) // Offset within the memory pool.
{
int index = offset / memblksize; // Offset where the memory block number
int nmemb=mallco_dev.memmap[index]; // Number of memory blocks
for (i = 0; i < nmemb; i++) // Zero out memory blocks
{
mallco_dev.memmap[index+i] = 0;
}
return 0;
} else return 2; // Offset Super.
}
//Free memory (external call)
//ptr:Memory address
void myfree(void *ptr)
{
uint32_t offset;
if (ptr == NULL) return; // Address 0.
offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase;
_mem_free(offset); //Free up memory
}
//Allocating memory(External call)
//size:Memory size (in bytes)
//Return values: the first address of the allocated memory.
void *mymalloc(uint32_t size)
{
uint32_t offset;
offset = _mem_malloc(size);
if (offset == 0XFFFFFFFF) return NULL;
else return (void*)((uint32_t)mallco_dev.membase + offset);
}
//Reallocating memory (external call)
//*ptr:The old memory address
//size:Amount of memory to allocate (in bytes)
//Return values: the first address of the newly allocated memory.
void *myrealloc(void *ptr,uint32_t size)
{
uint32_t offset;
offset = _mem_malloc(size);
if (offset == 0XFFFFFFFF) return NULL;
else
{
mymemcpy((void*)((uint32_t)mallco_dev.membase + offset), ptr, size); // Copy the old memory contents to the new memory
myfree(ptr); // Free old memory
return (void*)((uint32_t)mallco_dev.membase + offset); // Returns a new memory address
}
}

View File

@@ -0,0 +1,78 @@
/**
******************************************************************************
* @file malloc.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides code for the configuration of
* the memory heap instances.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __malloc_H
#define __malloc_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
#ifndef NULL
#define NULL 0
#endif
// Define three memory pools
#define MEM_BLOCK_SIZE 32 // Block size is 32 bytes
#define MEM_MAX_SIZE (20 * 1024) // Maximum memory management 20k
#define MEM_ALLOC_TABLE_SIZE (MEM_MAX_SIZE / MEM_BLOCK_SIZE) // Memory table size
//Memory management controller
struct _m_mallco_dev
{
void (*init)(void); // Initialize
uint8_t (*perused)(void); // Memory usage
uint8_t *membase; // Memory pool management SRAMBANK a region of memory
uint16_t *memmap; // Memory status table
uint8_t memrdy; // Memory management is ready to
};
extern struct _m_mallco_dev mallco_dev; //Defined in malloc.c
void mymemset(void *s,uint8_t c,uint32_t count); // Setting memory
void mymemcpy(void *des,void *src,uint32_t n); // Copy memory
void mymem_init(void); // Memory initialization function (external/internal calls)
uint8_t mem_perused(void); // For memory usage (external/internal calls)
////////////////////////////////////////////////////////////////////////////////
//Users call a function
void myfree(void *ptr); // Memory release (external call)
void *mymalloc(uint32_t size); // Memory allocation (external call)
void *myrealloc(void *ptr, uint32_t size); // Reallocating memory (external call)
#ifdef __cplusplus
}
#endif
#endif /*__ brtc_H */
/**
* @}
*/
/**
* @}
*/
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,135 @@
/**
******************************************************************************
* @file relay.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of relay control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "relay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//Relay port definitions
/* Charge Relay Port/Pin definition */
#define CHG_RLY_PORT (PortC)
#define CHG_RLY_PIN (Pin09)
/* Discharge Relay Port/Pin definition */
#define DSG_RLY_PORT (PortD)
#define DSG_RLY_PIN (Pin15)
/* Pre-Charge Relay Port/Pin definition */
#define PCHG_RLY_PORT (PortD)
#define PCHG_RLY_PIN (Pin13)
/* Charge Relay Status Port/Pin definition */
#define CHG_RLY_STS_PORT (PortC)
#define CHG_RLY_STS_PIN (Pin08)
/* Discharge Relay Status Port/Pin definition */
#define DSG_RLY_STS_PORT (PortD)
#define DSG_RLY_STS_PIN (Pin14)
/* Discharge Relay Status Port/Pin definition */
#define PCHG_RLY_STS_PORT (PortD)
#define PCHG_RLY_STS_PIN (Pin12)
// Relay port definitions
#define CHG_RLY_OFF PORT_ResetBits(CHG_RLY_PORT , CHG_RLY_PIN );
#define CHG_RLY_ON PORT_SetBits (CHG_RLY_PORT , CHG_RLY_PIN );
#define DSG_RLY_OFF PORT_ResetBits(DSG_RLY_PORT , DSG_RLY_PIN );
#define DSG_RLY_ON PORT_SetBits (DSG_RLY_PORT , DSG_RLY_PIN );
#define PRE_CHG_RLY_ON PORT_ResetBits(PCHG_RLY_PORT, PCHG_RLY_PIN);
#define PRE_CHG_RLY_OFF PORT_SetBits (PCHG_RLY_PORT, PCHG_RLY_PIN);
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
// Relay IO Initialize
void Relay_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enPinOType = Pin_OType_Od;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* Relay Control Port/Pin initialization */
PORT_Init(CHG_RLY_PORT , CHG_RLY_PIN , &stcPortInit);
PORT_Init(DSG_RLY_PORT , DSG_RLY_PIN , &stcPortInit);
PORT_Init(PCHG_RLY_PORT, PCHG_RLY_PIN, &stcPortInit);
CHG_RLY_OFF;
DSG_RLY_OFF;
PRE_CHG_RLY_OFF;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* Relay Status Port/Pin initialization */
PORT_Init(CHG_RLY_STS_PORT , CHG_RLY_STS_PIN , &stcPortInit);
PORT_Init(DSG_RLY_STS_PORT , DSG_RLY_STS_PIN , &stcPortInit);
PORT_Init(PCHG_RLY_STS_PORT, PCHG_RLY_STS_PIN, &stcPortInit);
}
void Relay_On(uint8_t id)
{
switch (id) {
case '0': DSG_RLY_ON; break;
case '1': CHG_RLY_ON; break;
case '2': PRE_CHG_RLY_ON; break;
}
}
void Relay_Off(uint8_t id)
{
switch (id) {
case '0': DSG_RLY_OFF; break;
case '1': CHG_RLY_OFF; break;
case '2': PRE_CHG_RLY_OFF; break;
}
}
uint8_t Relay_Status(uint8_t id)
{
uint8_t result = 0;
switch (id) {
case 0: result = PORT_GetBit(DSG_RLY_STS_PORT , DSG_RLY_STS_PIN ); break;
case 1: result = PORT_GetBit(CHG_RLY_STS_PORT , CHG_RLY_STS_PIN ); break;
case 2: result = PORT_GetBit(PCHG_RLY_STS_PORT, PCHG_RLY_STS_PIN); break;
}
return result;
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,45 @@
/**
******************************************************************************
* @file relay.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of relay control functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _RELAY_H
#define _RELAY_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void Relay_Init(void); // Initialize
void Relay_DeInit(void); // DeInitialize
void Relay_On(uint8_t id);
void Relay_Off(uint8_t id);
uint8_t Relay_Status(uint8_t id);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,367 @@
/**
******************************************************************************
* @file rtc_io.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the code of the realtime clock functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
//////////////////////////////////////////////////////////////////////////
//// DS1302.C ////
//// Driver for Real Time Clock ////
//// ////
//// rtc_init() Call after power up////
//// ////
//// rtc_set_datetime(day,mth,year,dow,hour,min) Set the date/time ////
//// ////
//// rtc_get_date(day,mth,year,dow) Get the date ////
//// ////
//// rtc_get_time(hr,min,sec) Get the time ////
//// ////
//// rtc_write_nvr(address,data) Write to NVR ////
//// ////
//// data = rtc_read_nvr(address) Read from NVR ////
//// ////
//////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996,2003 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS C ////
//// compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, reproduction////
//// or distribution is permitted without written permission. ////
//// Derivative programs created using this software in object code ////
//// form are not restricted in any way. ////
//////////////////////////////////////////////////////////////////////////
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "rtc_io.h"
#include "delay.h"
#include "stdio.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* RTC IO Port/Pin definition */
#define RTC_IO_CLK_PORT (PortD)
#define RTC_IO_CLK_PIN (Pin11)
#define RTC_IO_DAT_PORT (PortD)
#define RTC_IO_DAT_PIN (Pin10)
#define RTC_IO_RST_PORT (PortD)
#define RTC_IO_RST_PIN (Pin09)
// --------------------------------------------------------------------------------
// RTC-Bus-Line
// --------------------------------------------------------------------------------
#define RTC_CLK_LOW PORT_ResetBits(RTC_IO_CLK_PORT, RTC_IO_CLK_PIN) // rtc data line Low-Level
#define RTC_CLK_HIGH PORT_SetBits(RTC_IO_CLK_PORT, RTC_IO_CLK_PIN) // rtc data line High-Level
#define RTC_DAT_LOW PORT_ResetBits(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN) // rtc data line Low-Level
#define RTC_DAT_HIGH PORT_SetBits(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN) // rtc data line High-Level
#define RTC_DAT_IN PORT_GetBit(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN) // rtc data line read
#define RTC_RST_LOW PORT_ResetBits(RTC_IO_RST_PORT, RTC_IO_RST_PIN) // rtc data line Low-Level
#define RTC_RST_HIGH PORT_SetBits(RTC_IO_RST_PORT, RTC_IO_RST_PIN) // rtc data line High-Level
#define CLK_DIV 10
#define Tdc 200 / CLK_DIV // Min.
#define Tcdh 280 / CLK_DIV // Min.
#define Tcdd 800 / CLK_DIV // Max.
#define Tcl 1000 / CLK_DIV // Min.
#define Tch 1000 / CLK_DIV // Min.
#define Tcc 4000 / CLK_DIV // Min.
#define Tcch 240 / CLK_DIV // Min.
#define Tcwh 4000 / CLK_DIV // Min.
#define Tcdz 280 / CLK_DIV // Max.
#define Tccz 280 / CLK_DIV // Max.
#define RD_ADDR_RTC_YEAR 0x8D
#define RD_ADDR_RTC_MONTH 0x89
#define RD_ADDR_RTC_DATE 0x87
#define RD_ADDR_RTC_WDAY 0x8B
#define RD_ADDR_RTC_HOUR 0x85
#define RD_ADDR_RTC_MIN 0x83
#define RD_ADDR_RTC_SEC 0x81
#define WR_ADDR_RTC_YEAR 0x8C
#define WR_ADDR_RTC_MONTH 0x88
#define WR_ADDR_RTC_DATE 0x86
#define WR_ADDR_RTC_WDAY 0x8A
#define WR_ADDR_RTC_HOUR 0x84
#define WR_ADDR_RTC_MIN 0x82
#define WR_ADDR_RTC_SEC 0x80
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private prototype functions -----------------------------------------------*/
// send 'databyte' to 'port'
void outp(uint8_t HighLow);
// read byte from 'port'
uint8_t inp(void);
// 1-Wire Timing Generation
// Pause for exactly 'tick' number of ticks = 0.25us
void tickDelay(uint16_t tick); // Implementation is platform specific
//-----------------------------------------------------------------------------
// Set the 1-Wire timing to 'standard' (standard=1) or 'overdrive' (standard=0).
//
/* Private functions ---------------------------------------------------------*/
void tickDelay(uint16_t tick)
{
delay_us(tick);
}
void RTC_IO_Config(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
/* LED Port/Pin initialization */
PORT_Init(RTC_IO_CLK_PORT, RTC_IO_CLK_PIN, &stcPortInit);
PORT_Init(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN, &stcPortInit);
PORT_Init(RTC_IO_RST_PORT, RTC_IO_RST_PIN, &stcPortInit);
PORT_ResetBits(RTC_IO_CLK_PORT, RTC_IO_CLK_PIN);
PORT_ResetBits(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN);
PORT_ResetBits(RTC_IO_RST_PORT, RTC_IO_RST_PIN);
}
void rtc_dat_config(uint8_t inout)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
if (inout == 1)
{
// Output
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
PORT_ResetBits(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN);
PORT_Init(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN, &stcPortInit);
}
else
{
// Input
stcPortInit.enPinMode = Pin_Mode_In;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Disable;
PORT_Init(RTC_IO_DAT_PORT, RTC_IO_DAT_PIN, &stcPortInit);
}
}
void outp(uint8_t HighLow)
{
if (HighLow) RTC_DAT_HIGH;
else RTC_DAT_LOW;
}
uint8_t inp(void)
{
return RTC_DAT_IN;
}
void write_ds1302_byte(uint8_t cmd)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
outp((cmd >> i) & 0x01);
delay_ns(Tcl);
RTC_CLK_HIGH;
delay_ns(Tch);
RTC_CLK_LOW;
}
}
void write_ds1302(uint8_t cmd, uint8_t data)
{
rtc_dat_config(1);
RTC_RST_HIGH;
delay_ns(Tcc);
write_ds1302_byte(cmd);
write_ds1302_byte(data);
RTC_RST_LOW;
delay_ns(Tcwh);
}
uint8_t read_ds1302(uint8_t cmd)
{
uint8_t data = 0;
rtc_dat_config(1);
if (cmd == 0)
cmd = cmd;
RTC_RST_HIGH;
delay_ns(Tcc - Tcl);
write_ds1302_byte(cmd);
rtc_dat_config(0);
for (int i = 0; i < 8; i++)
{
delay_ns(Tcdd);
data |= (inp() << i);
delay_ns(Tcl-Tcdd);
RTC_CLK_HIGH;
delay_ns(Tch);
RTC_CLK_LOW;
}
RTC_RST_LOW;
rtc_dat_config(1);
delay_ns(Tcwh);
return (data);
}
void rtc_init(void)
{
uint8_t x;
RTC_IO_Config();
RTC_RST_HIGH;
delay_ns(Tch);
RTC_CLK_LOW;
write_ds1302(0x8e, 0);
write_ds1302(0x90, 0xa6);
x = read_ds1302(0x81);
if ((x & 0x80) != 0)
write_ds1302(0x80, 0);
}
uint8_t bcd2byte(uint8_t bcd)
{
return ((bcd >> 4) * 10) + (bcd & 0x0F);
}
uint8_t byte2bcd(uint8_t byte)
{
return ((byte / 10) << 4) + (byte % 10);
}
void rtc_set_datetime(uint8_t *DateTime)
{
int i = 0;
write_ds1302(WR_ADDR_RTC_YEAR , byte2bcd(DateTime[i++]));
write_ds1302(WR_ADDR_RTC_MONTH, byte2bcd(DateTime[i++]));
write_ds1302(WR_ADDR_RTC_DATE , byte2bcd(DateTime[i++]));
write_ds1302(WR_ADDR_RTC_HOUR , byte2bcd(DateTime[i++]));
write_ds1302(WR_ADDR_RTC_MIN , byte2bcd(DateTime[i++]));
write_ds1302(WR_ADDR_RTC_SEC , byte2bcd(DateTime[i++]));
}
void rtc_get_datetime(uint8_t *DateTime)
{
int i = 0;
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_YEAR));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_MONTH));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_DATE));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_WDAY));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_HOUR));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_MIN));
DateTime[i++] = bcd2byte(read_ds1302(RD_ADDR_RTC_SEC));
}
uint8_t rtc_get_year(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_YEAR));
}
uint8_t rtc_get_month(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_MONTH));
}
uint8_t rtc_get_date(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_DATE));
}
uint8_t rtc_get_wday(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_WDAY));
}
uint8_t rtc_get_hour(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_HOUR));
}
uint8_t rtc_get_min(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_MIN));
}
uint8_t rtc_get_sec(void)
{
return bcd2byte(read_ds1302(RD_ADDR_RTC_SEC));
}
void rtc_get_date1(uint8_t *day, uint8_t *mth, uint8_t *year, uint8_t *dow)
{
*day = read_ds1302(0x87);
*mth = read_ds1302(0x89);
*year = read_ds1302(0x8d);
*dow = read_ds1302(0x8b);
}
void rtc_get_time(uint8_t *hr, uint8_t *min, uint8_t *sec)
{
*hr = read_ds1302(0x85);
*min = read_ds1302(0x83);
*sec = read_ds1302(0x81);
}
void rtc_write_nvr(uint8_t address, uint8_t data)
{
write_ds1302((address << 1) | 0xc0, data);
}
uint8_t rtc_read_nvr(uint8_t address)
{
return (read_ds1302((address << 1) | 0xc1));
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,55 @@
/**
******************************************************************************
* @file rtc_io.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the realtime clock functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef _RTC_IO_H_
#define _RTC_IO_H_
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void rtc_init(void);
void rtc_set_datetime(uint8_t *DateTime);
void rtc_get_datetime(uint8_t *DateTime);
uint8_t rtc_get_year(void);
uint8_t rtc_get_month(void);
uint8_t rtc_get_date(void);
uint8_t rtc_get_wday(void);
uint8_t rtc_get_hour(void);
uint8_t rtc_get_min(void);
uint8_t rtc_get_sec(void);
void rtc_write_nvr(uint8_t address, uint8_t data);
uint8_t rtc_read_nvr(uint8_t address);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,232 @@
/**
******************************************************************************
* @file spi.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the code of the spi communication.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "spi.h"
#include "console.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* SPI1 Configuration */
/* SPI_SCK Port/Pin definition */
#define SPI1_SCK_PORT (PortC)
#define SPI1_SCK_PIN (Pin12)
#define SPI1_SCK_FUNC (Func_Spi1_Sck)
/* SPI_MOSI Port/Pin definition */
#define SPI1_MOSI_PORT (PortD)
#define SPI1_MOSI_PIN (Pin02)
#define SPI1_MOSI_FUNC (Func_Spi1_Mosi)
/* SPI_MISO Port/Pin definition */
#define SPI1_MISO_PORT (PortD)
#define SPI1_MISO_PIN (Pin01)
#define SPI1_MISO_FUNC (Func_Spi1_Miso)
/* SPI3 Configuration */
/* SPI_SCK Port/Pin definition */
#define SPI3_SCK_PORT (PortB)
#define SPI3_SCK_PIN (Pin13)
#define SPI3_SCK_FUNC (Func_Spi3_Sck)
/* SPI_MOSI Port/Pin definition */
#define SPI3_MOSI_PORT (PortB)
#define SPI3_MOSI_PIN (Pin15)
#define SPI3_MOSI_FUNC (Func_Spi3_Mosi)
/* SPI_MISO Port/Pin definition */
#define SPI3_MISO_PORT (PortB)
#define SPI3_MISO_PIN (Pin14)
#define SPI3_MISO_FUNC (Func_Spi3_Miso)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//Following is the SPI module initialization code, and configured to master mode
//SPI port initialization
//Needle is SPI1 initialization
void Spi1_Config(void)
{
stc_spi_init_t stcSpiInit;
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Enable;
/* SPI Port/Pin initialization */
PORT_Init(SPI1_MISO_PORT, SPI1_MISO_PIN, &stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
PORT_Init(SPI1_MOSI_PORT, SPI1_MOSI_PIN, &stcPortInit);
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcSpiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(SPI1_UNIT_CLOCK, Enable);
/* Configuration SPI pin */
PORT_SetFunc(SPI1_SCK_PORT, SPI1_SCK_PIN, SPI1_SCK_FUNC, Disable);
PORT_SetFunc(SPI1_MOSI_PORT, SPI1_MOSI_PIN, SPI1_MOSI_FUNC, Disable);
PORT_SetFunc(SPI1_MISO_PORT, SPI1_MISO_PIN, SPI1_MISO_FUNC, Disable);
/* Configuration SPI structure */
stcSpiInit.enClkDiv = SpiClkDiv64;
stcSpiInit.enFrameNumber = SpiFrameNumber1;
stcSpiInit.enDataLength = SpiDataLengthBit8;
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
stcSpiInit.enSckPolarity = SpiSckIdleLevelLow;
stcSpiInit.enSckPhase = SpiSckOddSampleEvenChange;
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
stcSpiInit.enWorkMode = SpiWorkMode3Line;
stcSpiInit.enTransMode = SpiTransFullDuplex;
stcSpiInit.enCommAutoSuspendEn = Disable;
stcSpiInit.enModeFaultErrorDetectEn = Disable;
stcSpiInit.enParitySelfDetectEn = Disable;
stcSpiInit.enParityEn = Disable;
stcSpiInit.enParity = SpiParityEven;
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
SPI_Init(SPI1_UNIT, &stcSpiInit);
SPI_Cmd(SPI1_UNIT, Enable);
}
//Following is the SPI module initialization code, and configured to master mode
//SPI port initialization
//Needle is SPI3 initialization
void Spi3_Config(void)
{
stc_spi_init_t stcSpiInit;
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
stcPortInit.enExInt = Disable;
stcPortInit.enPullUp = Enable;
/* SPI Port/Pin initialization */
PORT_Init(SPI3_MISO_PORT, SPI3_MISO_PIN, &stcPortInit);
stcPortInit.enPinMode = Pin_Mode_In;
PORT_Init(SPI3_MOSI_PORT, SPI3_MOSI_PIN, &stcPortInit);
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcSpiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);
/* Configuration SPI pin */
PORT_SetFunc(SPI3_SCK_PORT, SPI3_SCK_PIN, SPI3_SCK_FUNC, Disable);
PORT_SetFunc(SPI3_MOSI_PORT, SPI3_MOSI_PIN, SPI3_MOSI_FUNC, Disable);
PORT_SetFunc(SPI3_MISO_PORT, SPI3_MISO_PIN, SPI3_MISO_FUNC, Disable);
/* Configuration SPI structure */
stcSpiInit.enClkDiv = SpiClkDiv2;
stcSpiInit.enFrameNumber = SpiFrameNumber1;
stcSpiInit.enDataLength = SpiDataLengthBit8;
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
stcSpiInit.enSckPolarity = SpiSckIdleLevelLow;
stcSpiInit.enSckPhase = SpiSckOddSampleEvenChange;
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
stcSpiInit.enWorkMode = SpiWorkMode3Line;
stcSpiInit.enTransMode = SpiTransFullDuplex;
stcSpiInit.enCommAutoSuspendEn = Disable;
stcSpiInit.enModeFaultErrorDetectEn = Disable;
stcSpiInit.enParitySelfDetectEn = Disable;
stcSpiInit.enParityEn = Disable;
stcSpiInit.enParity = SpiParityEven;
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
SPI_Init(SPI3_UNIT, &stcSpiInit);
SPI_Cmd(SPI3_UNIT, Enable);
}
/**
*******************************************************************************
** \brief SPI3 flash write byte function
**
** \param [in] u8Data SPI write data to flash
**
** \retval uint8_t SPI receive data from flash
**
******************************************************************************/
uint8_t Spi3Flash_WriteReadByte(uint8_t u8Data)
{
uint8_t u8Byte = 0;
/* Wait tx buffer empty */
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty))
{
}
/* Send data */
SPI_SendData8(SPI3_UNIT, u8Data);
/* Wait rx buffer full */
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagReceiveBufferFull))
{
}
/* Receive data */
u8Byte = SPI_ReceiveData8(SPI3_UNIT);
return u8Byte;
}
// SPI1 read and write bytes
// TxData: the bytes to write
// Return value: reads a byte
uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{
while (Reset == SPI_GetFlag(SPI1_UNIT, SpiFlagSendBufferEmpty)) { }//Waiting to be sent
SPI_SendData8(SPI1_UNIT, TxData);
while (Reset == SPI_GetFlag(SPI1_UNIT, SpiFlagReceiveBufferFull)) {}
return SPI_ReceiveData8(SPI1_UNIT); //Returned by SPIx recently received data
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* @file spi.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the spi communication.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS3
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SPI_H
#define __SPI_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
/* Exported types ------------------------------------------------------------*/
/* Exported defines ----------------------------------------------------------*/
/* SPI_NSS Port/Pin definition */
#define SPI1_NSS_PORT (PortD)
#define SPI1_NSS_PIN (Pin00)
#define SPI1_NSS_HIGH() (PORT_SetBits(SPI1_NSS_PORT, SPI1_NSS_PIN))
#define SPI1_NSS_LOW() (PORT_ResetBits(SPI1_NSS_PORT, SPI1_NSS_PIN))
#define SPI3_NSS_PORT (PortB)
#define SPI3_NSS_PIN (Pin12)
#define SPI3_NSS_HIGH() (PORT_SetBits(SPI3_NSS_PORT, SPI3_NSS_PIN))
#define SPI3_NSS_LOW() (PORT_ResetBits(SPI3_NSS_PORT, SPI3_NSS_PIN))
/* SPI unit and clock definition */
#define SPI1_UNIT (M4_SPI1)
#define SPI1_UNIT_CLOCK (PWC_FCG1_PERIPH_SPI1)
#define SPI3_UNIT (M4_SPI3)
#define SPI3_UNIT_CLOCK (PWC_FCG1_PERIPH_SPI3)
/* FLASH parameters */
#define FLASH_PAGE_SIZE (0x100u)
#define FLASH_SECTOR_SIZE (0x1000u)
#define FLASH_MAX_ADDR (0x800000ul)
#define FLASH_DUMMY_BYTE_VALUE (0xffu)
#define FLASH_BUSY_BIT_MASK (0x01u)
/* FLASH instruction */
#define FLASH_INSTR_WRITE_ENABLE (0x06u)
#define FLASH_INSTR_PAGE_PROGRAM (0x02u)
#define FLASH_INSTR_STANDARD_READ (0x03u)
#define FLASH_INSTR_ERASE_4KB_SECTOR (0x20u)
#define FLASH_INSTR_READ_SR1 (0x05u)
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void Spi1_Config(void);
void Spi3_Config(void);
uint8_t Spi3Flash_WriteReadByte(uint8_t u8Data); //SPI bus read/write bytes
uint8_t SPI1_ReadWriteByte(uint8_t TxData);
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,341 @@
/**
******************************************************************************
* @file usart.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the codes of the usart comm. functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
#include <includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#ifdef CONSOLE_DEBUG
/* USART channel definition */
#define DEBUG_CH (M4_USART1)
/* USART baudrate definition */
#define DEBUG_BAUDRATE (115200ul)
/* USART RX Port/Pin definition */
#define DEBUG_RX_PORT (PortA)
#define DEBUG_RX_PIN (Pin10)
#define DEBUG_RX_FUNC (Func_Usart1_Rx)
/* USART TX Port/Pin definition */
#define DEBUG_TX_PORT (PortA)
#define DEBUG_TX_PIN (Pin09)
#define DEBUG_TX_FUNC (Func_Usart1_Tx)
/* USART interrupt number */
#define DEBUG_RI_NUM (INT_USART1_RI)
#define DEBUG_EI_NUM (INT_USART1_EI)
#define DEBUG_TI_NUM (INT_USART1_TI)
#define DEBUG_TCI_NUM (INT_USART1_TCI)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void debug_port_init(void);
void DebugRxIrqCallback(void); //Serial port 1 interrupt service routine
void DebugTxIrqCallback(void); //Serial port 1 interrupt service routine
void DebugErrIrqCallback(void);
void DebugTxCmpltIrqCallback(void);
#endif /* CONSOLE_DEBUG */
/* Private functions ---------------------------------------------------------*/
/**
*******************************************************************************
** \brief Re-target fputc function.
**
** \param [in] ch
** \param [in] f
**
** \retval int32_t
**
******************************************************************************/
int32_t fputc(int32_t ch, FILE *f)
{
(void)f; /* Prevent unused argument compilation warning */
#ifdef CONSOLE_DEBUG
Debug_PutChar(ch);
#endif // #ifdef CONSOLE_DEBUG
return ch;
}
#ifdef CONSOLE_DEBUG
UART1_Info Uart1;
//Initializes IO serial port 1
//Bound: baud rate
void debug_usart_init(void)
{
en_result_t enRet = Ok;
stc_irq_regi_conf_t stcIrqRegiCfg;
const stc_usart_uart_init_t stcInitCfg = {
UsartIntClkCkNoOutput,
UsartClkDiv_1,
UsartDataBits8,
UsartDataLsbFirst,
UsartOneStopBit,
UsartParityNone,
UsartSampleBit8,
UsartStartBitFallEdge,
UsartRtsEnable,
};
debug_port_init();
/* Initialize UART */
enRet = USART_UART_Init(DEBUG_CH, &stcInitCfg);
if (enRet != Ok)
{
while (1)
{
}
}
/* Set baudrate */
enRet = USART_SetBaudrate(DEBUG_CH, DEBUG_BAUDRATE);
if (enRet != Ok)
{
while (1)
{
}
}
/* Set USART RX IRQ */
stcIrqRegiCfg.enIRQn = Int000_IRQn;
stcIrqRegiCfg.pfnCallback = &DebugRxIrqCallback;
stcIrqRegiCfg.enIntSrc = DEBUG_RI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART RX error IRQ */
stcIrqRegiCfg.enIRQn = Int001_IRQn;
stcIrqRegiCfg.pfnCallback = &DebugErrIrqCallback;
stcIrqRegiCfg.enIntSrc = DEBUG_EI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART TX IRQ */
stcIrqRegiCfg.enIRQn = Int002_IRQn;
stcIrqRegiCfg.pfnCallback = &DebugTxIrqCallback;
stcIrqRegiCfg.enIntSrc = DEBUG_TI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART TX complete IRQ */
stcIrqRegiCfg.enIRQn = Int003_IRQn;
stcIrqRegiCfg.pfnCallback = &DebugTxCmpltIrqCallback;
stcIrqRegiCfg.enIntSrc = DEBUG_TCI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/*Enable RX && RX interupt function*/
USART_FuncCmd(DEBUG_CH, UsartRx, Enable);
// USART_FuncCmd(DEBUG_CH, UsartTx, Enable);
USART_FuncCmd(DEBUG_CH, UsartRxInt, Enable);
// USART_FuncCmd(DEBUG_CH, UsartTxAndTxEmptyInt, Enable);
}
void debug_port_init(void)
{
uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \
PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
/* Enable peripheral clock */
PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);
/* Initialize USART IO */
PORT_SetFunc(DEBUG_RX_PORT, DEBUG_RX_PIN, DEBUG_RX_FUNC, Disable);
PORT_SetFunc(DEBUG_TX_PORT, DEBUG_TX_PIN, DEBUG_TX_FUNC, Disable);
}
/**
*******************************************************************************
** \brief Debug RX irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
void DebugRxIrqCallback(void) //Serial port 1 interrupt service routine
{
uint8_t rx_data;
if (Set == USART_GetStatus(DEBUG_CH, UsartRxNoEmpty)) {
rx_data = USART_RecData(DEBUG_CH) & 0xFF; /* Read one byte from the receive data register. */
Uart1.RxBuf[Uart1.RxInPos++] = rx_data;
Uart1.RxInPos %= UART1_RX_BUFFER_SIZE;
if (Uart1.RxInPos == Uart1.RxOutPos) {
Uart1.RxOutPos++;
Uart1.RxOutPos %= UART1_RX_BUFFER_SIZE;
}
}
NVIC_ClearPendingIRQ(Int000_IRQn);
}
/**
*******************************************************************************
** \brief Debug RX error irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void DebugErrIrqCallback(void)
{
if (Set == USART_GetStatus(DEBUG_CH, UsartFrameErr))
{
USART_ClearStatus(DEBUG_CH, UsartFrameErr);
}
if (Set == USART_GetStatus(DEBUG_CH, UsartParityErr))
{
USART_ClearStatus(DEBUG_CH, UsartParityErr);
}
if (Set == USART_GetStatus(DEBUG_CH, UsartOverrunErr))
{
USART_ClearStatus(DEBUG_CH, UsartOverrunErr);
}
NVIC_ClearPendingIRQ(Int001_IRQn);
}
void DebugTxIrqCallback(void) //Serial port 1 interrupt service routine
{
if (Set == USART_GetStatus(DEBUG_CH, UsartTxEmpty)) {
/* Write one byte to the transmit data register */
USART_SendData(DEBUG_CH, Uart1.TxBuf[Uart1.TxOutPos++]);
Uart1.TxOutPos %= UART1_TX_BUFFER_SIZE;
if (Uart1.TxOutPos == Uart1.TxInPos) {
/* Disable the USART1 Transmit interrupt */
USART_FuncCmd(DEBUG_CH, UsartTxEmptyInt, Disable);
USART_FuncCmd(DEBUG_CH, UsartTxCmpltInt, Enable);
}
}
NVIC_ClearPendingIRQ(Int002_IRQn);
}
/**
*******************************************************************************
** \brief USART TX complete irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void DebugTxCmpltIrqCallback(void)
{
USART_FuncCmd(DEBUG_CH, UsartTxCmpltInt, Disable);
USART_FuncCmd(DEBUG_CH, UsartTx, Disable);
NVIC_ClearPendingIRQ(Int003_IRQn);
}
/*******************************************************************************
* Function Name : void UART1_PutChar(char data)
* Description : Send 1 byte via UART1
* Parameters : ASCII code
* Return : None
*******************************************************************************/
void Debug_PutChar(const uint8_t ascii)
{
CPU_SR_ALLOC();
while (((Uart1.TxInPos + 1)% UART1_TX_BUFFER_SIZE) == (Uart1.TxOutPos % UART1_TX_BUFFER_SIZE)) {
USART_FuncCmd(DEBUG_CH, UsartTxAndTxEmptyInt, Enable);
}
CPU_CRITICAL_ENTER();
Uart1.TxBuf[Uart1.TxInPos++] = ascii;
Uart1.TxInPos %= UART1_TX_BUFFER_SIZE;
USART_FuncCmd(DEBUG_CH, UsartTxAndTxEmptyInt, Enable);
CPU_CRITICAL_EXIT();
}
/*******************************************************************************
* Function Name : uint8_t UART1_GetChar(char *data)
* Description : Send 1 byte data to UART1 transmit buffer
* Parameters : none
* Return : Transmission result (0: buffer empty, 1: buffer has data)
*******************************************************************************/
int Debug_GetChar(uint8_t *data)
{
if (Uart1.RxInPos != Uart1.RxOutPos) {
data[0] = Uart1.RxBuf[Uart1.RxOutPos];
Uart1.RxOutPos++;
Uart1.RxOutPos %= UART1_RX_BUFFER_SIZE;
return 1;
}
else
return 0;
}
/*******************************************************************************
* Function Name : uint8_t UART1_GetChar(char *data)
* Description : Send 1 byte data to UART1 transmit buffer
* Parameters : none
* Return : Transmission result (0: buffer empty, 1: buffer has data)
*******************************************************************************/
uint8_t UART1_GC(void)
{
uint8_t result = 0;
if (Uart1.RxInPos != Uart1.RxOutPos)
{
result = Uart1.RxBuf[Uart1.RxOutPos];
Uart1.RxOutPos++;
Uart1.RxOutPos %= UART1_RX_BUFFER_SIZE;
}
return result;
}
#endif // #ifdef CONSOLE_DEBUG
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,60 @@
/**
******************************************************************************
* @file usart.h
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 07-Feb-2022
* @brief This file provides all the headers of the usart comm. functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2022 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS2
* @{
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H
#define __USART_H
/* Includes ------------------------------------------------------------------*/
#include "hc32_ddl.h"
#ifdef CONSOLE_DEBUG
/* Defines -------------------------------------------------------------------*/
#define UART1_TX_BUFFER_SIZE 1024
#define UART1_RX_BUFFER_SIZE 128
/* Type declarations ---------------------------------------------------------*/
typedef struct{
uint16_t RxInPos, RxOutPos;
uint16_t TxInPos, TxOutPos;
uint8_t RxBuf[UART1_RX_BUFFER_SIZE];
uint8_t TxBuf[UART1_TX_BUFFER_SIZE];
} UART1_Info;
void debug_usart_init(void);
//void uart1_init(uint32_t bound);
int Debug_GetChar(uint8_t *data);
void Debug_PutChar(const uint8_t ascii);
//void UART1_PutStr(uint8_t *str, uint16_t len);
//void UART1_printf(const char *fmt,...);
uint8_t UART1_GC(void);
#endif /* CONSOLE_DEBUG */
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,349 @@
/**
******************************************************************************
* File Name : w25qxx.c
* Description : This file provides code for the configuration
* of w25qxx configuration.
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "spi.h"
#include "w25qxx.h"
#include "delay.h"
#include "usart.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint16_t W25QXX_TYPE = W25Q128; // The default is W25Q128
uint8_t W25QXX_BUFFER[4096];
/* Private function prototypes -----------------------------------------------*/
en_result_t SpiFlash_WaitForWriteEnd(void);
/* Private functions ---------------------------------------------------------*/
// 4Kbytes to a Sector
// 16 slices for 1 Block
// W25Q40 : Capacity of 512K bytes, and a total of 16 Block, 128 Sector
// W25Q128: Capacity of 16M bytes, and a total of 128 Block, 4096 Sector
//Initializes IO port SPI FLASH
void W25QXX_Init(void)
{
stc_port_init_t stcPortInit;
/* configure structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
PORT_Init(SPI3_NSS_PORT, SPI3_NSS_PIN, &stcPortInit);
SPI3_NSS_HIGH();
Spi3_Config();
W25QXX_TYPE = W25QXX_ReadID(); // Read FLASH ID.
}
// The status register read W25QXX
// BIT7 6 5 4 3 2 1 0
// SPR RV TB BP2 BP1 BP0 WEL BUSY
// SPR:Default 0, the State Register protection, used with WP
// TB,BP2,BP1,BP0:FLASH write-protect setting
// WEL: write lock
// BUSY: busy flag bits (1, busy; 0, idle)
// Default:0x00
uint8_t W25QXX_ReadSR(void)
{
uint8_t byte = 0;
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_ReadStatusReg); // Sends a read status register command
byte = Spi3Flash_WriteReadByte(FLASH_DUMMY_BYTE_VALUE); // Read a byte
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle));
SPI3_NSS_HIGH();
return byte;
}
// Write W25QXX status register
// Only the SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)You can write!!!
void W25QXX_Write_SR(uint8_t sr)
{
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_WriteStatusReg); // Sending of taking the State register command
Spi3Flash_WriteReadByte(sr); // Writes a byte
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle));
SPI3_NSS_HIGH();
W25QXX_Wait_Busy(); //Waiting to be written to the end
}
//W25QXX write enable
//WEL is set
void W25QXX_Write_Enable(void)
{
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_WriteEnable); // Send written
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle));
SPI3_NSS_HIGH(); // Cancel selected
}
//W25QXX write protect
//WEL reset
void W25QXX_Write_Disable(void)
{
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_WriteDisable); // Send written
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle));
SPI3_NSS_HIGH(); // Cancel selected
}
//Read the chip ID
//Return values are as follows:
//0XEF13,Chip and the model is W25Q80
//0XEF14,Chip and the model is W25Q16
//0XEF15,Chip and the model is W25Q32
//0XEF16,Chip and the model is W25Q64
//0XEF17,Chip and the model is W25Q128
uint16_t W25QXX_ReadID(void)
{
uint16_t Temp = 0;
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(0x90);//Send the read ID command
Spi3Flash_WriteReadByte(0x00);
Spi3Flash_WriteReadByte(0x00);
Spi3Flash_WriteReadByte(0x00);
Temp|=Spi3Flash_WriteReadByte(0xFF)<<8;
Temp|=Spi3Flash_WriteReadByte(0xFF);
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle))
{
}
SPI3_NSS_HIGH();
return Temp;
}
//Read SPI FLASH
//Starting at the specified address reads the specified length of data
//pBuffer:The data store
//ReadAddr:Read start address(24bit)
//NumByteToRead:Number of bytes to read(Max 65535)
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
uint16_t i;
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_ReadData); //Send read commands
Spi3Flash_WriteReadByte((uint8_t)((ReadAddr)>>16)); //Send 24bit
Spi3Flash_WriteReadByte((uint8_t)((ReadAddr)>>8));
Spi3Flash_WriteReadByte((uint8_t)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=Spi3Flash_WriteReadByte(0XFF); //Cycle readings
}
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle))
{
}
SPI3_NSS_HIGH();
}
//SPI in one page (0~65535) written in less than 256 bytes of data
//Start write up to 256 bytes of data at the specified address
//pBuffer:The data store
//WriteAddr:Start writing the address (24bit)
//NumByteToWrite:Number of bytes to be written (up to 256), this number should not exceed the number of remaining bytes of the page!!!
void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t i;
W25QXX_Write_Enable(); //SET WEL
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_PageProgram); //Send a written page command
Spi3Flash_WriteReadByte((uint8_t)((WriteAddr)>>16)); //Send 24bit
Spi3Flash_WriteReadByte((uint8_t)((WriteAddr)>>8));
Spi3Flash_WriteReadByte((uint8_t)WriteAddr);
for(i=0;i<NumByteToWrite;i++)Spi3Flash_WriteReadByte(pBuffer[i]);//Circulating wrote
SPI3_NSS_HIGH(); //Cancel selected
W25QXX_Wait_Busy(); //Waiting to be written to the end
}
//No test write SPI FLASH
//Must ensure that writes all the data in the range of addresses to 0XFF, or write data in non-0XFF will fail!
//With automatic feed function
//Starting at the specified address to write to the specified length of data, but make sure that the address is out of range!
//pBuffer:The data store
//WriteAddr:Start write address(24bit)
//NumByteToWrite:Number of bytes to write(Max 65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t pageremain;
pageremain=256-WriteAddr%256; //Number of bytes remaining single page
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//Less than 256 bytes
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;//Write end
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //Minus has written a number of bytes
if(NumByteToWrite>256)pageremain=256; //Once you can write to 256 bytes
else pageremain=NumByteToWrite; //Less than 256 bytes
}
};
}
//Write SPI FLASH
//Starting at the specified address to write to the specified length of data
//This function erases the operation!
//pBuffer:The data store
//WriteAddr:Start write address(24bit)
//NumByteToWrite:Number of bytes to write(Max 65535)
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;//Sector address
secoff=WriteAddr%4096;//In the sector of migration
secremain=4096-secoff;//Slice the remaining space
//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//Testing
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//Not greater than 4,096 bytes
while(1)
{
WDT_RefreshCounter();
W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//Read out the contents of an entire sector
for(i=0;i<secremain;i++)//Calibration data
{
if(W25QXX_BUF[secoff+i]!=0XFF)break;//Need to erase
}
if(i<secremain)//Need to erase
{
W25QXX_Erase_Sector(secpos);//Erase this sector
for(i=0;i<secremain;i++) //Copy
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//Write the whole sector
}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//Writing has been erased, write directly to the sector the remaining interval.
if(NumByteToWrite==secremain)break;//Write end
else//Write over
{
secpos++;//Increased sector address 1
secoff=0;//Offset is 0
pBuffer+=secremain; //Offset pointer
WriteAddr+=secremain;//Write the address offset
NumByteToWrite-=secremain; //Diminishing bytes
if(NumByteToWrite>4096)secremain=4096; //Next sector but still not finished
else secremain=NumByteToWrite; //Next slice to finish
}
};
}
//Erase the entire chip
//Wait for long...
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_ChipErase); //Send erase command
SPI3_NSS_HIGH(); //Cancel selected
W25QXX_Wait_Busy(); //Wait for end of the chip erase
}
//Erase one sector
//Dst_Addr:Sector address set according to actual capacity
//Erasing a mountain at least time: 150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{
//Monitor Falsh erasure, testing
// printf("fe:%x\r\n",Dst_Addr);
Dst_Addr*=4096;
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_SectorErase); //Send sector erase command
Spi3Flash_WriteReadByte((uint8_t)((Dst_Addr)>>16)); //Send 24bit
Spi3Flash_WriteReadByte((uint8_t)((Dst_Addr)>>8));
Spi3Flash_WriteReadByte((uint8_t)Dst_Addr);
SPI3_NSS_HIGH(); //Cancel selected
W25QXX_Wait_Busy(); //Wait for the erase to complete
}
//Waiting for a free
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR() & 0x01) == 0x01); // Wait for the BUSY emptying
}
//Enter the power off mode
void W25QXX_PowerDown(void)
{
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_PowerDown); //Send the power command
SPI3_NSS_HIGH(); //Cancel selected
delay_us(3); //Wait for the TPD
}
//Wake up
void W25QXX_WAKEUP(void)
{
SPI3_NSS_LOW(); // Enabling devices
Spi3Flash_WriteReadByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
SPI3_NSS_HIGH(); //Cancel selected
delay_us(3); //Waiting for TRES1
}
/**
*******************************************************************************
** \brief SPI flash wait for write operation end function
**
** \param [in] None
**
** \retval Ok Flash internal operation finish
** \retval ErrorTimeout Flash internal operation timeout
**
******************************************************************************/
en_result_t SpiFlash_WaitForWriteEnd(void)
{
en_result_t enRet = Ok;
uint8_t u8Status = 0u;
uint32_t u32Timeout;
stc_clk_freq_t stcClkFreq;
CLK_GetClockFreq(&stcClkFreq);
u32Timeout = stcClkFreq.sysclkFreq / 1000u;
SPI3_NSS_LOW();
Spi3Flash_WriteReadByte(FLASH_INSTR_READ_SR1);
do
{
u8Status = Spi3Flash_WriteReadByte(FLASH_DUMMY_BYTE_VALUE);
u32Timeout--;
} while ((u32Timeout != 0ul) &&
((u8Status & FLASH_BUSY_BIT_MASK) == FLASH_BUSY_BIT_MASK));
if (FLASH_BUSY_BIT_MASK == u8Status)
{
enRet = ErrorTimeout;
}
while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle))
{
}
SPI3_NSS_HIGH();
return enRet;
}
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/

View File

@@ -0,0 +1,80 @@
#ifndef __W25QXX_H
#define __W25QXX_H
#include "hc32_ddl.h"
//////////////////////////////////////////////////////////////////////////////////
//This program is for educational purposes only, without the author's permission, may not be used for any other purpose
//ALIENTEK STM32F4 Explorer Board
//W25QXX Driver code
//Hot Atomic @ALIENTEK
//Forum: www.openedv.com
//Date modified: 2014/5/6
//Version: V1.0
//All rights reserved pirated reserved.
//Copyright(C) Guangzhou wing electronic technology limited company 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//W25X/Q series chip list
//W25Q80 ID 0XEF13
//W25Q16 ID 0XEF14
//W25Q32 ID 0XEF15
//W25Q64 ID 0XEF16
//W25Q128 ID 0XEF17
#define W25Q40 0XEF12
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
#define SPI_FLASH_ADDR (0x00000000)
#define SPI_FLASH_LAST_64K_BLOCK (0x00070000)
#define SPI_FLASH_LAST_32K_BLOCK (0x00078000)
#define SPI_FLASH_LAST_4K_SECTOR (0x0007F000)
#define SPI_FLASH_BLOCK_SIZE (0X10000)
#define SPI_FLASH_SECTOR_SIZE (0X1000)
#define SPI_FLASH_PAGESIZE (0x100) // 256 bytes
#define FLASH_DUMMY_BYTE_VALUE (0xffu)
#define FLASH_BUSY_BIT_MASK (0x01u)
extern uint16_t W25QXX_TYPE; //Define W25QXX chips
//////////////////////////////////////////////////////////////////////////////////
//Instruction list
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
void W25QXX_Init(void);
uint16_t W25QXX_ReadID(void); //Read FLASH ID
uint8_t W25QXX_ReadSR(void); //Read status register
void W25QXX_Write_SR(uint8_t sr); //Write status register
void W25QXX_Write_Enable(void); //Write enable
void W25QXX_Write_Disable(void); //Write-protect
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead); //Read Flash
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//Write Flash
void W25QXX_Erase_Chip(void); //All erase
void W25QXX_Erase_Sector(uint32_t Dst_Addr); //Sector erase
void W25QXX_Wait_Busy(void); //Waiting for a free
void W25QXX_PowerDown(void); //Enter the power off mode
void W25QXX_WAKEUP(void); //Wake up
#endif
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/