Si115X.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #include <Arduino.h>
  2. #include "Si115X.h"
  3. Si115X::Si115X(uint8_t addr) {
  4. device_address = addr;
  5. }
  6. /**
  7. * Configures a channel at a given index
  8. */
  9. void Si115X::config_channel(uint8_t index, const uint8_t *conf){
  10. int len = sizeof(conf);
  11. if(len != 4 || index > 5)
  12. return;
  13. int inc = index * len;
  14. // ADCCONFIGx:
  15. // - bits[7] - Reserved
  16. // - bits[6:5] - A/D conversion rate
  17. // - bits[4:0] - ADC MUX select (see below)
  18. // 00000 - Small IR 00001 - Medium IR 00010 - Large IR
  19. // 01011 - Visible 01101 - Large Visible
  20. param_set(Si115X::ADCCONFIG_0 + inc, conf[0]);
  21. // ADCSENSx:
  22. // - bits[7] - ADC high signal range enable
  23. // - bits[6:4] - an internal accumulation of samples
  24. // - bits[3:0] - Measurement time for 512 decimation rate
  25. param_set(Si115X::ADCSENS_0 + inc, conf[1]);
  26. // ADCPOSTx:
  27. // - bits[7] - Reserved
  28. // - bits[6] - HOSTOUTx size(0 = 16 bits, 1 = 24 bits)
  29. // - bits[5:3] - Number of bits to shift right of the output
  30. // - bits[2] - Threshold polarity
  31. // - bits[1:0] - Threshold enable
  32. param_set(Si115X::ADCPOST_0 + inc, conf[2]);
  33. // MEASCONFIGx:
  34. // - bits[7:6] - MEASCOUNTx select
  35. // - bits[5:4] - Reserved
  36. // - bits[3] - LEDx_A or LEDx_B BANK select
  37. // - bits[2:0] - LEDx enable
  38. param_set(Si115X::MEASCONFIG_0 + inc, conf[3]);
  39. }
  40. /**
  41. * Writes data over i2c
  42. */
  43. void Si115X::write_data(uint8_t addr, const uint8_t *data, size_t len){
  44. Wire.beginTransmission(addr);
  45. Wire.write(data, len);
  46. Wire.endTransmission();
  47. }
  48. /**
  49. * Reads data from a register over i2c
  50. */
  51. int Si115X::read_register(uint8_t addr, uint8_t reg, int bytesOfData){
  52. int val = -1;
  53. Si115X::write_data(addr, &reg, sizeof(reg));
  54. Wire.requestFrom(addr, (uint8_t)bytesOfData);
  55. if(Wire.available())
  56. val = Wire.read();
  57. return val;
  58. }
  59. /**
  60. * param set as shown in the datasheet
  61. */
  62. void Si115X::param_set(uint8_t loc, uint8_t val){
  63. const auto preResponse0 = read_register(device_address, RESPONSE_0);
  64. uint8_t packet[2];
  65. packet[0] = HOSTIN_0;
  66. packet[1] = val;
  67. write_data(device_address, packet, sizeof(packet));
  68. packet[0] = COMMAND;
  69. packet[1] = loc | PARAM_SET;
  70. write_data(device_address, packet, sizeof(packet));
  71. while ((read_register(device_address, RESPONSE_0) & 0x0f) != ((preResponse0 + 1) & 0x0f))
  72. {
  73. yield();
  74. }
  75. }
  76. /**
  77. * param query as shown in the datasheet
  78. */
  79. int Si115X::param_query(uint8_t loc){
  80. const auto preResponse0 = read_register(device_address, RESPONSE_0);
  81. uint8_t packet[2];
  82. packet[0] = COMMAND;
  83. packet[1] = loc | PARAM_QUERY;
  84. write_data(device_address, packet, sizeof(packet));
  85. while ((read_register(device_address, RESPONSE_0) & 0x0f) != ((preResponse0 + 1) & 0x0f))
  86. {
  87. yield();
  88. }
  89. return read_register(device_address, RESPONSE_1);
  90. }
  91. /**
  92. * Sends command to the command register
  93. */
  94. uint8_t Si115X::send_command(uint8_t code){
  95. const auto preResponse0 = read_register(device_address, RESPONSE_0);
  96. uint8_t packet[2];
  97. packet[0] = COMMAND;
  98. packet[1] = code;
  99. write_data(device_address, packet, sizeof(packet));
  100. while (true)
  101. {
  102. const auto response = read_register(device_address, RESPONSE_0);
  103. if (response & 0x10)
  104. {
  105. // CMD_ERR
  106. packet[0] = COMMAND;
  107. packet[1] = RESET_CMD_CTR;
  108. write_data(device_address, packet, sizeof(packet));
  109. return response;
  110. }
  111. else if ((response & 0x0f) == ((preResponse0 + 1) & 0x0f))
  112. {
  113. break;
  114. }
  115. yield();
  116. }
  117. return 0;
  118. }
  119. /**
  120. * Returns int given a byte array
  121. */
  122. int Si115X::get_int_from_bytes(const uint8_t *data, size_t len){
  123. int result = 0;
  124. int shift = 8 * len;
  125. for(size_t i = 0; i < len; i++){
  126. shift -= 8;
  127. result |= ((data[i] << shift) & (0xFF << shift));
  128. }
  129. return result;
  130. }
  131. bool Si115X::Begin(bool mode){
  132. is_autonomous = mode;
  133. Wire.begin();
  134. // Wire.setClock(400000);
  135. // send_command(RESET_SW);
  136. if (ReadByte(0x00) != 0x51) {
  137. return false;
  138. }
  139. // Reset
  140. uint8_t packet[2];
  141. packet[0] = COMMAND;
  142. packet[1] = RESET_SW;
  143. write_data(device_address, packet, sizeof(packet));
  144. // Wait for the reset to complete
  145. while (read_register(device_address, RESPONSE_0) != 0x2f)
  146. {
  147. yield();
  148. }
  149. // Enable 2 channels for proximity measurement
  150. param_set(CHAN_LIST, 0B000011);
  151. // Enable Interrupt
  152. write_register(device_address, IRQ_ENABLE, 0B000011);
  153. // Initialize LED current
  154. param_set(LED1_A, 0x3F);
  155. param_set(LED1_B, 0x3F);
  156. // Configure ADC and enable LED drive
  157. if (is_autonomous) {
  158. param_set(MEASRATE_H, 0);
  159. param_set(MEASRATE_L, 1); // 1 for a base period of 800 us
  160. param_set(MEASCOUNT_0, 1);
  161. param_set(MEASCOUNT_1, 1);
  162. param_set(THRESHOLD0_L, 0);
  163. param_set(THRESHOLD0_H, 0);
  164. uint8_t conf[4]; // ADCCONFIGx, ADCSENSx, ADCPOSTx, MEASCONFIGx
  165. conf[0] = 0B01100000; // 1x Small IR
  166. conf[1] = 0B00000010; // 48.8us Nominal Measurement time for 512 decimation rate
  167. conf[2] = 0B00000001; // 16-bits output, Interrupt when the measurement is larger than THRESHOLD0
  168. conf[3] = 0B01000001; // enable LED1A, the time between measurements is 800*MEASRATE*MEASCOUNT0 us
  169. config_channel(0, conf);
  170. conf[0] = 0B01101011; // 1x Visible
  171. conf[1] = 0B00000010; // 48.8us Nominal Measurement time for 512 decimation rate
  172. conf[2] = 0B00000001; // 16-bits output, Interrupt when the measurement is larger than THRESHOLD0
  173. conf[3] = 0B10001001; // enable LED1B, the time between measurements is 800*MEASRATE*MEASCOUNT1 us
  174. config_channel(1, conf);
  175. send_command(START);
  176. }
  177. else {
  178. param_set(ADCCONFIG_0, 0b00000000); // 1x Small IR
  179. param_set(ADCSENS_0, 0b10000000); // Enables the high signal range
  180. param_set(ADCPOST_0, 0b00000000);
  181. param_set(MEASCONFIG_0, 0b00000000);
  182. param_set(ADCCONFIG_1, 0b00001011); // 1x Visible
  183. param_set(ADCSENS_1, 0b10000000); // Enables the high signal range
  184. param_set(ADCPOST_1, 0b00000000);
  185. param_set(MEASCONFIG_1, 0b00000000);
  186. }
  187. return true;
  188. }
  189. uint16_t Si115X::ReadIR(void) {
  190. if (!is_autonomous) send_command(FORCE);
  191. uint8_t data[2];
  192. data[0] = read_register(device_address, HOSTOUT_0);
  193. data[1] = read_register(device_address, HOSTOUT_1);
  194. return (data[0] << 8) + data[1];
  195. }
  196. uint16_t Si115X::ReadVisible(void) {
  197. if (!is_autonomous) send_command(FORCE);
  198. uint8_t data[2];
  199. data[0] = read_register(device_address, HOSTOUT_2);
  200. data[1] = read_register(device_address, HOSTOUT_3);
  201. return (data[0] << 8) + data[1];
  202. }
  203. uint8_t Si115X::ReadByte(uint8_t Reg) {
  204. Wire.beginTransmission(device_address);
  205. Wire.write(Reg);
  206. Wire.endTransmission();
  207. Wire.requestFrom(device_address, (uint8_t)1);
  208. return Wire.read();
  209. }