Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: LIDAR Lite address move

  1. #1
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26

    LIDAR Lite address move

    Good Morning All!

    I'm getting two LIDAR's (Garmin Lidar Lite V3 (not HP)) together running from one Teensy 3.2. Had this working once a year back, but am having an issue getting back to where it was....

    The LIDAR enable pins are tied to DIO 16, and 17. SCL0 and SDA0 are pulled up with 2.5K, and am getting 100% good I2C transactions for distance reads. It'll spit out distances for days and days without error. I'm using i2c_t3.h.
    Anyway, not time to get them both working together at separate addresses......
    I'm starting by just trying to read back the LIDAR address from the 0x16 and 0x17 registers. Would like to confirm they read back OK before charging ahead. The output of the code below is: "High:48 Low:128" Since 0x62 ( 0000 0000 0110 0010 ) is the default address, I was expecting something like "High:0 Low:98".

    Does anything jump out at anyone? Also, I'm only checking nackack's returning from Wire.endTransmission(), if anyone can suggest a way to
    check at every read or write, that would be really nice.

    Here's the code........
    /* Registers to change default I2C addresses
    * Available addresses are 7 bit values with a '0' at the LSB. i.e. even hex numbers
    * 1. Read high and low address bytes from 0x16 and 0x17
    * 2. Write high byte to 0x18
    * 3. Write low byte to 0x19
    * 4. Write new I2C address to 0x1a
    * 5. Write 0x08 to 0x1e to disable old I2C address
    * The default I2C addresses will be restored after a power cycle.

    #define UNIT_ID_HIGH 0x16 // Read serial number high byte
    #define UNIT_ID_LOW 0x17 // Read serial number low byte
    #define I2C_ID_HIGH 0x18 // Write high byte for SN unlock
    #define I2C_ID_LOW 0x19 // Write low byte for SN unlock
    #define I2C_SEC_ADDR 0x1a // Write new I2C address after unlock
    #define I2C_CONFIG 0x1e // Write 0x08 to 0x1e to disable default (0x62) address
    ******************************/

    void MoveLidar_1_Address(void){
    uint8_t nackack = 100;
    byte reading_HighAddr, reading_LowAddr;

    digitalWrite(PIN_LIDAR_1_PWR_ENAB_LOW, LOW); // Just one LIDAR selected for address change.
    digitalWrite(PIN_LIDAR_2_PWR_ENAB_LOW, HIGH); delay(10);

    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Default LIDAR address
    Wire.write(UNIT_ID_HIGH); // Set up Garmin to return data as two sequential I2C reads.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack); // routine to count the errors.
    }
    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_HighAddr = Wire.readByte() ;

    nackack = 100; // nackack was 0 after the last I2C transaction, reset it.
    while (nackack != 0) { //While NACK keep going (i.e. continue polling until success message 0 is received ) Need a watchdog.
    Wire.beginTransmission(0x62); //Hardcode now to det default address
    Wire.write(UNIT_ID_LOW); // Set up Garmin to return data as two sequential I2C reads.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }
    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_LowAddr = Wire.readByte() ;
    Error_I2C_LIDAR (nackack); //For now, to echo errors returned from LIDAR to serial monitor.
    Serial.print("High:"); Serial.print(reading_HighAddr); Serial.print(" Low:"); Serial.println(reading_LowAddr);
    delay(3000);

    /* Code to execute the remaining steps will go here....
    * for now, just trying to confirm that one can get back the
    * default (0x62) address
    * I2C_ID_HIGH 0x18 // Write high byte for SN unlock
    * I2C_ID_LOW 0x19 // Write low byte for SN unlock
    * I2C_SEC_ADDR 0x1a // Write new I2C address after unlock
    * I2C_CONFIG 0x1e // Write 0x08 to 0x1e to disable default (0x62) address */
    return;
    }

    int Error_I2C_LIDAR (int ErrCode) { // Code to branch calling routine toward recovery from error.
    switch (ErrCode) {
    case 0: break; //success, continue I2C transaction by reading the data next.
    case 1: Serial.print(ErrCode); Serial.println(" - Data too long"); err_cnt += 1; break;
    case 2: Serial.print(ErrCode); Serial.println(" - Received ADDR NACK"); err_cnt += 1; break;
    case 3: Serial.print(ErrCode); Serial.println(" - Received DATA NACK"); err_cnt += 1; break;
    case 4: Serial.print(ErrCode); Serial.print(" - Other Error "); err_cnt += 1;
    Serial.println(err_cnt); break;
    default: break;
    }
    return err_cnt;
    }

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,166
    Your code generates compiler error messages. For a start there's no setup() and loop() functions and you have not included an I2C library.

    You've also commented out the defines for UNIT_ID_HIGH etc.
    Move this line:
    Code:
    ******************************/
    in front of:
    Code:
    #define UNIT_ID_HIGH 0x16 // Read serial number high byte
    Once those things are fixed, you still have not declared err_cnt, PIN_LIDAR_1_PWR_ENAB_LOW and PIN_LIDAR_2_PWR_ENAB_LOW.

    You can't check for nack on each write. When you write a byte, the library does not send it immediately. It stores the byte in a buffer and then returns 1 unless the buffer was already full in which case it returns 0. All the bytes in the buffer are sent when you call the endTransmission function.

    Your code would be a lot more readable if you used the Tools|Auto Format option in the IDE.

    Pete

  3. #3
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26

    Completed (?) source for moving LidarLite to new I2C address

    Hello again All,
    More on switching Garmin LIDAR Lite I2C address... needed if you want to share two on a single I2C bus.

    I'm going to work on the assumption that the "High:48 Low:128" bytes returned from 0x16 and 0x17 aren't really the 0x62 default address at all, rather, they're whatever they are, and can be written into the 0x18 and 0x19 registers. And it might actually be working? That is, if I run the code once, it does print "High:48 Low:128", and if I run it a second time......no responce, unless I power down the LIDAR, then it does indeed seem to reset itself to the default 0x62 address and gives me the "High:48 Low:128" message! So, it "works"-ish.

    Trouble is though, that when I enable the second lidar at the end, that lidar doesn't respond anymore to all the code beyond MoveLidar_1_Address(), which used to work, and still should.

    /* Registers to change default I2C addresses from Garmin spec sheet.
    * Available addresses are 7 bit values with a '0' at the LSB. i.e. even hex numbers
    * 1. Read high and low address bytes from 0x16 and 0x17
    * 2. Write high byte to 0x18
    * 3. Write low byte to 0x19
    * 4. Write new I2C address to 0x1a
    * 5. Write 0x08 to 0x1e to disable old I2C address
    * The default I2C addresses will be restored after a power cycle.

    #define UNIT_ID_HIGH 0x16 // Read serial number high byte
    #define UNIT_ID_LOW 0x17 // Read serial number low byte
    #define I2C_ID_HIGH 0x18 // Write high byte for SN unlock
    #define I2C_ID_LOW 0x19 // Write low byte for SN unlock
    #define I2C_SEC_ADDR 0x1a // Write new I2C address after unlock
    #define I2C_CONFIG 0x1e // Write 0x08 to 0x1e to disable default (0x62) address
    ******************************/

    void MoveLidar_1_Address(void){

    uint8_t nackack = 100; //For grabbing LIDAR I2C replies
    byte reading_HighAddr, reading_LowAddr; //to hold the "address values"(?) that must be moved.

    digitalWrite(PIN_LIDAR_1_PWR_ENAB_LOW, LOW); // Just one LIDAR selected for address change.
    digitalWrite(PIN_LIDAR_2_PWR_ENAB_LOW, HIGH); delay(10);

    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Default LIDAR address
    Wire.write(UNIT_ID_HIGH); // Set up Garmin to return data as two sequential I2C reads.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }
    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_HighAddr = Wire.readByte() ;

    nackack = 100; // nackack was 0 after the last I2C transaction, reset it.
    while (nackack != 0) { //While NACK keep going (i.e. continue polling until success message 0 is received ) Need a watchdog.
    Wire.beginTransmission(0x62); //Hardcode now to det default address
    Wire.write(UNIT_ID_LOW); // Set up Garmin to return data as two sequential I2C reads.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }
    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_LowAddr = Wire.readByte() ;
    Error_I2C_LIDAR (nackack); //For now, to echo errors returned from LIDAR to serial monitor.
    Serial.print("High:"); Serial.print(reading_HighAddr); Serial.print(" Low:"); Serial.println(reading_LowAddr);

    nackack = 100;
    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Prepare I2C device to read
    Wire.write(I2C_ID_HIGH); // Tell LIDAR to accept unlock high byte read from 0x16
    Wire.write(reading_HighAddr);
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }

    nackack = 100;
    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Prepare I2C device to read
    Wire.write(I2C_ID_LOW); // Tell LIDAR to accept unlock low byte read from 0x17
    Wire.write(reading_LowAddr);
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }

    nackack = 100;
    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Prepare I2C device to read
    Wire.write(I2C_SEC_ADDR); // Tell LIDAR to accept unlock high byte read from 0x16
    Wire.write(0x65); // THIS IS THE DESIRED NEW ADDRESS
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }

    nackack = 100; // Wrap it all up by teling LIDAR to switch away from default address
    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Prepare I2C device to read
    Wire.write(I2C_CONFIG); // Get ready to accept disable instruction.
    Wire.write(0x08); // Data to disable old I2C address.
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);
    }

    // Now the other LIDAR can be enabled and there should be one at I2C 0x62, and 0x65
    digitalWrite(PIN_LIDAR_2_PWR_ENAB_LOW, HIGH);

    delay(3000); // Wait 3 seconds to read what's been sent to the serial monitor.

    return;
    }

    int Error_I2C_LIDAR (int ErrCode) { // Code to branch calling routine toward recovery from error.
    #ifdef BENCHTOP_PROTOTYPE // #undef this to compile for actual device.
    switch (ErrCode) {
    case 0: break; //success, continue I2C transaction by reading the data next.
    case 1: Serial.print(ErrCode); Serial.println(" - Data too long"); err_cnt += 1; break;
    case 2: Serial.print(ErrCode); Serial.println(" - Received ADDR NACK"); err_cnt += 1; break;
    case 3: Serial.print(ErrCode); Serial.println(" - Received DATA NACK"); err_cnt += 1; break;
    case 4: Serial.print(ErrCode); Serial.print(" - Other Error "); err_cnt += 1;
    Serial.println(err_cnt); break;
    default: Serial.print(ErrCode); Serial.print(" - WAY Other Error"); break;
    }
    #endif
    return err_cnt;
    }

  4. #4
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26
    Sorry Pete, it's just part of a much larger program not really meant to post as 'compiler ready'. The defines for UNIT_ID_HIGH, etc, are indeed insluded in a .h file, I just kept a commented out version handy for reference.
    Thanks very much for your reply though.

    This is highly interesting, I thought I had this right based on the 'ack' in the Garmin I2C timing diagrams. My bad.
    "You can't check for nack on each write. When you write a byte, the library does not send it immediately. It stores the byte in a buffer and then returns 1 unless the buffer was already full in which case it returns 0. All the bytes in the buffer are sent when you call the endTransmission function. Do you mean one should put the nackack = Wire.endTransmission(I2C_STOP, 1000);
    outside the while(nackack != 0){} loop? And I guess then if they're buffered up, I need to read a string of bytes back and pick them apart to see how may tries the transmissions took?

    Your code would be a lot more readable if you used the Tools|Auto Format option in the IDE."
    Will do that on the next post........ apologies for the un-readability of the code. I lost the tabs I put in there to make it a bit better.

    Regards,
    -a
    Last edited by amensch; 02-24-2019 at 03:37 PM.

  5. #5
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26
    Trying something like this... doesn't return the high and low bytes, rather I think it's hung.......getting out the o-scope.......
    ...... a little more readable.....will work on that.

    digitalWrite(PIN_LIDAR_1_PWR_ENAB_LOW, LOW); // Just one LIDAR selected for address change.
    digitalWrite(PIN_LIDAR_2_PWR_ENAB_LOW, HIGH); delay(10);

    while (nackack != 0) {
    Wire.beginTransmission(0x62); //Default LIDAR address
    Wire.write(UNIT_ID_HIGH); // Set up Garmin to return data as two sequential I2C reads.
    }
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);

    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_HighAddr = Wire.readByte() ;
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);


    nackack = 100; // nackack was 0 after the last I2C transaction, reset it.
    while (nackack != 0) { //While NACK keep going (i.e. continue polling until success message 0 is received ) Need a watchdog.
    Wire.beginTransmission(0x62); //Hardcode now to det default address
    Wire.write(UNIT_ID_LOW); // Set up Garmin to return data as two sequential I2C reads.
    }
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);

    Wire.requestFrom(0x62, 1, I2C_STOP, 1000 ); //Request 1 byte from slave (the LIDAR)
    reading_LowAddr = Wire.readByte() ;
    nackack = Wire.endTransmission(I2C_STOP, 1000);
    Error_I2C_LIDAR (nackack);

    Serial.print("High:"); Serial.print(reading_HighAddr); Serial.print(" Low:"); Serial.println(reading_LowAddr);

  6. #6
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26
    Duh. Duh. Duh.

  7. #7
    Member
    Join Date
    Jun 2018
    Location
    Northeast USA
    Posts
    26
    Problem solved: After some work with the I2C calls & a memory dump to Garmin, they did a firmware update to get the I2C alternate addressing to work. If you wish to run dual LL3 LIDARS on a single I2C bus, i2c_t3 works great but get LIDARS with date codes after May 2019.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •