/**
*
* @file main.c
* @brief this file contains example command sequences and functions to interface with the bq76PL455 from a
* microcontroller. The examples provided are described in the bq76PL455 Communications Examples application
* note, and the sections that correlate to each example are noted in the comments.
*
* This code was written for the TMS570LS04x Launchpad Board, modified to remove R8, allowing use of the SCI1 UART.
* A bq76PL455EVM single-ended communication interface is connected to the Boosterpack connectors J1 and J2 as
* shown below. Connection of these boards must be made by the user.
*
* J1 pin 1 (+3V3) -> bq76PL455EVM J3 pin 3 (VIO)
* J1 pin 3 (SCI1_RX) -> bq76PL455EVM J3 pin 5 (TX) **remove R8 from TMS570LS04x Launchpad
* J1 pin 4 (SCI1_TX) -> bq76PL455EVM J3 pin 4 (RX)
* J2 pin 1 (GND) -> bq76PL455EVM J3 pin 1 (DGND)
* J2 pin 3 (GIOA0) -> bq76PL455EVM J3 pin 6 (nWAKE)
* J2 pin 4 (GIOA1) -> bq76PL455EVM J3 pin 2 (nFAULT)
*
* J2 pin 7 (SPI1SOMI) -> bq34z100EVM J7 pin 3 (SDA)
* J2 pin 8 (GIOA6) -> bq34z100EVM J7 pin 2 (SCL)
* J3 pin 2 (GND) -> bq34z100EVM J7 pin 1 (GND)
*
* @author Stephen Holland - Texas Instruments, Inc
* @date June 2013
* @version 1.0 Initial version*-++++++++
* @note Built with CCS for Hercules Version: 5.4.0
*/
/*****************************************************************************
**
** Copyright (c) 2011-2014 Texas Instruments
**
******************************************************************************/
/* USER CODE BEGIN (0) */
/* USER CODE END */
/* Include Files */
#include "sys_common.h"
#include "system.h"
/* USER CODE BEGIN (1) */
#include "gio.h"
#include "sci.h"
#include "rti.h"
#include "sys_vim.h"
#include "swi_util.h"
#include "pinmux.h"
#include "pl455.h"
#include "emb1428.h"
#include"can.h"
/* Set define below to the following modes:
* BalanceToAverage = balance all cells to average, charging and discharging from/to the external isoalted 12V supply
* Charge = charge the 16 cells one at a time, charging the lowest cell from the external isoalted 12V supply
* Discharge = discharge the 16 cells one at a time, disharging the highest cell to the external isoalted 12V supply
*/
#define BalanceToAverage // BalanceToAverage, Charge or Discharge
#define SIZE 8 // Cantransmit array size
int UART_RX_RDY = 0;
int RTI_TIMEOUT = 0;
BYTE bFrame[132]; // Krunal made global variable.
double Battery_Voltage[16];
int a=0,j=0,c=0,d=0,e=0,b=0;
uint8 tx_data1[SIZE],tx_data2[SIZE],tx_data3[SIZE],tx_data4[SIZE],tx_data5[SIZE]; // transmit data array
void extractelements(uint8 start,uint8 end); // extract data from bframe by venkantesh ,aswini, krunal
/* USER CODE END */
/** @fn void main(void)
* @brief Application main function
* @note This function is empty by default.
*
* This function is called after startup.
* The user can use this function to implement the application.
*/
/* USER CODE BEGIN (2) */
/* USER CODE END */
void main(void)
{
/* USER CODE BEGIN (3) */
systemInit();
gioInit();
sciInit();
sciSetBaudrate(sciREG, 250000);
rtiInit();
vimInit();
muxInit();
extractelements(0,64);
//canInit(); // can1 -> can2
_enable_IRQ();
// initialize local variables
int nSent, nRead, nTopFound = 0, nTopID = 0, tempCount;
int nDev_ID = 0, nGrp_ID = 0;
// BYTE bFrame[132];
uint32 wTemp = 0;
BYTE bTemp;
float cellSample;
int incCount, decCount;
float maxCell = 0, minCell = 5, maxCellDelta, cellAverage;
int maxCellNum, minCellNum, cellToBalance, cellBalanceDir,cellToBalance1,cellBalanceDir1;
// nSent = WriteReg(0, 12, 0x40, 1, FRMWRT_ALL_NR); // send out broadcast pwrdown command
// delayms(5); //~5ms
// WakePL455();
// CommClear();
// CommReset();
gioSetBit(gioPORTA, 7, 1); // enable TOP
delayms(100);
//ResetPL455();
//nSent = WriteReg(0, 12, 0x80, 1, FRMWRT_ALL_NR);//to check reset pl455
// Wake all devices
// The wake tone will awaken any device that is already in shutdown and the pwrdown will shutdown any device
// that is already awake. The least number of times to sequence wake and pwrdown will be half the number of
// boards to cover the worst case combination of boards already awake or shutdown.
for(nDev_ID = 0; nDev_ID < TOTALBOARDS; nDev_ID++) {
nSent = WriteReg(nDev_ID, 12, 0x40, 1, FRMWRT_ALL_NR); // send out broadcast pwrdown command
delayms(5); //~5ms
WakePL455();
delayms(5); //~5ms
}
nRead = ReadReg(0, 96, &bTemp, 1, 0); // Read System Fault register
// Mask Customer Checksum Fault bit
nSent = WriteReg(0, 107, 0x8000, 2, FRMWRT_ALL_NR); // set mask for customer checksum fault
// Clear all faults
// nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags
// nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register
// Auto-address all boards
nSent = WriteReg(0, 14, 0x18, 1, FRMWRT_ALL_NR); // set auto-address mode on all boards
nSent = WriteReg(0, 12, 0x08, 1, FRMWRT_ALL_NR); // enter auto address mode on all boards, the next write to this ID will be its address
for (nDev_ID = 0; nDev_ID < TOTALBOARDS; nDev_ID++)
{
nSent = WriteReg(nDev_ID, 10, nDev_ID, 1, FRMWRT_ALL_NR); // send address to each board
}
/* Enable all communication interfaces on all boards in the stack */
nSent = WriteReg(0, 16, 0x10F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces on all boards in stack
/* Change to final baud rate used in the application (set by BAUDRATE define in pl455.h).
* Up to this point, all communication is at 250Kb, as the COMM_RESET done at the initial
* startup resets the bq76PL455 UART to 250Kb. */
switch(BAUDRATE)
{
case 125000:
nSent = WriteReg(0, 16, 0x00F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces
delayus(100);
sciSetBaudrate(sciREG, BAUDRATE);
break;
case 250000:
delayus(100);
break;
case 500000:
nSent = WriteReg(0, 16, 0x20F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces
delayus(100);
sciSetBaudrate(sciREG, BAUDRATE);
break;
case 1000000:
nSent = WriteReg(0, 16, 0x30F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces
delayus(100);
sciSetBaudrate(sciREG, BAUDRATE);
break;
}
/* Set communications interfaces appropriately for their position in the stack, and
* for baud rate used in the application (set by BAUDRATE define in pl455.h).
*/
for (nDev_ID = TOTALBOARDS - 1; nDev_ID >= 0; --nDev_ID)
{
// read device ID to see if there is a response
nRead = ReadReg(nDev_ID, 10, &wTemp, 1, 0); // 0ms timeout
if(nRead == 0) // if nothing is read then this board doesn't exist
nTopFound = 0;
else // a response was received
{
if(nTopFound == 0)
{ // if the last board was not present but this one is, this is the top board
if(nDev_ID == 0) // this is the only board
{
switch(BAUDRATE)
{
case 125000:
nSent = WriteReg(nDev_ID, 16, 0x0080, 2, FRMWRT_SGL_NR); // enable only single-end comm port on board
break;
case 250000:
nSent = WriteReg(nDev_ID, 16, 0x1080, 2, FRMWRT_SGL_NR); // enable only single-end comm port on board
break;
case 500000:
nSent = WriteReg(nDev_ID, 16, 0x2080, 2, FRMWRT_SGL_NR); // enable only single-end comm port on board
break;
case 1000000:
nSent = WriteReg(nDev_ID, 16, 0x3080, 2, FRMWRT_SGL_NR); // enable only single-end comm port on board
break;
}
}
else // this is the top board of a stack
{
switch(BAUDRATE)
{
case 125000:
nSent = WriteReg(nDev_ID, 16, 0x0028, 2, FRMWRT_SGL_NR); // enable only comm-low and fault-low for the top board
break;
case 250000:
nSent = WriteReg(nDev_ID, 16, 0x1028, 2, FRMWRT_SGL_NR); // enable only comm-low and fault-low for the top board
break;
case 500000:
nSent = WriteReg(nDev_ID, 16, 0x2028, 2, FRMWRT_SGL_NR); // enable only comm-low and fault-low for the top board
break;
case 1000000:
nSent = WriteReg(nDev_ID, 16, 0x3028, 2, FRMWRT_SGL_NR); // enable only comm-low and fault-low for the top board
break;
}
nTopFound = 1;
nTopID = nDev_ID;
}
}
else // this is a middle or bottom board
{
if(nDev_ID == 0) // this is a bottom board of a stack
{
switch(BAUDRATE)
{
case 125000:
nSent = WriteReg(nDev_ID, 16, 0x00D0, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high and single-end comm port on bottom board
break;
case 250000:
nSent = WriteReg(nDev_ID, 16, 0x10D0, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high and single-end comm port on bottom board
break;
case 500000:
nSent = WriteReg(nDev_ID, 16, 0x20D0, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high and single-end comm port on bottom board
break;
case 1000000:
nSent = WriteReg(nDev_ID, 16, 0x30D0, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high and single-end comm port on bottom board
break;
}
}
else // this is a middle board
{
switch(BAUDRATE)
{
case 125000:
nSent = WriteReg(nDev_ID, 16, 0x0078, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high, comm-low and fault-low on all middle boards
break;
case 250000:
nSent = WriteReg(nDev_ID, 16, 0x1078, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high, comm-low and fault-low on all middle boards
break;
case 500000:
nSent = WriteReg(nDev_ID, 16, 0x2078, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high, comm-low and fault-low on all middle boards
break;
case 1000000:
nSent = WriteReg(nDev_ID, 16, 0x3078, 2, FRMWRT_SGL_NR); // enable comm-high, fault-high, comm-low and fault-low on all middle boards
break;
}
}
}
}
}
delayus(100);
nSent = WriteReg(0, 40, 0x00, 1, FRMWRT_ALL_NR); // clear communications timeout register
// Clear all faults
nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags
nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register
delayms(5);
nRead = ReadReg(0, 82, &bTemp, 2, 0); // Read Fault Summary register
nRead = ReadReg(0, 96, &bTemp, 1, 0); // Read System Fault register
nRead = ReadReg(0, 97, &bTemp, 2, 0); // Read Chip Fault register
/* Configure sample period and oversampling
* Best results are:
* cells/AUX
* - 60us ADC sample period (ADC_PERIOD_VOL = 0xB)
* - staying on a channel to oversample (CMD_OVS_CYCLE = 0)
* - 12.6us ADC sample period when oversampling (CMD_OVS_HPER/CMD_OVS_GPER = 3)
* - 8 oversamples (CMD_OVSMP = 3)
* - total sample time for all cell and AUX6 channels to be 16 cell channels only:
* 100us + (60us + (12.6us x 7)) x 16 = 2.47ms
* Internal temperatures
* - 100us initial sample delay (ADC_PERIOD_VOL = 0xC)
*/
// Configure AFE
nSent = WriteReg(0, 61, 0x00, 1, FRMWRT_ALL_NR); // set 0 initial delay
// Configure cell voltage and internal temp sample period
nSent = WriteReg(0, 62, 0xBC, 1, FRMWRT_ALL_NR); // set 60us cell and 100us temp ADC sample period
// Configure AUX voltage sample period AUX0-5 are external thermistor, AUX6 is current sense
nSent = WriteReg(0, 63, 0x44444444, 4, FRMWRT_ALL_NR); // set 12.6us AUX sample period
// Configure the oversampling rate
nSent = WriteReg(0, 7, 0x7B, 1, FRMWRT_ALL_NR); // set 8x oversampling, stay on channel for oversample and 12.6us oversample period for cell and AUX
// Set AFE_PCTL
nSent = WriteReg(0, 15, 0x80, 1, FRMWRT_ALL_NR); // set AFE_PCTL bit to on (only enable AFE when sampling)
// Clear all faults
nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register
nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags
// Select identical number of cells and channels on all modules simultaneously
nSent = WriteReg(0, 13, 0x10, 1, FRMWRT_ALL_NR); // set number of cells to 16
nSent = WriteReg(0, 3, 0xFFFF0000, 4, FRMWRT_ALL_NR); // select 16 cell, AUX channel 6
// nSent = WriteReg(0, 3, 0xFFFFFF00, 4, FRMWRT_ALL_NR); // select 16 cell, all AUX
// Set cell over-voltage and cell under-voltage thresholds on a single board
nSent = WriteReg(0, 144, 0xD1EC, 2, FRMWRT_ALL_NR); // set OV threshold = 4.1000V
nSent = WriteReg(0, 142, 0x6148, 2, FRMWRT_ALL_NR); // set UV threshold = 1.9000V
// Set cell over-voltage and cell under-voltage thresholds on all boards simultaneously
nSent = WriteReg(0, 144, 0xD1EC, 2, FRMWRT_ALL_NR); // set OV threshold = 4.1000V
nSent = WriteReg(0, 142, 0x6148, 2, FRMWRT_ALL_NR); // set UV threshold = 1.9000V
delayms(1);
/* Main loop */
for(nDev_ID = 0; nDev_ID < TOTALBOARDS; nDev_ID++) {
nRead = ReadReg(nDev_ID, 0, &bTemp, 2, 0); // Read SREV register
nRead = ReadReg(nDev_ID, 40, &bTemp, 1, 0); // Read communication timeout register
nRead = ReadReg(nDev_ID, 250, &bTemp, 1, 0); // Read burn count register
}
delayus(100);
// Send broadcast request to board 1 to sample and store results
// nSent = WriteReg(0, 2, 0, 1, FRMWRT_ALL_NR); // send sync sample and store command
nSent = WriteReg(0, 2, 0, 1, FRMWRT_SGL_NR); // send sync sample and store command
delayus(2800); // still need to wait for sampling to complete
// Read stored sample data from boards
// nSent = WriteReg(0, 2, (0x20 | (nTopID & 0x0F)), 1, FRMWRT_ALL_R); // send read stored values command
nSent = WriteReg(0, 2, 0x20, 1, FRMWRT_SGL_R); // send read stored values command
// nSent = WaitRespFrame(bFrame, (35 * (nTopID + 1)), 0); // 32 bytes data + packet header + CRC, 0ms timeout
nSent = WaitRespFrame(bFrame, 35, 0); // 32 bytes data + packet header + CRC, 0ms timeout
delayms(5);
extractelements(1,32); // Function call for extract elements
// extract transmit data on can1
// canTransmit(canREG1, canMESSAGE_BOX1, tx_data1);
// canTransmit(canREG1, canMESSAGE_BOX2, tx_data2);
// canTransmit(canREG1, canMESSAGE_BOX3, tx_data3);
// canTransmit(canREG1, canMESSAGE_BOX4, tx_data4);
// canTransmit(canREG1, canMESSAGE_BOX5, tx_data5);
/*
* Find the max and min cell channels and their voltages. It's pretty self-explanatory ;-)
*/
// Initialize variables
maxCell = 0;
minCell = 5;
maxCellNum = 0;
minCellNum = 0;
maxCellDelta = 0;
cellAverage = 0;
cellToBalance = 0;
cellToBalance1 = 3;
cellBalanceDir1 = discharge;
initEMB1428Interface(0);
EMB_Vset(0, 1); // Set the DAC output
do{
for(decCount = 16, incCount = 1; incCount < 17; incCount ++, decCount--)
{
// Send request to board 1 to sample and store results
nSent = WriteReg(1, 2, 0, 1, FRMWRT_SGL_NR); // send sync sample and store command
delayus(2800); // still need to wait for sampling to complete
// Read stored sample data from boards
nSent = WriteReg(1, 2, 0x20, 1, FRMWRT_SGL_R); // send read stored values command
nSent = WaitRespFrame(bFrame, 35, 0); // 32 bytes data + packet header + CRC, 0ms timeout
cellSample = (bFrame[incCount*2-1]<<8|bFrame[incCount*2]) * 0.000076295;
if(incCount == 1)
{
maxCell = cellSample;
minCell = cellSample;
maxCellNum = 16;
minCellNum = 16;
cellAverage = cellSample;
}
else
{
cellAverage += cellSample;
if(cellSample > maxCell)
{
maxCell = cellSample;
maxCellNum = decCount;
}
else
{
if(cellSample < minCell)
{
minCell = cellSample;
minCellNum = decCount;
}
}
}
}
cellAverage /= 16;
maxCellDelta = maxCell - cellAverage;
/*
* Choose cell to balance
*/
#ifdef BalanceToAverage
// Balance to average
if(maxCellDelta > 0.005)
{
if((cellAverage - minCell) > (maxCell - cellAverage))
{
maxCellDelta = cellAverage - minCell;
cellToBalance = minCellNum;
cellBalanceDir = charge;
}
else
{
maxCellDelta = maxCell - cellAverage;
cellToBalance = maxCellNum;
cellBalanceDir = discharge;
}
}
else
cellToBalance = 0;
#endif
#ifdef Charge
// Charge to 4.2V
if((cellAverage - minCell) > (maxCell - cellAverage))
maxCellDelta = cellAverage - minCell;
else
maxCellDelta = maxCell - cellAverage;
cellToBalance = minCellNum;
cellBalanceDir = charge;
#endif
#ifdef Discharge
// Discharge to 2.5V
if((cellAverage - minCell) > (maxCell - cellAverage))
maxCellDelta = cellAverage - minCell;
else
maxCellDelta = maxCell - cellAverage;
cellToBalance = maxCellNum;
cellBalanceDir = discharge;
#endif
//Balance target cell for 1 second, then relax for 3 seconds
if(cellToBalance1) // Only balance if celToBalance is not set to 0
{
EMB_Start(1, cellToBalance1, cellBalanceDir1);
delayms(1000);
EMB_Stop(1, cellToBalance1);
delayms(3000);
}
#ifdef Discharge
}while(minCell > 2.5); // Min threshold for discharge
#else
}while(maxCell < 4.2); // Max threshold for charge or balance to average
#endif
//to reset pl455
//nSent = WriteReg(0, 12, 0x80, 1, FRMWRT_ALL_NR);
// Send out broadcast pwrdown command
nSent = WriteReg(0, 12, 0x40, 1, FRMWRT_ALL_NR);
delayms(2);
//systemPowerDown(SYS_DOZE_MODE);
while(1);
/* USER CODE END */
}
/* USER CODE BEGIN (4) */
void extractelements(uint8 start,uint8 end)
{
int i,j1=0,j2=0,j3=0,j4=0,j5=0,j6=0,j7=0;
int a=0,j=0,c=0,d=0,e=0,b=0;
for(i=start;i<=end;i++)
{
if(i<=8)
{
tx_data1[i-1]=bFrame[i];
}
else if(i>8&&i<=16)
{
tx_data2[j1]=bFrame[i];
j1++;
}
else if(i>16&&i<=24)
{
tx_data3[j2]=bFrame[i];
j2++;
}
else if(i>24&&i<=32)
{
tx_data4[j3]=bFrame[i];
j3++;
}
}
for(b=0;b<16;b++)
{
if(b<4)
{
Battery_Voltage[b]=((2*2.5*(tx_data1[a]<<8 | tx_data1[a+1]))/65535);
a+=2;
}
else if(b>3 && b<8)
{
Battery_Voltage[b] =((2*2.5*(tx_data2[c]<<8 | tx_data2[c+1]))/65535);
c+=2;
}
else if(b>7&&b<12)
{
Battery_Voltage[b]=((2*2.5*(tx_data3[d]<<8 | tx_data3[d+1]))/65535);
d+=2;
}
else if(b>11&&b<16)
{
Battery_Voltage[b]=((2*2.5*(tx_data4[e]<<8 | tx_data4[e+1]))/65535);
e+=2;
}
}
}
/* USER CODE END */
yes i am using the same EM1402EVM code with SPI commands. I am attaching the same. Please go through it.
Thanks,
Gargi