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 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.

  • Thank you Glen.

    I will check it and get back to you

  • Hi Glen,

    I have a query over LED switch on/off.

    I am able to get the Raw PPG of RED and IR LED and I am able to switch (on/off) these two LEDs by using MCU timer peripherals in milliseconds. I am using two timeslot which is A and B and able to read the FIFO data.

    Timeslot A for RED

    Timeslot B for IR

    Is there any option by using ADPD4101 registers to switch LED on/off in us ??

    Like...

    Timeslot A, RED on for 250 us and Timeslot B, IR should be in off-state ----- Both Timeslots off ----- Timeslot B IR on for 250us and Timeslot A RED should be in off-state ----- Both Timeslots off ------ should continue in the same way.

    Please have a look at the below pic.

    Looking forward for your suggestion

    Regards,

    Sudharsan

  • Hi Sudharsan,

    You can turn on/off the LED drivers by setting the related registers. The registers 0x0105/0x0106 for timeslot A, 0x0125/0x0126 for timeslot B, ... and the registers 0x0109 for timeslot A, 0x0129 for timeslot B together turn on and off the LEDs and control the pulse width. If the settings in registers 0x0105/0x0106, 0x0125/0x0126, ... are zero, the LED drivers are off. The on duration of the LED drivers are set in register 0x0109, 0x0129, ...The registers 0x0109, 0x0129, ... can set the offset for LED pulses as well. Please refer Figure 35 on page.30 of ADPD4100-4101 datasheet for the timing.

    There is absolutely no need for any external circuit to control the LEDs.

    Regards,

    Glen B.  

  • Hi Glen,

    Thanks for your response.

    I have selected Timeslots A and B

    RED led configured in Timeslot A   (LED pulse width - 5 us on, 18us off)

    IR led configured in Timeslot B (LED pulse width - 5 us on, 18us off)

    I am able to read both PPG data from FIFO like below that I mentioned

    [Timeslot A CH1 data]  [Timeslot B CH1 data]

    Please correct the below sequence If I am wrong.

    LED on/off also will follow the sequence right??

    [ PRECON ] [ TS A RED 5us on ]  [ TS A RED 5us off ] [ TS A IR 5us on ] [ TS A RED 5us off ] ....

    Regards,

    Sudharsan

  • Hi Sudharsan,

    The red and IR can not be on alternately in the same timeslot. Figure 35 in the ADPD4100-4101 datasheet is a good example of timing for your reference. Depending on your setting of number of  pulses (0x0107 for TsA, 0x0127 for TsB, ...) and pulse period (0x0108 for TsA, 0x0128 for TsB, ...), you can have the sequence below:

    [TsA precon]

    [TsA LED offset]

    [TsA LED on/1st pulse] [TsA LED off/ period minus on-time] 

    [TsA LED on/2nd pulse] [TsA LED off/ period minus on-time] 

    ....

    [TsA LED on/last pulse] [TsA LED off/ period minus on-time] 

    [TsB precon]

    [TsB LED offset]

    [TsB LED on/1st pulse] [TsB LED off/ period minus on-time] 

    [TsB LED on/2nd pulse] [TsB LED off/ period minus on-time] 

    ....

    [TsB LED on/last pulse] [TsB LED off/ period minus on-time] 

    ...

    Just be curious, is there any specific reason for you to choose 5us pulse? Please note that the BPF has its passband from 100 kHz to 390 kHz and may not be optimal for 5us LED pulses. 

    Regards,

    Glen B.

Reply
  • Hi Sudharsan,

    The red and IR can not be on alternately in the same timeslot. Figure 35 in the ADPD4100-4101 datasheet is a good example of timing for your reference. Depending on your setting of number of  pulses (0x0107 for TsA, 0x0127 for TsB, ...) and pulse period (0x0108 for TsA, 0x0128 for TsB, ...), you can have the sequence below:

    [TsA precon]

    [TsA LED offset]

    [TsA LED on/1st pulse] [TsA LED off/ period minus on-time] 

    [TsA LED on/2nd pulse] [TsA LED off/ period minus on-time] 

    ....

    [TsA LED on/last pulse] [TsA LED off/ period minus on-time] 

    [TsB precon]

    [TsB LED offset]

    [TsB LED on/1st pulse] [TsB LED off/ period minus on-time] 

    [TsB LED on/2nd pulse] [TsB LED off/ period minus on-time] 

    ....

    [TsB LED on/last pulse] [TsB LED off/ period minus on-time] 

    ...

    Just be curious, is there any specific reason for you to choose 5us pulse? Please note that the BPF has its passband from 100 kHz to 390 kHz and may not be optimal for 5us LED pulses. 

    Regards,

    Glen B.

Children
  • Hi Glen,

    We are not using internal BPF.

    We have seen clean signal on 5us pulse.

    Number of pulse = 32, Number of repeats = 1 (default)

    To calculate SPO2, it is necessary to do RED and IR LED on/off one after other, repeatedly.

    For the above, we have been configured RED in TS A and IR in TS B

    I understood your explanation 

    TS A RED LED on/off  - 32 times

    TS B IR LED on/off  - 32 times

    Regards

    Sudharsan