Post Go back to editing

How to drive the LED in ADPD4101 sensor?

Hi,

We are using ADPD4101 sensor which is using I2C interface. I am unable to drive the LED which is present in ADPD4101 sensor.

I have attached my code snippet here. I am looking ahead for your suggestion on ADPD4101 sensor LED drive.

int32_t adpd410x_reg_read(nrf_drv_twi_t const *p_instance, uint16_t address, uint16_t *store_data)
{
	uint32_t ret_code;
	uint8_t buff[] = {0, 0, 0, 0};

        buff[0] = ((address >> 8) & 0x00ff) | 0x80;
        buff[1] = address & 0xff;
        /* No stop bit */
        ret_code = nrf_drv_twi_tx(p_instance, HRM_I2C_ADDRESS, buff, 2, true);
        if(ret_code != NRF_SUCCESS)
           return ret_code;
        ret_code = nrf_drv_twi_rx(p_instance, HRM_I2C_ADDRESS, (buff + 2), 2);
        if(ret_code != NRF_SUCCESS)
           return ret_code;

	*store_data = ((uint16_t)buff[2] << 8) & 0xff00;
	*store_data |= buff[3] & 0xff;

	return NRF_SUCCESS;
}
/**
 * @brief Write device register.
 * @param address - Register address.
 * @param data - New register value.
 * @return NRF_SUCCESS in case of success, FAILURE otherwise.
 */
int32_t adpd410x_reg_write(nrf_drv_twi_t const *p_instance, uint16_t address, uint16_t data)
{
	uint8_t buff[] = {0, 0, 0, 0};

          buff[0] = ((address >> 8) & 0x00ff) | 0x80;
          buff[1] = address & 0xff;
          buff[2] = (data >> 8) & 0x00ff;
          buff[3] = data & 0xff;

        return nrf_drv_twi_tx(p_instance, HRM_I2C_ADDRESS, buff, 4, false);
}

/**
 * @brief Do a software reset.
 * @return NRF_SUCCESS in case of success, FAILURE otherwise.
 */
int32_t adpd410x_reset(nrf_drv_twi_t const *p_instance)
{
	int32_t ret;

	ret = adpd410x_reg_write(p_instance, ADPD410X_REG_SYS_CTL, BITM_SYS_CTL_SW_RESET);
	if(ret != NRF_SUCCESS)
          return ret;
}

uint16_t reg_temp_1, val_1;
void get_ADPD4_chip_ID(nrf_drv_twi_t const *p_instance, uint8_t i2c_line)
{
        int32_t ret_code;
       
	ret_code = adpd410x_reg_read(p_instance, ADPD410X_REG_CHIP_ID, &reg_temp_1);
	if(ret_code != NRF_SUCCESS){ 
          NRF_LOG_INFO("HRM I2C read failure");
          return;
        }
        val_1 = reg_temp_1 & BITM_CHIP_ID;
        if((val_1) == (uint16_t)ADPD410X_CHIP_ID){
            NRF_LOG_INFO("ADPD4101 CHIP-ID read success");
        }
        else{
            NRF_LOG_INFO("ADPD4101 CHIP-ID read failure");   
        }
}

/**
 * @brief Set operation mode.
 * @return NRF_SUCCESS in case of success, FAILURE otherwise.
 */
int32_t adpd410x_set_opmode(nrf_drv_twi_t const *p_instance, uint16_t opmode)
{
	return adpd410x_reg_write(p_instance, ADPD410X_REG_OPMODE, opmode); 
}


/**
 * @brief Set number of active time slots.
 * @param timeslot_no - Last time slot to be enabled.
 * @return NRF_SUCCESS in case of success, FAILURE otherwise.
 */
int32_t adpd410x_set_last_timeslot(nrf_drv_twi_t const *p_instance, enum adpd410x_timeslots timeslot_no)
{
	return adpd410x_reg_write(p_instance, ADPD410X_REG_OPMODE, timeslot_no);
}

/**
 * @brief Set device sampling frequency.
 * @param sampling_freq - New sampling frequency.
 * @return NRF_SUCCESS in case of success, FAILURE otherwise.
 */
