Browse Source

batt_smbus: Adds ManufacturerAccess, write_reg, and write_block functions

Also fixes the the PEC calculation for writing. See
http://cache.freescale.com/files/32bit/doc/app_note/AN4471.pdf and
http://www.ti.com/lit/an/sloa132/sloa132.pdf for more details for more
details on SMBus reading and writing including with and without PECs.
sbg
ksschwabe 9 years ago committed by Lorenz Meier
parent
commit
7fc0b0925c
  1. 106
      src/drivers/batt_smbus/batt_smbus.cpp

106
src/drivers/batt_smbus/batt_smbus.cpp

@ -92,9 +92,13 @@ @@ -92,9 +92,13 @@
#define BATT_SMBUS_MANUFACTURE_NAME 0x20 ///< manufacturer name
#define BATT_SMBUS_MANUFACTURE_INFO 0x25 ///< cell voltage register
#define BATT_SMBUS_CURRENT 0x2a ///< current register
#define BATT_SMBUS_MEASUREMENT_INTERVAL_MS (1000000 / 10) ///< time in microseconds, measure at 10hz
#define BATT_SMBUS_MEASUREMENT_INTERVAL_MS (1000000 / 10) ///< time in microseconds, measure at 10Hz
#define BATT_SMBUS_TIMEOUT_MS 10000000 ///< timeout looking for battery 10seconds after startup
#define BATT_SMBUS_MANUFACTURER_ACCESS 0x00
#define BATT_SMBUS_MANUFACTURER_DATA 0x23
#define BATT_SMBUS_MANUFACTURER_BLOCK_ACCESS 0x44
#define BATT_SMBUS_PEC_POLYNOMIAL 0x07 ///< Polynomial for calculating PEC
#ifndef CONFIG_SCHED_WORKQUEUE
@ -166,18 +170,35 @@ private: @@ -166,18 +170,35 @@ private:
*/
int read_reg(uint8_t reg, uint16_t &val);
/**
* Write a word to specified register
*/
int write_reg(uint8_t reg, uint16_t val);
/**
* Read block from bus
* @return returns number of characters read if successful, zero if unsuccessful
*/
uint8_t read_block(uint8_t reg, uint8_t *data, uint8_t max_len, bool append_zero);
/**
* Write block to the bus
* @return the number of characters sent if successful, zero if unsuccessful
*/
uint8_t write_block(uint8_t reg, uint8_t *data, uint8_t len);
/**
* Calculate PEC for a read or write from the battery
* @param buff is the data that was read or will be written
*/
uint8_t get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len) const;
/**
* Write a word to Manufacturer Access register (0x00)
* @param cmd the word to be written to Manufacturer Access
*/
uint8_t ManufacturerAccess(uint16_t cmd);
// internal variables
bool _enabled; ///< true if we have successfully connected to battery
work_s _work; ///< work queue for scheduling reads
@ -480,6 +501,27 @@ BATT_SMBUS::read_reg(uint8_t reg, uint16_t &val) @@ -480,6 +501,27 @@ BATT_SMBUS::read_reg(uint8_t reg, uint16_t &val)
return ret;
}
int
BATT_SMBUS::write_reg(uint8_t reg, uint16_t val)
{
uint8_t buff[4]; // reg + 2 bytes of data + PEC
buff[0] = reg;
buff[2] = uint8_t(val << 8) & 0xff;
buff[1] = (uint8_t)val;
buff[3] = get_PEC(reg, false, &buff[1], 2); // Append PEC
// write bytes to register
int ret = transfer(buff, 3, nullptr, 0);
if (ret != OK) {
debug("Register write error");
}
// return success or failure
return ret;
}
uint8_t
BATT_SMBUS::read_block(uint8_t reg, uint8_t *data, uint8_t max_len, bool append_zero)
{
@ -520,6 +562,31 @@ BATT_SMBUS::read_block(uint8_t reg, uint8_t *data, uint8_t max_len, bool append_ @@ -520,6 +562,31 @@ BATT_SMBUS::read_block(uint8_t reg, uint8_t *data, uint8_t max_len, bool append_
return bufflen;
}
uint8_t
BATT_SMBUS::write_block(uint8_t reg, uint8_t *data, uint8_t len)
{
uint8_t buff[len + 3]; // buffer to hold results
usleep(1);
buff[0] = reg;
buff[1] = len;
memcpy(&buff[2], data, len);
buff[len + 2] = get_PEC(reg, false, &buff[1], len + 1); // Append PEC
// send bytes
int ret = transfer(buff, len + 3, nullptr, 0);
// return zero on failure
if (ret != OK) {
debug("Block write error\n");
return 0;
}
// return success
return len;
}
uint8_t
BATT_SMBUS::get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len) const
{
@ -528,13 +595,33 @@ BATT_SMBUS::get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len @@ -528,13 +595,33 @@ BATT_SMBUS::get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len
return 0;
}
// prepare temp buffer for calcing crc
uint8_t tmp_buff[len + 3];
/**
* Note: The PEC is calculated on all the message bytes. See http://cache.freescale.com/files/32bit/doc/app_note/AN4471.pdf
* and http://www.ti.com/lit/an/sloa132/sloa132.pdf for more details
*/
// prepare temp buffer for calculating crc
uint8_t tmp_buff_len;
if (reading) {
tmp_buff_len = len + 3;
} else {
tmp_buff_len = len + 2;
}
uint8_t tmp_buff[tmp_buff_len];
tmp_buff[0] = (uint8_t)get_address() << 1;
tmp_buff[1] = cmd;
if (reading) {
tmp_buff[2] = tmp_buff[0] | (uint8_t)reading;
memcpy(&tmp_buff[3], buff, len);
} else {
memcpy(&tmp_buff[2], buff, len);
}
// initialise crc to zero
uint8_t crc = 0;
uint8_t shift_reg = 0;
@ -561,6 +648,19 @@ BATT_SMBUS::get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len @@ -561,6 +648,19 @@ BATT_SMBUS::get_PEC(uint8_t cmd, bool reading, const uint8_t buff[], uint8_t len
return crc;
}
uint8_t
BATT_SMBUS::ManufacturerAccess(uint16_t cmd)
{
// write bytes to Manufacturer Access
int ret = write_reg(BATT_SMBUS_MANUFACTURER_ACCESS, cmd);
if (ret != OK) {
debug("Manufacturer Access error");
}
return ret;
}
///////////////////////// shell functions ///////////////////////
void

Loading…
Cancel
Save