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.

Committer:
dmwahl
Date:
Sun Jul 25 18:15:36 2021 +0000
Revision:
3:a0e12d12f780
Parent:
2:7083c7257556
Initial rough start to the BQ76PL536A (or BQ76PL536A-Q1) code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dmwahl 3:a0e12d12f780 1 ///-----------------------------------------------------------------
dmwahl 3:a0e12d12f780 2 /// Description: BQ76PL536A Driver
dmwahl 3:a0e12d12f780 3 /// Author: David Wahl
dmwahl 3:a0e12d12f780 4 /// Date: 13-JUL-2021
dmwahl 3:a0e12d12f780 5 /// Notes: Initial release
dmwahl 3:a0e12d12f780 6 ///
dmwahl 3:a0e12d12f780 7 /// Revision History:
dmwahl 3:a0e12d12f780 8 /// Name: Date: Description:
dmwahl 3:a0e12d12f780 9 ///-----------------------------------------------------------------
dmwahl 3:a0e12d12f780 10
dmwahl 0:47a258755906 11 #include "bq76pl536a.h"
dmwahl 0:47a258755906 12 //===========================================================================
dmwahl 0:47a258755906 13 // Default constructor. Setup spi interface and run init functions
dmwahl 0:47a258755906 14 BQ76PL536A::BQ76PL536A(SPI _spi, PinName _cs, u8t _numDev, u16t _cov, u16t _cuv, u8t _balanceTimeout, bool _balanceEnabled)
dmwahl 0:47a258755906 15 //===========================================================================
dmwahl 1:4ae1a58697d7 16 : spi(_spi),
dmwahl 1:4ae1a58697d7 17 cs(_cs),
dmwahl 1:4ae1a58697d7 18 numDev(_numDev),
dmwahl 1:4ae1a58697d7 19 cov(_cov),
dmwahl 1:4ae1a58697d7 20 cuv(_cuv),
dmwahl 1:4ae1a58697d7 21 balanceTimeout(_balanceTimeout),
dmwahl 1:4ae1a58697d7 22 balanceEnabled(_balanceEnabled)
dmwahl 0:47a258755906 23 {
dmwahl 1:4ae1a58697d7 24 DigitalOut cs(_cs);
dmwahl 0:47a258755906 25 cs = 1;
dmwahl 1:4ae1a58697d7 26 spi.format(8,1);
dmwahl 3:a0e12d12f780 27 spi.frequency(2.5e6);
dmwahl 1:4ae1a58697d7 28
dmwahl 1:4ae1a58697d7 29 cs=0;
dmwahl 1:4ae1a58697d7 30 wait_ms(1);
dmwahl 1:4ae1a58697d7 31 cs=1;
dmwahl 1:4ae1a58697d7 32 wait_ms(1);
dmwahl 1:4ae1a58697d7 33
dmwahl 2:7083c7257556 34 softReset();
dmwahl 0:47a258755906 35 setAddresses();
dmwahl 0:47a258755906 36 };
dmwahl 0:47a258755906 37
dmwahl 0:47a258755906 38
dmwahl 3:a0e12d12f780 39 //===========================================================================
dmwahl 3:a0e12d12f780 40 // Convert raw values to cell voltage
dmwahl 3:a0e12d12f780 41 float BQ76PL536A::cellVolts(u8t lobyte, u8t hibyte)
dmwahl 3:a0e12d12f780 42 //===========================================================================
dmwahl 3:a0e12d12f780 43 {
dmwahl 3:a0e12d12f780 44 float cv = (((((u16t)lobyte << 8) + (u16t)hibyte)*6250/16383)/1000.0); // [V]
dmwahl 3:a0e12d12f780 45 //float cv = (((lobyte * 256) + hibyte)*6250/16383); // [mV]
dmwahl 3:a0e12d12f780 46
dmwahl 3:a0e12d12f780 47 return cv;
dmwahl 3:a0e12d12f780 48 };
dmwahl 3:a0e12d12f780 49 //===========================================================================
dmwahl 0:47a258755906 50
dmwahl 0:47a258755906 51
dmwahl 0:47a258755906 52 //===========================================================================
dmwahl 0:47a258755906 53 // Start conversion on all devices
dmwahl 0:47a258755906 54 void BQ76PL536A::adcConvert()
dmwahl 0:47a258755906 55 //===========================================================================
dmwahl 0:47a258755906 56 {
dmwahl 0:47a258755906 57 write(BROADCAST_ADDR, ADC_CONVERT_REG, 1);
dmwahl 0:47a258755906 58 }
dmwahl 0:47a258755906 59
dmwahl 0:47a258755906 60 //===========================================================================
dmwahl 1:4ae1a58697d7 61 // Reset all devices in stack
dmwahl 1:4ae1a58697d7 62 void BQ76PL536A::softReset()
dmwahl 1:4ae1a58697d7 63 //===========================================================================
dmwahl 1:4ae1a58697d7 64 {
dmwahl 1:4ae1a58697d7 65 write(BROADCAST_ADDR, RESET_REG, BQ76PL536A_RESET);
dmwahl 1:4ae1a58697d7 66 }
dmwahl 1:4ae1a58697d7 67
dmwahl 1:4ae1a58697d7 68 //===========================================================================
dmwahl 0:47a258755906 69 // Address devices
dmwahl 0:47a258755906 70 void BQ76PL536A::setAddresses()
dmwahl 0:47a258755906 71 //===========================================================================
dmwahl 0:47a258755906 72 {
dmwahl 1:4ae1a58697d7 73 for(u8t i=0; i<numDev; i++) {
dmwahl 2:7083c7257556 74 write(DISCOVERY_ADDR, ADDRESS_CONTROL_REG, i+1);
dmwahl 0:47a258755906 75 }
dmwahl 0:47a258755906 76 }
dmwahl 0:47a258755906 77
dmwahl 3:a0e12d12f780 78 /*//===========================================================================
dmwahl 1:4ae1a58697d7 79 // Device status
dmwahl 1:4ae1a58697d7 80 u8t BQ76PL536A::devStatus()
dmwahl 0:47a258755906 81 //===========================================================================
dmwahl 0:47a258755906 82 {
dmwahl 1:4ae1a58697d7 83 //update to use numDev
dmwahl 1:4ae1a58697d7 84 u8t currentStatus[1];
dmwahl 1:4ae1a58697d7 85 read(1,DEVICE_STATUS_REG,1,currentStatus);
dmwahl 1:4ae1a58697d7 86 return currentStatus[0];
dmwahl 0:47a258755906 87 }
dmwahl 3:a0e12d12f780 88 //===========================================================================*/
dmwahl 0:47a258755906 89
dmwahl 0:47a258755906 90 //===========================================================================
dmwahl 0:47a258755906 91 // Read one or more bytes from the BQ76 device stack. Count does not include CRC byte.
dmwahl 3:a0e12d12f780 92 bool BQ76PL536A::readAll(u8t deviceAddress)
dmwahl 3:a0e12d12f780 93 //===========================================================================
dmwahl 3:a0e12d12f780 94 {
dmwahl 3:a0e12d12f780 95 //error = 0;
dmwahl 3:a0e12d12f780 96 read(deviceAddress,0,64,bqPackData);
dmwahl 3:a0e12d12f780 97 return false;
dmwahl 3:a0e12d12f780 98 }
dmwahl 3:a0e12d12f780 99
dmwahl 3:a0e12d12f780 100 //===========================================================================
dmwahl 3:a0e12d12f780 101 // Read one or more bytes from the BQ76 device stack. Count does not include CRC byte.
dmwahl 3:a0e12d12f780 102 bool BQ76PL536A::read(u8t deviceAddress, u8t regAddress, u8t count, u8t *pRegisterValue)
dmwahl 0:47a258755906 103 //===========================================================================
dmwahl 0:47a258755906 104 {
dmwahl 0:47a258755906 105 error = 0;
dmwahl 3:a0e12d12f780 106 bool crcGood = true;
dmwahl 0:47a258755906 107 u8t logicalAddress = (deviceAddress << 1 | 0); // Shift address left 1 bit
dmwahl 1:4ae1a58697d7 108 u8t crcInput[3+count];
dmwahl 1:4ae1a58697d7 109 crcInput[0] = logicalAddress;
dmwahl 1:4ae1a58697d7 110 crcInput[1] = regAddress;
dmwahl 1:4ae1a58697d7 111 crcInput[2] = count;
dmwahl 0:47a258755906 112
dmwahl 0:47a258755906 113 cs = 0;
dmwahl 2:7083c7257556 114 spi.write(logicalAddress);
dmwahl 0:47a258755906 115 spi.write(regAddress);
dmwahl 0:47a258755906 116 spi.write(count);
dmwahl 0:47a258755906 117
dmwahl 0:47a258755906 118 //Read data. Last byte is CRC data.
dmwahl 0:47a258755906 119 for (int i = 0; i <= count; i++) {
dmwahl 0:47a258755906 120 pRegisterValue[i] = spi.write(0x00);
dmwahl 1:4ae1a58697d7 121 if (i != count) {
dmwahl 1:4ae1a58697d7 122 crcInput[3+i] = pRegisterValue[i];
dmwahl 1:4ae1a58697d7 123 }
dmwahl 0:47a258755906 124 if (i == count) {
dmwahl 3:a0e12d12f780 125 if (pec(crcInput,3+count) != pRegisterValue[i]) {
dmwahl 0:47a258755906 126 error = 1;
dmwahl 3:a0e12d12f780 127 crcGood = false;
dmwahl 3:a0e12d12f780 128 }
dmwahl 0:47a258755906 129 }
dmwahl 0:47a258755906 130 }
dmwahl 0:47a258755906 131 cs = 1; //End of transmission, slave select high
dmwahl 3:a0e12d12f780 132 return crcGood;
dmwahl 0:47a258755906 133 }
dmwahl 0:47a258755906 134
dmwahl 0:47a258755906 135 //===========================================================================
dmwahl 1:4ae1a58697d7 136 // Write one byte to the BQ76 device stack. Should add code to read back written register and compare...
dmwahl 0:47a258755906 137 void BQ76PL536A::write(u8t deviceAddress, u8t regAddress, u8t regData)
dmwahl 0:47a258755906 138 //===========================================================================
dmwahl 0:47a258755906 139 {
dmwahl 1:4ae1a58697d7 140 u8t logicalAddress = (deviceAddress << 1 | 1); // Shift address left one bit and set LSB
dmwahl 0:47a258755906 141 u8t crcInput[3] = {logicalAddress, regAddress, regData};
dmwahl 0:47a258755906 142
dmwahl 1:4ae1a58697d7 143 cs = 0;
dmwahl 0:47a258755906 144 spi.write(logicalAddress);
dmwahl 0:47a258755906 145 spi.write(regAddress);
dmwahl 0:47a258755906 146 spi.write(regData);
dmwahl 1:4ae1a58697d7 147 spi.write(pec(crcInput, sizeof(crcInput)/sizeof(crcInput[0])));
dmwahl 0:47a258755906 148 cs = 1;
dmwahl 0:47a258755906 149 }
dmwahl 0:47a258755906 150
dmwahl 0:47a258755906 151 //===========================================================================
dmwahl 0:47a258755906 152 // Calculate CRC byte to verify data integrity
dmwahl 1:4ae1a58697d7 153 u8t BQ76PL536A::pec(u8t crcBuffer[], u8t crcLength)
dmwahl 0:47a258755906 154 //===========================================================================
dmwahl 0:47a258755906 155 {
dmwahl 1:4ae1a58697d7 156 //u8t crcTestInput[3] = {0x01,0x3b,0x01}; // should return 0x02
dmwahl 0:47a258755906 157 u8t crc = 0;
dmwahl 1:4ae1a58697d7 158 u8t temp = 0;
dmwahl 1:4ae1a58697d7 159 for (u8t i = 0; i < crcLength; i++) {
dmwahl 0:47a258755906 160 temp = crc ^ crcBuffer[i];
dmwahl 0:47a258755906 161 crc = crcTable[temp];
dmwahl 0:47a258755906 162 }
dmwahl 0:47a258755906 163 return crc;
dmwahl 0:47a258755906 164 }