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
  • +1
    •  Analog Employees 
    on Jun 10, 2021 3:47 PM

    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,

    I need your support on PPG measurements and I hope you know that I am using ADPD4101 sensor

    I have configured following registers

    1. Standby mode during write operations, Go mode after write operation

    2. 1 MHz LF Oscillator

    3. FIFO interrupt configured and Watermark level set to 20 bytes and GPIO 0 pin configured as an interrupt

    4. LEDs 1A, 2A, 3A, 4A, 4B configured with appropriate current settings - Able to operate

    5. Sampling frequency - 300 Hz

    6. Timeslot A has been selected - I request you to give me more information about Timeslots

    a) How many Timeslots can be used ? Currently I have used only Timeslot A. Is there anything like, we have to use only Timeslot A and  B for LEDs. C and D for Inputs/ GPIOs. Please clarify the same. I have also attached My HRM sensor schematic

    7. LED pulse width and offset 20us and 16us respectively

    8. In Register 0x0100 written value = 0x4000       Enable Channel 2   //<! impulse mode with offset = 0

    9. In Register 0x0101 written value = 0x00E6      Skip preconditioning, Band pass filter bypassed

    10. In Register 0x0110 written value = 0x0003     Configure number of bytes - 3 bytes (Max 4 bytes)

    11. TIA gain 100k and Vref = 0.88v

    12. In Register 0x0107 written value = 0x010C    No. of ADC pulses 

    13. In Register 0x0108 written value = 0x1000     float mode, minimum period

    14. In Register 0x010A written value = 0x0203     Integrator pulse width, bandpass filter powered down

    15. In Register 0x010B written value = 0x01A0    Integrator pulse timing offset

    16. In Register 0x010C written value = 0x0210    Modulation pulse width and offset

    17. In Register 0x010C written value = 0x0210    IN2 connected to VC1...IN4, IN8 connected to VC2

    b) I need to read the Channel 1 and Channel 2. How do I specifically read from channel 1 and Channel 2 ??

    c) Currently I am getting 3 bytes from FIFO on every single read. How do I verify whether I am receiving correct PPG outputs.

    I thought that I would get 20 bytes after periodic read from FIFO. But I have got 3 bytes every time. What is that DATA FORMAT bytes actually that I configured with ?

    d)  Decimation factor - I did not set this register. What do I need to set with ? or Does this very essential to set? (This is to calculate ODR right ??)

    e) Does it have standard sampling mode and Digital Integration mode ? If so, need to know detailed information.

    f) What is the Dark signal registers for?  and  What is the Lit signal registers for?

    Regards

    Sudharsan

  • +1
    •  Analog Employees 
    on Jun 15, 2021 6:55 PM in reply to SK377

    Hi Sudharsan,

    You can find the answers to most of your questions in the ADPD4100/ADPD4101 datasheet. You can start with simple configuration such as those come with our evaluation software Applications Wavetool.

    For your convenience, please refer to my comments below:

    6. Timeslot A has been selected - I request you to give me more information about Timeslots

    a) How many Timeslots can be used ? Currently I have used only Timeslot A. Is there anything like, we have to use only Timeslot A and  B for LEDs. C and D for Inputs/ GPIOs. Please clarify the same. I have also attached My HRM sensor schematic

    The ADPD4101 supports up to 12 timeslots. There is no specific application associated with any timeslot. You can use a timeslot for any measurement. The input pins can be configured different in each timeslot. The GPIOs can be configured quite differently. Please refer to register map for registers 0x0023 and 0x0024 for details.

    b) I need to read the Channel 1 and Channel 2. How do I specifically read from channel 1 and Channel 2 ??

    You can enable CH2 by setting bit[14] of register 0x0100 for timeslot A, register 0x0120 for timeslot B, and so on. The data in the FIFO is organized sequentially as timeslot A, timeslot B, ... For instance, if you have timeslots A with CH1, timeslot B with CH1 & CH2, and timeslot C with CH1, then the data stream as following: [A_CH1]-[B_CH1]-[B_CH2]-[C_CH1]-[A_CH1]]-[B_CH1]-[B_CH2]-[C_CH1]- ..., depending on your FIFO threshold setting in register 0x0006.

    c) Currently I am getting 3 bytes from FIFO on every single read. How do I verify whether I am receiving correct PPG outputs. 

    I thought that I would get 20 bytes after periodic read from FIFO. But I have got 3 bytes every time. What is that DATA FORMAT bytes actually that I configured with ?

    I am not sure how your code reads the FIFO. Please check if it reads all the data in the FIFO for each FIFO interrupt handling.

    d) Decimation factor - I did not set this register. What do I need to set with ? or Does this very essential to set? (This is to calculate ODR right ??)

    The decimation factor is for reducing the ODR. Check the register map of register 0x0112/0x0132/0x0152... for details.

    e) Does it have standard sampling mode and Digital Integration mode ? If so, need to know detailed information.

    The ADPD4101 supports multiple acquisition mode, including float mode, continuous mode, digital integration mode, and other modes. Refer to the datasheet for details.

    f) What is the Dark signal registers for?  and  What is the Lit signal registers for?

    In measurement with photodiode (PD), there is very small dark current with no photons hitting the PD if the PD is reverse biased (that is very typical for PD to achieve fast response). The dark current is acquired as dark signal and saved in the dark signal register. The LIT is the sample when there are photons hitting the PD. Lit minus Dark will give the true photocurrent. Please refer to Figure 23 in the datasheet for details.

    Regards,

    Glen B.

  • Hi Glen,

    Thanks for your reply.

    Have a query on FIFO TH and Read data.

    FIFO data reading from ADPD410X_REG_FIFO_DATA - 0x002F register

    I have added snippet. Please verify it

    /*******************Setting up ADPD410x************************/
    { 
            data = 0x4000;                       //Enable Channel 2, Standard sampling mode, Rin 500 ohms
    	    ret = adpd410x_reg_write(p_instance, ADPD410X_REG_TS_CTRL(m_timeslot_no), data);       //0x0100
    
            data = 0x1410;                       //LED Pulse width set to 20us & offset 16us
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_LED_PULSE(m_timeslot_no), data); //0x0109
    
            data = 0x00E6;                       //Skip preconditioning, Band pass filter bypassed < precond = 0 >
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_TS_PATH(m_timeslot_no), data); //0x0101
    
            data = 0x0004;                       //Configure number of bytes - 4 bytes (Max 4 bytes)
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_DATA1(m_timeslot_no), data); //0x0110
    
            data = 0x02C1;                       //TIA gain 100k, Vref = 0.88V
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_AFE_TRIM(m_timeslot_no), data); //0x0101
    
            data = 0x010C;                       //[15:8] = No of pulses...[7:0] Number of seq repeats //Eg: 1 pulse * 5 repeat = 12 pulses
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_COUNTS(m_timeslot_no), data); //0x0107
    
            data = 0x0000;                       //continuous connect mode
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_PERIOD(m_timeslot_no), data); //0x0108
    
            data = 0x0203;                       //Integrator pulse width - 3us, bandpass filter powered down
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INTEG_WIDTH(m_timeslot_no), data); //0x010A
    
            data = 0x0210;                       //Integrator pulse timing offset 
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INTEG_OFFSET(m_timeslot_no), data); //0x010B
    
            data = 0x0001;                       //No Modulation //0:7 cannot be 0
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_MOD_PULSE(m_timeslot_no), data); //0x010C
    
    
            data = 0x0099;                       // -++- int pattern
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_ADC_OFF1(m_timeslot_no), data); //0x010D
            if(ret != NRF_SUCCESS)
                return ret;
    
            data = 0x0000;                       //No offset - review if needed
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_ADC_OFF1(m_timeslot_no), data); //0x010E
            if(ret != NRF_SUCCESS)
                return ret;
    
            data = 0x0000;                       //No offset - review if needed
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_ADC_OFF2(m_timeslot_no), data); //0x010F
    
            data = 0x0000;                       //No decimation
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_DECIMATE(m_timeslot_no), data); //0x0112
            
            data = 0x0000;                       //All inputs single Ended, VC1, VC2 set to AVDD during sleep
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INPUT_CFG, data); 
                  
            data = 0x4000;                       //IN8 connected to VC2
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INPUTS(m_timeslot_no), data);  //0x0102 
    
            data = 0x9000;                       //IN8 connected to VC2 during sleep
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INPUT_SLEEP, data); //0x0020
    }
    
    {
    /***********GPIO configs*******************/
            reg_data = 0x0002;          //gpio0 is output, normal
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_GPIO_CFG, reg_data);
    
            reg_data = 0x0002;          //gpio0 interruput x (pin cgf0 configured as output)
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_GPIO01, reg_data);
    
    /*************FIFO configs*****************/
            reg_data = 0x000A;          //20 bytes FIFO
            ret = adpd410x_reg_write(p_instance, ADPD410X_REG_FIFO_TH, reg_data);
    
            ret = adpd410x_reg_read(p_instance, ADPD410X_REG_INT_ENABLE_XD, &reg_data);
            if(ret == SUCCESS)
            {
                reg_data = (reg_data & 0x7FFFU) | ((0x1U) << 15U);
                ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INT_ENABLE_XD, reg_data);  /* Enable INTX */
            }
    
            if(ret == SUCCESS)
            {
                ret = adpd410x_reg_read(p_instance, ADPD410X_REG_INT_ENABLE_YD, &reg_data);
                if(ret == SUCCESS)
                {
                  /* Overflow and Underflow enabled */
                  reg_data = (reg_data & 0x9FFFU) | ((0x1U) << 14U) | ((0x1U) << 13U);
                  
                  /* write register with prepared value on INT Y */
                  ret = adpd410x_reg_write(p_instance, ADPD410X_REG_INT_ENABLE_YD, reg_data);  /* Enable INTY */
                }
            }
    }
    
    
    /****************Read FIFO byte count and FIFO data********************/
    
    {
    	int32_t ret;                           //0x0000
    	ret = adpd410x_reg_read(p_instance, ADPD410X_REG_FIFO_STATUS, &bytes);
    
        print("Data count = %X", bytes);
    	bytes &= BITM_INT_STATUS_FIFO_FIFO_BYTE_COUNT;
    	return bytes;
    }
    
    {
        int32_t ret;
        uint8_t cnt = 0;
        uint16_t data_buff[20] = {0};
        uint16_t bytes;
    
        adpd410x_get_FIFO_bytecount(p_instance, bytes);
    
    	for(cnt = 0; cnt < bytes; cnt++){          //0x002F
                adpd410x_reg_read(p_instance, ADPD410X_REG_FIFO_DATA, (data_buff + cnt));
                print("Data = %02X", *(data_buff + cnt));
    	}
    }

    I have configured only IN8 connected to channel VC2 (Please refer the schematic which I attached previously).

    In DATA_FORMAT register configured, Number of bytes of signal data to be written to the FIFO = 4 bytes

    I am able to read FIFO data. When I read FIFO I have got byte count as 8 (Reading periodically in every 5 seconds once)

    Please refer the screenshot below

    I am unable to get the FIFO data repeatedly and also FIFO TH level not reached if I set with 10, 20, etc.

    I have written code to read the FIFO data, Is that Right? Please check the register configs also

    Looking ahead for your comments

    Regards

    Sudharsan

  • Hi Glen,

    I have observed the following registers

    FIFO byte count  (0x0000) which was continuously incrementing. In my program 

    FIFO INT status data (0x0001) - When I read this register its was showing value as 0x8001 when it reaches FIFO Threshold of 100 bytes that I defined.

    Using GPIO0 as an interrupt pin which I configured as an Output normal.

    Register - 0x0022   value - 0x0002

    Register - 0x0023   value - 0x0002

    Is this config right?

    But only thing is that, I am not getting any interrupt on controller side even after status showing correct values. Looking ahead for your comments

    Regards

    Sudharsan

  • 0
    •  Analog Employees 
    on Jun 17, 2021 3:11 PM in reply to SK377

    HI Sudharsan,

    I will ask one of our software engineer to check your code.

    Regards,

    Glen B.

Reply Children
No Data