Adafruit_BusIO_Register.cpp (9753B)
1 #include <Adafruit_BusIO_Register.h> 2 3 /*! 4 * @brief Create a register we access over an I2C Device (which defines the 5 * bus and address) 6 * @param i2cdevice The I2CDevice to use for underlying I2C access 7 * @param reg_addr The address pointer value for the I2C/SMBus register, can 8 * be 8 or 16 bits 9 * @param width The width of the register data itself, defaults to 1 byte 10 * @param byteorder The byte order of the register (used when width is > 1), 11 * defaults to LSBFIRST 12 * @param address_width The width of the register address itself, defaults 13 * to 1 byte 14 */ 15 Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, 16 uint16_t reg_addr, 17 uint8_t width, 18 uint8_t byteorder, 19 uint8_t address_width) { 20 _i2cdevice = i2cdevice; 21 _spidevice = NULL; 22 _addrwidth = address_width; 23 _address = reg_addr; 24 _byteorder = byteorder; 25 _width = width; 26 } 27 28 /*! 29 * @brief Create a register we access over an SPI Device (which defines the 30 * bus and CS pin) 31 * @param spidevice The SPIDevice to use for underlying SPI access 32 * @param reg_addr The address pointer value for the SPI register, can 33 * be 8 or 16 bits 34 * @param type The method we use to read/write data to SPI (which is not 35 * as well defined as I2C) 36 * @param width The width of the register data itself, defaults to 1 byte 37 * @param byteorder The byte order of the register (used when width is > 1), 38 * defaults to LSBFIRST 39 * @param address_width The width of the register address itself, defaults 40 * to 1 byte 41 */ 42 Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, 43 uint16_t reg_addr, 44 Adafruit_BusIO_SPIRegType type, 45 uint8_t width, 46 uint8_t byteorder, 47 uint8_t address_width) { 48 _spidevice = spidevice; 49 _spiregtype = type; 50 _i2cdevice = NULL; 51 _addrwidth = address_width; 52 _address = reg_addr; 53 _byteorder = byteorder; 54 _width = width; 55 } 56 57 /*! 58 * @brief Create a register we access over an I2C or SPI Device. This is a 59 * handy function because we can pass in NULL for the unused interface, allowing 60 * libraries to mass-define all the registers 61 * @param i2cdevice The I2CDevice to use for underlying I2C access, if NULL 62 * we use SPI 63 * @param spidevice The SPIDevice to use for underlying SPI access, if NULL 64 * we use I2C 65 * @param reg_addr The address pointer value for the I2C/SMBus/SPI register, 66 * can be 8 or 16 bits 67 * @param type The method we use to read/write data to SPI (which is not 68 * as well defined as I2C) 69 * @param width The width of the register data itself, defaults to 1 byte 70 * @param byteorder The byte order of the register (used when width is > 1), 71 * defaults to LSBFIRST 72 * @param address_width The width of the register address itself, defaults 73 * to 1 byte 74 */ 75 Adafruit_BusIO_Register::Adafruit_BusIO_Register( 76 Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice, 77 Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width, 78 uint8_t byteorder, uint8_t address_width) { 79 _spidevice = spidevice; 80 _i2cdevice = i2cdevice; 81 _spiregtype = type; 82 _addrwidth = address_width; 83 _address = reg_addr; 84 _byteorder = byteorder; 85 _width = width; 86 } 87 88 /*! 89 * @brief Write a buffer of data to the register location 90 * @param buffer Pointer to data to write 91 * @param len Number of bytes to write 92 * @return True on successful write (only really useful for I2C as SPI is 93 * uncheckable) 94 */ 95 bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) { 96 97 uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), 98 (uint8_t)(_address >> 8)}; 99 100 if (_i2cdevice) { 101 return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth); 102 } 103 if (_spidevice) { 104 if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { 105 addrbuffer[0] &= ~0x80; 106 } 107 if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) { 108 addrbuffer[0] |= 0x80; 109 } 110 if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) { 111 addrbuffer[0] &= ~0x80; 112 addrbuffer[0] |= 0x40; 113 } 114 return _spidevice->write(buffer, len, addrbuffer, _addrwidth); 115 } 116 return false; 117 } 118 119 /*! 120 * @brief Write up to 4 bytes of data to the register location 121 * @param value Data to write 122 * @param numbytes How many bytes from 'value' to write 123 * @return True on successful write (only really useful for I2C as SPI is 124 * uncheckable) 125 */ 126 bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { 127 if (numbytes == 0) { 128 numbytes = _width; 129 } 130 if (numbytes > 4) { 131 return false; 132 } 133 134 // store a copy 135 _cached = value; 136 137 for (int i = 0; i < numbytes; i++) { 138 if (_byteorder == LSBFIRST) { 139 _buffer[i] = value & 0xFF; 140 } else { 141 _buffer[numbytes - i - 1] = value & 0xFF; 142 } 143 value >>= 8; 144 } 145 return write(_buffer, numbytes); 146 } 147 148 /*! 149 * @brief Read data from the register location. This does not do any error 150 * checking! 151 * @return Returns 0xFFFFFFFF on failure, value otherwise 152 */ 153 uint32_t Adafruit_BusIO_Register::read(void) { 154 if (!read(_buffer, _width)) { 155 return -1; 156 } 157 158 uint32_t value = 0; 159 160 for (int i = 0; i < _width; i++) { 161 value <<= 8; 162 if (_byteorder == LSBFIRST) { 163 value |= _buffer[_width - i - 1]; 164 } else { 165 value |= _buffer[i]; 166 } 167 } 168 169 return value; 170 } 171 172 /*! 173 * @brief Read cached data from last time we wrote to this register 174 * @return Returns 0xFFFFFFFF on failure, value otherwise 175 */ 176 uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; } 177 178 /*! 179 * @brief Read a buffer of data from the register location 180 * @param buffer Pointer to data to read into 181 * @param len Number of bytes to read 182 * @return True on successful write (only really useful for I2C as SPI is 183 * uncheckable) 184 */ 185 bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) { 186 uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), 187 (uint8_t)(_address >> 8)}; 188 189 if (_i2cdevice) { 190 return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len); 191 } 192 if (_spidevice) { 193 if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { 194 addrbuffer[0] |= 0x80; 195 } 196 if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) { 197 addrbuffer[0] &= ~0x80; 198 } 199 if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) { 200 addrbuffer[0] |= 0x80 | 0x40; 201 } 202 return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len); 203 } 204 return false; 205 } 206 207 /*! 208 * @brief Read 2 bytes of data from the register location 209 * @param value Pointer to uint16_t variable to read into 210 * @return True on successful write (only really useful for I2C as SPI is 211 * uncheckable) 212 */ 213 bool Adafruit_BusIO_Register::read(uint16_t *value) { 214 if (!read(_buffer, 2)) { 215 return false; 216 } 217 218 if (_byteorder == LSBFIRST) { 219 *value = _buffer[1]; 220 *value <<= 8; 221 *value |= _buffer[0]; 222 } else { 223 *value = _buffer[0]; 224 *value <<= 8; 225 *value |= _buffer[1]; 226 } 227 return true; 228 } 229 230 /*! 231 * @brief Read 1 byte of data from the register location 232 * @param value Pointer to uint8_t variable to read into 233 * @return True on successful write (only really useful for I2C as SPI is 234 * uncheckable) 235 */ 236 bool Adafruit_BusIO_Register::read(uint8_t *value) { 237 if (!read(_buffer, 1)) { 238 return false; 239 } 240 241 *value = _buffer[0]; 242 return true; 243 } 244 245 /*! 246 * @brief Pretty printer for this register 247 * @param s The Stream to print to, defaults to &Serial 248 */ 249 void Adafruit_BusIO_Register::print(Stream *s) { 250 uint32_t val = read(); 251 s->print("0x"); 252 s->print(val, HEX); 253 } 254 255 /*! 256 * @brief Pretty printer for this register 257 * @param s The Stream to print to, defaults to &Serial 258 */ 259 void Adafruit_BusIO_Register::println(Stream *s) { 260 print(s); 261 s->println(); 262 } 263 264 /*! 265 * @brief Create a slice of the register that we can address without 266 * touching other bits 267 * @param reg The Adafruit_BusIO_Register which defines the bus/register 268 * @param bits The number of bits wide we are slicing 269 * @param shift The number of bits that our bit-slice is shifted from LSB 270 */ 271 Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits( 272 Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) { 273 _register = reg; 274 _bits = bits; 275 _shift = shift; 276 } 277 278 /*! 279 * @brief Read 4 bytes of data from the register 280 * @return data The 4 bytes to read 281 */ 282 uint32_t Adafruit_BusIO_RegisterBits::read(void) { 283 uint32_t val = _register->read(); 284 val >>= _shift; 285 return val & ((1 << (_bits)) - 1); 286 } 287 288 /*! 289 * @brief Write 4 bytes of data to the register 290 * @param data The 4 bytes to write 291 * @return True on successful write (only really useful for I2C as SPI is 292 * uncheckable) 293 */ 294 bool Adafruit_BusIO_RegisterBits::write(uint32_t data) { 295 uint32_t val = _register->read(); 296 297 // mask off the data before writing 298 uint32_t mask = (1 << (_bits)) - 1; 299 data &= mask; 300 301 mask <<= _shift; 302 val &= ~mask; // remove the current data at that spot 303 val |= data << _shift; // and add in the new data 304 305 return _register->write(val, _register->width()); 306 } 307 308 /*! 309 * @brief The width of the register data, helpful for doing calculations 310 * @returns The data width used when initializing the register 311 */ 312 uint8_t Adafruit_BusIO_Register::width(void) { return _width; }