Adafruit_MCP4728.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*!
  2. * @file Adafruit_MCP4728.cpp
  3. *
  4. * @mainpage Adafruit MCP4728 4-Channel 12-Bit I2C DAC library
  5. *
  6. * @section intro_sec Introduction
  7. *
  8. * I2C Driver for the Adafruit MCP4728 4-Channel 12-Bit I2C DAC library
  9. *
  10. * This is a library for the Adafruit MCP4728 breakout:
  11. * https://www.adafruit.com/product/4470
  12. *
  13. * Adafruit invests time and resources providing this open source code,
  14. * please support Adafruit and open-source hardware by purchasing products from
  15. * Adafruit!
  16. *
  17. * @section dependencies Dependencies
  18. * This library depends on the Adafruit BusIO library
  19. *
  20. *
  21. * @section author Author
  22. *
  23. * Bryan Siepert for Adafruit Industries
  24. *
  25. * @section license License
  26. *
  27. * BSD (see license.txt)
  28. *
  29. * @section HISTORY
  30. *
  31. * v1.0 - First release
  32. */
  33. #include "Adafruit_MCP4728.h"
  34. #include "Arduino.h"
  35. #include <Wire.h>
  36. /*!
  37. * @brief Instantiates a new MCP4728 class
  38. */
  39. Adafruit_MCP4728::Adafruit_MCP4728(void) {}
  40. /*!
  41. * @brief Sets up the hardware and initializes I2C
  42. * @param i2c_address
  43. * The I2C address to be used.
  44. * @param wire
  45. * The Wire object to be used for I2C connections.
  46. * @return True if initialization was successful, otherwise false.
  47. */
  48. boolean Adafruit_MCP4728::begin(uint8_t i2c_address, TwoWire *wire) {
  49. i2c_dev = new Adafruit_I2CDevice(i2c_address, wire);
  50. if (!i2c_dev->begin()) {
  51. return false;
  52. }
  53. return true;
  54. }
  55. /**
  56. * @brief Sets the input register for a given channel to the specified settings
  57. *
  58. * @param channel The channel to update
  59. * @param new_value The new value to assign
  60. * @param new_vref Optional vref setting - Defaults to `MCP4728_VREF_VDD`
  61. * @param new_gain Optional gain setting - Defaults to `MCP4728_GAIN_1X`
  62. * @param new_pd_mode Optional power down mode setting - Defaults to
  63. * `MCP4728_PD_MOOE_NORMAL`
  64. * @param udac Optional UDAC setting - Defaults to `false`, latching
  65. * immediately. Set to `true` to latch when the LDAC pin is pulled low
  66. *
  67. * @return true if the write was successful
  68. * @return false if there was an error with I2C communication between the MCU
  69. * and the DAC
  70. */
  71. bool Adafruit_MCP4728::setChannelValue(
  72. MCP4728_channel_t channel, uint16_t new_value, MCP4728_vref_t new_vref,
  73. MCP4728_gain_t new_gain, MCP4728_pd_mode_t new_pd_mode, bool udac) {
  74. uint8_t output_buffer[3];
  75. // build the setter header/ "address"
  76. // 0 1 0 0 0 DAC1 DAC0 UDAC[A]
  77. uint8_t sequential_write_cmd = MCP4728_MULTI_IR_CMD;
  78. sequential_write_cmd |= (channel << 1);
  79. sequential_write_cmd |= udac;
  80. output_buffer[0] = sequential_write_cmd;
  81. // VREF PD1 PD0 Gx D11 D10 D9 D8 [A] D7 D6 D5 D4 D3 D2 D1 D0 [A]
  82. new_value |= (new_vref << 15);
  83. new_value |= (new_pd_mode << 13);
  84. new_value |= (new_gain << 12);
  85. output_buffer[1] = new_value >> 8;
  86. output_buffer[2] = new_value & 0xFF;
  87. if (!i2c_dev->write(output_buffer, 3)) {
  88. return false;
  89. }
  90. return true;
  91. }
  92. /**
  93. * @brief Set the values of all four channels simultaneously with minimal delay
  94. * or configuration
  95. *
  96. * @param channel_a_value The value to assign to channel A
  97. * @param channel_b_value The value to assign to channel B
  98. * @param channel_c_value The value to assign to channel C
  99. * @param channel_d_value The value to assign to channel D
  100. * @return true if the write was successful
  101. * @return false if there was an error with I2C communication between the MCU
  102. * and the DAC
  103. */
  104. bool Adafruit_MCP4728::fastWrite(uint16_t channel_a_value,
  105. uint16_t channel_b_value,
  106. uint16_t channel_c_value,
  107. uint16_t channel_d_value) {
  108. uint8_t output_buffer[8];
  109. output_buffer[0] = channel_a_value >> 8;
  110. output_buffer[1] = channel_a_value & 0xFF;
  111. output_buffer[2] = channel_b_value >> 8;
  112. output_buffer[3] = channel_b_value & 0xFF;
  113. output_buffer[4] = channel_c_value >> 8;
  114. output_buffer[5] = channel_c_value & 0xFF;
  115. output_buffer[6] = channel_d_value >> 8;
  116. output_buffer[7] = channel_d_value & 0xFF;
  117. if (!i2c_dev->write(output_buffer, 8)) {
  118. return false;
  119. }
  120. return true;
  121. }
  122. /**
  123. * @brief Saves the DAC's input register settings to the internal EEPROM,
  124. * makeing them the default values when the ADC is powered on
  125. *
  126. * @return true if the write was successful
  127. * @return false if there was an error with I2C communication between the MCU
  128. * and the DAC */
  129. bool Adafruit_MCP4728::saveToEEPROM(void) {
  130. uint8_t input_buffer[24];
  131. uint8_t output_buffer[9];
  132. i2c_dev->read(input_buffer, 24);
  133. // build header byte 0 1 0 1 0 DAC1 DAC0 UDAC [A]
  134. uint8_t eeprom_write_cmd = MCP4728_MULTI_EEPROM_CMD; // 0 1 0 1 0 xxx
  135. eeprom_write_cmd |=
  136. (MCP4728_CHANNEL_A << 1); // DAC1 DAC0, start at channel A obvs
  137. eeprom_write_cmd |= 0; // UDAC ; yes, latch please
  138. // First byte is the write command+options
  139. output_buffer[0] = eeprom_write_cmd;
  140. // copy the incoming input register bytes to the outgoing buffer
  141. // Channel A
  142. output_buffer[1] = input_buffer[1];
  143. output_buffer[2] = input_buffer[2];
  144. // Channel B
  145. output_buffer[3] = input_buffer[7];
  146. output_buffer[4] = input_buffer[8];
  147. // Channel C
  148. output_buffer[5] = input_buffer[13];
  149. output_buffer[6] = input_buffer[14];
  150. // Channel D
  151. output_buffer[7] = input_buffer[19];
  152. output_buffer[8] = input_buffer[20];
  153. if (!i2c_dev->write(output_buffer, 9)) {
  154. return false;
  155. }
  156. delay(15);
  157. return true;
  158. }
  159. /**
  160. * @brief Read the current value of one DAC value.
  161. *
  162. * @param channel the channel to read
  163. * @return current value of the specified channel
  164. */
  165. uint16_t Adafruit_MCP4728::getChannelValue(MCP4728_channel_t channel) {
  166. uint16_t value;
  167. uint8_t input_buffer[24];
  168. /* 24 bytes are (3 bytes outreg, 3 bytes EEPROM) x 4 channels */
  169. uint8_t reg_base = 6 * ((uint8_t)channel);
  170. i2c_dev->read(input_buffer, 24);
  171. value =
  172. input_buffer[reg_base + 2] + ((0x0F & input_buffer[reg_base + 1]) << 8);
  173. return value;
  174. }
  175. /**
  176. * @brief Read the current value of one EEPROM value.
  177. *
  178. * @param channel the channel to read
  179. * @return current value of the specified channel
  180. */
  181. uint16_t Adafruit_MCP4728::getEEPROMValue(MCP4728_channel_t channel) {
  182. uint16_t value;
  183. uint8_t input_buffer[24];
  184. /* 24 bytes are (3 bytes outreg, 3 bytes EEPROM) x 4 channels */
  185. uint8_t reg_base = 6 * ((uint8_t)channel);
  186. i2c_dev->read(input_buffer, 24);
  187. value =
  188. input_buffer[reg_base + 5] + ((0x0F & input_buffer[reg_base + 4]) << 8);
  189. return value;
  190. }