Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:f06ed53310a3, committed 2018-02-07
- Comitter:
- APS_Lab
- Date:
- Wed Feb 07 08:26:04 2018 +0000
- Child:
- 1:4dd3e328a30b
- Commit message:
- Ver1.0;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Wed Feb 07 08:26:04 2018 +0000 @@ -0,0 +1,4 @@ +.build +.mbed +projectfiles +*.py*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC6811.cpp Wed Feb 07 08:26:04 2018 +0000
@@ -0,0 +1,449 @@
+/*
+ LTC6811-1: Multicell Battery Monitor
+ LTC6811.cpp
+*/
+
+#include "mbed.h"
+#include "LTC681x.h"
+#include "LTC6811.h"
+
+
+void LTC6811_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=12;
+ ic[cic].ic_reg.stat_channels=4;
+ ic[cic].ic_reg.aux_channels=6;
+ ic[cic].ic_reg.num_cv_reg=4;
+ ic[cic].ic_reg.num_gpio_reg=2;
+ ic[cic].ic_reg.num_stat_reg=3;
+ }
+}
+
+/*
+Starts cell voltage conversion
+*/
+void LTC6811_adcv(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP, //Discharge Permit
+ uint8_t CH //Cell Channels to be measured
+)
+{
+ LTC681x_adcv(MD,DCP,CH);
+}
+
+//Starts cell voltage and SOC conversion
+void LTC6811_adcvsc(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ LTC681x_adcvsc(MD,DCP);
+}
+
+// Starts cell voltage and GPIO 1&2 conversion
+void LTC6811_adcvax(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ LTC681x_adcvax(MD,DCP);
+}
+
+//Starts cell voltage overlap conversion
+void LTC6811_adol(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ LTC681x_adol(MD,DCP);
+}
+
+//Starts cell voltage self test conversion
+void LTC6811_cvst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ LTC681x_cvst(MD,ST);
+}
+
+//Start an Auxiliary Register Self Test Conversion
+void LTC6811_axst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ LTC681x_axst(MD,ST);
+}
+
+//Start a Status Register Self Test Conversion
+void LTC6811_statst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ LTC681x_statst(MD,ST);
+}
+
+//Sends the poll adc command
+uint8_t LTC6811_pladc()
+{
+ return(LTC681x_pladc());
+}
+
+//This function will block operation until the ADC has finished it's conversion
+uint32_t LTC6811_pollAdc()
+{
+ return(LTC681x_pollAdc());
+}
+
+//Start a GPIO and Vref2 Conversion
+void LTC6811_adax(
+ uint8_t MD, //ADC Mode
+ uint8_t CHG //GPIO Channels to be measured)
+)
+{
+ LTC681x_adax(MD,CHG);
+}
+
+//Start an GPIO Redundancy test
+void LTC6811_adaxd(
+ uint8_t MD, //ADC Mode
+ uint8_t CHG //GPIO Channels to be measured)
+)
+{
+ LTC681x_adaxd(MD,CHG);
+}
+
+//Start a Status ADC Conversion
+void LTC6811_adstat(
+ uint8_t MD, //ADC Mode
+ uint8_t CHST //GPIO Channels to be measured
+)
+{
+ LTC681x_adstat(MD,CHST);
+}
+
+// Start a Status register redundancy test Conversion
+void LTC6811_adstatd(
+ uint8_t MD, //ADC Mode
+ uint8_t CHST //GPIO Channels to be measured
+)
+{
+ LTC681x_adstatd(MD,CHST);
+}
+
+
+// Start an open wire Conversion
+void LTC6811_adow(
+ uint8_t MD, //ADC Mode
+ uint8_t PUP //Discharge Permit
+)
+{
+ LTC681x_adow(MD,PUP);
+}
+
+// Reads and parses the LTC6811 cell voltage registers.
+uint8_t LTC6811_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);
+}
+
+/*
+ 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 aux_codes variable
+*/
+int8_t LTC6811_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;
+ LTC681x_rdaux(reg,total_ic,ic);
+ return (pec_error);
+}
+
+/*
+ Reads and parses the LTC6811 stat registers.
+ The function is used
+ to read the parsed stat codes of the LTC6811. This function will send the requested
+ read commands parse the data and store the stat voltages in stat_codes variable
+*/
+int8_t LTC6811_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);
+}
+
+/*
+ The command clears the cell voltage registers and intiallizes
+ all values to 1. The register will read back hexadecimal 0xFF
+ after the command is sent.
+*/
+void LTC6811_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 LTC6811_clraux()
+{
+ LTC681x_clraux();
+}
+
+/*
+ The command clears the Stat registers and intiallizes
+ all values to 1. The register will read back hexadecimal 0xFF
+ after the command is sent.
+
+*/
+void LTC6811_clrstat()
+{
+ LTC681x_clrstat();
+}
+
+/*
+ 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 LTC6811_clrsctrl()
+{
+ LTC681x_clrsctrl();
+}
+
+//Starts the Mux Decoder diagnostic self test
+void LTC6811_diagn()
+{
+ LTC681x_diagn();
+}
+
+/*
+ This command will write the configuration registers of the LTC6811-1s
+ connected in a daisy chain stack. The configuration is written in descending
+ order so the last device's configuration is written first.
+*/
+void LTC6811_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);
+}
+
+
+/*
+Reads configuration registers of a LTC6811 daisy chain
+*/
+int8_t LTC6811_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 = LTC681x_rdcfg(total_ic,ic);
+ return(pec_error);
+}
+
+/*
+Writes the pwm registers of a LTC6811 daisy chain
+*/
+void LTC6811_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 LTC6811 daisy chain
+*/
+int8_t LTC6811_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 the COMM registers of a LTC6811 daisy chain
+*/
+void LTC6811_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 LTC6811 daisy chain
+*/
+int8_t LTC6811_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 LTC6811 SPI/I2C port
+*/
+void LTC6811_stcomm()
+{
+ LTC681x_stcomm();
+}
+
+//Helper function to set discharge bit in CFG register
+void LTC6811_set_discharge(int Cell, uint8_t total_ic, cell_asic ic[])
+{
+ for (int i=0; i<total_ic; i++)
+ {
+ 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));
+ }
+ }
+}
+
+// Runs the Digital Filter Self Test
+int16_t LTC6811_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic ic[])
+{
+ int16_t error = 0;
+ error = LTC681x_run_cell_adc_st(adc_reg,total_ic,ic);
+ return(error);
+}
+
+//runs the redundancy self test
+int16_t LTC6811_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);
+}
+//Runs the datasheet algorithm for open wire
+void LTC6811_run_openwire(uint8_t total_ic, cell_asic ic[])
+{
+ LTC681x_run_openwire(total_ic,ic);
+}
+// Runs the ADC overlap test for the IC
+uint16_t LTC6811_run_adc_overlap(uint8_t total_ic, cell_asic ic[])
+{
+ uint16_t error = 0;
+ LTC681x_run_adc_overlap(total_ic, ic);
+ return(error);
+}
+
+void LTC6811_max_min(uint8_t total_ic, cell_asic ic_cells[],
+ cell_asic ic_min[],
+ cell_asic ic_max[],
+ cell_asic ic_delta[])
+{
+ for (int j=0; j < total_ic; j++)
+ {
+ for (int i = 0; i< 12; i++)
+ {
+ if (ic_cells[j].cells.c_codes[i]>ic_max[j].cells.c_codes[i])ic_max[j].cells.c_codes[i]=ic_cells[j].cells.c_codes[i];
+ else if (ic_cells[j].cells.c_codes[i]<ic_min[j].cells.c_codes[i])ic_min[j].cells.c_codes[i]=ic_cells[j].cells.c_codes[i];
+ ic_delta[j].cells.c_codes[i] = ic_max[j].cells.c_codes[i] - ic_min[j].cells.c_codes[i];
+ }
+ }
+
+
+
+
+}
+
+void LTC6811_init_max_min(uint8_t total_ic, cell_asic ic[],cell_asic ic_max[],cell_asic ic_min[])
+{
+ for (int j=0; j < total_ic; j++)
+ {
+ for (int i = 0; i< ic[j].ic_reg.cell_channels; i++)
+ {
+ ic_max[j].cells.c_codes[i]=0;
+ ic_min[j].cells.c_codes[i]=0xFFFF;
+ }
+ }
+
+}
+
+//Helper function that increments PEC counters
+void LTC6811_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 LTC6811_reset_crc_count(uint8_t total_ic, cell_asic ic[])
+{
+ LTC681x_reset_crc_count(total_ic,ic);
+}
+
+//Helper function to intialize CFG variables.
+void LTC6811_init_cfg(uint8_t total_ic, cell_asic ic[])
+{
+ LTC681x_init_cfg(total_ic,ic);
+}
+//Helper function to set CFGR variable
+void LTC6811_set_cfgr(uint8_t nIC, cell_asic ic[], bool refon, bool adcopt, bool gpio[5],bool dcc[12])
+{
+ LTC681x_set_cfgr_refon(nIC,ic,refon);
+ LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
+ LTC681x_set_cfgr_gpio(nIC,ic,gpio);
+ LTC681x_set_cfgr_dis(nIC,ic,dcc);
+}
+//Helper function to set the REFON bit
+void LTC6811_set_cfgr_refon(uint8_t nIC, cell_asic ic[], bool refon)
+{
+ LTC681x_set_cfgr_refon(nIC,ic,refon);
+}
+//Helper function to set the adcopt bit
+void LTC6811_set_cfgr_adcopt(uint8_t nIC, cell_asic ic[], bool adcopt)
+{
+ LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
+}
+//Helper function to set GPIO bits
+void LTC6811_set_cfgr_gpio(uint8_t nIC, cell_asic ic[],bool gpio[5])
+{
+ LTC681x_set_cfgr_gpio(nIC,ic,gpio);
+}
+//Helper function to control discharge
+void LTC6811_set_cfgr_dis(uint8_t nIC, cell_asic ic[],bool dcc[12])
+{
+ LTC681x_set_cfgr_dis(nIC,ic,dcc);
+}
+//Helper Function to set uv value in CFG register
+void LTC6811_set_cfgr_uv(uint8_t nIC, cell_asic ic[],uint16_t uv)
+{
+ LTC681x_set_cfgr_uv(nIC, ic, uv);
+}
+//helper function to set OV value in CFG register
+void LTC6811_set_cfgr_ov(uint8_t nIC, cell_asic ic[],uint16_t ov)
+{
+ LTC681x_set_cfgr_ov( nIC, ic, ov);
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LTC6811.h Wed Feb 07 08:26:04 2018 +0000 @@ -0,0 +1,352 @@ +/* + LTC6811-1: Multicell Battery Monitor + LTC6811.h +*/ + +#ifndef LTC6811_H +#define LTC6811_H + +#include "mbed.h" +//#include <stdint.h> +#include "LTC681x.h" + +#define CELL 1 +#define AUX 2 +#define STAT 3 + + + +void LTC6811_init_reg_limits(uint8_t total_ic, cell_asic ic[]); + + +/*! 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 LTC6811_diagn(); + + +//! 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 LTC6811_pladc(); + + +//! 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 LTC6811_pollAdc(); + +/*! Starts cell voltage conversion +*/ +void LTC6811_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 LTC6811_adcvax( + uint8_t MD, //!< ADC Conversion Mode + uint8_t DCP //!< Controls if Discharge is permitted during conversion +); + + +/*! Starts cell voltage self test conversion +*/ +void LTC6811_cvst( + uint8_t MD, //!< ADC Conversion Mode + uint8_t ST //!< Self Test Mode +); + +/*! Starts cell voltage and SOC conversion +*/ +void LTC6811_adcvsc( + uint8_t MD, //!< ADC Conversion Mode + uint8_t DCP //!< Controls if Discharge is permitted during conversion +); +/*! Starts cell voltage overlap conversion +*/ +void LTC6811_adol( + uint8_t MD, //!< ADC Conversion Mode + uint8_t DCP //!< Discharge permitted during conversion +); + +/*! Start an open wire Conversion +*/ +void LTC6811_adow( + uint8_t MD, //!< ADC Conversion Mode + uint8_t PUP //!< Controls if Discharge is permitted during conversion +); + + +/*! Start a GPIO and Vref2 Conversion +*/ +void LTC6811_adax( + uint8_t MD, //!< ADC Conversion Mode + uint8_t CHG //!< Sets which GPIO channels are converted +); + +/*! Start an GPIO Redundancy test +*/ +void LTC6811_adaxd( + uint8_t MD, //!< ADC Conversion Mode + uint8_t CHG //!< Sets which GPIO channels are converted +); + +/*! Start an Auxiliary Register Self Test Conversion +*/ +void LTC6811_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 LTC6811_adstat( + uint8_t MD, //!< ADC Conversion Mode + uint8_t CHST //!< Sets which Stat channels are converted +); + +/*! Start a Status register redundancy test Conversion +*/ +void LTC6811_adstatd( + uint8_t MD, //!< ADC Mode + uint8_t CHST //!< Sets which Status channels are converted +); + + +/*! Start a Status Register Self Test Conversion +*/ +void LTC6811_statst( + uint8_t MD, //!< ADC Conversion Mode + uint8_t ST //!< Sets if self test 1 or 2 is run +); + +/*! Reads and parses the LTC6811 cell voltage registers. + + @return int8_t, PEC Status. + 0: No PEC error detected + -1: PEC error detected, retry read +*/ +uint8_t LTC6811_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. + ); + + + +/*! Reads and parses the LTC6811 auxiliary registers. +@return int8_t, PEC Status + 0: No PEC error detected + -1: PEC error detected, retry read +*/ +int8_t LTC6811_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 LTC6811 stat registers. + +@return int8_t, PEC Status + 0: No PEC error detected + -1: PEC error detected, retry read +*/ +int8_t LTC6811_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[] + ); + +/*! Clears the LTC6811 cell voltage registers +*/ +void LTC6811_clrcell(); + +/*! Clears the LTC6811 Auxiliary registers +*/ +void LTC6811_clraux(); + +/*! Clears the LTC6811 Stat registers +*/ +void LTC6811_clrstat(); + +/*! Clears the LTC6811 Sctrl registers +*/ +void LTC6811_clrsctrl(); + +/*! Write the LTC6811 configuration register +*/ +void LTC6811_wrcfg(uint8_t nIC, //!< The number of ICs being written + cell_asic ic[] //!< a two dimensional array of the configuration data that will be written + ); + +void LTC6811_wrcfgb(uint8_t nIC, //!< The number of ICs being written + cell_asic ic[] //!< a two dimensional array of the configuration data that will be written + ); +/*! Reads configuration registers of a LTC6811 daisy chain +@return int8_t, PEC Status. + 0: Data read back has matching PEC + -1: Data read back has incorrect PEC +*/ +int8_t LTC6811_rdcfg(uint8_t nIC, //!< number of ICs in the daisy chain + cell_asic ic[] //!< a two dimensional array that the function stores the read configuration data + ); + +int8_t LTC6811_rdcfgb(uint8_t nIC, //!< number of ICs in the daisy chain + cell_asic ic[] //!< a two dimensional array that the function stores the read configuration data + ); +/*! Write the LTC6811 PWM register +*/ +void LTC6811_wrpwm(uint8_t nIC, //!< number of ICs in the daisy chain + uint8_t pwmReg, + cell_asic ic[] + ); + +/*! Reads pwm registers of a LTC6811 daisy chain + +*/ +int8_t LTC6811_rdpwm(uint8_t nIC, //!< number of ICs in the daisy chain + uint8_t pwmReg, + cell_asic ic[] //!< a two dimensional array that the function stores the read pwm data + ); + +/*! Write the LTC6811 Sctrl register +*/ +void LTC6811_wrsctrl(uint8_t nIC, //!< number of ICs in the daisy chain + uint8_t sctrl_reg, + cell_asic ic[] + ); + + +/*! Reads sctrl registers of a LTC6811 daisy chain +@return int8_t, PEC Status. + 0: Data read back has matching PEC + -1: Data read back has incorrect PEC +*/ +int8_t LTC6811_rdsctrl(uint8_t nIC, //!< 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 + ); + + +/*! Start Sctrl data communication +This command will start the sctrl pulse communication over the spins +*/ +void LTC6811_stsctrl(); + + +/*! Write the LTC6811 COMM register +*/ +void LTC6811_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 LTC6811 daisy chain +@return int8_t, PEC Status. + + 0: Data read back has matching PEC + + -1: Data read back has incorrect PEC + +*/ +int8_t LTC6811_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 */ +void LTC6811_stcomm(); + + +/*! @returns returns the register data pattern for a given ADC MD and Self test */ +uint16_t LTC6811_st_lookup( + uint8_t MD, //!< ADC Conversion Mode + uint8_t ST //!< Self test number +); + +void LTC6811_set_discharge(int Cell, + uint8_t total_ic, + cell_asic ic[]); + +/*! Helper function that runs the ADC Self Tests*/ +int16_t LTC6811_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 LTC6811_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 LTC6811_run_openwire(uint8_t total_ic, + cell_asic ic[]); + +void LTC6811_set_discharge(int Cell, + uint8_t total_ic, + cell_asic ic[]); + +/*! Helper Function that runs the ADC Overlap test*/ +uint16_t LTC6811_run_adc_overlap(uint8_t total_ic, + cell_asic ic[]); + +/*! Helper Function that counts overall PEC errors and register/IC PEC errors*/ +void LTC6811_check_pec(uint8_t total_ic, + uint8_t reg, + cell_asic ic[]); + +/*! Helper Function that resets the PEC error counters */ +void LTC6811_reset_crc_count(uint8_t total_ic, + cell_asic ic[]); + +/*! Helper Function to initialize the CFGR data structures*/ +void LTC6811_init_cfg(uint8_t total_ic, + cell_asic ic[]); + +/*! Helper function to set appropriate bits in CFGR register based on bit function*/ +void LTC6811_set_cfgr(uint8_t nIC, + cell_asic ic[], + bool refon, + bool adcopt, + bool gpio[5], + bool dcc[12]); + +/*! Helper function to turn the refon bit HIGH or LOW*/ +void LTC6811_set_cfgr_refon(uint8_t nIC, + cell_asic ic[], + bool refon); + +/*! Helper function to turn the ADCOPT bit HIGH or LOW*/ +void LTC6811_set_cfgr_adcopt(uint8_t nIC, + cell_asic ic[], + bool adcopt); + +/*! Helper function to turn the GPIO bits HIGH or LOW*/ +void LTC6811_set_cfgr_gpio(uint8_t nIC, + cell_asic ic[], + bool gpio[]); + +/*! Helper function to turn the DCC bits HIGH or LOW*/ +void LTC6811_set_cfgr_dis(uint8_t nIC, + cell_asic ic[], + bool dcc[]); +/*! Helper function to set uv field in CFGRA register*/ +void LTC6811_set_cfgr_uv(uint8_t nIC, + cell_asic ic[], + uint16_t uv); + +/*! Helper function to set ov field in CFGRA register*/ +void LTC6811_set_cfgr_ov(uint8_t nIC, + cell_asic ic[], + uint16_t ov); + +void LTC6811_init_max_min(uint8_t total_ic, + cell_asic ic[], + cell_asic ic_max[], + cell_asic ic_min[]); + +void LTC6811_max_min(uint8_t total_ic, cell_asic ic_cells[], + cell_asic ic_min[], + cell_asic ic_max[], + cell_asic ic_delta[]); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC681x.cpp Wed Feb 07 08:26:04 2018 +0000
@@ -0,0 +1,1469 @@
+/*
+ General BMS Library
+ LTC681x.cpp
+*/
+
+#include "mbed.h"
+
+#include "LTC681x.h"
+#include "bms.h"
+//#include "LT_SPI.h"
+
+
+void wakeup_idle(uint8_t total_ic)
+{
+ for (int i =0; i<total_ic; i++) {
+ //spi2_CS = 0;
+// wait_ms(2); //Guarantees the isoSPI will be in ready mode
+ spi_read_byte(0xff);
+ //spi2_CS = 1;
+ }
+}
+
+//Generic wakeup commannd to wake the LTC6813 from sleep
+void wakeup_sleep(uint8_t total_ic)
+{
+ for (int i =0; i<total_ic; i++) {
+ //spi2_CS = 0;
+ delay_u(300); // Guarantees the LTC6813 will be in standby
+ //spi2_CS = 1;
+ delay_u(10);
+ }
+}
+
+//Generic function to write 68xx commands. Function calculated PEC for tx_cmd data
+void cmd_68(uint8_t tx_cmd[2])
+{
+ uint8_t cmd[4];
+ uint16_t cmd_pec;
+// uint8_t md_bits;
+
+ cmd[0] = tx_cmd[0];
+ cmd[1] = tx_cmd[1];
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+ //spi2_CS = 0;
+ spi_write_array(4,cmd);
+ //spi2_CS = 1;
+}
+
+//Generic function to write 68xx commands and write payload data. Function calculated PEC for tx_cmd data
+void write_68(uint8_t total_ic , uint8_t tx_cmd[2], uint8_t data[])
+{
+ const uint8_t BYTES_IN_REG = 6;
+ const uint8_t CMD_LEN = 4+(8*total_ic);
+ uint8_t *cmd;
+ uint16_t data_pec;
+ uint16_t cmd_pec;
+ uint8_t cmd_index;
+
+ cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
+ cmd[0] = tx_cmd[0];
+ cmd[1] = tx_cmd[1];
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+ cmd_index = 4;
+ for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) { // executes for each LTC681x in daisy chain, this loops starts with
+ // the last IC on the stack. The first configuration written is
+ // received by the last IC in the daisy chain
+
+ for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
+ cmd[cmd_index] = data[((current_ic-1)*6)+current_byte];
+ cmd_index = cmd_index + 1;
+ }
+
+ data_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &data[(current_ic-1)*6]); // calculating the PEC for each Iss configuration register data
+ cmd[cmd_index] = (uint8_t)(data_pec >> 8);
+ cmd[cmd_index + 1] = (uint8_t)data_pec;
+ cmd_index = cmd_index + 2;
+ }
+
+
+ //spi2_CS = 0;
+ spi_write_array(CMD_LEN, cmd);
+ //spi2_CS = 1;
+ free(cmd);
+}
+
+//Generic function to write 68xx commands and read data. Function calculated PEC for tx_cmd data
+int8_t read_68( uint8_t total_ic, uint8_t tx_cmd[2], uint8_t *rx_data)
+{
+ const uint8_t BYTES_IN_REG = 8;
+ uint8_t cmd[4];
+ uint8_t data[256];
+ int8_t pec_error = 0;
+ uint16_t cmd_pec;
+ uint16_t data_pec;
+ uint16_t received_pec;
+
+ // data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t)); // This is a problem because it can fail
+
+ cmd[0] = tx_cmd[0];
+ cmd[1] = tx_cmd[1];
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+
+
+ //spi2_CS = 0;
+ spi_write_read(cmd, 4, data, (BYTES_IN_REG*total_ic)); //Read the configuration data of all ICs on the daisy chain into
+ //spi2_CS = 1; //rx_data[] array
+
+ for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) { //executes for each LTC681x in the daisy chain and packs the data
+ //into the r_comm array as well as check the received Config data
+ //for any bit errors
+ for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
+ rx_data[(current_ic*8)+current_byte] = data[current_byte + (current_ic*BYTES_IN_REG)];
+ }
+ received_pec = (rx_data[(current_ic*8)+6]<<8) + rx_data[(current_ic*8)+7];
+ data_pec = pec15_calc(6, &rx_data[current_ic*8]);
+ if (received_pec != data_pec) {
+ pec_error = -1;
+ }
+ }
+
+
+ return(pec_error);
+}
+
+
+/*
+ Calculates and returns the CRC15
+ */
+uint16_t pec15_calc(uint8_t len, //Number of bytes that will be used to calculate a PEC
+ uint8_t *data //Array of data that will be used to calculate a PEC
+ )
+{
+ uint16_t remainder,addr;
+
+ remainder = 16;//initialize the PEC
+ for (uint8_t i = 0; i<len; i++) { // loops for each byte in data array
+ addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
+//#ifdef MBED
+ remainder = (remainder<<8)^crc15Table[addr];
+//#else
+// remainder = (remainder<<8)^pgm_read_word_near(crc15Table+addr);
+//#endif
+ }
+ return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
+}
+
+//Starts cell voltage conversion
+void LTC681x_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);
+}
+
+
+//Starts cell voltage and SOC conversion
+void LTC681x_adcvsc(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ 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 | (DCP<<4) | 0x07;
+ cmd_68(cmd);
+
+}
+
+// Starts cell voltage and GPIO 1&2 conversion
+void LTC681x_adcvax(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ 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 | ((DCP&0x01)<<4) + 0x6F;
+ cmd_68(cmd);
+}
+
+//Starts cell voltage overlap conversion
+void LTC681x_adol(
+ uint8_t MD, //ADC Mode
+ uint8_t DCP //Discharge Permit
+)
+{
+ 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 + (DCP<<4) +0x01;
+ cmd_68(cmd);
+}
+
+//Starts cell voltage self test conversion
+void LTC681x_cvst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ uint8_t cmd[2];
+ uint8_t md_bits;
+
+ md_bits = (MD & 0x02) >> 1;
+ cmd[0] = md_bits + 0x02;
+ md_bits = (MD & 0x01) << 7;
+ cmd[1] = md_bits + ((ST)<<5) +0x07;
+ cmd_68(cmd);
+
+}
+
+//Start an Auxiliary Register Self Test Conversion
+void LTC681x_axst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ 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 + ((ST&0x03)<<5) +0x07;
+ cmd_68(cmd);
+
+}
+
+//Start a Status Register Self Test Conversion
+void LTC681x_statst(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ uint8_t cmd[2];
+ uint8_t md_bits;
+
+ md_bits = (MD & 0x02) >> 1;
+ cmd[0] = md_bits + 0x04;
+ md_bits = (MD & 0x01) << 7;
+ cmd[1] = md_bits + ((ST&0x03)<<5) +0x0F;
+ cmd_68(cmd);
+
+}
+
+//Sends the poll adc command
+uint8_t LTC681x_pladc()
+{
+ uint8_t cmd[4];
+ uint8_t adc_state = 0xFF;
+ 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);
+
+
+ //spi2_CS = 0;
+ spi_write_array(4,cmd);
+// adc_state = spi_read_byte(0xFF);
+ //spi2_CS = 1;
+ return(adc_state);
+}
+
+//This function will block operation until the ADC has finished it's conversion
+uint32_t LTC681x_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);
+
+ //spi2_CS = 0;
+ 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;
+ }
+ }
+ //spi2_CS = 1;
+
+
+ return(counter);
+}
+
+//Start a GPIO and Vref2 Conversion
+void LTC681x_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);
+
+}
+
+//Start an GPIO Redundancy test
+void LTC681x_adaxd(
+ 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 + CHG ;
+ cmd_68(cmd);
+}
+
+//Start a Status ADC Conversion
+void LTC681x_adstat(
+ uint8_t MD, //ADC Mode
+ uint8_t CHST //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 + 0x68 + CHST ;
+ cmd_68(cmd);
+}
+
+// Start a Status register redundancy test Conversion
+void LTC681x_adstatd(
+ uint8_t MD, //ADC Mode
+ uint8_t CHST //GPIO Channels to be measured
+)
+{
+ uint8_t cmd[2];
+ uint8_t md_bits;
+
+ md_bits = (MD & 0x02) >> 1;
+ cmd[0] = md_bits + 0x04;
+ md_bits = (MD & 0x01) << 7;
+ cmd[1] = md_bits + 0x08 + CHST ;
+ cmd_68(cmd);
+
+}
+
+
+// Start an open wire Conversion
+void LTC681x_adow(
+ uint8_t MD, //ADC Mode
+ uint8_t PUP //Discharge Permit
+)
+{
+ uint8_t cmd[2];
+ uint8_t md_bits;
+ md_bits = (MD & 0x02) >> 1;
+ cmd[0] = md_bits + 0x02;
+ md_bits = (MD & 0x01) << 7;
+ cmd[1] = md_bits + 0x28 + (PUP<<6) ;//+ CH;
+ cmd_68(cmd);
+}
+
+// Reads the raw cell voltage register data
+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
+ )
+{
+ const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
+ uint8_t cmd[4];
+ uint16_t cmd_pec;
+
+ if (reg == 1) { //1: RDCVA
+ cmd[1] = 0x04;
+ cmd[0] = 0x00;
+ } else if (reg == 2) { //2: RDCVB
+ cmd[1] = 0x06;
+ cmd[0] = 0x00;
+ } else if (reg == 3) { //3: RDCVC
+ cmd[1] = 0x08;
+ cmd[0] = 0x00;
+ } else if (reg == 4) { //4: RDCVD
+ cmd[1] = 0x0A;
+ cmd[0] = 0x00;
+ } else if (reg == 5) { //4: RDCVE
+ cmd[1] = 0x09;
+ cmd[0] = 0x00;
+ } else if (reg == 6) { //4: RDCVF
+ cmd[1] = 0x0B;
+ cmd[0] = 0x00;
+ }
+
+
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+
+ //spi2_CS = 0;
+ spi_write_read(cmd,4,data,(REG_LEN*total_ic));
+ //spi2_CS = 1;
+
+}
+
+//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)
+{
+
+ const uint8_t BYT_IN_REG = 6;
+ const uint8_t CELL_IN_REG = 3;
+ int8_t pec_error = 0;
+ uint16_t parsed_cell;
+ uint16_t received_pec;
+ uint16_t data_pec;
+ uint8_t data_counter = current_ic*NUM_RX_BYT; //data counter
+
+
+ for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) { // This loop parses the read back data into cell voltages, it
+ // loops once for each of the 3 cell voltage codes in the register
+
+ parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);//Each cell code is received as two bytes and is combined to
+ // create the parsed cell voltage code
+ cell_codes[current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
+ data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter
+ //must increment by two for each parsed cell code
+ }
+
+ received_pec = (cell_data[data_counter] << 8) | cell_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
+ //after the 6 cell voltage data bytes
+ data_pec = pec15_calc(BYT_IN_REG, &cell_data[(current_ic) * NUM_RX_BYT]);
+
+ if (received_pec != data_pec) {
+ pec_error = 1; //The pec_error variable is simply set negative if any PEC errors
+ ic_pec[cell_reg-1]=1;
+ } else {
+ ic_pec[cell_reg-1]=0;
+ }
+ data_counter=data_counter+2;
+ return(pec_error);
+}
+
+/*
+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 LTC6811_rdaux() 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
+ )
+{
+ const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
+ uint8_t cmd[4];
+ uint16_t cmd_pec;
+
+
+ if (reg == 1) { //Read back auxiliary group A
+ cmd[1] = 0x0C;
+ cmd[0] = 0x00;
+ } else if (reg == 2) { //Read back auxiliary group B
+ cmd[1] = 0x0e;
+ cmd[0] = 0x00;
+ } else if (reg == 3) { //Read back auxiliary group C
+ cmd[1] = 0x0D;
+ cmd[0] = 0x00;
+ } else if (reg == 4) { //Read back auxiliary group D
+ cmd[1] = 0x0F;
+ cmd[0] = 0x00;
+ } else { //Read back auxiliary group A
+ cmd[1] = 0x0C;
+ cmd[0] = 0x00;
+ }
+
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+
+ //spi2_CS = 0;
+ spi_write_read(cmd,4,data,(REG_LEN*total_ic));
+ //spi2_CS = 1;
+
+}
+
+/*
+The function reads a single stat register and stores the read data
+in the *data point as a byte array. This function is rarely used outside of
+the LTC6811_rdstat() 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
+ )
+{
+ const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
+ uint8_t cmd[4];
+ uint16_t cmd_pec;
+
+
+ if (reg == 1) { //Read back statiliary group A
+ cmd[1] = 0x10;
+ cmd[0] = 0x00;
+ } else if (reg == 2) { //Read back statiliary group B
+ cmd[1] = 0x12;
+ cmd[0] = 0x00;
+ }
+
+ else { //Read back statiliary group A
+ cmd[1] = 0x10;
+ cmd[0] = 0x00;
+ }
+
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+
+ //spi2_CS = 0;
+ spi_write_read(cmd,4,data,(REG_LEN*total_ic));
+ //spi2_CS = 1;
+
+}
+
+/*
+The command clears the cell voltage registers and intiallizes
+all values to 1. The register will read back hexadecimal 0xFF
+after the command is sent.
+*/
+void LTC681x_clrcell()
+{
+ uint8_t cmd[2]= {0x07 , 0x11};
+ cmd_68(cmd);
+}
+
+
+/*
+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()
+{
+ uint8_t cmd[2]= {0x07 , 0x12};
+ cmd_68(cmd);
+}
+
+
+/*
+The command clears the Stat registers and intiallizes
+all values to 1. The register will read back hexadecimal 0xFF
+after the command is sent.
+
+*/
+void LTC681x_clrstat()
+{
+ uint8_t cmd[2]= {0x07 , 0x13};
+ cmd_68(cmd);
+}
+/*
+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()
+{
+ uint8_t cmd[2]= {0x00 , 0x18};
+ cmd_68(cmd);
+}
+//Starts the Mux Decoder diagnostic self test
+void LTC681x_diagn()
+{
+ uint8_t cmd[2] = {0x07 , 0x15};
+ cmd_68(cmd);
+}
+
+//Reads and parses the LTC681x cell voltage registers.
+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
+ )
+{
+ int8_t pec_error = 0;
+ uint8_t *cell_data;
+ uint8_t c_ic = 0;
+ cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
+
+ if (reg == 0) {
+ for (uint8_t cell_reg = 1; cell_reg<ic[0].ic_reg.num_cv_reg+1; cell_reg++) { //executes once for each of the LTC6811 cell voltage registers
+ LTC681x_rdcv_reg(cell_reg, total_ic,cell_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 = pec_error + parse_cells(current_ic,cell_reg, cell_data,
+ &ic[c_ic].cells.c_codes[0],
+ &ic[c_ic].cells.pec_match[0]);
+ }
+ }
+ }
+
+ else {
+ LTC681x_rdcv_reg(reg, total_ic,cell_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 = pec_error + parse_cells(current_ic,reg, &cell_data[8*c_ic],
+ &ic[c_ic].cells.c_codes[0],
+ &ic[c_ic].cells.pec_match[0]);
+ }
+ }
+ LTC681x_check_pec(total_ic,CELL,ic);
+ free(cell_data);
+ return(pec_error);
+}
+
+
+
+/*
+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 aux_codes variable
+*/
+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[]//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 LTC6811 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_cells(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);
+}
+
+// Reads and parses the LTC681x stat registers.
+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[]
+ )
+
+{
+
+ const uint8_t BYT_IN_REG = 6;
+ const uint8_t GPIO_IN_REG = 3;
+
+ uint8_t *data;
+ uint8_t data_counter = 0;
+ int8_t pec_error = 0;
+ uint16_t parsed_stat;
+ uint16_t received_pec;
+ uint16_t data_pec;
+ uint8_t c_ic = 0;
+ data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
+
+ if (reg == 0) {
+
+ for (uint8_t stat_reg = 1; stat_reg< 3; stat_reg++) { //executes once for each of the LTC6811 stat voltage registers
+ data_counter = 0;
+ LTC681x_rdstat_reg(stat_reg, total_ic,data); //Reads the raw statiliary register data into the data[] array
+
+ for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6811 in the daisy chain
+ if (ic->isospi_reverse == false) {
+ c_ic = current_ic;
+ } else {
+ c_ic = total_ic - current_ic - 1;
+ }
+ // current_ic is used as the IC counter
+ if (stat_reg ==1) {
+ for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
+ // loops once for each of the 3 gpio voltage codes in the register
+
+ parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
+ ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
+ data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
+
+ }
+ } else if (stat_reg == 2) {
+ parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
+ data_counter = data_counter +2;
+ ic[c_ic].stat.stat_codes[3] = parsed_stat;
+ ic[c_ic].stat.flags[0] = data[data_counter++];
+ ic[c_ic].stat.flags[1] = data[data_counter++];
+ ic[c_ic].stat.flags[2] = data[data_counter++];
+ ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
+ ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
+ }
+
+ received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
+ //after the 6 gpio voltage data bytes
+ data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
+
+ if (received_pec != data_pec) {
+ pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
+ ic[c_ic].stat.pec_match[stat_reg-1]=1;
+ //are detected in the received serial data
+ } else {
+ ic[c_ic].stat.pec_match[stat_reg-1]=0;
+ }
+
+ data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
+ //must be incremented by 2 bytes to point to the next ICs gpio voltage data
+ }
+
+
+ }
+
+ } else {
+
+ LTC681x_rdstat_reg(reg, total_ic, data);
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6811 in the daisy chain
+ // current_ic is used as an IC counter
+ if (ic->isospi_reverse == false) {
+ c_ic = current_ic;
+ } else {
+ c_ic = total_ic - current_ic - 1;
+ }
+ if (reg ==1) {
+ for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
+ // loops once for each of the 3 gpio voltage codes in the register
+ parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
+ // create the parsed gpio voltage code
+
+ ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
+ data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
+ //must increment by two for each parsed gpio voltage code
+
+ }
+ } else if (reg == 2) {
+ parsed_stat = data[data_counter++] + (data[data_counter++]<<8); //Each gpio codes is received as two bytes and is combined to
+ ic[c_ic].stat.stat_codes[3] = parsed_stat;
+ ic[c_ic].stat.flags[0] = data[data_counter++];
+ ic[c_ic].stat.flags[1] = data[data_counter++];
+ ic[c_ic].stat.flags[2] = data[data_counter++];
+ ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
+ ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
+ }
+
+
+ received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
+ //after the 6 gpio voltage data bytes
+ data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
+ if (received_pec != data_pec) {
+ pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
+ ic[c_ic].stat.pec_match[reg-1]=1;
+
+ }
+
+ data_counter=data_counter+2;
+ }
+ }
+ LTC681x_check_pec(total_ic,STAT,ic);
+ free(data);
+ return (pec_error);
+}
+
+//Write the LTC681x CFGRA
+void LTC681x_wrcfg(uint8_t total_ic, //The number of ICs being written to
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2] = {0x00 , 0x01} ;
+ uint8_t write_buffer[256];
+ uint8_t write_count = 0;
+ uint8_t c_ic = 0;
+ 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;
+ }
+
+ for (uint8_t data = 0; data<6; data++) {
+ write_buffer[write_count] = ic[c_ic].config.tx_data[data];
+ write_count++;
+ }
+ }
+ write_68(total_ic, cmd, write_buffer);
+}
+
+//Write the LTC681x CFGRB
+void LTC681x_wrcfgb(uint8_t total_ic, //The number of ICs being written to
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2] = {0x00 , 0x24} ;
+ uint8_t write_buffer[256];
+ uint8_t write_count = 0;
+ uint8_t c_ic = 0;
+ 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;
+ }
+
+ for (uint8_t data = 0; data<6; data++) {
+ write_buffer[write_count] = ic[c_ic].configb.tx_data[data];
+ write_count++;
+ }
+ }
+ write_68(total_ic, cmd, write_buffer);
+}
+
+//Read CFGA
+int8_t LTC681x_rdcfg(uint8_t total_ic, //Number of ICs in the system
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2]= {0x00 , 0x02};
+ 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].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 CFGB
+int8_t LTC681x_rdcfgb(uint8_t total_ic, //Number of ICs in the system
+ cell_asic ic[]
+ )
+{
+ 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,CFGRB,ic);
+ return(pec_error);
+}
+
+//Looks up the result pattern for digital filter self test
+uint16_t LTC681x_st_lookup(
+ uint8_t MD, //ADC Mode
+ uint8_t ST //Self Test
+)
+{
+ uint16_t test_pattern = 0;
+ if (MD == 1) {
+ if (ST == 1) {
+ test_pattern = 0x9565;
+ } else {
+ test_pattern = 0x6A9A;
+ }
+ } else {
+ if (ST == 1) {
+ test_pattern = 0x9555;
+ } else {
+ test_pattern = 0x6AAA;
+ }
+ }
+ return(test_pattern);
+}
+
+//Clears all of the DCC bits in the configuration registers
+void clear_discharge(uint8_t total_ic, cell_asic ic[])
+{
+ for (int i=0; i<total_ic; i++) {
+ ic[i].config.tx_data[4] = 0;
+ ic[i].config.tx_data[5] = 0;
+ }
+}
+
+// Runs the Digital Filter Self Test
+int16_t LTC681x_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic ic[])
+{
+ int16_t error = 0;
+ uint16_t expected_result = 0;
+ for (int self_test = 1; self_test<3; self_test++) {
+
+ expected_result = LTC681x_st_lookup(2,self_test);
+ wakeup_idle(total_ic);
+ switch (adc_reg) {
+ case CELL:
+ wakeup_idle(total_ic);
+ LTC681x_clrcell();
+ LTC681x_cvst(2,self_test);
+ LTC681x_pollAdc();//this isn't working
+ wakeup_idle(total_ic);
+ error = LTC681x_rdcv(0, total_ic,ic);
+ for (int cic = 0; cic < total_ic; cic++) {
+ for (int channel=0; channel< ic[cic].ic_reg.cell_channels; channel++) {
+ if (ic[cic].cells.c_codes[channel] != expected_result) {
+ error = error+1;
+ }
+ }
+ }
+ break;
+ case AUX:
+ error = 0;
+ wakeup_idle(total_ic);
+ LTC681x_clraux();
+ LTC681x_axst(2,self_test);
+ LTC681x_pollAdc();
+ delay_m(10);
+ wakeup_idle(total_ic);
+ LTC681x_rdaux(0, total_ic,ic);
+ for (int cic = 0; cic < total_ic; cic++) {
+ for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
+ if (ic[cic].aux.a_codes[channel] != expected_result) {
+ error = error+1;
+ }
+ }
+ }
+ break;
+ case STAT:
+ wakeup_idle(total_ic);
+ LTC681x_clrstat();
+ LTC681x_statst(2,self_test);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ error = LTC681x_rdstat(0,total_ic,ic);
+ for (int cic = 0; cic < total_ic; cic++) {
+ for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
+ if (ic[cic].stat.stat_codes[channel] != expected_result) {
+ error = error+1;
+ }
+ }
+ }
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+ }
+ return(error);
+}
+
+//runs the redundancy self test
+int16_t LTC681x_run_adc_redundancy_st(uint8_t adc_mode, uint8_t adc_reg, uint8_t total_ic, cell_asic ic[])
+{
+ int16_t error = 0;
+ for (int self_test = 1; self_test<3; self_test++) {
+ wakeup_idle(total_ic);
+ switch (adc_reg) {
+ case AUX:
+ LTC681x_clraux();
+ LTC681x_adaxd(adc_mode,AUX_CH_ALL);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ error = LTC681x_rdaux(0, total_ic,ic);
+ for (int cic = 0; cic < total_ic; cic++) {
+ for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
+ if (ic[cic].aux.a_codes[channel] >= 65280) {
+ error = error+1;
+ }
+ }
+ }
+ break;
+ case STAT:
+ LTC681x_clrstat();
+ LTC681x_adstatd(adc_mode,STAT_CH_ALL);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ error = LTC681x_rdstat(0,total_ic,ic);
+ for (int cic = 0; cic < total_ic; cic++) {
+ for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
+ if (ic[cic].stat.stat_codes[channel] >= 65280) {
+ error = error+1;
+ }
+ }
+ }
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+ }
+ return(error);
+}
+
+//Runs the datasheet algorithm for open wire
+void LTC681x_run_openwire(uint8_t total_ic, cell_asic ic[])
+{
+ uint16_t OPENWIRE_THRESHOLD = 4000;
+ const uint8_t N_CHANNELS = ic[0].ic_reg.cell_channels;
+
+ cell_asic pullUp_cell_codes[total_ic];
+ cell_asic pullDwn_cell_codes[total_ic];
+ cell_asic openWire_delta[total_ic];
+ int8_t error;
+
+ wakeup_sleep(total_ic);
+ LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ error = LTC681x_rdcv(0, total_ic,pullUp_cell_codes);
+
+ wakeup_idle(total_ic);
+ LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
+ LTC681x_pollAdc();
+ wakeup_idle(total_ic);
+ error = LTC681x_rdcv(0, total_ic,pullDwn_cell_codes);
+
+ for (int cic=0; cic<total_ic; cic++) {
+ ic[cic].system_open_wire =0;
+ for (int cell=0; cell<N_CHANNELS; cell++) {
+ if (pullDwn_cell_codes[cic].cells.c_codes[cell]>pullUp_cell_codes[cic].cells.c_codes[cell]) {
+ openWire_delta[cic].cells.c_codes[cell] = pullDwn_cell_codes[cic].cells.c_codes[cell] - pullUp_cell_codes[cic].cells.c_codes[cell] ;
+ } else {
+ openWire_delta[cic].cells.c_codes[cell] = 0;
+ }
+
+ }
+ }
+ for (int cic=0; cic<total_ic; cic++) {
+ for (int cell=1; cell<N_CHANNELS; cell++) {
+
+ if (openWire_delta[cic].cells.c_codes[cell]>OPENWIRE_THRESHOLD) {
+ ic[cic].system_open_wire += (1<<cell);
+
+ }
+ }
+ if (pullUp_cell_codes[cic].cells.c_codes[0] == 0) {
+ ic[cic].system_open_wire += 1;
+ }
+ if (pullUp_cell_codes[cic].cells.c_codes[N_CHANNELS-1] == 0) {
+ ic[cic].system_open_wire += (1<<(N_CHANNELS));
+ }
+ }
+}
+
+// Runs the ADC overlap test for the IC
+uint16_t LTC681x_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;
+ wakeup_idle(total_ic);
+ LTC681x_adol(MD_7KHZ_3KHZ,DCP_DISABLED);
+ LTC681x_pollAdc();
+ 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));
+ }
+ }
+ return(error);
+}
+
+//Helper function that increments PEC counters
+void LTC681x_check_pec(uint8_t total_ic,uint8_t reg, cell_asic ic[])
+{
+ switch (reg) {
+ case CFGR:
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+ ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].config.rx_pec_match;
+ ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].config.rx_pec_match;
+ }
+ break;
+
+ case CFGRB:
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+ ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].configb.rx_pec_match;
+ ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].configb.rx_pec_match;
+ }
+ break;
+ case CELL:
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+ for (int i=0; i<ic[0].ic_reg.num_cv_reg; i++) {
+ ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].cells.pec_match[i];
+ ic[current_ic].crc_count.cell_pec[i] = ic[current_ic].crc_count.cell_pec[i] + ic[current_ic].cells.pec_match[i];
+ }
+ }
+ break;
+ case AUX:
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+ for (int i=0; i<ic[0].ic_reg.num_gpio_reg; i++) {
+ ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + (ic[current_ic].aux.pec_match[i]);
+ ic[current_ic].crc_count.aux_pec[i] = ic[current_ic].crc_count.aux_pec[i] + (ic[current_ic].aux.pec_match[i]);
+ }
+ }
+
+ break;
+ case STAT:
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+
+ for (int i=0; i<ic[0].ic_reg.num_stat_reg-1; i++) {
+ ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].stat.pec_match[i];
+ ic[current_ic].crc_count.stat_pec[i] = ic[current_ic].crc_count.stat_pec[i] + ic[current_ic].stat.pec_match[i];
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+//Helper Function to reset PEC counters
+void LTC681x_reset_crc_count(uint8_t total_ic, cell_asic ic[])
+{
+ for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
+ ic[current_ic].crc_count.pec_count = 0;
+ ic[current_ic].crc_count.cfgr_pec = 0;
+ for (int i=0; i<6; i++) {
+ ic[current_ic].crc_count.cell_pec[i]=0;
+
+ }
+ for (int i=0; i<4; i++) {
+ ic[current_ic].crc_count.aux_pec[i]=0;
+ }
+ for (int i=0; i<2; i++) {
+ ic[current_ic].crc_count.stat_pec[i]=0;
+ }
+ }
+}
+
+//Helper function to intialize CFG variables.
+void LTC681x_init_cfg(uint8_t total_ic, cell_asic ic[])
+{
+ bool REFON = true;
+ bool ADCOPT = false;
+ bool gpioBits[5] = {true,true,true,true,true};
+ bool dccBits[12] = {false,false,false,false,false,false,false,false,false,false,false,false};
+ 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;
+ }
+ LTC681x_set_cfgr(current_ic ,ic,REFON,ADCOPT,gpioBits,dccBits);
+
+ }
+}
+
+//Helper function to set CFGR variable
+void LTC681x_set_cfgr(uint8_t nIC, cell_asic ic[], bool refon, bool adcopt, bool gpio[5],bool dcc[12])
+{
+ LTC681x_set_cfgr_refon(nIC,ic,refon);
+ LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
+ LTC681x_set_cfgr_gpio(nIC,ic,gpio);
+ LTC681x_set_cfgr_dis(nIC,ic,dcc);
+}
+
+//Helper function to set the REFON bit
+void LTC681x_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 LTC681x_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 LTC681x_set_cfgr_gpio(uint8_t nIC, cell_asic ic[],bool gpio[5])
+{
+ for (int i =0; i<5; i++) {
+ if (gpio[i])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 LTC681x_set_cfgr_dis(uint8_t nIC, cell_asic ic[],bool dcc[12])
+{
+ for (int i =0; i<8; i++) {
+ if (dcc[i])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[i+8])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 uv value in CFG register
+void LTC681x_set_cfgr_uv(uint8_t nIC, cell_asic ic[],uint16_t uv)
+{
+ uint16_t tmp = (uv/16)-1;
+ ic[nIC].config.tx_data[1] = 0x00FF & tmp;
+ ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0xF0;
+ ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x0F00 & tmp)>>8);
+}
+
+//helper function to set OV value in CFG register
+void LTC681x_set_cfgr_ov(uint8_t nIC, cell_asic ic[],uint16_t ov)
+{
+ uint16_t tmp = (ov/16);
+ ic[nIC].config.tx_data[3] = 0x00FF & (tmp>>4);
+ ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0x0F;
+ ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x000F & tmp)<<4);
+}
+
+//Writes the comm register
+void LTC681x_wrcomm(uint8_t total_ic, //The number of ICs being written to
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2]= {0x07 , 0x21};
+ uint8_t write_buffer[256];
+ uint8_t write_count = 0;
+ uint8_t c_ic = 0;
+ 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;
+ }
+
+ for (uint8_t data = 0; data<6; data++) {
+ write_buffer[write_count] = ic[c_ic].com.tx_data[data];
+ write_count++;
+ }
+ }
+ write_68(total_ic, cmd, write_buffer);
+}
+
+/*
+Reads COMM registers of a LTC6811 daisy chain
+*/
+int8_t LTC681x_rdcomm(uint8_t total_ic, //Number of ICs in the system
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2]= {0x07 , 0x22};
+ 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].com.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].com.rx_pec_match = 1;
+ } else ic[c_ic].com.rx_pec_match = 0;
+ }
+ return(pec_error);
+}
+
+/*
+Shifts data in COMM register out over LTC6811 SPI/I2C port
+*/
+void LTC681x_stcomm()
+{
+
+ uint8_t cmd[4];
+ uint16_t cmd_pec;
+
+ cmd[0] = 0x07;
+ cmd[1] = 0x23;
+ cmd_pec = pec15_calc(2, cmd);
+ cmd[2] = (uint8_t)(cmd_pec >> 8);
+ cmd[3] = (uint8_t)(cmd_pec);
+
+ //spi2_CS = 0;
+ spi_write_array(4,cmd);
+ for (int i = 0; i<9; i++) {
+ spi_read_byte(0xFF);
+ }
+ //spi2_CS = 1;
+
+}
+
+// Writes the pwm register
+void LTC681x_wrpwm(uint8_t total_ic,
+ uint8_t pwmReg,
+ cell_asic ic[]
+ )
+{
+ uint8_t cmd[2];
+ uint8_t write_buffer[256];
+ uint8_t write_count = 0;
+ uint8_t c_ic = 0;
+ if (pwmReg == 0) {
+ cmd[0] = 0x00;
+ cmd[1] = 0x20;
+ } else {
+ 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;
+ }
+ for (uint8_t data = 0; data<6; data++) {
+ write_buffer[write_count] = ic[c_ic].pwm.tx_data[data];
+ write_count++;
+ }
+ }
+ write_68(total_ic, cmd, write_buffer);
+}
+
+
+/*
+Reads pwm registers of a LTC6811 daisy chain
+*/
+int8_t LTC681x_rdpwm(uint8_t total_ic, //Number of ICs in the system
+ uint8_t pwmReg,
+ cell_asic ic[]
+ )
+{
+// const uint8_t BYTES_IN_REG = 8;
+
+ 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;
+
+ if (pwmReg == 0) {
+ cmd[0] = 0x00;
+ cmd[1] = 0x22;
+ } else {
+ 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<8; byte++) {
+ ic[c_ic].pwm.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].pwm.rx_pec_match = 1;
+ } else ic[c_ic].pwm.rx_pec_match = 0;
+ }
+ return(pec_error);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC681x.h Wed Feb 07 08:26:04 2018 +0000
@@ -0,0 +1,580 @@
+/*
+ General BMS Library
+ LTC681x.h
+*/
+#ifndef LTC681X_H
+#define LTC681X_H
+
+#include "mbed.h"
+//#include <stdint.h>
+#include "bms.h"
+//#include "LT_SPI.h"
+
+//#define MBED
+//#ifdef MBED
+//#include "mbed.h"//remove when using with LINDUINO
+//#endif
+
+//#ifdef LINDUINO
+//#include <Arduino.h>
+//#endif
+
+//#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 10
+
+//! 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[9];//!< 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;
+
+
+
+
+/*! 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();
+
+//! 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 LTC681x_pladc();
+
+//! 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 LTC681x_pollAdc();
+
+/*! 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);
+
+/*! 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() 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() 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();
+/*! 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();
+
+/*! 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();
+
+/*! 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();
+
+/*! 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();
+
+/*! 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 register
+
+ 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.
+ );
+
+
+/*! Reads pwm registers of a LTC6811 daisy chain
+*/
+int8_t LTC681x_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[] //!< ASIC Variable
+ );
+
+/*! Write the LTC681x PWM register
+
+ This command will write the pwm registers of the LTC681x
+ connected in a daisy chain stack. The pwm is written in descending
+ order so the last device's pwm is written first.
+*/
+void LTC681x_wrpwm(uint8_t total_ic, //!< The number of ICs being written to
+ uint8_t pwmReg, //!< The PWM Register to be written
+ cell_asic ic[] //!< ASIC Variable
+ );
+
+/*! issues a stcomm command and clocks data out of the COMM register */
+void LTC681x_stcomm();
+
+/*! Reads comm registers of a LTC681x daisy chain
+*/
+int8_t LTC681x_rdcomm(uint8_t total_ic, //!< Number of ICs in the system
+ cell_asic ic[] //!< ASIC Variable
+ );
+
+/*! Write the LTC681x COMM register
+
+ This command will write the comm registers of the LTC681x
+ connected in a daisy chain stack. The comm is written in descending
+ order so the last device's configuration is written first.
+ */
+void LTC681x_wrcomm(uint8_t total_ic, //!< The number of ICs being written to
+ cell_asic ic[] ///!< ASIC Variable
+ );
+
+/*! 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 runs the ADC Overlap test*/
+uint16_t LTC681x_run_adc_overlap(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],
+ bool dcc[12]);
+
+/*! 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[],
+ bool dcc[]);
+/*! Helper function to set uv field in CFGRA register*/
+void LTC681x_set_cfgr_uv(uint8_t nIC,
+ cell_asic ic[],
+ uint16_t uv);
+
+/*! Helper function to set ov field in CFGRA register*/
+void LTC681x_set_cfgr_ov(uint8_t nIC,
+ cell_asic ic[],
+ uint16_t ov);
+
+
+
+//#ifdef MBED
+//This needs a PROGMEM = when using with a LINDUINO
+const uint16_t crc15Table[256] = {0x0,0xc599, 0xceab, 0xb32, 0xd8cf, 0x1d56, 0x1664, 0xd3fd, 0xf407, 0x319e, 0x3aac, //!<precomputed CRC15 Table
+ 0xff35, 0x2cc8, 0xe951, 0xe263, 0x27fa, 0xad97, 0x680e, 0x633c, 0xa6a5, 0x7558, 0xb0c1,
+ 0xbbf3, 0x7e6a, 0x5990, 0x9c09, 0x973b, 0x52a2, 0x815f, 0x44c6, 0x4ff4, 0x8a6d, 0x5b2e,
+ 0x9eb7, 0x9585, 0x501c, 0x83e1, 0x4678, 0x4d4a, 0x88d3, 0xaf29, 0x6ab0, 0x6182, 0xa41b,
+ 0x77e6, 0xb27f, 0xb94d, 0x7cd4, 0xf6b9, 0x3320, 0x3812, 0xfd8b, 0x2e76, 0xebef, 0xe0dd,
+ 0x2544, 0x2be, 0xc727, 0xcc15, 0x98c, 0xda71, 0x1fe8, 0x14da, 0xd143, 0xf3c5, 0x365c,
+ 0x3d6e, 0xf8f7,0x2b0a, 0xee93, 0xe5a1, 0x2038, 0x7c2, 0xc25b, 0xc969, 0xcf0, 0xdf0d,
+ 0x1a94, 0x11a6, 0xd43f, 0x5e52, 0x9bcb, 0x90f9, 0x5560, 0x869d, 0x4304, 0x4836, 0x8daf,
+ 0xaa55, 0x6fcc, 0x64fe, 0xa167, 0x729a, 0xb703, 0xbc31, 0x79a8, 0xa8eb, 0x6d72, 0x6640,
+ 0xa3d9, 0x7024, 0xb5bd, 0xbe8f, 0x7b16, 0x5cec, 0x9975, 0x9247, 0x57de, 0x8423, 0x41ba,
+ 0x4a88, 0x8f11, 0x57c, 0xc0e5, 0xcbd7, 0xe4e, 0xddb3, 0x182a, 0x1318, 0xd681, 0xf17b,
+ 0x34e2, 0x3fd0, 0xfa49, 0x29b4, 0xec2d, 0xe71f, 0x2286, 0xa213, 0x678a, 0x6cb8, 0xa921,
+ 0x7adc, 0xbf45, 0xb477, 0x71ee, 0x5614, 0x938d, 0x98bf, 0x5d26, 0x8edb, 0x4b42, 0x4070,
+ 0x85e9, 0xf84, 0xca1d, 0xc12f, 0x4b6, 0xd74b, 0x12d2, 0x19e0, 0xdc79, 0xfb83, 0x3e1a, 0x3528,
+ 0xf0b1, 0x234c, 0xe6d5, 0xede7, 0x287e, 0xf93d, 0x3ca4, 0x3796, 0xf20f, 0x21f2, 0xe46b, 0xef59,
+ 0x2ac0, 0xd3a, 0xc8a3, 0xc391, 0x608, 0xd5f5, 0x106c, 0x1b5e, 0xdec7, 0x54aa, 0x9133, 0x9a01,
+ 0x5f98, 0x8c65, 0x49fc, 0x42ce, 0x8757, 0xa0ad, 0x6534, 0x6e06, 0xab9f, 0x7862, 0xbdfb, 0xb6c9,
+ 0x7350, 0x51d6, 0x944f, 0x9f7d, 0x5ae4, 0x8919, 0x4c80, 0x47b2, 0x822b, 0xa5d1, 0x6048, 0x6b7a,
+ 0xaee3, 0x7d1e, 0xb887, 0xb3b5, 0x762c, 0xfc41, 0x39d8, 0x32ea, 0xf773, 0x248e, 0xe117, 0xea25,
+ 0x2fbc, 0x846, 0xcddf, 0xc6ed, 0x374, 0xd089, 0x1510, 0x1e22, 0xdbbb, 0xaf8, 0xcf61, 0xc453,
+ 0x1ca, 0xd237, 0x17ae, 0x1c9c, 0xd905, 0xfeff, 0x3b66, 0x3054, 0xf5cd, 0x2630, 0xe3a9, 0xe89b,
+ 0x2d02, 0xa76f, 0x62f6, 0x69c4, 0xac5d, 0x7fa0, 0xba39, 0xb10b, 0x7492, 0x5368, 0x96f1, 0x9dc3,
+ 0x585a, 0x8ba7, 0x4e3e, 0x450c, 0x8095
+ };
+
+//#else
+//const uint16_t crc15Table[256] PROGMEM = {0x0,0xc599, 0xceab, 0xb32, 0xd8cf, 0x1d56, 0x1664, 0xd3fd, 0xf407, 0x319e, 0x3aac, //!<precomputed CRC15 Table
+// 0xff35, 0x2cc8, 0xe951, 0xe263, 0x27fa, 0xad97, 0x680e, 0x633c, 0xa6a5, 0x7558, 0xb0c1,
+// 0xbbf3, 0x7e6a, 0x5990, 0x9c09, 0x973b, 0x52a2, 0x815f, 0x44c6, 0x4ff4, 0x8a6d, 0x5b2e,
+// 0x9eb7, 0x9585, 0x501c, 0x83e1, 0x4678, 0x4d4a, 0x88d3, 0xaf29, 0x6ab0, 0x6182, 0xa41b,
+// 0x77e6, 0xb27f, 0xb94d, 0x7cd4, 0xf6b9, 0x3320, 0x3812, 0xfd8b, 0x2e76, 0xebef, 0xe0dd,
+// 0x2544, 0x2be, 0xc727, 0xcc15, 0x98c, 0xda71, 0x1fe8, 0x14da, 0xd143, 0xf3c5, 0x365c,
+// 0x3d6e, 0xf8f7,0x2b0a, 0xee93, 0xe5a1, 0x2038, 0x7c2, 0xc25b, 0xc969, 0xcf0, 0xdf0d,
+// 0x1a94, 0x11a6, 0xd43f, 0x5e52, 0x9bcb, 0x90f9, 0x5560, 0x869d, 0x4304, 0x4836, 0x8daf,
+// 0xaa55, 0x6fcc, 0x64fe, 0xa167, 0x729a, 0xb703, 0xbc31, 0x79a8, 0xa8eb, 0x6d72, 0x6640,
+// 0xa3d9, 0x7024, 0xb5bd, 0xbe8f, 0x7b16, 0x5cec, 0x9975, 0x9247, 0x57de, 0x8423, 0x41ba,
+// 0x4a88, 0x8f11, 0x57c, 0xc0e5, 0xcbd7, 0xe4e, 0xddb3, 0x182a, 0x1318, 0xd681, 0xf17b,
+// 0x34e2, 0x3fd0, 0xfa49, 0x29b4, 0xec2d, 0xe71f, 0x2286, 0xa213, 0x678a, 0x6cb8, 0xa921,
+// 0x7adc, 0xbf45, 0xb477, 0x71ee, 0x5614, 0x938d, 0x98bf, 0x5d26, 0x8edb, 0x4b42, 0x4070,
+// 0x85e9, 0xf84, 0xca1d, 0xc12f, 0x4b6, 0xd74b, 0x12d2, 0x19e0, 0xdc79, 0xfb83, 0x3e1a, 0x3528,
+// 0xf0b1, 0x234c, 0xe6d5, 0xede7, 0x287e, 0xf93d, 0x3ca4, 0x3796, 0xf20f, 0x21f2, 0xe46b, 0xef59,
+// 0x2ac0, 0xd3a, 0xc8a3, 0xc391, 0x608, 0xd5f5, 0x106c, 0x1b5e, 0xdec7, 0x54aa, 0x9133, 0x9a01,
+// 0x5f98, 0x8c65, 0x49fc, 0x42ce, 0x8757, 0xa0ad, 0x6534, 0x6e06, 0xab9f, 0x7862, 0xbdfb, 0xb6c9,
+// 0x7350, 0x51d6, 0x944f, 0x9f7d, 0x5ae4, 0x8919, 0x4c80, 0x47b2, 0x822b, 0xa5d1, 0x6048, 0x6b7a,
+// 0xaee3, 0x7d1e, 0xb887, 0xb3b5, 0x762c, 0xfc41, 0x39d8, 0x32ea, 0xf773, 0x248e, 0xe117, 0xea25,
+// 0x2fbc, 0x846, 0xcddf, 0xc6ed, 0x374, 0xd089, 0x1510, 0x1e22, 0xdbbb, 0xaf8, 0xcf61, 0xc453,
+// 0x1ca, 0xd237, 0x17ae, 0x1c9c, 0xd905, 0xfeff, 0x3b66, 0x3054, 0xf5cd, 0x2630, 0xe3a9, 0xe89b,
+// 0x2d02, 0xa76f, 0x62f6, 0x69c4, 0xac5d, 0x7fa0, 0xba39, 0xb10b, 0x7492, 0x5368, 0x96f1, 0x9dc3,
+// 0x585a, 0x8ba7, 0x4e3e, 0x450c, 0x8095
+// };
+//#endif
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Wed Feb 07 08:26:04 2018 +0000 @@ -0,0 +1,57 @@ +# Getting started with Blinky on mbed OS + +This guide reviews the steps required to get Blinky working on an mbed OS platform. + +Please install [mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli). + +## Import the example application + +From the command-line, import the example: + +``` +mbed import mbed-os-example-blinky +cd mbed-os-example-blinky +``` + +### Now compile + +Invoke `mbed compile`, and specify the name of your platform and your favorite toolchain (`GCC_ARM`, `ARM`, `IAR`). For example, for the ARM Compiler 5: + +``` +mbed compile -m K64F -t ARM +``` + +Your PC may take a few minutes to compile your code. At the end, you see the following result: + +``` +[snip] ++----------------------------+-------+-------+------+ +| Module | .text | .data | .bss | ++----------------------------+-------+-------+------+ +| Misc | 13939 | 24 | 1372 | +| core/hal | 16993 | 96 | 296 | +| core/rtos | 7384 | 92 | 4204 | +| features/FEATURE_IPV4 | 80 | 0 | 176 | +| frameworks/greentea-client | 1830 | 60 | 44 | +| frameworks/utest | 2392 | 512 | 292 | +| Subtotals | 42618 | 784 | 6384 | ++----------------------------+-------+-------+------+ +Allocated Heap: unknown +Allocated Stack: unknown +Total Static RAM memory (data + bss): 7168 bytes +Total RAM memory (data + bss + heap + stack): 7168 bytes +Total Flash memory (text + data + misc): 43402 bytes +Image: .\.build\K64F\ARM\mbed-os-example-blinky.bin +``` + +### Program your board + +1. Connect your mbed device to the computer over USB. +1. Copy the binary file to the mbed device. +1. Press the reset button to start the program. + +The LED on your platform turns on and off. + +## Troubleshooting + +If you have problems, you can review the [documentation](https://os.mbed.com/docs/latest/tutorials/debugging.html) for suggestions on what could be wrong and how to fix it.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bms.cpp Wed Feb 07 08:26:04 2018 +0000
@@ -0,0 +1,65 @@
+#include "mbed.h"
+#include "bms.h"
+
+SPI spi(D11, D12, D13);
+DigitalOut cs(D10);
+
+void delay_u(uint16_t micro)
+{
+ wait_us(micro);
+}
+
+void delay_m(uint16_t milli)
+{
+ wait_ms(milli);
+}
+
+void spi_enable(void) // Configures SCK frequency. Use constant defined in header file.
+{
+ cs = 1; //high as init for disable SPI
+ spi.format(8, 3); //byte width, spi mode
+ spi.frequency(1000000); //1MHz
+}
+
+
+/*
+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
+ )
+{
+ for (uint8_t i = 0; i < len; i++) {
+ spi.write((int8_t)data[i]);
+ }
+}
+
+/*
+ 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
+ )
+{
+ for (uint8_t i = 0; i < tx_len; i++) {
+ spi.write(tx_Data[i]);
+ }
+
+ for (uint8_t i = 0; i < rx_len; i++) {
+
+ rx_data[i] = (uint8_t)spi.write(0xFF);
+ }
+
+}
+
+
+uint8_t spi_read_byte(uint8_t tx_dat)
+{
+ uint8_t data;
+ data = (uint8_t)spi.write(0xFF);
+ return(data);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bms.h Wed Feb 07 08:26:04 2018 +0000 @@ -0,0 +1,26 @@ +void delay_u(uint16_t micro); + +void delay_m(uint16_t milli); + +void set_spi_freq(); + +void spi_enable(void); + +/* +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Feb 07 08:26:04 2018 +0000
@@ -0,0 +1,678 @@
+
+#include "mbed.h"
+#include "bms.h"
+#include "LTC681x.h"
+#include "LTC6811.h"
+
+#define UI_BUFFER_SIZE 64
+#define SERIAL_TERMINATOR '\n'
+
+#define ENABLED 1
+#define DISABLED 0
+
+#define DATALOG_ENABLED 1
+#define DATALOG_DISABLED 0
+DigitalOut led1(LED1);
+Serial pc(USBTX, USBRX);
+
+void run_command(uint32_t cmd);
+void measurement_loop(uint8_t datalog_en);
+void print_menu();
+void print_cells(uint8_t datalog_en);
+void print_open();
+void print_aux(uint8_t datalog_en);
+void print_stat();
+void print_config();
+void print_rxconfig();
+void print_pec(void);
+void serial_print_hex(uint8_t data);
+void check_error(int error);
+//char get_char();
+//void read_config_data(uint8_t cfg_data[][6], uint8_t nIC);
+
+/**********************************************************
+ Setup Variables
+ The following variables can be modified to
+ configure the software.
+
+***********************************************************/
+const uint8_t TOTAL_IC = 1;//!<number of ICs in the daisy chain
+char ui_buffer[UI_BUFFER_SIZE];
+
+
+//ADC Command Configurations
+//const uint8_t ADC_OPT = ADC_OPT_DISABLED; // See LTC6811_daisy.h for Options
+const uint8_t ADC_CONVERSION_MODE = MD_7KHZ_3KHZ;//MD_7KHZ_3KHZ; //MD_26HZ_2KHZ;//MD_7KHZ_3KHZ; // See LTC6811_daisy.h for Options
+const uint8_t ADC_DCP = DCP_DISABLED; // See LTC6811_daisy.h for Options
+const uint8_t CELL_CH_TO_CONVERT = CELL_CH_ALL; // See LTC6811_daisy.h for Options
+const uint8_t AUX_CH_TO_CONVERT = AUX_CH_ALL; // See LTC6811_daisy.h for Options
+const uint8_t STAT_CH_TO_CONVERT = STAT_CH_ALL; // See LTC6811_daisy.h for Options
+
+const uint16_t MEASUREMENT_LOOP_TIME = 500;//milliseconds(mS)
+
+//Under Voltage and Over Voltage Thresholds
+const uint16_t OV_THRESHOLD = 41000; // Over voltage threshold ADC Code. LSB = 0.0001
+const uint16_t UV_THRESHOLD = 30000; // Under voltage threshold ADC Code. LSB = 0.0001
+
+//Loop Measurement Setup These Variables are ENABLED or DISABLED Remember ALL CAPS
+const uint8_t WRITE_CONFIG = DISABLED; // This is ENABLED or DISABLED
+const uint8_t READ_CONFIG = DISABLED; // This is ENABLED or DISABLED
+const uint8_t MEASURE_CELL = ENABLED; // This is ENABLED or DISABLED
+const uint8_t MEASURE_AUX = DISABLED; // This is ENABLED or DISABLED
+const uint8_t MEASURE_STAT = DISABLED; //This is ENABLED or DISABLED
+const uint8_t PRINT_PEC = DISABLED; //This is ENABLED or DISABLED
+
+
+// Read data from the serial interface into the ui_buffer buffer
+uint8_t read_data();
+
+// Read a float value from the serial interface
+float read_float();
+
+// Read an integer from the serial interface.
+// The routine can recognize Hex, Decimal, Octal, or Binary
+// Example:
+// Hex: 0x11 (0x prefix)
+// Decimal: 17
+// Octal: O21 (leading letter O prefix)
+// Binary: B10001 (leading letter B prefix)
+int32_t read_int();
+
+// Read a string from the serial interface. Returns a pointer to the ui_buffer.
+char *read_string();
+
+// Read a character from the serial interface
+int8_t read_char();
+
+/************************************
+ END SETUP
+*************************************/
+
+/******************************************************
+ *** Global Battery Variables received from 681x commands
+ These variables store the results from the LTC6811
+ register reads and the array lengths must be based
+ on the number of ICs on the stack
+ ******************************************************/
+
+cell_asic bms_ic[TOTAL_IC];
+
+/*!*********************************************************************
+ \brief main loop
+***********************************************************************/
+int main(void)
+{
+ uint32_t user_command;
+
+ pc.baud(115200);
+ spi_enable();
+ LTC681x_init_cfg(TOTAL_IC, bms_ic);
+ LTC6811_reset_crc_count(TOTAL_IC,bms_ic);
+ LTC6811_init_reg_limits(TOTAL_IC,bms_ic);
+ print_menu();
+
+ while(1) {
+ //pc.printf("check 00\n");
+ //while(!pc.readable()) {
+ wait(0.3);
+ // pc.printf("check 001\n");
+ //} // Check for user input
+ //pc.printf("check 01\n");
+ user_command = read_int(); // Read the user commandi
+ pc.printf("command -> %d \n", user_command);
+ run_command(user_command);
+ }
+}
+
+/*!*****************************************
+ \brief executes the user command
+*******************************************/
+
+void run_command(uint32_t cmd)
+{
+ int8_t error = 0;
+ uint32_t conv_time = 0;
+// uint32_t user_command;
+ int8_t readIC=0;
+ char input = 0;
+ switch (cmd) {
+
+ case 1: // Write Configuration Register
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ print_config();
+ break;
+
+ case 2: // Read Configuration Register
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_rdcfg(TOTAL_IC,bms_ic);
+ check_error(error);
+ print_rxconfig();
+ break;
+
+ case 3: // Start Cell ADC Measurement
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_adcv(ADC_CONVERSION_MODE,ADC_DCP,CELL_CH_TO_CONVERT);
+ conv_time = LTC6811_pollAdc();
+ pc.printf("cell conversion completed in:");
+ pc.printf("%.1f",((float)conv_time/1000));
+ pc.printf("mS\n");
+ break;
+
+ case 4: // Read Cell Voltage Registers
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_rdcv(0, TOTAL_IC,bms_ic); // Set to read back all cell voltage registers
+ check_error(error);
+ print_cells(DATALOG_DISABLED);
+ break;
+
+ case 5: // Start GPIO ADC Measurement
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_adax(ADC_CONVERSION_MODE , AUX_CH_TO_CONVERT);
+ LTC6811_pollAdc();
+ pc.printf("aux conversion completed\n");
+ pc.printf("\n");
+ break;
+
+ case 6: // Read AUX Voltage Registers
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_rdaux(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
+ check_error(error);
+ print_aux(DATALOG_DISABLED);
+ break;
+
+ case 7: // Start Status ADC Measurement
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_adstat(ADC_CONVERSION_MODE, STAT_CH_TO_CONVERT);
+ LTC6811_pollAdc();
+ pc.printf("stat conversion completed\n");
+ pc.printf("\n");
+ break;
+
+ case 8: // Read Status registers
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
+ check_error(error);
+ print_stat();
+ break;
+
+ case 9: // Loop Measurements
+ pc.printf("transmit 'm' to quit\n");
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ while (input != 'm') {
+ //if (pc.readable()) {
+ input = read_char();
+ //}
+
+ measurement_loop(DATALOG_DISABLED);
+
+ wait_ms(MEASUREMENT_LOOP_TIME);
+ }
+ //print_menu();
+ break;
+
+ case 10: // Run open wire self test
+ print_pec();
+
+ break;
+
+ case 11: // Read in raw configuration data
+ LTC6811_reset_crc_count(TOTAL_IC,bms_ic);
+ break;
+
+ case 12: // Run the ADC/Memory Self Test
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_run_cell_adc_st(CELL,ADC_CONVERSION_MODE,bms_ic);
+ pc.printf("%d", error);
+ pc.printf(" : errors detected in Digital Filter and CELL Memory\n");
+
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_run_cell_adc_st(AUX,ADC_CONVERSION_MODE, bms_ic);
+ pc.printf("%d",error);
+ pc.printf(" : errors detected in Digital Filter and AUX Memory\n");
+
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_run_cell_adc_st(STAT,ADC_CONVERSION_MODE, bms_ic);
+ pc.printf("%d",error);
+ pc.printf(" : errors detected in Digital Filter and STAT Memory\n");
+ print_menu();
+ break;
+
+ case 13: // Enable a discharge transistor
+ pc.printf("Please enter the Spin number\n");
+ readIC = (int8_t)read_int();
+ LTC6811_set_discharge(readIC,TOTAL_IC,bms_ic);
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ print_config();
+ break;
+
+ case 14: // Clear all discharge transistors
+ clear_discharge(TOTAL_IC,bms_ic);
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ print_config();
+ break;
+
+ case 15: // Clear all ADC measurement registers
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_clrcell();
+ LTC6811_clraux();
+ LTC6811_clrstat();
+ pc.printf("All Registers Cleared\n");
+ break;
+
+ case 16: // Run the Mux Decoder Self Test
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_diagn();
+ wait_ms(5);
+ error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
+ check_error(error);
+ error = 0;
+ for (int ic = 0;
+ ic<TOTAL_IC;
+ ic++) {
+ if (bms_ic[ic].stat.mux_fail[0] != 0) error++;
+ }
+ if (error==0) pc.printf("Mux Test: PASS\n");
+ else pc.printf("Mux Test: FAIL\n");
+
+ break;
+
+ case 17: // Run ADC Overlap self test
+ wakeup_sleep(TOTAL_IC);
+ error = (int8_t)LTC6811_run_adc_overlap(TOTAL_IC,bms_ic);
+ if (error==0) pc.printf("Overlap Test: PASS\n");
+ else pc.printf("Overlap Test: FAIL\n");
+ break;
+
+ case 18: // Run ADC Redundancy self test
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_run_adc_redundancy_st(ADC_CONVERSION_MODE,AUX,TOTAL_IC, bms_ic);
+ pc.printf("%d",error);
+ pc.printf(" : errors detected in AUX Measurement\n");
+
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_run_adc_redundancy_st(ADC_CONVERSION_MODE,STAT,TOTAL_IC, bms_ic);
+ pc.printf("%d",error);
+ pc.printf(" : errors detected in STAT Measurement\n");
+ break;
+
+ case 19:
+ LTC6811_run_openwire(TOTAL_IC, bms_ic);
+ print_open();
+ break;
+
+ case 20: //Datalog print option Loop Measurements
+ pc.printf("transmit 'm' to quit\n");
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ while (input != 'm') {
+ //if (pc.readable()) {
+ input = read_char();
+ //}
+
+ measurement_loop(DATALOG_ENABLED);
+
+ wait_ms(MEASUREMENT_LOOP_TIME);
+ }
+ print_menu();
+ break;
+
+ case 'm': //prints menu
+ print_menu();
+ break;
+
+ default:
+ pc.printf("Incorrect Option\n");
+ break;
+ }
+}
+
+void measurement_loop(uint8_t datalog_en)
+{
+ int8_t error = 0;
+ if (WRITE_CONFIG == ENABLED) {
+ wakeup_sleep(TOTAL_IC);
+ LTC6811_wrcfg(TOTAL_IC,bms_ic);
+ print_config();
+ }
+
+ if (READ_CONFIG == ENABLED) {
+ wakeup_sleep(TOTAL_IC);
+ error = LTC6811_rdcfg(TOTAL_IC,bms_ic);
+ check_error(error);
+ print_rxconfig();
+ }
+
+ if (MEASURE_CELL == ENABLED) {
+ wakeup_idle(TOTAL_IC);
+ LTC6811_adcv(ADC_CONVERSION_MODE,ADC_DCP,CELL_CH_TO_CONVERT);
+ LTC6811_pollAdc();
+ wakeup_idle(TOTAL_IC);
+ error = LTC6811_rdcv(0, TOTAL_IC,bms_ic);
+ check_error(error);
+ print_cells(datalog_en);
+
+ }
+
+ if (MEASURE_AUX == ENABLED) {
+ wakeup_idle(TOTAL_IC);
+ LTC6811_adax(ADC_CONVERSION_MODE , AUX_CH_ALL);
+ LTC6811_pollAdc();
+ wakeup_idle(TOTAL_IC);
+ error = LTC6811_rdaux(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
+ check_error(error);
+ print_aux(datalog_en);
+ }
+
+ if (MEASURE_STAT == ENABLED) {
+ wakeup_idle(TOTAL_IC);
+ LTC6811_adstat(ADC_CONVERSION_MODE, STAT_CH_ALL);
+ LTC6811_pollAdc();
+ wakeup_idle(TOTAL_IC);
+ error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
+ check_error(error);
+ print_stat();
+ }
+
+ if (PRINT_PEC == ENABLED) {
+ print_pec();
+ }
+
+}
+
+
+/*!*********************************
+ \brief Prints the main menu
+***********************************/
+void print_menu()
+{
+ pc.printf("Please enter LTC6811 Command\n");
+ pc.printf("Write Configuration: 1 | Reset PEC Counter: 11\n");
+ pc.printf("Read Configuration: 2 | Run ADC Self Test: 12\n");
+ pc.printf("Start Cell Voltage Conversion: 3 | Set Discharge: 13\n");
+ pc.printf("Read Cell Voltages: 4 | Clear Discharge: 14\n");
+ pc.printf("Start Aux Voltage Conversion: 5 | Clear Registers: 15\n");
+ pc.printf("Read Aux Voltages: 6 | Run Mux Self Test: 16\n");
+ pc.printf("Start Stat Voltage Conversion: 7 | Run ADC overlap Test: 17\n");
+ pc.printf("Read Stat Voltages: 8 | Run Digital Redundancy Test: 18\n");
+ pc.printf("loop Measurements: 9 | Run Open Wire Test: 19\n");
+ pc.printf("Read PEC Errors: 10 | Loop measurements with datalog output: 20\n");
+ pc.printf("\n");
+ pc.printf("Please enter command:\n");
+ pc.printf("\n");
+}
+
+/*!************************************************************
+ \brief Prints cell voltage codes to the serial port
+ *************************************************************/
+void print_cells(uint8_t datalog_en)
+{
+ for (int current_ic = 0 ; current_ic < TOTAL_IC; current_ic++) {
+
+ if (datalog_en == 0) {
+ pc.printf("IC%d, ", current_ic+1);
+ for (int i=0; i<bms_ic[0].ic_reg.cell_channels; i++) {
+ pc.printf("C%d:", i+1);
+ pc.printf("%.4f, ", bms_ic[current_ic].cells.c_codes[i]*0.0001);
+ }
+ pc.printf("\n");
+ } else {
+ pc.printf("Cells, ");
+ for (int i=0; i<bms_ic[0].ic_reg.cell_channels; i++) {
+ pc.printf("%.4f, ",bms_ic[current_ic].cells.c_codes[i]*0.0001);
+ }
+ }
+
+ }
+ pc.printf("\n");
+}
+
+/*!****************************************************************************
+ \brief Prints Open wire test results to the serial port
+ *****************************************************************************/
+void print_open()
+{
+ for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
+ if (bms_ic[current_ic].system_open_wire == 0) {
+ pc.printf("No Opens Detected on IC%d\n", current_ic+1);
+ } else {
+ for (int cell=0; cell<bms_ic[0].ic_reg.cell_channels+1; cell++) {
+ if ((bms_ic[current_ic].system_open_wire &(1<<cell))>0) {
+ pc.printf("There is an open wire on IC%d Channel: %d\n", current_ic + 1, cell);
+ }
+ }
+ }
+ }
+}
+
+/*!****************************************************************************
+ \brief Prints GPIO voltage codes and Vref2 voltage code onto the serial port
+ *****************************************************************************/
+void print_aux(uint8_t datalog_en)
+{
+
+ for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
+ if (datalog_en == 0) {
+ pc.printf(" IC%d", current_ic+1);
+ for (int i=0; i < 5; i++) {
+ pc.printf(" GPIO-%d:%.4f,", i+1, bms_ic[current_ic].aux.a_codes[i]*0.0001);
+ }
+ pc.printf("Vref2:%.4f\n", bms_ic[current_ic].aux.a_codes[5]*0.0001);
+ } else {
+ pc.printf("AUX, ");
+ for (int i=0; i < 6; i++) {
+ pc.printf("%.4f,", bms_ic[current_ic].aux.a_codes[i]*0.0001);
+ }
+ }
+ }
+ pc.printf("\n");
+}
+
+/*!****************************************************************************
+ \brief Prints Status voltage codes and Vref2 voltage code onto the serial port
+ *****************************************************************************/
+void print_stat()
+{
+
+ for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
+ pc.printf("IC%d", current_ic+1);
+ pc.printf(" SOC:%.4f,", bms_ic[current_ic].stat.stat_codes[0]*0.0001*20);
+ pc.printf(" Itemp:%.4f,", bms_ic[current_ic].stat.stat_codes[1]*0.0001);
+ pc.printf(" VregA:%.4f,", bms_ic[current_ic].stat.stat_codes[2]*0.0001);
+ pc.printf(" VregD:%.4f\n", bms_ic[current_ic].stat.stat_codes[3]*0.0001);
+ }
+
+ pc.printf("\n");
+}
+
+/*!******************************************************************************
+ \brief Prints the configuration data that is going to be written to the LTC6811
+ to the serial port.
+ ********************************************************************************/
+void print_config()
+{
+ int cfg_pec;
+
+ pc.printf("Written Configuration: \n");
+ for (int current_ic = 0; current_ic<TOTAL_IC; current_ic++) {
+ pc.printf(" IC ");
+ pc.printf("%d", current_ic+1);
+ pc.printf(": ");
+ pc.printf("0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[0]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[1]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[2]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[3]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[4]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.tx_data[5]);
+ pc.printf(", Calculated PEC: 0x");
+ cfg_pec = pec15_calc(6,&bms_ic[current_ic].config.tx_data[0]);
+ serial_print_hex((uint8_t)(cfg_pec>>8));
+ pc.printf(", 0x");
+ serial_print_hex((uint8_t)(cfg_pec));
+ pc.printf("\n");
+ }
+ pc.printf("\n");
+}
+
+/*!*****************************************************************
+ \brief Prints the configuration data that was read back from the
+ LTC6811 to the serial port.
+ *******************************************************************/
+void print_rxconfig()
+{
+ pc.printf("Received Configuration ");
+ for (int current_ic=0; current_ic<TOTAL_IC; current_ic++) {
+ pc.printf(" IC ");
+ pc.printf("%d", current_ic+1);
+ pc.printf(": 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[0]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[1]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[2]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[3]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[4]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[5]);
+ pc.printf(", Received PEC: 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[6]);
+ pc.printf(", 0x");
+ serial_print_hex(bms_ic[current_ic].config.rx_data[7]);
+ pc.printf("\n");
+ }
+ pc.printf("\n");
+}
+
+void print_pec()
+{
+ for (int current_ic=0; current_ic<TOTAL_IC; current_ic++) {
+ pc.printf("\n%d", bms_ic[current_ic].crc_count.pec_count);
+ pc.printf(" : PEC Errors Detected on IC");
+ pc.printf("%d\n", current_ic+1);
+ }
+}
+
+
+void serial_print_hex(uint8_t data)
+{
+ if (data < 16) {
+ pc.printf("0x0%X", data);
+ } else
+ pc.printf("0x%X", data);
+}
+
+//Function to check error flag and print PEC error message
+void check_error(int error)
+{
+ if (error == -1) {
+ pc.printf("A PEC error was detected in the received data");
+ }
+}
+
+
+// hex conversion constants
+char hex_digits[16]= {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+// global variables
+
+char hex_to_byte_buffer[5]= {
+ '0', 'x', '0', '0', '\0'
+}; // buffer for ASCII hex to byte conversion
+char byte_to_hex_buffer[3]= {
+ '\0','\0','\0'
+};
+
+// Read data from the serial interface into the ui_buffer
+uint8_t read_data()
+{
+ uint8_t index = 0; //index to hold current location in ui_buffer
+ int c; // single character used to store incoming keystrokes
+ //pc.printf("check 1\n");
+ while (index < UI_BUFFER_SIZE-1) {
+ //pc.printf("check 2\n");
+ c = pc.getc(); //read one character
+ //return c;
+ //pc.printf("check 3\n");
+
+ if (((char) c == '\r') || ((char) c == '\n')) break; // if carriage return or linefeed, stop and return data
+ if ( ((char) c == '\x7F') || ((char) c == '\x08') ) { // remove previous character (decrement index) if Backspace/Delete key pressed index--;
+ if (index > 0) index--;
+ } else if (c >= 0) {
+ ui_buffer[index++]=(char) c; // put character into ui_buffer
+ }
+ //pc.printf("check 4\n");
+
+ }
+ ui_buffer[index]='\0'; // terminate string with NULL
+
+ if ((char) c == '\r') { // if the "last" character was a carriage return, also clear linefeed if it is next character
+ wait_ms(1);
+ //pc.printf("check 5\n");
+
+ if (pc.readable()==1) {
+ //pc.printf("check 6\n");
+ pc.getc(); // if linefeed appears, read it and throw it away
+ }
+ //pc.printf("check 7\n");
+
+ }
+ //pc.printf("check 8\n");
+
+ return index; // return number of characters, not including null terminator
+}
+
+// Read a float value from the serial interface
+float read_float()
+{
+ float data;
+ read_data();
+ data = atof(ui_buffer);
+ return(data);
+}
+
+// Read an integer from the serial interface.
+// The routine can recognize Hex, Decimal, Octal, or Binary
+// Example:
+// Hex: 0x11 (0x prefix)
+// Decimal: 17
+// Octal: 021 (leading zero prefix)
+// Binary: B10001 (leading B prefix)
+int32_t read_int()
+{
+ int32_t data;
+ read_data();
+ if (ui_buffer[0] == 'm')
+ return('m');
+ if ((ui_buffer[0] == 'B') || (ui_buffer[0] == 'b')) {
+ data = strtol(ui_buffer+1, NULL, 2);
+ } else
+ data = strtol(ui_buffer, NULL, 0);
+ return(data);
+}
+
+// Read a string from the serial interface. Returns a pointer to the ui_buffer.
+char *read_string()
+{
+ read_data();
+ return(ui_buffer);
+}
+
+// Read a character from the serial interface
+int8_t read_char()
+{
+ read_data();
+ return(ui_buffer[0]);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Wed Feb 07 08:26:04 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#caeaa49d68c67ee00275cece10cd88e0ed0f6ed3