int32_t adpd410x_set_sampling_freq(nrf_drv_twi_t const *p_instance, uint32_t sampling_freq)
{
	int32_t ret;
	uint32_t reg_load;
	uint16_t reg_temp;
#if 1

        ret = adpd410x_reg_read(p_instance, ADPD410X_REG_SYS_CTL, &reg_temp);
        if(ret != NRF_SUCCESS)
            return ret;
        if(reg_temp & BITP_SYS_CTL_LFOSC_SEL)
            reg_load = ADPD410X_LOW_FREQ_OSCILLATOR_FREQ1;
        else
            reg_load = ADPD410X_LOW_FREQ_OSCILLATOR_FREQ2;

        reg_load /= sampling_freq;
#endif
        reg_load = ADPD410X_LOW_FREQ_OSCILLATOR_FREQ2;
	ret = adpd410x_reg_write(p_instance, ADPD410X_REG_TS_FREQ, (reg_load & 0xFFFF));
	if(ret != NRF_SUCCESS)
          return ret;
}

int32_t ADPD410x_device_setup(nrf_drv_twi_t const *p_instance, enum adpd410x_timeslots m_timeslot_no, uint8_t i2c_line)
{
        int32_t ret;
        uint16_t data;

        data = 0x4000;                           //Enable Channel 2
	ret = adpd410x_reg_write(p_instance, ADPD410X_REG_TS_CTRL(m_timeslot_no), data);       //0x0100
        if(ret != NRF_SUCCESS)
            return ret;

        if(i2c_line == 1)
        {
            data = 0x1000;                       //IN2 connected to VC1...IN7
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INPUTS(m_timeslot_no), data);   //0x0102
            if(ret != NRF_SUCCESS)
                return ret;         
        }
        else
        {
            //m_timeslot_no = 6;                 //Setup inputs 
            data = 0x4043;                       //IN2 connected to VC1...IN4, IN8 connected to VC2
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INPUTS(m_timeslot_no), data);   //0x01C2-G slot //0x0102
            if(ret != NRF_SUCCESS)
                return ret;
        }

	data = 0x0E0E;                       //21 mA output current & slot A has been selected 1A, 2A
	ret = adpd410x_reg_write(p_instance, ADPD410X_REG_LED_POW12(m_timeslot_no), data);  //0x0105
        if(ret != NRF_SUCCESS)
            return ret;

        data = 0x0E0E;                       //21 mA output current & slot A has been selected 3A, 4A
	ret = adpd410x_reg_write(p_instance, ADPD410X_REG_LED_POW34(m_timeslot_no), data);  //0x0106
        if(ret != NRF_SUCCESS)
            return ret;

        data = 0xFF0A;                       //Pulse width max & offset max/2
        ret = adpd410x_reg_write(p_instance, ADPD410X_REG_LED_PULSE(m_timeslot_no), data); //0x0109
        if(ret != NRF_SUCCESS)
            return ret;

#if 0
        data = 0x1E00;                       //21 mA output current & slot B has been selected 4B
        ret = adpd410x_reg_write(p_instance, ADPD410X_REG_LED_POW34(m_timeslot_no), data);  //0x0126
        if(ret != NRF_SUCCESS)
            return ret;
#endif
}

int32_t adpd410x_set_clock_freq(nrf_drv_twi_t const *p_instance)
{
      int32_t ret;
      ret = adpd410x_reg_write(p_instance, ADPD410X_REG_SYS_CTL, 0x0002);    //1 Mhz low freq internal oscillator selected
      if(ret != NRF_SUCCESS)
        return ret;
}

void init_ADPD410x(nrf_drv_twi_t const *p_instance)
{
        adpd410x_reset(p_instance);                 //SW reset
        adpd410x_set_opmode(p_instance, BITP_OPMODE_OP_MODE);  //standby mode 
        adpd410x_set_clock_freq(p_instance);        //1 Mhz sampling freq
        //adpd410x_set_sampling_freq(p_instance, SAMPLING_FREQ);   //For 1MHz freq - Sampling rate will be 100Hz   
        adpd410x_set_last_timeslot(p_instance, ADPD410X_TS_A); //Time slot A
}

main()
{

/*Check ADPD4101 sensor */
      get_ADPD4_chip_ID(&m_twi, I2C_LINE0);
      get_ADPD4_chip_ID(&m_twi_1, I2C_LINE1);
      ADPD410x_device_setup(&m_twi, ADPD410X_TS_A, I2C_LINE1);
      nrf_delay_ms(10);
      ADPD410x_device_setup(&m_twi_1, ADPD410X_TS_A, I2C_LINE0);
      nrf_delay_ms(10);
      adpd410x_set_opmode(&m_twi, 0x0001);  // Changing from standby mode to Go mode
      adpd410x_set_opmode(&m_twi_1, 0x0001); // Changing from standby mode to Go mode
      
}

