Hello,
I am building an application based on the AFE4404. For the proof of concept, we are interfacing the AFE4404 with the Arduino Mega. We are able to initialize and communicate with the AFE4404 but the ADC data we read seems random and there is no visible PPG waveform. I would like to know if there is any other processing that needs to be done on the raw ADC data before it can be plotted.
Here is the afe4404 library we are using, which is a direct copy of the official afe4404 library with Arduino HAL modifications.
//AFE4404.c #include "AFE4404.h" void AFE4404_Reg_Init(void) { AFE4404_Disable_Read(); AFE4404_Reg_Write(1, 100); //AFE_LED2STC AFE4404_Reg_Write(2, 399); //AFE_LED2ENDC AFE4404_Reg_Write(3, 802); //AFE_LED1LEDSTC AFE4404_Reg_Write(4, 1201); //AFE_LED1LEDENDC AFE4404_Reg_Write(5, 501); //AFE_ALED2STC AFE4404_Reg_Write(6, 800); //AFE_ALED2ENDC AFE4404_Reg_Write(7, 902); //AFE_LED1STC AFE4404_Reg_Write(8, 1201); //AFE_LED1ENDC AFE4404_Reg_Write(9, 0); //AFE_LED2LEDSTC AFE4404_Reg_Write(10, 399); //AFE_LED2LEDENDC AFE4404_Reg_Write(11, 1303); //AFE_ALED1STC AFE4404_Reg_Write(12, 1602); //AFE_ALED1ENDC AFE4404_Reg_Write(13, 409); //AFE_LED2CONVST AFE4404_Reg_Write(14, 1468); //AFE_LED2CONVEND AFE4404_Reg_Write(15, 1478); //AFE_ALED2CONVST AFE4404_Reg_Write(16, 2537); //AFE_ALED2CONVEND AFE4404_Reg_Write(17, 2547); //AFE_LED1CONVST AFE4404_Reg_Write(18, 3606); //AFE_LED1CONVEND AFE4404_Reg_Write(19, 3616); //AFE_ALED1CONVST AFE4404_Reg_Write(20, 4675); //AFE_ALED1CONVEND AFE4404_Reg_Write(21, 401); //AFE_ADCRSTSTCT0 AFE4404_Reg_Write(22, 407); //AFE_ADCRSTENDCT0 AFE4404_Reg_Write(23, 1470); //AFE_ADCRSTSTCT1 AFE4404_Reg_Write(24, 1476); //AFE_ADCRSTENDCT1 AFE4404_Reg_Write(25, 2539); //AFE_ADCRSTSTCT2 AFE4404_Reg_Write(26, 2545); //AFE_ADCRSTENDCT2 AFE4404_Reg_Write(27, 3608); //AFE_ADCRSTSTCT3 AFE4404_Reg_Write(28, 3614); //AFE_ADCRSTENDCT3 AFE4404_Reg_Write(54, 401); //AFE_LED3LEDSTC AFE4404_Reg_Write(55, 800); //AFE_LED3LEDENDC AFE4404_Reg_Write(29, 39999); //AFE_PRPCOUNT AFE4404_Reg_Write(30, 0x000103); //AFE_CONTROL1 TimerEN = 1; NUMAV = 3 AFE4404_Reg_Write(32, 0x008003); //AFE_TIA_SEP_GAIN (LED2) ENSEPGAIN = 1; LED2/LED3 gain = 50K AFE4404_Reg_Write(33, 0x000005); //AFE_TIA_GAIN (LED1) LED1/LED1AMB gain = 50K AFE4404_Reg_Write(58, 0x000000); //AFE_DAC_SETTING_REG AFE4404_Reg_Write(34, 0x0030CF); //LED3 - 3.125mA; LED2 - 3.125mA; LED1 - 12.5mA //AFE4404_Reg_Write(34, 0x00379E); AFE4404_Reg_Write(35, 0x124218); //DYN1, LEDCurr, DYN2, Ext CLK, DYN3, DYN4 //0x000200); - 0x200 Osc mode //AFE_CONTROL2 AFE4404_Reg_Write(49, 0x000020); //ENABLE_INPUT_SHORT AFE4404_Reg_Write(57, 0); //CLKDIV_PRF AFE4404_Reg_Write(50, 5475); //AFE_DPD1STC AFE4404_Reg_Write(51, 39199); //AFE_DPD1ENDC AFE4404_Enable_Read(); } /**********************************************************************************************************/ /* AFE4404_Init */ /**********************************************************************************************************/ void AFE4404_Init(void) { Wire.begin(); AFE4404_RESETZ_Init (); //AFE4404_Enable_HWPDN (); //AFE4404_Disable_HWPDN (); AFE4404_Trigger_HWReset (); AFE4404_ADCRDY_Interrupt_Init(); AFE4404_Reg_Init(); } /**********************************************************************************************************/ /* AFE4404_RESETZ_Init */ /**********************************************************************************************************/ void AFE4404_RESETZ_Init (void) { pinMode(RESET_PIN, OUTPUT); digitalWrite(RESET_PIN, HIGH); } /**********************************************************************************************************/ /* AFE4404_Enable_HWPDN */ /**********************************************************************************************************/ void AFE4404_Enable_HWPDN (void) { digitalWrite(RESET_PIN, LOW); delay(10); // ~10ms delay with 16MHz clock } /**********************************************************************************************************/ /* AFE4404_Disable_HWPDN */ /**********************************************************************************************************/ void AFE4404_Disable_HWPDN (void) { digitalWrite(RESET_PIN, HIGH); delay(10); // ~10ms delay with 16MHz clock } /**********************************************************************************************************/ /* AFE4404_Trigger_HWReset */ /**********************************************************************************************************/ void AFE4404_Trigger_HWReset (void) { digitalWrite(RESET_PIN, LOW); delayMicroseconds(30); digitalWrite(RESET_PIN, HIGH); delay(10); } /**********************************************************************************************************/ /* AFE4404_Diagnostics_Check */ /**********************************************************************************************************/ /*unsigned char AFE4404_Diagnostics_Check (void) { AFE4404_Disable_Read(); AFE4404_Reg_Write(0x23,0x000200); // Enable internal oscillator AFE4404_Reg_Write(0x1E,0x000100); // TIMER_EN AFE4404_Reg_Write(0,4); // DIAG_EN __delay_cycles(160000); // ~10ms delay AFE4404_Enable_Read(); return ((unsigned char)AFE4404_Reg_Read(48)); //DIAG status }*/ /*********************************************************************************************************/ /* AFE4404_Reg_Write */ /*********************************************************************************************************/ void AFE4404_Reg_Write (unsigned char reg_address, unsigned long data) { unsigned char configData[3]; configData[0]=(unsigned char)(data >>16); configData[1]=(unsigned char)(((data & 0x00FFFF) >>8)); configData[2]=(unsigned char)(((data & 0x0000FF))); I2C_write(AFE4404_I2C_DEFAULT_ADDRESS, reg_address, configData, 3); } /**********************************************************************************************************/ /* AFE4404_Reg_Read */ /**********************************************************************************************************/ signed long AFE4404_Reg_Read(unsigned char Reg_address) { unsigned char configData[3]; signed long retVal; I2C_read (AFE4404_I2C_DEFAULT_ADDRESS, Reg_address, configData, 3); retVal = configData[0]; retVal = (retVal << 8) | configData[1]; retVal = (retVal << 8) | configData[2]; if (Reg_address >= 0x2A && Reg_address <= 0x2F) { if (retVal & 0x00200000) // check if the ADC value is positive or negative { retVal &= 0x003FFFFF; // convert it to a 22 bit value //retVal = (~retVal)+1; return (retVal^0xFFC00000); } } return retVal; } /**********************************************************************************************************/ /* AFE4404_Enable_Read */ /**********************************************************************************************************/ void AFE4404_Enable_Read (void) { unsigned char configData[3]; configData[0]=0x00; configData[1]=0x00; configData[2]=0x01; I2C_write (AFE4404_I2C_DEFAULT_ADDRESS, CONTROL0, configData, 3); } /**********************************************************************************************************/ /* AFE4404_Disable_Read */ /**********************************************************************************************************/ void AFE4404_Disable_Read (void) { unsigned char configData[3]; configData[0]=0x00; configData[1]=0x00; configData[2]=0x00; I2C_write (AFE4404_I2C_DEFAULT_ADDRESS, CONTROL0, configData, 3); } /**********************************************************************************************************/ /* AFE4404_ADCRDY_Interrupt_Init */ /**********************************************************************************************************/ void AFE4404_ADCRDY_Interrupt_Init (void) { pinMode(AFE_INTERRUPT_PIN, INPUT); } /**********************************************************************************************************/ /* AFE4404_ADCRDY_Interrupt_Enable */ /**********************************************************************************************************/ void AFE4404_ADCRDY_Interrupt_Enable (void) { //CLEAR_INT_FLAG_ON_ADC_RDY_PIN(); //P2IFG &= ~AFE_ADC_DRDY; // P2.3 IFG cleared //ENABLE_INT_ON_ADC_RDY_PIN(); //P2IE |= AFE_ADC_DRDY; // P2.3 interrupt enabled } /**********************************************************************************************************/ /* AFE4404_ADCRDY_Interrupt_Disable */ /**********************************************************************************************************/ void AFE4404_ADCRDY_Interrupt_Disable (void) { //CLEAR_INT_FLAG_ON_ADC_RDY_PIN(); //P2IFG &= ~AFE_ADC_DRDY; // P2.3 IFG cleared //DISABLE_INT_ON_ADC_RDY_PIN(); //P2IE &= ~AFE_ADC_DRDY; // P2.3 interrupt disabled } void I2C_write (int slave_address, int reg_address, byte configData[], int byteCount) { signed long retVal; Wire.beginTransmission(slave_address); Wire.write(reg_address); // Serial.print(configData[0]); // Serial.print(","); // Serial.print(configData[1]); // Serial.print(","); // Serial.println(configData[2]); retVal = configData[0]; retVal = (retVal << 8) | configData[1]; retVal = (retVal << 8) | configData[2]; // Serial.println(retVal); // Serial.println(reg_address); Wire.write(configData, 3); Wire.endTransmission(); } inline void I2C_read(int slave_address, int reg_address, byte *read_Data, int byteCount) { Wire.beginTransmission(slave_address); Wire.write(reg_address); Wire.endTransmission(); Wire.requestFrom(slave_address, 3); while(Wire.available() && (byteCount != 0)) { *read_Data++ = Wire.read(); byteCount--; } } // End of file
One particular worry is the AFE4404_Reg_Read function that doesnt seem to convert the 2's complement values of the led back to decimal:
signed long AFE4404_Reg_Read(unsigned char Reg_address) { unsigned char configData[3]; signed long retVal; I2C_read (AFE4404_I2C_DEFAULT_ADDRESS, Reg_address, configData, 3); retVal = configData[0]; retVal = (retVal << 8) | configData[1]; retVal = (retVal << 8) | configData[2]; if (Reg_address >= 0x2A && Reg_address <= 0x2F) { if (retVal & 0x00200000) // check if the ADC value is positive or negative { retVal &= 0x003FFFFF; // convert it to a 22 bit value return (retVal^0xFFC00000); } } return retVal; }
Is this conversion done in the GUI application?
Also this link https://e2e.ti.com/support/data-converters/f/73/t/369445 suggests converting the ADC code to a voltage by dividing the 2's complement value.
15. How to convert ADC results code to voltage?
The ADC volts to codes conversion formula is:
ADC data (volts) = (ADC codes in two's complement format * Vref ) / 2^21
where Vref = 1.2V
Please can you explain why the ADC code is not converted to decimal first?