This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

EM1402EVM: charging happening for 3 secs in active cell balancing

Part Number: EM1402EVM

/**
 *
 *  @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 */
hi leslie,

yes i am using the same EM1402EVM code with SPI commands. I am attaching the same. Please go through it.

Thanks,

Gargi