Regards

Sudharsan

Parents
  • Hi  Sudharsan,

    Have you verified if your register read & write are working?

    With regard to the LED drivers, can you let us know your schematic of the LED(s) and/or PD(s)? The LED drivers of ADPD4101 are current sink and the LED(s) should be supplied with VLED. 

    Regards,

    Glen B. 

  • Hi Glen,

    Thanks for your reply.

    I2C read/write is working fine. LEDs are 1A, 2A, 3A, 4A and 4B

    I have resolved it, as I was not turning on the 1MHz LF OSC

    Its working. I am moving forward to do PPG measurement.

    I'll give you an update on PPG stuffs. I need your support on this sensor's software development, as I am new to this.

    Thanks and Regards

    Sudharsan

  • Hi Sathish,

    Its falling edge configuration on controller side.

    FIFO TH - 0x000A was for our testing.

    I am currently setting with ( 256 - 1 = 255 (0xFF)) 0xFF bytes as FIFO Threshold. Usually we will call it as FIFO Watermarking right?....and when FIFO buffer filling reaches the Watermark level, it will trigger the interrupt on configured pin right? 

    I hope the other register settings that I did correctly.

    Regards

    Sudharsan

  • Hi Sudharsan,

    Yes, it's watermark level for FIFO. whenever the FIFO reached the watermark level it will trigger the interrupt.

    You need to configure register 0x22 as inverted output (0x0003U). Since your host expecting falling edge to trigger interrupt.

    Change the register value and check.

    Regards,

    Sathishkumar K

  • Hi Sathish,

    I am getting interrupt on both settings in 0x22 register (output inverted and output normal)

    I have configured as a output inverted and tested and also I have tested with output normal.

    I am getting PPG values from FIFO but I still have no clarity on following register settings. Is this register settings are fine to move forward to calculate Raw PPG to HRM ???

    Currently, we are preferring continuous connect mode. No modulation and No ADC offset has been selected. Please refer the below settings and suggest your comments

    1. Selected continuous connect mode 
    
    data = 0x0000, Reg = 0x0108 
    
    2. Gain setting - TIA gain 100k, Vref = 0.88V  //LEDs current setting is 50mA
    
    data = 0x02C1, Reg = 0x0104
    
    3. Skipped the PRECON and Testing with signal data by passing through "TIA + BPF + INT + ADC" and  "TIA + INT + ADC"       
    
    data = 0x00DA or 0x00E6, Reg =  0x0101
    
    4. when data = 0x99 - getting negative values as well  //Chop settings
    
    data = 0x00AA, Reg = 0x010D
    
    5. ADC pulses = 32, Integrator Pulse width data = 3 us , Integrator Offset data = 0x0210 //16.5us

    Regards

    Sudharsan

  • Hi Sudharsan,

    Please follow the example below to config your sensor for PPG measurement:

    ################################################################
    ## ADPD4100 Reference Config File, single-ended IN1 only, timeslot A only
    ## Please review config file for your design. This is a generic config file.
    0009 0080 # 32MHz trim - trim your own clock
    000B 02B2 # 1MHz trim - trim your own clock
    000C 0012 # 32kHz trim - trim your own clock
    000D 2710 # 100 Hz
    000F 0006 # enable 1MHz osc
    0020 0004 # in1 connected to vc1 during sleep, everything else floating
    0021 0000 # all inputs single ended, vc1 set to Vdd during sleep
    0022 0003 # gpio0 is output, inverted
    0023 0002 # intx to gpio0
    0014 8000 # fifo thresh interrupt to intx
    0006 00FF # fifo threshold 128 bytes

    ## timeslot A - continuous connect mode

    0100 0000 # Rin = 500, tsA offset = 0, skip subsample
    0101 40DA # path = TIA + BPF + INT + ADC
    0102 0001 # IN1 to channel 1, others disconnected
    0103 5002 # precondition inputs to TIA_Vref, VC1 active state = V_delta
    0104 03C0 # Rf = 200k Rint = 400k
    0105 0017 # 38 mA on LED1A
    0106 0000
    0107 0104 # 4 pulses
    0108 0000 # period set by automatic period of continuous connect mode
    0109 0210 # led width= 2us led offset=16 us
    010A 0003 # integrator width=3 us
    010B 0210 # integrator offset=16.5 us - ADJUST FINE OFFSET
    010C 0001 # no modulation
    0110 0003 # signal size = 3 bytes
    010D 0099 # -++- int pattern
    010E 0000 # NO OFFSET - review if needed
    010F 0000 # NO OFFSET - review if needed
    0112 0000 # no decimation

    You need to make some adjustment to the registers below:

    Adjust register 0x0104: work with register 0x0105 and/or 0x0106 and adjust the TIA gain accordingly to avoid TIA saturation, recommended output at 70% full scale (8192 LSB per pulse as full scale. For instance, for 4-pulse config with chopping by register 0x010D, 70% full scale is 8192x4x0.7 = 23,000 LSBs)

    Adjust register 0x0105/0x0106 for LED current: please note at anytime only one group of LED drivers can be used, either LED1A/2A/3A/4A or LED1B/2B/3B/4B, not both.

    Adjust register 0x0104: increase the pulse number to multiples of 4 to improve SNR

    Adjust register 0x010B: change the integrator offset with a reflector setup to optimize the zero-crossing. Please note the zero-crossing changes with the TIA gain so the optimal integrator offset needs to be optimized for each TIA gain.

     

    Hope the information above helps.

     

    Regards,

     

    Glen B.

  • Hi,

    I would request you to verify the PPG logs with respect to the register settings.

    Please find the attached sheet which is having the sample PPG waveforms and entire register settings.

    7536.PPG_logs.xlsx

    Looking forward for your comments

    Thanks

    Sudharsan

  • Hi Sudharsan,

    The data in your spreadsheet doesn't look like PPG signal. Before we debug other issue, can you add the register 0x00B0 with 0x0010 to your config file and check if you get output 0x020100 (decimal 131328)? If you get a different number, there is something wrong with your FIFO reading. 

    Regards,

    Glen B.

  • Hi Glen,

    I did not understand that you mentioned the register address 0x00B0. 

    Are you really pointing to 0x00B0 register ?? If Yes, there is no register address 0x00B0 mentioned in ADPD4101 datasheet.

    I request you to check my register configurations that I have attached in that spread-sheet itself. I have copied the register settings which you have posted. 

    Please refer this below post...My register settings are exactly matching with that

    ez.analog.com/.../394040

    Regards

    Sudharsan

  • Hi Glen,

    Please check the Raw PPG data and the overall our register settings.

    I request you to review the below spread sheet

    3377.RawPPG_vs_FilteredData_28June.xlsx

    Regards,

    Sudharsan

  • Hi Glen,

    These all the below register setting which I have specifically changed.

    Reg:       Data:

     0x0100   0x4000  //Enabled channel-2

     0x0107   0x0104  //ADC pulse = 4
     0x0109   0xFF0A  //LED pulse-width and offset
     0x010D   0x0099  //Register pattern -++-

    Please check the Raw PPG data which I have collected and Please don't forget to reply for the below also

    " I did not understand that you mentioned the register address 0x00B0. 

    Are you really pointing to 0x00B0 register ?? If Yes, there is no register address 0x00B0 mentioned in ADPD4101 datasheet "

    Regards,

    Sudharsan

