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@3:a0e12d12f780, 2021-07-25 (annotated)
- 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?
User | Revision | Line number | New 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 | } |