|
@@ -1,10 +1,10 @@
|
|
|
-#include <adc.h>
|
|
|
|
|
-#include <stdint.h>
|
|
|
|
|
-#include <stdio.h>
|
|
|
|
|
#include "battery.h"
|
|
#include "battery.h"
|
|
|
#include "ti/driverlib/dl_i2c.h"
|
|
#include "ti/driverlib/dl_i2c.h"
|
|
|
#include "ti/driverlib/m0p/dl_core.h"
|
|
#include "ti/driverlib/m0p/dl_core.h"
|
|
|
#include "ti_msp_dl_config.h"
|
|
#include "ti_msp_dl_config.h"
|
|
|
|
|
+#include <adc.h>
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
|
|
|
volatile bool gRxComplete;
|
|
volatile bool gRxComplete;
|
|
|
volatile bool gTxComplete;
|
|
volatile bool gTxComplete;
|
|
@@ -14,96 +14,142 @@ uint8_t gRxPacket[I2C_RX_MAX_PACKET_SIZE];
|
|
|
uint32_t gTxADClen, gTxADCcount;
|
|
uint32_t gTxADClen, gTxADCcount;
|
|
|
uint32_t gRxADClen, gRxADCcount;
|
|
uint32_t gRxADClen, gRxADCcount;
|
|
|
|
|
|
|
|
-uint8_t ADC_ConstructConfigBytes(ADC_PARAMS params) {
|
|
|
|
|
-
|
|
|
|
|
- uint8_t config = 0;
|
|
|
|
|
-
|
|
|
|
|
- config |= ((params.channel - 1) << 5); // Channel Selection (Bits 6-5)
|
|
|
|
|
-
|
|
|
|
|
- config |= (1 << 4); // One-Shot Mode
|
|
|
|
|
|
|
+static ADC_PARAMS adc_params;
|
|
|
|
|
+static ADC_MeasurementState adc_state = ADC_STATE_CONFIGURE;
|
|
|
|
|
|
|
|
- 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;
|
|
|
|
|
- default: printf("ERROR: Invalid Gain!\n"); return 0;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+uint8_t ADC_ConstructConfigBytes(ADC_PARAMS params) {
|
|
|
|
|
|
|
|
- return config;
|
|
|
|
|
|
|
+ uint8_t config = 0;
|
|
|
|
|
+
|
|
|
|
|
+ config |= ((params.channel) << 5); // Channel Selection (Bits 6-5)
|
|
|
|
|
+
|
|
|
|
|
+ config |= (1 << 4); // One-Shot Mode
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ default:
|
|
|
|
|
+ printf("ERROR: Invalid Gain!\n");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return config;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* Tansmit Data from MCU to ADC: Function to SET configuration to ADC over I2C*/
|
|
|
|
|
|
|
+/* Tansmit Data from MCU to ADC: Function to SET configuration to ADC over
|
|
|
|
|
+ * I2C*/
|
|
|
|
|
+
|
|
|
|
|
|
|
|
void ADC_SetConfigurationBytes(ADC_PARAMS params) {
|
|
void ADC_SetConfigurationBytes(ADC_PARAMS params) {
|
|
|
- // **Construct Configuration Byte**
|
|
|
|
|
- uint8_t config_byte = ADC_ConstructConfigBytes(params);
|
|
|
|
|
-
|
|
|
|
|
- // Wait for I2C Bus to be Free**
|
|
|
|
|
- while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
|
|
|
|
|
-
|
|
|
|
|
- // **Start I2C Write Transaction**
|
|
|
|
|
- // Prepare TX Buffer:
|
|
|
|
|
- gTxPacket[0]= config_byte;
|
|
|
|
|
- gTxADClen= 1;
|
|
|
|
|
- gTxADCcount= 0;
|
|
|
|
|
- gTxComplete= false;
|
|
|
|
|
-
|
|
|
|
|
- DL_I2C_startControllerTransfer(I2C_controller_INST, ADC_TARGET_BASE_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_TX, gTxADClen);
|
|
|
|
|
- DL_I2C_enableInterrupt(I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
|
|
|
|
|
- //while(!gTxComplete);
|
|
|
|
|
- // **Ensure STOP Condition is Sent**
|
|
|
|
|
- while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
|
|
|
|
|
- printf("Configuration Sent Successfully for 0x%X!\n", config_byte);
|
|
|
|
|
|
|
+ // **Construct Configuration Byte**
|
|
|
|
|
+ uint8_t config_byte = ADC_ConstructConfigBytes(params);
|
|
|
|
|
+
|
|
|
|
|
+ // Wait for I2C Bus to be Free**
|
|
|
|
|
+ while (DL_I2C_getControllerStatus(I2C_controller_INST) &
|
|
|
|
|
+ DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
|
|
|
|
|
+ ;
|
|
|
|
|
+
|
|
|
|
|
+ // **Start I2C Write Transaction**
|
|
|
|
|
+ // Prepare TX Buffer:
|
|
|
|
|
+ gTxPacket[0] = config_byte;
|
|
|
|
|
+ gTxADClen = 1;
|
|
|
|
|
+ gTxADCcount = 0;
|
|
|
|
|
+ gTxComplete = false;
|
|
|
|
|
+
|
|
|
|
|
+ DL_I2C_flushControllerTXFIFO(I2C_controller_INST);
|
|
|
|
|
+ DL_I2C_fillControllerTXFIFO(I2C_controller_INST, (uint8_t*) &gTxPacket, 1);
|
|
|
|
|
+ DL_I2C_startControllerTransfer(I2C_controller_INST, ADC_TARGET_BASE_ADDRESS,
|
|
|
|
|
+ DL_I2C_CONTROLLER_DIRECTION_TX, gTxADClen);
|
|
|
|
|
+ //DL_I2C_enableInterrupt(I2C_controller_INST,
|
|
|
|
|
+ // DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
|
|
|
|
|
+ // while(!gTxComplete);
|
|
|
|
|
+ // **Ensure STOP Condition is Sent**
|
|
|
|
|
+ while (DL_I2C_getControllerStatus(I2C_controller_INST) &
|
|
|
|
|
+ DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
|
|
|
|
|
+ ;
|
|
|
|
|
+ // printf("Configuration Sent Successfully for 0x%X!\n", config_byte);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// **Interrupt handler for configuration completion**
|
|
|
|
|
-void I2C_ConfigInterruptHandler(void) {
|
|
|
|
|
- if (DL_I2C_getPendingInterrupt(I2C_controller_INST) == DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER) {
|
|
|
|
|
- gTxComplete = true;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
/*
|
|
/*
|
|
|
READY BIT:
|
|
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.
|
|
|
|
|
|
|
+ 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
|
|
1= Output Register has not been updated
|
|
|
0= Output Register has been updated
|
|
0= Output Register has been updated
|
|
|
|
|
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-bool ADC_CheckReadyBit(uint8_t slot_id, ADC_PARAMS params){
|
|
|
|
|
- uint8_t config_byte = ADC_ConstructConfigBytes(params);
|
|
|
|
|
- DL_I2C_startControllerTransfer(I2C_controller_INST, ADC_TARGET_BASE_ADDRESS+slot_id, DL_I2C_CONTROLLER_DIRECTION_RX, 1);
|
|
|
|
|
- config_byte= DL_I2C_receiveControllerData(I2C_controller_INST);
|
|
|
|
|
- bool ready= (config_byte & 0x80)==0; //Ready bit is bit 7
|
|
|
|
|
- printf("Slot: %d | Config Byte: 0x%02X | READY Bit: %d\n", slot_id, config_byte, ready);
|
|
|
|
|
- return ready;
|
|
|
|
|
|
|
+bool ADC_CheckReadyBit(uint8_t slot_id, ADC_PARAMS params) {
|
|
|
|
|
+ // Buffer for ADC data (MSB, LSB, Config Byte)
|
|
|
|
|
+ uint8_t adc_data[3];
|
|
|
|
|
+ uint8_t adc_address = ADC_TARGET_BASE_ADDRESS + slot_id;
|
|
|
|
|
+ printf("Reading ADC Data from MCP3428 for channel: %u\n", params.channel);
|
|
|
|
|
+ gRxADClen = 3;
|
|
|
|
|
+ gRxADCcount = 0;
|
|
|
|
|
+ gRxComplete = false;
|
|
|
|
|
+
|
|
|
|
|
+ DL_I2C_startControllerTransfer(I2C_controller_INST, adc_address,
|
|
|
|
|
+ DL_I2C_CONTROLLER_DIRECTION_RX, gRxADClen);
|
|
|
|
|
+ DL_I2C_enableInterrupt(I2C_controller_INST,
|
|
|
|
|
+ DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER);
|
|
|
|
|
+ while (DL_I2C_getControllerStatus(I2C_controller_INST) &
|
|
|
|
|
+ DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
|
|
|
|
|
+ ;
|
|
|
|
|
+ while (!gRxComplete)
|
|
|
|
|
+ ;
|
|
|
|
|
+
|
|
|
|
|
+ uint8_t config_adc_byte = gRxPacket[2];
|
|
|
|
|
+
|
|
|
|
|
+ // Ready bit is bit 7
|
|
|
|
|
+ bool ready = (config_adc_byte & 0x80) == 0;
|
|
|
|
|
+ printf("Slot: %d | Config Byte: 0x%02X | READY Bit: %d\n", slot_id,
|
|
|
|
|
+ config_adc_byte, ready);
|
|
|
|
|
+ return ready;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
/*
|
|
/*
|
|
|
-Function to read ADC DATA: This function simply retrieves the ADC raw digital output as 16-bit signed integer.
|
|
|
|
|
|
|
+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.
|
|
* 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.
|
|
|
|
|
|
|
+* 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:
|
|
* Since, the ADC output consists of two 8-bit bytes:
|
|
|
* - adc_data[0] (MSB)
|
|
* - adc_data[0] (MSB)
|
|
|
* - adc_data[1] (LSB)
|
|
* - 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()
|
|
|
|
|
|
|
+* 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:
|
|
* Parameters:
|
|
|
- I2C_controller_INST: Refererence to the I2C instance bring used.
|
|
- I2C_controller_INST: Refererence to the I2C instance bring used.
|
|
|
- DEF_TARGET_ADDR_ADC: Address of the ADC
|
|
- DEF_TARGET_ADDR_ADC: Address of the ADC
|
|
|
- - DL_I2C_CONTROLLER_DIRECTION_RX: Indicates that we want to receive the data from 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
|
|
- 2: Specifies that we expect 2 bytes from the ADC
|
|
|
* WAIT for the data to be received: (DL_I2C_getControllerStatus())
|
|
* WAIT for the data to be received: (DL_I2C_getControllerStatus())
|
|
|
- Waits until the ADC sends the data over I2C.
|
|
- Waits until the ADC sends the data over I2C.
|
|
@@ -115,167 +161,168 @@ Function to read ADC DATA: This function simply retrieves the ADC raw digital ou
|
|
|
ADC sends its 16-bit value in two parts over 8-bit I2C data frames.
|
|
ADC sends its 16-bit value in two parts over 8-bit I2C data frames.
|
|
|
* COMBINE the two bytes into 16-bit Integer:
|
|
* COMBINE the two bytes into 16-bit Integer:
|
|
|
- Shifts the MSB(first byte) left by 8 bits to make space for LSB.
|
|
- 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.
|
|
|
|
|
|
|
+ - Performs a bitwise OR operation to combine MSB and LSB into a single
|
|
|
|
|
+16-bit number.
|
|
|
* PRINT HEXADEC and DECIMAL format for DEBUGGING.
|
|
* 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
|
|
|
|
|
|
|
+* 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
|
|
- 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.
|
|
|
|
|
-
|
|
|
|
|
-*/
|
|
|
|
|
|
|
+* 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.
|
|
|
|
|
|
|
|
-int16_t ADC_ReadData(uint8_t slot_id, ADC_PARAMS params)
|
|
|
|
|
-{
|
|
|
|
|
- //Request ADC Conversion
|
|
|
|
|
- //ADC_SetConfigurationBytes(params);
|
|
|
|
|
-
|
|
|
|
|
- //Wait until data is ready
|
|
|
|
|
- while(!ADC_CheckReadyBit(slot_id, params)){
|
|
|
|
|
- delay_cycles(50000);
|
|
|
|
|
- }
|
|
|
|
|
- // Buffer for ADC data (MSB, LSB, Config Byte)
|
|
|
|
|
- uint8_t adc_data[3] = {0};
|
|
|
|
|
- int16_t raw_adc = 0;
|
|
|
|
|
- uint8_t bytes_to_read= 3;
|
|
|
|
|
- uint8_t adc_address= ADC_TARGET_BASE_ADDRESS + slot_id;
|
|
|
|
|
- printf("Reading ADC Data from MCP3428 for channel: %u\n", params.channel);
|
|
|
|
|
-
|
|
|
|
|
- if(DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS){
|
|
|
|
|
- printf("Error: I2C bus stuck! Resetting..\n");
|
|
|
|
|
- DL_I2C_resetControllerTransfer(I2C_controller_INST);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- gRxADClen= bytes_to_read;
|
|
|
|
|
- gRxADCcount= 0;
|
|
|
|
|
- gRxComplete= false;
|
|
|
|
|
-
|
|
|
|
|
- DL_I2C_startControllerTransfer(I2C_controller_INST, adc_address, DL_I2C_CONTROLLER_DIRECTION_RX, gRxADClen);
|
|
|
|
|
- DL_I2C_enableInterrupt(I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER);
|
|
|
|
|
- while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
|
|
|
|
|
- while(!gRxComplete);
|
|
|
|
|
-
|
|
|
|
|
- uint8_t msb= gRxPacket[0];
|
|
|
|
|
- uint8_t lsb= gRxPacket[1];
|
|
|
|
|
- uint8_t config_adc_byte= gRxPacket[2];
|
|
|
|
|
-
|
|
|
|
|
- uint8_t gain_setting = (config_adc_byte & 0x03);
|
|
|
|
|
- uint8_t gain_multiplier = (1 << gain_setting); // Gain values: 1, 2, 4, 8
|
|
|
|
|
-
|
|
|
|
|
- if (params.resolution==16){
|
|
|
|
|
- raw_adc= (msb << 8)| lsb;
|
|
|
|
|
- if(raw_adc > 32767) raw_adc-= 65536;
|
|
|
|
|
- }
|
|
|
|
|
- else if (params.resolution == 14) {
|
|
|
|
|
- raw_adc= ((msb & 0b00111111) << 8)| lsb;
|
|
|
|
|
- if(raw_adc > 8191) raw_adc-= 16384;
|
|
|
|
|
- }
|
|
|
|
|
- else if(params.resolution == 12){
|
|
|
|
|
- raw_adc = ((msb & 0b00001111) << 8) | lsb;
|
|
|
|
|
- if (raw_adc > 2047) raw_adc -= 4096;
|
|
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
|
|
+*/
|
|
|
|
|
|
|
|
- //printf("Gain %d: \n", gain_multiplier);
|
|
|
|
|
- printf("Raw ADC Value: 0x%0X (%d)\n", raw_adc, raw_adc);
|
|
|
|
|
- return raw_adc;
|
|
|
|
|
-
|
|
|
|
|
|
|
+int16_t ADC_ReadData(uint8_t slot_id, ADC_PARAMS params) {
|
|
|
|
|
+
|
|
|
|
|
+ // Buffer for ADC data (MSB, LSB, Config Byte)
|
|
|
|
|
+ uint8_t adc_data[3] = {0};
|
|
|
|
|
+ int16_t raw_adc = 0;
|
|
|
|
|
+ uint8_t bytes_to_read = 3;
|
|
|
|
|
+ uint8_t adc_address = ADC_TARGET_BASE_ADDRESS + slot_id;
|
|
|
|
|
+ // printf("Reading ADC Data from MCP3428 for channel: %u\n", params.channel);
|
|
|
|
|
+
|
|
|
|
|
+ if (DL_I2C_getControllerStatus(I2C_controller_INST) &
|
|
|
|
|
+ DL_I2C_CONTROLLER_STATUS_BUSY_BUS) {
|
|
|
|
|
+ printf("Error: I2C bus stuck! Resetting..\n");
|
|
|
|
|
+ // DL_I2C_resetControllerTransfer(I2C_controller_INST);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ gRxADClen = bytes_to_read;
|
|
|
|
|
+ gRxADCcount = 0;
|
|
|
|
|
+ gRxComplete = false;
|
|
|
|
|
+
|
|
|
|
|
+ DL_I2C_startControllerTransfer(I2C_controller_INST, adc_address,
|
|
|
|
|
+ DL_I2C_CONTROLLER_DIRECTION_RX, gRxADClen);
|
|
|
|
|
+ DL_I2C_enableInterrupt(I2C_controller_INST,
|
|
|
|
|
+ DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER);
|
|
|
|
|
+ while (DL_I2C_getControllerStatus(I2C_controller_INST) &
|
|
|
|
|
+ DL_I2C_CONTROLLER_STATUS_BUSY_BUS)
|
|
|
|
|
+ ;
|
|
|
|
|
+ while (!gRxComplete)
|
|
|
|
|
+ ;
|
|
|
|
|
+
|
|
|
|
|
+ uint8_t msb = gRxPacket[0];
|
|
|
|
|
+ uint8_t lsb = gRxPacket[1];
|
|
|
|
|
+ uint8_t config_adc_byte = gRxPacket[2];
|
|
|
|
|
+
|
|
|
|
|
+ uint8_t gain_setting = (config_adc_byte & 0x03);
|
|
|
|
|
+ uint8_t gain_multiplier = (1 << gain_setting); // Gain values: 1, 2, 4, 8
|
|
|
|
|
+
|
|
|
|
|
+ if (params.resolution == 16) {
|
|
|
|
|
+ raw_adc = (msb << 8) | lsb;
|
|
|
|
|
+ if (raw_adc > 32767)
|
|
|
|
|
+ raw_adc -= 65536;
|
|
|
|
|
+ } else if (params.resolution == 14) {
|
|
|
|
|
+ raw_adc = ((msb & 0b00111111) << 8) | lsb;
|
|
|
|
|
+ if (raw_adc > 8191)
|
|
|
|
|
+ raw_adc -= 16384;
|
|
|
|
|
+ } else if (params.resolution == 12) {
|
|
|
|
|
+ raw_adc = ((msb & 0b00001111) << 8) | lsb;
|
|
|
|
|
+ if (raw_adc > 2047)
|
|
|
|
|
+ raw_adc -= 4096;
|
|
|
|
|
+ }
|
|
|
|
|
+ printf("Raw ADC Value: 0x%0X (%d)\n", raw_adc, raw_adc);
|
|
|
|
|
+ return raw_adc;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// **Interrupt handler for ADC Read Completion**
|
|
// **Interrupt handler for ADC Read Completion**
|
|
|
void I2C_ADC_IRQHandler(void) {
|
|
void I2C_ADC_IRQHandler(void) {
|
|
|
- if (DL_I2C_getPendingInterrupt(I2C_controller_INST) == DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER) {
|
|
|
|
|
- gRxComplete = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (DL_I2C_getPendingInterrupt(I2C_controller_INST) ==
|
|
|
|
|
+ DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER) {
|
|
|
|
|
+ gRxComplete = true;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
/* Function to Convert ADC Reading to Voltage */
|
|
/* Function to Convert ADC Reading to Voltage */
|
|
|
uint16_t ADC_ConvertToVoltage(int16_t adc_value, ADC_PARAMS params) {
|
|
uint16_t ADC_ConvertToVoltage(int16_t adc_value, ADC_PARAMS params) {
|
|
|
- uint16_t measured_voltage= 0;
|
|
|
|
|
- uint16_t LSB= 0;
|
|
|
|
|
- uint32_t max_adc_value= 1;
|
|
|
|
|
-
|
|
|
|
|
- switch (params.resolution) {
|
|
|
|
|
- case 12: // 12-bit
|
|
|
|
|
- max_adc_value = 4095;
|
|
|
|
|
- break;
|
|
|
|
|
- case 14: // 14-bit
|
|
|
|
|
- max_adc_value = 16383;
|
|
|
|
|
- break;
|
|
|
|
|
- case 16: // 16-bit
|
|
|
|
|
- max_adc_value = 65535;
|
|
|
|
|
- break;
|
|
|
|
|
- default:
|
|
|
|
|
- printf("Error: Unknown ADC Resolution!\n");
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
- measured_voltage= (((uint32_t)adc_value * ADC_VREF_MV) * 3)/max_adc_value;
|
|
|
|
|
- return (uint16_t)measured_voltage;
|
|
|
|
|
|
|
+ uint16_t measured_voltage = 0;
|
|
|
|
|
+ uint16_t LSB = 0;
|
|
|
|
|
+ uint32_t max_adc_value = 1;
|
|
|
|
|
+
|
|
|
|
|
+ switch (params.resolution) {
|
|
|
|
|
+ case 12: // 12-bit
|
|
|
|
|
+ max_adc_value = 4095;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 14: // 14-bit
|
|
|
|
|
+ max_adc_value = 16383;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 16: // 16-bit
|
|
|
|
|
+ max_adc_value = 65535;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ printf("Error: Unknown ADC Resolution!\n");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ measured_voltage = (((uint32_t)adc_value * ADC_VREF_MV) * 3) / max_adc_value;
|
|
|
|
|
+ return (uint16_t)measured_voltage;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Function to Convert ADC Reading to Voltage */
|
|
/* Function to Convert ADC Reading to Voltage */
|
|
|
uint16_t ADC_ConvertToCurrent(int16_t adc_value, ADC_PARAMS params) {
|
|
uint16_t ADC_ConvertToCurrent(int16_t adc_value, ADC_PARAMS params) {
|
|
|
- int16_t current_mA= 0;
|
|
|
|
|
- //uint8_t r_shunt= 0.1;
|
|
|
|
|
- //Convert ADC value to voltage across shunt resistor:
|
|
|
|
|
- uint16_t voltage_mV= ADC_ConvertToVoltage(adc_value, params);
|
|
|
|
|
- uint8_t gain_multiplier= (1 <<(params.gain - 1));
|
|
|
|
|
- //Convert voltage drop across shunt resistor to current
|
|
|
|
|
- current_mA= (voltage_mV)/ (0.1 * gain_multiplier);
|
|
|
|
|
- //printf("Converted Current: %d mA.\n", current_mA);
|
|
|
|
|
- return (int16_t)current_mA;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void Battery_UpdateVoltage(ADC_PARAMS params){
|
|
|
|
|
- for(uint8_t slot=0; slot< NUM_SLOTS; slot++ ){
|
|
|
|
|
- //CH1: Voltage Setup
|
|
|
|
|
- params.channel= 1;
|
|
|
|
|
- int16_t raw_adc_voltage= ADC_ReadData(slot, params);
|
|
|
|
|
- batteries[slot].voltage= ADC_ConvertToVoltage(raw_adc_voltage, params);
|
|
|
|
|
- printf("Battery Voltage for slot %d is %u mV.\n", slot, batteries[slot].voltage);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ int16_t current_mA = 0;
|
|
|
|
|
+ // uint8_t r_shunt= 0.1;
|
|
|
|
|
+ // Convert ADC value to voltage across shunt resistor:
|
|
|
|
|
+ uint16_t voltage_mV = ADC_ConvertToVoltage(adc_value, params);
|
|
|
|
|
+ uint8_t gain_multiplier = (1 << (params.gain - 1));
|
|
|
|
|
+ // Convert voltage drop across shunt resistor to current
|
|
|
|
|
+ current_mA = (voltage_mV) / (0.1 * gain_multiplier);
|
|
|
|
|
+ // printf("Converted Current: %d mA.\n", current_mA);
|
|
|
|
|
+ return (int16_t)current_mA;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void Battery_UpdateCurrent(ADC_PARAMS params){
|
|
|
|
|
- for(uint8_t slot=0; slot< NUM_SLOTS; slot++ ){
|
|
|
|
|
- //CH2: Charge Current
|
|
|
|
|
- params.channel= 2;
|
|
|
|
|
- int16_t raw_adc_current= ADC_ReadData(slot, params);
|
|
|
|
|
- batteries[slot].current= ADC_ConvertToCurrent(raw_adc_current, params);
|
|
|
|
|
- printf("Battery current for slot %d is %u mA.\n", slot, batteries[slot].current);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void Battery_UpdateADCReading(){
|
|
|
|
|
- ADC_PARAMS adc_params;
|
|
|
|
|
-
|
|
|
|
|
- // For Channel 1: Voltage
|
|
|
|
|
- adc_params.channel= 1;
|
|
|
|
|
- adc_params.resolution= 12;
|
|
|
|
|
- adc_params.continuous= 0;
|
|
|
|
|
- adc_params.gain= 1;
|
|
|
|
|
- ADC_SetConfigurationBytes(adc_params);
|
|
|
|
|
- delay_cycles(50000);
|
|
|
|
|
- for(uint8_t slot=0; slot< NUM_SLOTS; slot++ ){
|
|
|
|
|
- int16_t raw_adc_voltage= ADC_ReadData(slot, adc_params);
|
|
|
|
|
- batteries[slot].voltage= ADC_ConvertToVoltage(raw_adc_voltage, adc_params);
|
|
|
|
|
- printf("Battery Voltage for slot %d is %u mV.\n", slot, batteries[slot].voltage);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //For Channel 2: Current
|
|
|
|
|
- adc_params.channel= 2;
|
|
|
|
|
- ADC_SetConfigurationBytes(adc_params);
|
|
|
|
|
- delay_cycles(50000);
|
|
|
|
|
-
|
|
|
|
|
- for(uint8_t slot=0; slot< NUM_SLOTS; slot++ ){
|
|
|
|
|
- int16_t raw_adc_current= ADC_ReadData(slot, adc_params);
|
|
|
|
|
- batteries[slot].current= ADC_ConvertToCurrent(raw_adc_current, adc_params);
|
|
|
|
|
- printf("Battery current for slot %d is %u mA.\n", slot, batteries[slot].current);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+void Battery_UpdateADCReading(uint8_t slot, uint8_t channel) {
|
|
|
|
|
+ while (adc_state != ADC_STATE_DONE) {
|
|
|
|
|
+ switch (adc_state) {
|
|
|
|
|
+
|
|
|
|
|
+ case ADC_STATE_CONFIGURE:
|
|
|
|
|
+ adc_params.channel = channel;
|
|
|
|
|
+ // printf("Channel: %d\n", adc_params.channel);
|
|
|
|
|
+ adc_params.resolution = 12;
|
|
|
|
|
+ adc_params.continuous = 1;
|
|
|
|
|
+ adc_params.gain = 1;
|
|
|
|
|
+ ADC_SetConfigurationBytes(adc_params);
|
|
|
|
|
+ adc_state = ADC_STATE_WAIT;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case ADC_STATE_WAIT:
|
|
|
|
|
+ if (ADC_CheckReadyBit(slot, adc_params)) {
|
|
|
|
|
+ adc_state = ADC_STATE_READ;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case ADC_STATE_READ:
|
|
|
|
|
+ if (channel == 0) {
|
|
|
|
|
+
|
|
|
|
|
+ int16_t raw_adc_voltage = ADC_ReadData(slot, adc_params);
|
|
|
|
|
+ batteries[slot].voltage =
|
|
|
|
|
+ ADC_ConvertToVoltage(raw_adc_voltage, adc_params);
|
|
|
|
|
+ printf("Battery voltage for slot %d is %u mV.\n", slot,
|
|
|
|
|
+ batteries[slot].voltage);
|
|
|
|
|
+ adc_state = ADC_STATE_DONE;
|
|
|
|
|
+
|
|
|
|
|
+ } else if (channel == 1) {
|
|
|
|
|
+
|
|
|
|
|
+ int16_t raw_adc_current = ADC_ReadData(slot, adc_params);
|
|
|
|
|
+ batteries[slot].current =
|
|
|
|
|
+ ADC_ConvertToCurrent(raw_adc_current, adc_params);
|
|
|
|
|
+ printf("Battery current for slot %d is %u mA.\n", slot,
|
|
|
|
|
+ batteries[slot].current);
|
|
|
|
|
+
|
|
|
|
|
+ adc_state = ADC_STATE_DONE;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ channel = 0;
|
|
|
|
|
+ adc_state = ADC_STATE_CONFIGURE;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ adc_state = ADC_STATE_CONFIGURE;
|
|
|
}
|
|
}
|
|
|
-
|
|
|