Initial rough start to the BQ76PL536A (or BQ76PL536A-Q1) code. Free to use as long as you make any changes/improvements publicly available. Please notify me of any improvements.

bq76pl536a.cpp

Committer:
dmwahl
Date:
2021-07-25
Revision:
3:a0e12d12f780
Parent:
2:7083c7257556

File content as of revision 3:a0e12d12f780:

///-----------------------------------------------------------------
///   Description:      BQ76PL536A Driver
///   Author:           David Wahl
///   Date:             13-JUL-2021
///   Notes:            Initial release
///
///   Revision History:
///   Name:           Date:        Description:
///-----------------------------------------------------------------

#include "bq76pl536a.h"
//===========================================================================
// Default constructor. Setup spi interface and run init functions
BQ76PL536A::BQ76PL536A(SPI _spi, PinName _cs, u8t _numDev,  u16t _cov, u16t _cuv, u8t _balanceTimeout, bool _balanceEnabled)
//===========================================================================
    :   spi(_spi),
        cs(_cs),
        numDev(_numDev),
        cov(_cov),
        cuv(_cuv),
        balanceTimeout(_balanceTimeout),
        balanceEnabled(_balanceEnabled)
{
    DigitalOut cs(_cs);
    cs = 1;
    spi.format(8,1);
    spi.frequency(2.5e6);

    cs=0;
    wait_ms(1);
    cs=1;
    wait_ms(1);

    softReset();
    setAddresses();
};


//===========================================================================
// Convert raw values to cell voltage
float BQ76PL536A::cellVolts(u8t lobyte, u8t hibyte)
//===========================================================================
{
    float cv = (((((u16t)lobyte << 8) + (u16t)hibyte)*6250/16383)/1000.0); // [V]
    //float cv = (((lobyte * 256) + hibyte)*6250/16383); // [mV]

    return cv;
};
//===========================================================================


//===========================================================================
// Start conversion on all devices
void BQ76PL536A::adcConvert()
//===========================================================================
{
    write(BROADCAST_ADDR, ADC_CONVERT_REG, 1);
}

//===========================================================================
// Reset all devices in stack
void BQ76PL536A::softReset()
//===========================================================================
{
    write(BROADCAST_ADDR, RESET_REG, BQ76PL536A_RESET);
}

//===========================================================================
// Address devices
void BQ76PL536A::setAddresses()
//===========================================================================
{
    for(u8t i=0; i<numDev; i++)    {
        write(DISCOVERY_ADDR, ADDRESS_CONTROL_REG, i+1);
    }
}

/*//===========================================================================
// Device status
u8t BQ76PL536A::devStatus()
//===========================================================================
{
    //update to use numDev
    u8t currentStatus[1];
    read(1,DEVICE_STATUS_REG,1,currentStatus);
    return currentStatus[0];
}
//===========================================================================*/

//===========================================================================
// Read one or more bytes from the BQ76 device stack. Count does not include CRC byte.
bool BQ76PL536A::readAll(u8t deviceAddress)
//===========================================================================
{
    //error = 0;
    read(deviceAddress,0,64,bqPackData);
    return false;
}

//===========================================================================
// Read one or more bytes from the BQ76 device stack. Count does not include CRC byte.
bool BQ76PL536A::read(u8t deviceAddress, u8t regAddress, u8t count, u8t *pRegisterValue)
//===========================================================================
{
    error = 0;
    bool crcGood = true;
    u8t logicalAddress = (deviceAddress << 1 | 0); // Shift address left 1 bit
    u8t crcInput[3+count];
    crcInput[0] = logicalAddress;
    crcInput[1] = regAddress;
    crcInput[2] = count;

    cs = 0;
    spi.write(logicalAddress);
    spi.write(regAddress);
    spi.write(count);

    //Read data. Last byte is CRC data.
    for (int i = 0; i <= count; i++) {
        pRegisterValue[i] = spi.write(0x00);
        if (i != count) {
            crcInput[3+i] = pRegisterValue[i];
        }
        if (i == count) {
            if (pec(crcInput,3+count) != pRegisterValue[i]) {
                error = 1;
                crcGood = false;
            }
        }
    }
    cs = 1; //End of transmission, slave select high
    return crcGood;
}

//===========================================================================
// Write one byte to the BQ76 device stack. Should add code to read back written register and compare...
void BQ76PL536A::write(u8t deviceAddress, u8t regAddress, u8t regData)
//===========================================================================
{
    u8t logicalAddress = (deviceAddress << 1 | 1); // Shift address left one bit and set LSB
    u8t crcInput[3] = {logicalAddress, regAddress, regData};

    cs = 0;
    spi.write(logicalAddress);
    spi.write(regAddress);
    spi.write(regData);
    spi.write(pec(crcInput, sizeof(crcInput)/sizeof(crcInput[0])));
    cs = 1;
}

//===========================================================================
// Calculate CRC byte to verify data integrity
u8t BQ76PL536A::pec(u8t crcBuffer[], u8t crcLength)
//===========================================================================
{
    //u8t crcTestInput[3] = {0x01,0x3b,0x01}; // should return 0x02
    u8t crc = 0;
    u8t temp = 0;
    for (u8t i = 0; i < crcLength; i++) {
        temp = crc ^ crcBuffer[i];
        crc = crcTable[temp];
    }
    return crc;
}