| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- This adc file will handle:
- - packet configuration: bool
- - adc ready flag: bool
- - adc_read_raw: int_16
- Function to read ADC DATA: This function simply retrieves the ADC raw digital
- output as 16-bit signed integer.
- * The value returned is not yet converted to VOLTAGE.
- * adc_data[2]: Buffer with an array of size 2, to store two bytes of ADC data.
- * Since, the ADC output consists of two 8-bit bytes:
- * - adc_data[0] (MSB)
- * - adc_data[1] (LSB)
- * Next, we verify if the the I2C bus is busy using the function in the
- driverlib: DL_I2C_get ControllerStatus
- * - Prevents collisions by ensuring no two I2C device is using the same
- bus before initializing.
- * BEGIN I2C READ operation to request 2 bytes from the ADC->
- DL_I2C_startControllerTransfer()
- * Parameters:
- - I2C_controller_INST: Refererence to the I2C instance bring used.
- - DEF_TARGET_ADDR_ADC: Address of the ADC
- - DL_I2C_CONTROLLER_DIRECTION_RX: Indicates that we want to receive the data
- from ADC
- - 2: Specifies that we expect 2 bytes from the ADC
- * WAIT for the data to be received: (DL_I2C_getControllerStatus())
- - Waits until the ADC sends the data over I2C.
- - Ensures that the data transfer is complete before proceeding.
- * READ the two bytes of ADc Data:
- - adc_data[0] : MSB
- - adc_data[1] : LSB
- - adc_data[2] : config_bytes
- ADC sends its 16-bit value in two parts over 8-bit I2C data frames.
- * COMBINE the two bytes into 16-bit Integer:
- - Shifts the MSB(first byte) left by 8 bits to make space for LSB.
- - Performs a bitwise OR operation to combine MSB and LSB into a single
- 16-bit number.
- * PRINT HEXADEC and DECIMAL format for DEBUGGING.
- * Output code is in binary and is proportional to the Input Voltage and PGA
- settings.
- * From the datasheet:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22226a.pdf
- - Equation 4.4 is being used to convert the output codes to input voltage
- * The ACK bits after conversion is issued by the Master, when the device
- receives a READ command, it outputs two data bytes followed by a configuration
- register in 16 bit conversion mode the MSB(=sign bit) of the first data type is
- D15.
- */
- #include "src/interfaces/i2c_controller.h"
- #include "src/peripherals/adc/adc_interface.h"
- #include "ti_msp_dl_config.h"
- #include <stdio.h>
- #include "src/battery_data/battery.h"
- #include "src/config.h"
- /*
- * Creating Configuartion Register as mentioned in the datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22226a.pdf
- * Under section 5.2 Configuration Register
- * The function is private to ADC and is can only be called in this file
- */
- static uint8_t construct_config_byte(ADC_Params *params) {
- uint8_t config = 0;
-
- config |= ((params->channel) << 5); // Channel Selection (Bits 6-5)
-
- if (params->continuous == 1) {
- config |= (1 << 4); // Continous mode
- } else {
- // One-Shot mode
- // Bit set to zero, BUT the Ready bit needs to be set to start meausrement
- // (read/not write bit)
- config |= (1 << 7);
- }
-
- switch (params->resolution) {
-
- case 12:
- config |= (0b00 << 2);
- break;
- case 14:
- config |= (0b01 << 2);
- break;
- case 16:
- config |= (0b10 << 2);
- break;
- default:
- //printf("ERROR: Invalid Resolution!\n");
- return 0;
- }
-
- switch (params->gain) {
-
- case 1:
- config |= (0b00);
- break;
- case 2:
- config |= (0b01);
- break;
- case 4:
- config |= (0b10);
- break;
- case 8:
- config |= (0b11);
- break;
- default:
- //printf("ERROR: Invalid Gain!\n");
- return 0;
- }
- return config;
- }
- /* Tansmit Data from MCU to ADC: Function to SET configuration to ADC over
- * I2C*/
- static bool adc_configure(uint8_t slot_id, ADC_Params *params) {
- controllerTxPackage.packet[0] = construct_config_byte(params);
- // Wait for I2C Bus to be Free**
- uint32_t n_cycles = 0;
- while ((DL_I2C_getControllerStatus(I2C_controller_INST) &
- DL_I2C_CONTROLLER_STATUS_BUSY_BUS) && n_cycles++ < MAX_I2C_WAIT_RX)
- ;
- if (n_cycles == MAX_I2C_WAIT_RX) {
- printf("Error in reading from I2C Bus: Bus is not getting ready on config byte\n");
- }
- if(controllerTxPackage.packet[0] == 0xFF){
- // this clause can only happen if the internal memory management is messed up?!
- // the config function should take care that this is never the case
- #ifdef DEBUG_ADC
- printf("[ADC] Unable to send config bytes\n");
- #endif
- *battery_slots[slot_id].state = SLOT_ERR_CONFIGBYTE;
- return false;
- }
- // Prepare TX Buffer
- controllerTxPackage.len = 1;
- controllerTxPackage.count = 0;
- controllerTxPackage.complete = false;
- i2c_hal.write(battery_slots[slot_id].adc_addr);
-
- n_cycles = 0;
- while(!controllerTxPackage.complete && n_cycles++ < MAX_I2C_WAIT_RX);
- if (n_cycles == MAX_I2C_WAIT_RX) {
- #ifdef DEBUG_ADC
- printf("[ADC] No Response to the config byte!\n");
- #endif
- return false;
- }
- return true;
- }
- /*
- READY BIT:
- This bit is the data ready flag. In read mode, this bit indicates if the
- output register has been updated with a latest conversion result. In One-Shot
- Conversion mode, writing this bit to “1” initiates a new conversion.
- 1= Output Register has not been updated
- 0= Output Register has been updated
- */
- static bool adc_is_ready(uint8_t slot_id, ADC_Params *params) {
- uint8_t adc_address = battery_slots[slot_id].adc_addr;
- controllerRxPackage.len = 3;
- controllerRxPackage.count = 0;
- controllerRxPackage.complete = false;
- i2c_hal.read(adc_address);
- // Ready bit is bit 7
- while(!controllerRxPackage.complete);
- uint8_t config_adc_byte = controllerRxPackage.packet[2];
- bool ready = (config_adc_byte & 0x80) == 1;
- return ready;
- }
- static int16_t read_adc_raw_data(uint8_t slot_id, ADC_Params *params) {
- // Buffer for ADC data (MSB, LSB, Config Byte)
- uint32_t raw_adc = 0;
- controllerRxPackage.len = 3;
- controllerRxPackage.count = 0;
- controllerRxPackage.complete = false;
-
- i2c_hal.read(battery_slots[slot_id].adc_addr);
- uint32_t n_cycles = 0;
- while(!controllerRxPackage.complete && n_cycles++ < MAX_I2C_WAIT_RX);
- if (n_cycles == MAX_I2C_WAIT_RX) {
- return 0xffff;
- }
- uint8_t msb = controllerRxPackage.packet[0];
- uint8_t lsb = controllerRxPackage.packet[1];
- uint8_t config_adc_byte = controllerRxPackage.packet[2];
- uint32_t max_adc_val = 0;
- switch (params->resolution) {
- case 12: // 12-bit
- raw_adc = ((msb & 0b00001111) << 8) | lsb;
- max_adc_val = 4096;
- break;
- case 14: // 14-bit
- raw_adc = ((msb & 0b00111111) << 8) | lsb;
- max_adc_val = 16384;
- break;
- case 16: // 16-bit
- raw_adc = ((msb & 0b11111111) << 8) | lsb;
- max_adc_val = 65536;
- break;
- default:
- //printf("Error: Unknown ADC Resolution!\n");
- break;
- }
- return raw_adc * params->factor * 2048 / (max_adc_val/2) / params->gain;
- }
- ADC_Interface adc_hal= {
- .configure= adc_configure,
- .read_voltage = read_adc_raw_data,
- .is_ready= adc_is_ready,
- };
|