This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OPT3101: Read the OPT3101 register to calculate the distance

Part Number: OPT3101


Hi Team:

             I have completed OPT3101 calibration and stored the calibration parameters in the external EEPROM. Implement OPT3101 power-on to automatically load calibration parameters in the SDK;

             I need to optimize the code, do not use SDK, use C language to write the driver, have completed the initialization operation, and can normally read the register, but the distance parameter I read and calculate is wrong with the distance parameter read in the SDK, I use the same hardware. Read all register values in the address 0x00-0x98 range in the SDK and its own driver, except for read-only registers 0x08,0x09,0x0a,0x3B,0x3c, the values of the other registers are consistent, but the calculated distance data is inconsistent;

             

             

             

             

             I have completed internal crosstalk calibration before ranging, but the distance error is still large, is there any step I am missing?

            Thanks!!!

  • Hi Pengsheng,

    Our OPT3101 expert is out of office, please allow 1-2 days for the team to get back to your questions.

    Best regards,
    Nicole

  • Pengsheng,

      I am not able to read any of the data images you attached. The resolution is poor and the data font is to small. What registers do you read to get the distance. Can you show me how you calculate the distance? 

  • Gordon:

           I have realized automatic loading of calibration parameters stored in external EEPROM in OPT3101 SDK, and can correctly measure distance. I want to use C language to write opt3101 driver to realize automatic loading of calibration parameters in external EEPROM and correct measurement of distance. The picture on the right of my long transmission shows all the register addresses and parameters of OPT3101 read in SDK, and the picture on the left shows all the register addresses and parameters of OPT3101 read in my own program. Except for the read-only register, the rest register data are completely consistent, but the program I wrote myself has a large error in measuring the distance. If my program is missing those steps in reading distance data,    PS :  I'm using the same hardware to compare register data;

          This is my code for reading distance data:

          

          

           This is the parameter to my contrast register:

    0x00:0x000000
    0x01:0x120140
    0x02:0x92A4C8
    0x03:0x8001FF
    0x04:0x000017
    0x05:0x080960
    0x06:0x000042
    0x07:0x000000
    0x08:0x961E20
    0x09:0x4204DB
    0x0A:0x960108
    0x0B:0x0FC009
    0x0C:0xEB0000
    0x0D:0x006000
    0x0E:0x000000
    0x0F:0x144C4B
    0x10:0x004000
    0x11:0x003FD4
    0x12:0x000000
    0x13:0x036B00
    0x14:0x031279
    0x15:0xB02108
    0x16:0xC00100
    0x17:0x000000
    0x18:0x000000
    0x19:0x000000
    0x1A:0x000000
    0x1B:0x000000
    0x1C:0x000000
    0x1D:0x000000
    0x1E:0x000000
    0x1F:0x000000
    0x20:0x000000
    0x21:0x000000
    0x22:0x000000
    0x23:0x000000
    0x24:0x000000
    0x25:0x000000
    0x26:0x04000F
    0x27:0x26AC18
    0x28:0x000000
    0x29:0x3FFC41
    0x2A:0x78C920
    0x2B:0x026B6C
    0x2C:0x03146D
    0x2D:0x601638
    0x2E:0x3207A0
    0x2F:0x6308A2
    0x30:0xB0055C
    0x31:0x000FDE
    0x32:0x000A18
    0x33:0x00226E
    0x34:0x001F1B
    0x35:0x00472D
    0x36:0x007C5D
    0x37:0x000000
    0x38:0xC90000
    0x39:0xC40000
    0x3A:0x4F0000
    0x3B:0x00001C
    0x3C:0x00FFE2
    0x3D:0x000000
    0x3E:0x000000
    0x3F:0x000000
    0x40:0x2021E0
    0x41:0x978010
    0x42:0x0044EE
    0x43:0x000083
    0x44:0x000000
    0x45:0x00060B
    0x46:0x000000
    0x47:0x000978
    0x48:0x000970
    0x49:0x000970
    0x4A:0x000000
    0x4B:0x000407
    0x4C:0x00F23E
    0x4D:0x001144
    0x4E:0x00F881
    0x4F:0x000000
    0x50:0x200101
    0x51:0x004551
    0x52:0x0038DC
    0x53:0x0032AD
    0x54:0x000000
    0x55:0x000000
    0x56:0x000000
    0x57:0x000000
    0x58:0x000000
    0x59:0x000000
    0x5A:0x000000
    0x5B:0x000000
    0x5C:0x000000
    0x5D:0x000000
    0x5E:0x5A0C00
    0x5F:0x0000BB
    0x60:0x295B90
    0x61:0x000000
    0x62:0x000000
    0x63:0x000000
    0x64:0x280C00
    0x65:0x000000
    0x66:0x143000
    0x67:0x0011C0
    0x68:0x000000
    0x69:0x000000
    0x6A:0x001D05
    0x6B:0x000000
    0x6C:0x000000
    0x6D:0x000000
    0x6E:0x0A1AE2
    0x6F:0x000020
    0x70:0x001000
    0x71:0x000000
    0x72:0x000000
    0x73:0x000000
    0x74:0x000000
    0x75:0x000000
    0x76:0x000000
    0x77:0x000000
    0x78:0x001080
    0x79:0x000001
    0x7A:0x800000
    0x7B:0x00760C
    0x7C:0x000000
    0x7D:0x000000
    0x7E:0x000000
    0x7F:0x000000
    0x80:0x004E1F
    0x81:0x0000F2
    0x82:0x0000FA
    0x83:0x0000D0
    0x84:0x0000D8
    0x85:0x00267A
    0x86:0x002682
    0x87:0x002454
    0x88:0x002648
    0x89:0x001B58
    0x8A:0x001F40
    0x8B:0x000006
    0x8C:0x000064
    0x8D:0x000000
    0x8E:0x000000
    0x8F:0x000000
    0x90:0x002134
    0x91:0x002134
    0x92:0x002EE0
    0x93:0x000000
    0x94:0x00FFFF
    0x95:0xFFF000
    0x96:0xFFF000
    0x97:0x07F07F
    0x98:0x000000
    0x99:0x000001
    0x9A:0xFFF000
    0x9B:0x000000
    0x9C:0xFFF000
    0x9D:0x000000
    0x9E:0x000000
    0x9F:0x07F07F
    0xA0:0x002198
    0xA1:0x000000
    0xA2:0x000000
    0xA3:0x000000
    0xA4:0x000000
    0xA5:0x000000
    0xA6:0x000000
    0xA7:0x000000
    0xA8:0x000000
    0xA9:0x000000
    0xAA:0x000000
    0xAB:0x000000
    0xAC:0x000000
    0xAD:0x000000
    0xAE:0x000000
    0xAF:0x000000
    0xB0:0x000000
    0xB1:0x000000
    0xB2:0x000000
    0xB3:0x000000
    0xB4:0xE0E29F
    0xB5:0x000002
    0xB6:0x000000
    0xB7:0x000000
    0xB8:0x02587D
    0xB9:0x0004C8
    
    
    0x00:0x000000
    0x01:0x120140
    0x02:0x92A4C8
    0x03:0x8001FF
    0x04:0x000017
    0x05:0x080950
    0x06:0x000042
    0x07:0x000000
    0x08:0x961DF0
    0x09:0x40054F
    0x0A:0x95010A
    0x0B:0x0FC009
    0x0C:0xEB0000
    0x0D:0x006000
    0x0E:0x000000
    0x0F:0x144C4B
    0x10:0x004000
    0x11:0x003FD4
    0x12:0x000000
    0x13:0x036B00
    0x14:0x031279
    0x15:0xB02108
    0x16:0xC00100
    0x17:0x000000
    0x18:0x000000
    0x19:0x000000
    0x1A:0x000000
    0x1B:0x000000
    0x1C:0x000000
    0x1D:0x000000
    0x1E:0x000000
    0x1F:0x000000
    0x20:0x000000
    0x21:0x000000
    0x22:0x000000
    0x23:0x000000
    0x24:0x000000
    0x25:0x000000
    0x26:0x04000F
    0x27:0x26AC18
    0x28:0x000000
    0x29:0x3FFC41
    0x2A:0x78C920
    0x2B:0x026B6C
    0x2C:0x03146D
    0x2D:0x601638
    0x2E:0x3207A0
    0x2F:0x6308A2
    0x30:0xB0055C
    0x31:0x000FDE
    0x32:0x000A18
    0x33:0x00226E
    0x34:0x001F1B
    0x35:0x00472D
    0x36:0x007C5D
    0x37:0x000000
    0x38:0xC90000
    0x39:0xC40000
    0x3A:0x4F0000
    0x3B:0x000028
    0x3C:0x00FFD7
    0x3D:0x000000
    0x3E:0x000000
    0x3F:0x000000
    0x40:0x2021E0
    0x41:0x978010
    0x42:0x0044EE
    0x43:0x000083
    0x44:0x000000
    0x45:0x00060B
    0x46:0x000000
    0x47:0x000978
    0x48:0x000970
    0x49:0x000970
    0x4A:0x000000
    0x4B:0x000407
    0x4C:0x00F23E
    0x4D:0x001144
    0x4E:0x00F881
    0x4F:0x000000
    0x50:0x200101
    0x51:0x004551
    0x52:0x0038DC
    0x53:0x0032AD
    0x54:0x000000
    0x55:0x000000
    0x56:0x000000
    0x57:0x000000
    0x58:0x000000
    0x59:0x000000
    0x5A:0x000000
    0x5B:0x000000
    0x5C:0x000000
    0x5D:0x000000
    0x5E:0x5A0C00
    0x5F:0x0000BB
    0x60:0x295B90
    0x61:0x000000
    0x62:0x000000
    0x63:0x000000
    0x64:0x280C00
    0x65:0x000000
    0x66:0x143000
    0x67:0x0011C0
    0x68:0x000000
    0x69:0x000000
    0x6A:0x001D05
    0x6B:0x000000
    0x6C:0x000000
    0x6D:0x000000
    0x6E:0x0A1AE2
    0x6F:0x000020
    0x70:0x001000
    0x71:0x000000
    0x72:0x000000
    0x73:0x000000
    0x74:0x000000
    0x75:0x000000
    0x76:0x000000
    0x77:0x000000
    0x78:0x001080
    0x79:0x000001
    0x7A:0x800000
    0x7B:0x00760C
    0x7C:0x000000
    0x7D:0x000000
    0x7E:0x000000
    0x7F:0x000000
    0x80:0x004E1F
    0x81:0x0000F2
    0x82:0x0000FA
    0x83:0x0000D0
    0x84:0x0000D8
    0x85:0x00267A
    0x86:0x002682
    0x87:0x002454
    0x88:0x002648
    0x89:0x001B58
    0x8A:0x001F40
    0x8B:0x000006
    0x8C:0x000064
    0x8D:0x000000
    0x8E:0x000000
    0x8F:0x000000
    0x90:0x002134
    0x91:0x002134
    0x92:0x002EE0
    0x93:0x000000
    0x94:0x00FFFF
    0x95:0xFFF000
    0x96:0xFFF000
    0x97:0x07F07F
    0x98:0x000000
    0x99:0x000001
    0x9A:0xFFF000
    0x9B:0x000000
    0x9C:0xFFF000
    0x9D:0x000000
    0x9E:0x000000
    0x9F:0x07F07F
    0xA0:0x002198
    0xA1:0x000000
    0xA2:0x000000
    0xA3:0x000000
    0xA4:0x000000
    0xA5:0x000000
    0xA6:0x000000
    0xA7:0x000000
    0xA8:0x000000
    0xA9:0x000000
    0xAA:0x000000
    0xAB:0x000000
    0xAC:0x000000
    0xAD:0x000000
    0xAE:0x000000
    0xAF:0x000000
    0xB0:0x000000
    0xB1:0x000000
    0xB2:0x000000
    0xB3:0x000000
    0xB4:0xE0E29F
    0xB5:0x000002
    0xB6:0x000000
    0xB7:0x000000
    0xB8:0x02587D
    0xB9:0x0004C8
    
    
    

          Reg1.txt is the register address and value read in C code, Reg2.txt is the register address and value read in OPT3101 SDK;

          Thanks!!!!

  • Pengsheng,

      What register are you specifically reading and what is your formula in C, to get distance. 

    In the data sheet there is a formula to get distance from the phase.

    7.3.8 Output Data
    Phase and amplitude information is stored in registers which can be read out using the I2C interface. The device
    gives data ready after computation of the depth information on the general purpose I/O (GP1 or GP2) which can
    be used trigger the host to read the data from the device. Distance can be calculated from the phase using
    Equation 8. A single code of PHASE_OUT is 228.7μm.

    where

    • c = Speed of light
    • fMOD = 10 MHz, modulation frequency (8)
    Along with phase and amplitude of the signal, ambient ADC output and temperature sensor output are also
    stored in the registers. All the output data is stored in contiguous registers 8, 9, and 10.

  • Gordon:

        I read the 0x08 0x09 0x0A registers, calculate the distance using the 0x08 register low 16 bits, and the calculation formula is simplified:

       

       

       Thanks!!!!

  • Pengsheng,

    Your calculation for distance doesn't make sense. The number becomes quite large then when you shift >>16 you will end up with a rounding error. 

    You may want to work on the calculation formula. I don't have a C version, but I will look into it. 

  • Gordon:

         The calculation formula I used is referred to the program in OPT3101 SDK, and the phase value is signed 32-bit, so there will be no overflow when multiplied by 14989. The image is the code for calculating distance in the OPT3101 SDK

         

        The floating point type is not used in the distance calculation. According to the calculation formula of the picture, multiply by 14989 and then shift 16 bits to the right

         

         

         

        Thanks!!!

  • Pengsheng,

      You are correct. That is the formula in the SDK. Have you read out 0x08 register, used the formula in 7.3.8 of the data sheet manually, then compared that distance to the distance you calculated in the C Code? I wonder if you get two different values.

    I have not found a reason for the distance to be different. I will ask the programmers.  

  • Gordon:

        I'm sure calculted in C code is Correct, I debug and check the phase value, and the result calculated manually according to the calculation formula is consistent with the calculation result of MCU;

       

       phase = 7895;

       (7895*14989) / 65535 = 1805.69

       Let me describe the case of two different values again:

       1、I use the same hardware

       2、The hardware has completed all the calibration steps and the calibration parameters are stored in the external EEPROM

       3、I turned off all conditional compilation in the OPT3101 SDK and only opened the TESTING_LIVE_VIEW macro definition

            

        The result is that the distance tested by me in the SDK code is correct, but there is an error in the distance measured in the C code, which is about 1860mm in the SDK and about 1800mm in the C code;

      

        Thanks!!!!

  • Pengsheng,

      I am assuming that you have two boards. One board is running the SDK code and the other is running the C Code.

    Have you read out the register value of PHASE on both booards to see if the register values are the same and calculating different distances or are they different for each board indicating that here is a difference in measurement distance. 

    The reason is that according to the System Estimator tool, at 1.8m the distance accuracy could be +/-81mm of error at that distance. You show 60mm between the SDK and the C Code. It may be real error not a calculation error. At 81mm the total error is 0.045% and if you have a 60mm error it would be 0.033%. This is pretty good for overall acuracy. 

    Verify the phase register values before the calculation to see if the phase matches. 

  • Gordon:

        I think your method is not rigorous, different hardware needs to be calibrated, the coefficient obtained by calibration will be different, of course, there will be differences in the read registers, the conclusion drawn in this way is not of reference significance, my verification method is to use the same hardware, read all the register values are also consistent, but the C code and SDK obtained distance is not consistent

       Thanks!!!

  • Pengsheng,

      I was asking about your setup. I think I understand your setup better now. Can you send me the C Code for the calculation  so I can test it to see what distance I get?

  • Gordon:

          This is the github codebase link https://github.com/GavinBug/OPT3101_EEPROM.git, I use ARM core microcontroller;

          Thanks!!!

  • Pengsheng,

      I get "Not Found" when I click on the link. I really only need the section where you do the calculations for distance. 

  • Gordon

         This is  calculations for distance. 

         

    typedef struct
    {
    	int32_t  phase;
    	int32_t  amplitude;
    	uint16_t temperature;
    	uint16_t ambient;
    	uint8_t  channel;
    	int32_t  distance;
    }Opt3101Data_t;	
    
    typedef struct
    {
    	uint32_t phase; ///< phase value measured by the AFE. Actually 16 bit unsigned value upscaled to 17 bits with 1 bit of frameData::phaseovl flag added to the MSB. Same as OPT3101::registers::phase_out
    	bool phaseovl; ///< phase overload flag, specifying if phase value detected exceeds 16 bits. (greater than 65535). OPT3101::registers::.phase_overflow
    	bool phaseovlf2; ///< phase overload flag for frequency 2, specifying if phase value detected exceeds 16 bits. (greater than 65535). Same as OPT3101::registers::phase_overflow_f2
    	bool ambovl; ///< ambient over load flag which flags if the AFE is saturated due to very high ambient condition. Same as OPT3101::registers::amb_ovl_flag
    	bool illumDac; ///< flag that specifies which of the auto-hdr register config from where the measurement is made. Same as OPT3101::registers::hdr_mode 
    	uint8_t ledChannel; ///< value that specifies from which channel the measurement is made. Same as OPT3101::registers::tx_channel
    	bool frameStatus; ///< flag that specifies if the measurement is a valid data. Same as OPT3101::registers::frame_status
    	bool dealiasFreq; ///< flag that specifies if the measurement is done with fundamental frequency of de-alias frequency. Same as OPT3101::registers::mod_freq
    	uint8_t frameCounter; ///< Frame counter which counts every data ready. Same as combination of OPT3101::register::frame_count0 , OPT3101::registers::frame_count1 and OPT3101::registers::frame_count2
    	uint16_t amplitude; ///< amplitude value measured by AFE. 15 bit representation of the signal. Same as OPT3101::registers::amp_out
    	bool sigovl; ///< flag that specifies if the AFE is saturated due to signal. Same as OPT3101::registers::sig_ovl_flag
    	uint8_t dealiasBin; ///< value that specifies the de-aliased bin number. Same as OPT3101::registers::dealias_bin
    	uint16_t ambient; ///< value specifies the ambient light measured by the ambient cancellation block. Same as OPT3101::registers::amb_data
    	uint16_t temp; ///< value of internal temp sensor read from register 0x0A. Same as OPT3101::registers::tmain . This is updated every data ready.
    	uint16_t tmain; ///< value of internal temp sensor read from register OPT3101::registers::tmain
    	uint16_t tillum; ///< value of external temp sensor read using the I2C Master. Same as OPT3101::registers::tillum
    }Opt3101frameData_t;
    
    
    
    void CaptureFrameData(Opt3101frameData_t *opt3101)
    {
    
    	uint8_t c0;
    	uint32_t data32[3];
    	/// <b>Algorithm of the method is as follows</b>
    	//host->sleep((dev->configurationFlags_frameTimeInMilliSeconds)<<1); ///* Sleep host for a specified time depending on device configuration to OPT3101 AFE can update measurements to the registers.
    	for (c0 = 8; c0 < 11; c0++) ///* Performs a direct read of I2C registers 0x08 0x09 and 0x0A directly though hostController::readI2C method 
    	{
    	  Read_OPT3101_Register(c0, &data32[c0-8]);
    	}	
    	
    	opt3101->phase = data32[0] & 0xFFFF; ///* Maps the I2C read values to the class members like OPT3101::frameData::phase, OPT3101::frameData::amplitude etc 
    	opt3101->phaseovl = (data32[0] >> 16) & 0x1;
    	opt3101->phase |= (((uint32_t) opt3101->phaseovl) << 16);
    
    	opt3101->illumDac = (data32[0] >> 17) & 0x01;
    	opt3101->ledChannel = (data32[0] >> 18) & 0x03;
    	opt3101->frameStatus = (data32[0] >> 20) & 0x01;
    	opt3101->dealiasFreq = (data32[0] >> 21) & 0x01;
    	opt3101->ambovl = (data32[0] >> 22) & 0x01;
    	opt3101->frameCounter = (data32[0] >> 23) & 0x01;
    	opt3101->amplitude = data32[1] & 0xFFFF;
    	opt3101->frameCounter |= ((data32[1] >> 16) & 0x03) << 1;
    	opt3101->sigovl = (data32[1] >> 18) & 0x01;
    	opt3101->phaseovlf2 = (data32[1] >> 19) & 0x01;
    	opt3101->dealiasBin = (data32[1] >> 20) & 0x0F;
    	opt3101->frameCounter |= (data32[2] & 0x03) << 3;
    	opt3101->ambient = (data32[2] >> 2) & 0x3FF;
    	opt3101->temp = (data32[2] >> 12) & 0xFFF;
    	opt3101->tmain = opt3101->temp;
    }
    
    
    
    static Opt3101frameData_t Data[3];
    
    
    void ReadOpt3101Data(Opt3101Data_t *opt3101)
    {
    
    	Opt3101frameData_t framedata;
    
        uint8_t i; 	
    
    	CaptureFrameData(&framedata);
    
    	Data[framedata.ledChannel] = framedata;
      
    	opt3101->channel = framedata.ledChannel;
    	
    	opt3101->ambient = Data[framedata.ledChannel].ambient;
    	
    	opt3101->amplitude = Data[framedata.ledChannel].amplitude;
    	
    	opt3101->phase = Data[framedata.ledChannel].phase;
    	
    	opt3101->distance = (opt3101->phase*14989)>>16;	
    	
    	opt3101->temperature = (Data[framedata.ledChannel].tmain >> 3) - 256;
    }
    
     

        Thanks!

  • Pengsheng,

      I have gone over your code and the math. It works for me. The results are good.  

    The only thing I see that doesn't make sense is that you read out 0-8 registers. TMain resides in the 10th register, but you reference TMain. It may not matter but check your registers to make sure that you are getting the correct data for phase from register 0x08. Since there is no 0x06 you may be off by 1 register. I can't verify this because I am not actually running the code, just walking through it. 

  • Gordon:

        Please look at the program code carefully, I read the register data from the address 0x08-0x0A, I consult the data manual, there is no 0x06 address register, I ask you have an external EEPROM OPT3101 demo board, my test condition is to automatically load the stored external EEPROM calibration data and then read the data;

        

       

          Thanks!!!

  • Hi Pengsheng,

    Thanks for your patience as the team works through your questions. There may be a slight delay due to the US holiday 5/27.

    Best regards,
    Nicole

  • Pengsheng,

      I understand, you are not reading from register 0x00, you are starting with 0x08 through 0x0A. The code looks good. The math looks good. The only suggestion I have is to use a debugger and do a step by step to look at the register values and math as you step through it. The problem is not obvious. 

    What else can you tell me about- the problem?

  • Gordon:

           This is the address of the github repository and whether my C code is missing any initialization steps

           https://github.com/GavinBug/OPT3101_EEPROM.git

           Thanks!!!

  • Pengsheng,

      Thank you for the code link. I have been looking at it. I still think using a debugger and looking at the steps and registers as you move through it would be a good idea. 

  • Gordon:

        I'm comparing SDK and my own C code to read all the registers, repeated reading, except for the relevant registers about distance measurement, the data of 0x05 register is inconsistent, the SDK code reads the data of 0x05 register, check the data manual, the 0-21bit of this register should be fixed, but the data I read will change. Yes 0x05 register data manual Is there a problem?

        

          This is me reading register 0x05 data:

          

          

         

        Does the 0x05 register have any other functions?

        Thanks!!

  • Pengsheng,

      The only usable data in 05h is "23:22 I2C_NUM_BYTES_TRAN2" The other bits are for internal use only and will not be consistent, or usable by the customer. Reading these bits will only cause confusion. Internally most reserved registers may have more than one function and output factory data for multiple conditions. TI will not support internal functions externally or for customer use.   

  • Gordon:

          The same hardware, after automatically loading parameters, SDK and C code read the value of the 0x05 register inconsistent is normal? Now I print out serial port many times, except for registers related to ranging 0x08.0x09.0x0A.0x3B.0x3C, and 0x05, the two codes read the value are the same, now there is a difference between the two codes ranging, through the other bits of register 0x05 can see what is the reason?Can you tell me what bit15-0 in register 0x05 means;

          Thanks!!!!

         

  • Hi Pengsheng,

    The bits in register 0x05 will not be consistent, as Gordon has mentioned. These bits are used for internal information only and should be ignored.

    Best regards,
    Nicole