Adafruit_BusIO_Register.cpp 12 KB

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