Reply
  • Hi Glen,

    These all the below register setting which I have specifically changed.

    Reg:       Data:

     0x0100   0x4000  //Enabled channel-2

     0x0107   0x0104  //ADC pulse = 4
     0x0109   0xFF0A  //LED pulse-width and offset
     0x010D   0x0099  //Register pattern -++-

    Please check the Raw PPG data which I have collected and Please don't forget to reply for the below also

    " I did not understand that you mentioned the register address 0x00B0. 

    Are you really pointing to 0x00B0 register ?? If Yes, there is no register address 0x00B0 mentioned in ADPD4101 datasheet "

    Regards,

    Sudharsan

Children
  • Hi Sudharsan,

    You data doesn't look like PPG signal. There are a few strange settings in your config, including

    -  [0100]4000   # it looked like you enabled both CH1 and CH2; however, your register [0102]4000 indicates that only IN8 connecting to CH2. When you have CH2 enabled,  both CH1 and CH2 data are written to FIFO with size defined by resigter [0110]0003.

    -  [0109]FF0A  # indicate LED pulse width of 255us with 10us offset. What exactly do you plan to achieve? The typical LED pulse is 2us or 3us.

    -  [0104]03C0 and [0106]0036 # What is the distance between your LED and PD? With TIA gain of 200k and LED3A current of 0x36 (or 81mA), the TIA may be saturated already.

    With regard to register 0x00B0, it is not published in the datasheet. We suggest customers this register when we suspect there is an issue with the I2C or SPI FIFO reading.

    I strongly recommend that you contact your local ADI application engineer for a meeting with us so that we can review your design and solve your problem more efficiently. 

    Regards,

    Glen B.

  • Thank you Glen

    We were setting the LED pulse high as our application is Finger probing application and not wrist worn application. We are trying to get the PPG data and not getting it yet.

    Please refer the image that I attached here

    The distance between LED and Photo diode is 10-15mm and it is placed facing each other and not side by side.

    However we have a contact with local representative.

    Thanks

    Sudharsan

  • Hi Sudharsan,

    Thanks for the picture. 

    I assume you tested with red or IR LED(s) for your transmissive PPG. Is it correct? As mentioned earlier, your setting of register 0x0109 is not correct. 

     Please ask you local representative to schedule a meeting with us if you like.

    Regards,

    Glen B.

  • Adding to the above conversation,

    I have tried the register write 0x00B0 with 0x0010. I have got the output as decimal '131328' always. Hence it is proved that, there is no issue with the FIFO reading.

    We are using green LED to get Raw PPG.

    Regards

    Sudharsan

  • Hi Sudharsan,

    Thanks for the update on FIFO reading.

    As your device works in the transmissive mode, the green light cannot penetrate the finger tip and the PD cannot get any signal. You may be able to get some signal with red LED. What you really need is the IR LED.

    Regards,

    Glen B.

  • Hi Glen,

    Thanks for your support.

    I have checked with RED and IR LED. Its delivering convincible outputs.

    Also we have to do with green LED and PD connected  via IN4 to VC2.

    /**********************************/

    sampling freq = 400 hz

    0x03C0 //0x0104 //TIA gain

    ADC_PULSES 0x0120 //0x0107 

    LED_PULSE_OFFSET 0x0512 //0x0109 //5us - on 18us - off

    /**********************************/

    Do you have any comments on these registers to get PPG on green LED?

    Regards,

    Sudharsan

  • Hi Sudharsan,

    The green LED does not work in the transmissive mode since the penetration depth of the green light is shallow, typically a few mm maximal. The green LED usually works very well in reflective mode, which means the green LED and PD are on the same side of the finger tip with 2-3 mm separation.

    Is there any specific reason for the PD cathode connected to VC2? If you use VC2 as reverse bias for PD, you need to check registers 0x0020 and 0x0021 for proper setting. For the LED pulses, 5us is too long and not power efficient. Please note that the recommended pulse width is 2us or 3us.    

    Regards,

    Glen B.

  • Hi Glen,

    We have used RED and IR LED also, with that we got good PPG signal. Thanks for the given Green LED information, and we will relocate it near ADPD  for future implementation.

    In our requirement, we need different range of Wavelength and multiple LEDs. We used 3 Photo diode and we used VC2. Earlier, we were in the impression of that VC1 should be connected to IN1,3,5,7 and VC2 should be connected to IN2,4,6,8.. After implementation, we realized that it could be a common one.

    Thanks for your prompt response.

    Regards

    Sudharsan

  • Hi Glen,

    We are using 1300nm IR LED and photo diode (part number:  0090-3111-185).

    We were able to get PPG waveform with lot of high peaks involved. We tried to change gain setting of channel where it connected but we have not seen any major difference in it.

    We have also tried current setting from 10.5mA to 70.5mA and observed similar results.

    I have attached register configurations and sample PPG data below here. Please suggest us, Is there any other parameter need to change to get better waveform for this photodiode?

    2425.Reg_setting.txt    8510.RawPPG_1300nm.xlsx

    Regards

    Sudharsan

  • Hi Sudharsan,

    I cannot see your sample PPG data. Keep in mind that the signal is determined by the photodiode (PD) current, which depends on the wavelength, the quantum efficiency of LED/PD, as well as the spectral response of the PD. The ADPD4100 part measures the photo current, regardless of the the wavelength and the LED & PD type. If the signal has high quality at other wavelengths (such as 650nm/Red and 880nm/IR), it will certain that the low quality PPG at 1300nm is due to problem in the optical design 

    I came across a conference proceeding (PDF) LED Based Sensor System for Non-Invasive Measurement of the Hemoglobin Concentration in Human Blood (researchgate.net), which suggest that the PPG signal with 1300nm is weak (refer to Figure 7). You may also want to check out this article Penetration depth of photons in biological tissues from hyperspectral imaging in shortwave infrared in transmission and reflection geometries (nih.gov) for the much high tissue absorption at 1300nm.

    You can also check the datasheet of your PD and LED and optimize your config accordingly.

    Regards,

    Glen B.