adc_hal.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. This adc file will handle:
  3. - packet configuration: bool
  4. - adc ready flag: bool
  5. - adc_read_raw: int_16
  6. Function to read ADC DATA: This function simply retrieves the ADC raw digital
  7. output as 16-bit signed integer.
  8. * The value returned is not yet converted to VOLTAGE.
  9. * adc_data[2]: Buffer with an array of size 2, to store two bytes of ADC data.
  10. * Since, the ADC output consists of two 8-bit bytes:
  11. * - adc_data[0] (MSB)
  12. * - adc_data[1] (LSB)
  13. * Next, we verify if the the I2C bus is busy using the function in the
  14. driverlib: DL_I2C_get ControllerStatus
  15. * - Prevents collisions by ensuring no two I2C device is using the same
  16. bus before initializing.
  17. * BEGIN I2C READ operation to request 2 bytes from the ADC->
  18. DL_I2C_startControllerTransfer()
  19. * Parameters:
  20. - I2C_controller_INST: Refererence to the I2C instance bring used.
  21. - DEF_TARGET_ADDR_ADC: Address of the ADC
  22. - DL_I2C_CONTROLLER_DIRECTION_RX: Indicates that we want to receive the data
  23. from ADC
  24. - 2: Specifies that we expect 2 bytes from the ADC
  25. * WAIT for the data to be received: (DL_I2C_getControllerStatus())
  26. - Waits until the ADC sends the data over I2C.
  27. - Ensures that the data transfer is complete before proceeding.
  28. * READ the two bytes of ADc Data:
  29. - adc_data[0] : MSB
  30. - adc_data[1] : LSB
  31. - adc_data[2] : config_bytes
  32. ADC sends its 16-bit value in two parts over 8-bit I2C data frames.
  33. * COMBINE the two bytes into 16-bit Integer:
  34. - Shifts the MSB(first byte) left by 8 bits to make space for LSB.
  35. - Performs a bitwise OR operation to combine MSB and LSB into a single
  36. 16-bit number.
  37. * PRINT HEXADEC and DECIMAL format for DEBUGGING.
  38. * Output code is in binary and is proportional to the Input Voltage and PGA
  39. settings.
  40. * From the datasheet:
  41. https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22226a.pdf
  42. - Equation 4.4 is being used to convert the output codes to input voltage
  43. * The ACK bits after conversion is issued by the Master, when the device
  44. receives a READ command, it outputs two data bytes followed by a configuration
  45. register in 16 bit conversion mode the MSB(=sign bit) of the first data type is
  46. D15.
  47. */
  48. #include "src/interfaces/i2c_controller.h"
  49. #include "src/peripherals/adc/adc_interface.h"
  50. #include "ti_msp_dl_config.h"
  51. #include <stdio.h>
  52. #include "src/battery_data/battery.h"
  53. #include "src/config.h"
  54. /*
  55. * Creating Configuartion Register as mentioned in the datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22226a.pdf
  56. * Under section 5.2 Configuration Register
  57. * The function is private to ADC and is can only be called in this file
  58. */
  59. static uint8_t construct_config_byte(ADC_Params *params) {
  60. uint8_t config = 0;
  61. config |= ((params->channel) << 5); // Channel Selection (Bits 6-5)
  62. if (params->continuous == 1) {
  63. config |= (1 << 4); // Continous mode
  64. } else {
  65. // One-Shot mode
  66. // Bit set to zero, BUT the Ready bit needs to be set to start meausrement
  67. // (read/not write bit)
  68. config |= (1 << 7);
  69. }
  70. switch (params->resolution) {
  71. case 12:
  72. config |= (0b00 << 2);
  73. break;
  74. case 14:
  75. config |= (0b01 << 2);
  76. break;
  77. case 16:
  78. config |= (0b10 << 2);
  79. break;
  80. default:
  81. //printf("ERROR: Invalid Resolution!\n");
  82. return 0;
  83. }
  84. switch (params->gain) {
  85. case 1:
  86. config |= (0b00);
  87. break;
  88. case 2:
  89. config |= (0b01);
  90. break;
  91. case 4:
  92. config |= (0b10);
  93. break;
  94. case 8:
  95. config |= (0b11);
  96. break;
  97. default:
  98. //printf("ERROR: Invalid Gain!\n");
  99. return 0;
  100. }
  101. return config;
  102. }
  103. /* Tansmit Data from MCU to ADC: Function to SET configuration to ADC over
  104. * I2C*/
  105. static bool adc_configure(uint8_t slot_id, ADC_Params *params) {
  106. controllerTxPackage.packet[0] = construct_config_byte(params);
  107. // Wait for I2C Bus to be Free**
  108. uint32_t n_cycles = 0;
  109. while ((DL_I2C_getControllerStatus(I2C_controller_INST) &
  110. DL_I2C_CONTROLLER_STATUS_BUSY_BUS) && n_cycles++ < MAX_I2C_WAIT_RX)
  111. ;
  112. if (n_cycles == MAX_I2C_WAIT_RX) {
  113. printf("Error in reading from I2C Bus: Bus is not getting ready on config byte\n");
  114. }
  115. if(controllerTxPackage.packet[0] == 0xFF){
  116. // this clause can only happen if the internal memory management is messed up?!
  117. // the config function should take care that this is never the case
  118. #ifdef DEBUG_ADC
  119. printf("[ADC] Unable to send config bytes\n");
  120. #endif
  121. *battery_slots[slot_id].state = SLOT_ERR_CONFIGBYTE;
  122. return false;
  123. }
  124. // Prepare TX Buffer
  125. controllerTxPackage.len = 1;
  126. controllerTxPackage.count = 0;
  127. controllerTxPackage.complete = false;
  128. i2c_hal.write(battery_slots[slot_id].adc_addr);
  129. n_cycles = 0;
  130. while(!controllerTxPackage.complete && n_cycles++ < MAX_I2C_WAIT_RX);
  131. if (n_cycles == MAX_I2C_WAIT_RX) {
  132. #ifdef DEBUG_ADC
  133. printf("[ADC] No Response to the config byte!\n");
  134. #endif
  135. return false;
  136. }
  137. return true;
  138. }
  139. /*
  140. READY BIT:
  141. This bit is the data ready flag. In read mode, this bit indicates if the
  142. output register has been updated with a latest conversion result. In One-Shot
  143. Conversion mode, writing this bit to “1” initiates a new conversion.
  144. 1= Output Register has not been updated
  145. 0= Output Register has been updated
  146. */
  147. static bool adc_is_ready(uint8_t slot_id, ADC_Params *params) {
  148. uint8_t adc_address = battery_slots[slot_id].adc_addr;
  149. controllerRxPackage.len = 3;
  150. controllerRxPackage.count = 0;
  151. controllerRxPackage.complete = false;
  152. i2c_hal.read(adc_address);
  153. // Ready bit is bit 7
  154. while(!controllerRxPackage.complete);
  155. uint8_t config_adc_byte = controllerRxPackage.packet[2];
  156. bool ready = (config_adc_byte & 0x80) == 1;
  157. return ready;
  158. }
  159. static int16_t read_adc_raw_data(uint8_t slot_id, ADC_Params *params) {
  160. // Buffer for ADC data (MSB, LSB, Config Byte)
  161. uint32_t raw_adc = 0;
  162. controllerRxPackage.len = 3;
  163. controllerRxPackage.count = 0;
  164. controllerRxPackage.complete = false;
  165. i2c_hal.read(battery_slots[slot_id].adc_addr);
  166. uint32_t n_cycles = 0;
  167. while(!controllerRxPackage.complete && n_cycles++ < MAX_I2C_WAIT_RX);
  168. if (n_cycles == MAX_I2C_WAIT_RX) {
  169. return 0xffff;
  170. }
  171. uint8_t msb = controllerRxPackage.packet[0];
  172. uint8_t lsb = controllerRxPackage.packet[1];
  173. uint8_t config_adc_byte = controllerRxPackage.packet[2];
  174. uint32_t max_adc_val = 0;
  175. switch (params->resolution) {
  176. case 12: // 12-bit
  177. raw_adc = ((msb & 0b00001111) << 8) | lsb;
  178. max_adc_val = 4096;
  179. break;
  180. case 14: // 14-bit
  181. raw_adc = ((msb & 0b00111111) << 8) | lsb;
  182. max_adc_val = 16384;
  183. break;
  184. case 16: // 16-bit
  185. raw_adc = ((msb & 0b11111111) << 8) | lsb;
  186. max_adc_val = 65536;
  187. break;
  188. default:
  189. //printf("Error: Unknown ADC Resolution!\n");
  190. break;
  191. }
  192. return raw_adc * params->factor * 2048 / (max_adc_val/2) / params->gain;
  193. }
  194. ADC_Interface adc_hal= {
  195. .configure= adc_configure,
  196. .read_voltage = read_adc_raw_data,
  197. .is_ready= adc_is_ready,
  198. };