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.
main.cpp
- Committer:
- roger5641
- Date:
- 2017-11-12
- Revision:
- 1:ba1b0ea1c745
- Parent:
- 0:3547f7580dbd
- Child:
- 2:e0ec3ed506ea
File content as of revision 1:ba1b0ea1c745:
/*!
Linear Technology DC2259 Demonstration Board
LTC6811-1: Battery stack monitor
REVISION HISTORY
$Revision: 7139 $
$Date: 2017-06-01 13:55:14 -0700 (Thu, 01 Jun 2017) $
@verbatim
NOTES
Setup:
Set the terminal baud rate to 115200 and select the newline terminator.
Ensure all jumpers on the demo board are installed in their default positions from the factory.
Refer to Demo Manual DC2259.
USER INPUT DATA FORMAT:
decimal : 1024
hex : 0x400
octal : 02000 (leading 0)
binary : B10000000000
float : 1024.0
@endverbatim
http://www.linear.com/product/LTC6811-1
http://www.linear.com/product/LTC6811-1#demoboards
Copyright (c) 2017, Linear Technology Corp.(LTC)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of Linear Technology Corp.
The Linear Technology Linduino is not affiliated with the official Arduino team.
However, the Linduino is only possible because of the Arduino team's commitment
to the open-source community. Please, visit http://www.arduino.cc and
http://store.arduino.cc , and consider a purchase that will help fund their
ongoing work.
Copyright 2017 Linear Technology Corp. (LTC)
*/
/*! @file
@ingroup LTC6811-1
*/
#include "mbed.h"
#include <stdint.h>
#include "LT_SPI.h"
#include "UserInterface.h"
#include "LTC681x.h"
#include "LTC6811.h"
#define ENABLED 1
#define DISABLED 0
#define DATALOG_ENABLED 1
#define DATALOG_DISABLED 0
//char get_char();
void print_menu();
void read_config_data(uint8_t cfg_data[][6], uint8_t nIC);
void print_cells(uint8_t datalog_en);
void print_open();
void print_config();
void print_rxconfig();
void print_aux(uint8_t datalog_en);
void print_stat();
void check_error(int error);
/**********************************************************
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
//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
/************************************
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];
void run_command(uint32_t cmd);
void measurement_loop(uint8_t datalog_en);
void print_pec(void);
void serial_print_hex(uint8_t data);
/*!**********************************************************************
\brief Inititializes hardware and variables
***********************************************************************/
void setup()
{
pc.baud(115200);
// quikeval_SPI_connect();
CS_PIN = 1;
spi_enable(); // This will set the Linduino to have a 1MHz Clock
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();
}
/*!*********************************************************************
\brief main loop
***********************************************************************/
int main(void)
{
while(1)
{
if (pc.readable()) // Check for user input
{
uint32_t user_command;
user_command = read_int(); // Read the user command
pc.printf("%d",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");
pc.printf("\r");
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");
pc.printf("\r");
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");
pc.printf("\r");
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");
wakeup_sleep(TOTAL_IC);
LTC6811_wrcfg(TOTAL_IC,bms_ic);
while (input != 'm')
{
if (pc.readable() > 0)
{
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");
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");
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 ");
else pc.printf("Mux Test: FAIL ");
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 ");
else pc.printf("Overlap Test: FAIL");
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");
wakeup_sleep(TOTAL_IC);
LTC6811_wrcfg(TOTAL_IC,bms_ic);
while (input != 'm')
{
if (pc.readable() > 0)
{
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");
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");
pc.printf("Write Configuration: 1 | Reset PEC Counter: 11 ");
pc.printf("Read Configuration: 2 | Run ADC Self Test: 12");
pc.printf("Start Cell Voltage Conversion: 3 | Set Discharge: 13");
pc.printf("Read Cell Voltages: 4 | Clear Discharge: 14");
pc.printf("Start Aux Voltage Conversion: 5 | Clear Registers: 15");
pc.printf("Read Aux Voltages: 6 | Run Mux Self Test: 16");
pc.printf("Start Stat Voltage Conversion: 7 | Run ADC overlap Test: 17");
pc.printf("Read Stat Voltages: 8 | Run Digital Redundancy Test: 18");
pc.printf("loop Measurements: 9 | Run Open Wire Test: 19");
pc.printf("Read PEC Errors: 10 | Loop measurements with datalog output: 20");
pc.printf("\r");
pc.printf("Please enter command: ");
pc.printf("\r");
}
/*!************************************************************
\brief Prints cell voltage codes to the pc 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 ");
pc.printf("%d",current_ic+1);
pc.printf(", ");
for (int i=0; i<bms_ic[0].ic_reg.cell_channels; i++)
{
pc.printf(" C");
pc.printf("%d",i+1);
pc.printf(":");
pc.printf("%.4f",bms_ic[current_ic].cells.c_codes[i]*0.0001);
pc.printf(",");
}
pc.printf("\r");
}
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(",");
}
}
}
pc.printf("\r");
}
/*!****************************************************************************
\brief Prints Open wire test results to the pc 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: ");
pc.printf("%d",current_ic+1);
pc.printf("\r");
}
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: ");
pc.printf("%d",current_ic + 1);
pc.printf(" Channel: ");
pc.printf("%d",cell);
}
}
}
}
}
/*!****************************************************************************
\brief Prints GPIO voltage codes and Vref2 voltage code onto the pc 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 ");
pc.printf("%d",current_ic+1);
for (int i=0; i < 5; i++)
{
pc.printf(" GPIO-");
pc.printf("%d",i+1);
pc.printf(":");
pc.printf("%.4f",bms_ic[current_ic].aux.a_codes[i]*0.0001);
pc.printf(",");
}
pc.printf(" Vref2");
pc.printf(":");
pc.printf("%.4f",bms_ic[current_ic].aux.a_codes[5]*0.0001);
pc.printf("\r");
}
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(",");
}
}
}
pc.printf("\r");
}
/*!****************************************************************************
\brief Prints Status voltage codes and Vref2 voltage code onto the pc port
*****************************************************************************/
void print_stat()
{
for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++)
{
pc.printf(" IC ");
pc.printf("%d",current_ic+1);
pc.printf(" SOC:");
pc.printf("%.4f",bms_ic[current_ic].stat.stat_codes[0]*0.0001*20);
pc.printf(",");
pc.printf(" Itemp:");
pc.printf("%.4f",bms_ic[current_ic].stat.stat_codes[1]*0.0001);
pc.printf(",");
pc.printf(" VregA:");
pc.printf("%.4f",bms_ic[current_ic].stat.stat_codes[2]*0.0001);
pc.printf(",");
pc.printf(" VregD:");
pc.printf("%.4f",bms_ic[current_ic].stat.stat_codes[3]*0.0001);
pc.printf("\r");
}
pc.printf("\r");
}
/*!******************************************************************************
\brief Prints the configuration data that is going to be written to the LTC6811
to the pc port.
********************************************************************************/
void print_config()
{
int cfg_pec;
pc.printf("Written Configuration: ");
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("\r");
}
pc.printf("\r");
}
/*!*****************************************************************
\brief Prints the configuration data that was read back from the
LTC6811 to the pc 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("\r");
}
pc.printf("\r");
}
void print_pec()
{
for (int current_ic=0; current_ic<TOTAL_IC; current_ic++)
{
pc.printf("");
pc.printf("%d",bms_ic[current_ic].crc_count.pec_count);
pc.printf(" : PEC Errors Detected on IC");
pc.printf("%d",current_ic+1);
}
}
void serial_print_hex(uint8_t data)
{
if (data< 16)
{
pc.printf("0");
pc.printf("%X",data);
}
else
pc.printf("%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'
//};
//
//char read_hex()
//// read 2 hex characters from the pc buffer and convert
//// them to a byte
//{
// byte data;
// hex_to_byte_buffer[2]=get_char();
// hex_to_byte_buffer[3]=get_char();
// get_char();
// get_char();
// data = strtol(hex_to_byte_buffer, NULL, 0);
// return(data);
//}
//
//char get_char()
//{
// // read a command from the pc port
// while (pc.readable() <= 0);
// return(pc.read());
//}
