garmin / LIDARLite_Arduino_Library

High-performance optical distance sensing.
Apache License 2.0
181 stars 84 forks source link

LIDAR-Lite v3HP - NACK attack on Arduino Due #23

Open Hasko1415 opened 4 years ago

Hasko1415 commented 4 years ago

I have tested LiDAR 3HP on both Arduino UNO and Due microcontroller board with I2C connection. It seems like the Due microcontroller is always encountered by NACK attack comparing to UNO board and I found the value of nackCatcher is 2 returning from endTransmission(). I suspect that the Due board clock speed affects the performance on LiDAR 3HP which I added delayMicroseconds() command after each write() and read() function in LIDARLite_v3HP.cpp to ensure that master and slave device have sufficient time to acknowledge. After several trying, it still remains unsolved.

jmseitz commented 4 years ago

Garmin has not tested the v3HP with an Arduino Due. That being said - You shouldn't have too many problems, but the Arduino Due boards can be finicky. The Wire.h library is also less than perfect. There may be other I2C library solutions available that you could try and possibly get better results if you want to continue with a Due.

However, below are a few things you could quickly try to see if they help. No guarantees. Good luck!!


1 - Since you are using the Due, you can remove most everything inside the #ifdef for FAST_I2C except the call to Wire.setClock(). This will make the code easier to read/follow and then you can try changing the I2C bus speed and see if it helps.

    // Initialize Arduino I2C (for communication to LidarLite)
    Wire.begin();
//  #ifdef FAST_I2C
//      #if ARDUINO >= 157
            Wire.setClock(400000UL); // Set I2C frequency to 400kHz (for Arduino Due)
//      #else
//          TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
//      #endif
//  #endif

2 - The Due has external pullup resistors on the I2C bus (the UNO does not). The code in the v3HP example sketches will cause internal pullups to be activated by default. You don't want both, so you should turn off those internal pullups when using the Due and see if that helps. This can be done by adding these two lines of code directly after the I2C initialization instructions in the setup() routine -

    digitalWrite(SCL, LOW);
    digitalWrite(SDA, LOW);

3 - I've found that the Due doesn't perform a repeated START on the I2C bus when using the Wire library read functions as written like they are in the Arduino Library source for the v3HP. Try replacing the read() function in the library with the following to get the Due to use a repeated START during a read and see if that helps -

void LIDARLite_v3HP::read(uint8_t regAddr,  uint8_t * dataBytes,
                           uint8_t numBytes, uint8_t lidarliteAddress)
{
    uint8_t   i = 0;
    uint8_t   numHere;

    // This single function performs the following actions -
    //     1) I2C START
    //     2) I2C write to set the address
    //     3) I2C REPEATED START
    //     4) I2C read to fetch the required data
    //     5) I2C STOP
    Wire.requestFrom
    (
        lidarliteAddress, // Slave address
        numBytes,         // number of consecutive bytes to read
        regAddr,          // address of first register to read
        1,                // number of bytes in regAddr
        true              // true = set STOP condition following I2C read
    );

    numHere = Wire.available();

    while (i < numHere)
    {
        dataBytes[i] = Wire.read();
        i++;
    }
}
Hasko1415 commented 4 years ago

I followed the guideline as suggested above, it alleviates NACK attack by changing read() function to repeated START. But the NACK attack on write() function(from 3HP cpp) is still not solved yet. I should mention that NACK attack occurred on both read() and write() while it starts measuring distances. Therefore, it leads into another issue that distance being read as “256” will never be true value after setting was changed. The value of distance “256” will randomly be detected at any time in any range during continuous distance measurement. I will upload the image to show to illustrate the issue.

LiDAR Lite 3HP issue report(with notes)
jmseitz commented 4 years ago

Glad that the read functions appears to be fixed. I'm honestly not sure what to tell you about the write side of things.

Unfortunately, Garmin doesn't have any further insight on the Arduino Due as it hasn't been tested with the v3HP. Garmin's platform for the code base here was an Arduino UNO and the base is merely an example of how one can communicate with the LIDAR-Lite v3HP. Its main purpose is to help illustrate how someone might design their own application.

If you want to continue with a Due, I would suggest examining your I2C bus signaling to try to determine where the issue might be. Then if you can point to an issue with the LIDAR-Lite you can go through Garmin Support to report your findings and get help.

If you're open to a different platform, this code base does work very well on the Arduino UNO. I've also used this code with an Arduino MEGA in the past and had good luck, so that's another low cost option for you to try. No guarantees, of course.

Sorry I can't be more help. Please report back if you find something interesting.

Good luck!