Translating Lidar Lite I2C example to Teensy

Status
Not open for further replies.
I have found that all update rates can freeze. Anything above 15ms is very unlikely to poll more than once, so this reduces communication over I2C quite a bit, but still eventual freezes for me.
 
LIDAR-LITE problem is not just with Teensy

Just FWIW, the below code works with 15 msec delay, but with 1 msec delay soon locks up when running on a "Seeeduino" (ATmega328p based Arduino-compatible). So the problem is not limited to Teensy in any way. When it locks up, SDA sometimes but not always stays low; SCL stays high. It happens whether the Arduino board is running at 5V or 3.3V.

Code:
/* http://pulsedlight3d.com
Modified to Teensy 3.1 by Kim Janson, www.levitezer.com
Further modified by John Beale, www.bealecorner.com
See also: forum.pjrc.com/threads/28036-Translating-Lidar-Lite-I2C-example-to-Teensy
  */

// #include <i2c_t3.h> // from https://github.com/nox771/i2c_t3  for Teensy 3
#include <Wire.h>  // for basic Arduino type boards
#define LIDARLite_ADDRESS 0x62 // Default I2C Address of LIDAR-Lite.
#define RegisterMeasure 0x00 // Register to write to initiate ranging.
#define MeasureValue 0x04 // Value to initiate ranging.
#define RegisterHighLowB 0x8f // Register to get both High and Low bytes in 1 call.
#define DLIMIT 10  // how many cm of reading difference to notice

byte MeasureArray[2];
int reading = 0;
int reading2 = 0;
int dOld = 0;  // previous distance reading
int dNew = 0;  // new reading
int dX;  // change in distance reading
long dT; // difference in time between readings
unsigned long tcount = 0;
long tNew, tOld;  // time in milliseconds()
uint8_t nackack = 100;
const int LED1 = 13;         // onboard signal LED 

void setup()
{
  pinMode(LED1,OUTPUT);       // enable digital output for turning on LED indicator   
  digitalWrite(LED1,HIGH);   
  Wire.begin();  // basic I2C library
  // Wire.begin(I2C_MASTER,0x00 ,I2C_PINS_18_19, I2C_PULLUP_INT, I2C_RATE_100); 
  // Wire.setOpMode(I2C_OP_MODE_ISR);
  Serial.begin(115200); // start serial communication at 9600bps
  MeasureArray[0]=0x00; // Register to write to initiate ranging.
  MeasureArray[1]=0x04; // Value to initiate ranging.
  delay(500);
  Serial.println("LIDAR Test #1 24-Mar-2015");
  digitalWrite(LED1,LOW);   
  tOld = millis();
}

void loop()
{
nackack = 0; //initiate ranging.
while ( nackack == 0) { 
  Wire.beginTransmission((int)LIDARLite_ADDRESS); // transmit to LIDAR-Lite
  nackack = Wire.write( MeasureArray,2); 
  if (nackack == 0)  { delay(1);} 
 } 

 nackack = 100; //end transmission
 while ( nackack != 0) { 
   nackack = Wire.endTransmission(); 
   if (nackack != 0) {delay(1);} 
 }
 
delay(1); 
digitalWrite(LED1,LOW);   

/* http://kb.pulsedlight3d.com/support/...ck-start-guide
"Periodically poll the unit and wait until an ACK is received. The unit responds to read 
or write requests with a NACK when the sensor is busy processing a command or performing a 
measurement. (Optionally, wait approx. 20 milliseconds after acquisition and then proceed
to read high and low bytes)"
15 ms gives about 17 to 18 ms reads. Would like to use polling, but how?  */

 nackack = 0;
 while ( nackack == 0){ //if error write again
 Wire.beginTransmission((int)LIDARLite_ADDRESS); // transmit to LIDAR-Lite
 nackack = Wire.write((int)RegisterHighLowB); // sets register pointer to (0x8f)
 if (nackack == 0){delay(1);} }

 nackack = 100;
 while ( nackack != 0){ // if not success (0) do a gain
 nackack = Wire.endTransmission(); // stop transmitting
 if (nackack != 0){delay(1);}
 }

 nackack = 0;
 while ( nackack == 0) { 
   nackack = Wire.requestFrom((int)LIDARLite_ADDRESS, 2); 
   if (nackack == 0) {delay(1);}
 } // request 2 bytes from LIDAR-Lite

delay(1);
if(2 == Wire.available()) // if two bytes were received
 {
  delay(1);
  reading = -1;
  while ( reading == -1) { 
    reading = Wire.read(); 
    if (reading == -1){delay(1);}
  }

  reading = reading << 8; // shift high byte to be high 8 bits
  reading2 = -1;
  while ( reading2 == -1)
    { 
     reading2 = Wire.read(); 
     if (reading2 == -1) {delay(1);}
    }
 
    reading |= reading2; // receive low byte as lower 8 bits

    tcount++;
    dNew = reading;
    dX = dNew - dOld;
    // if new distance has changed much, print: distance, time, reading count
    if (abs(dX) > DLIMIT) {
      tNew = millis();
      dT = (tNew - tOld);
      float vel = 1000.0 * dX / dT;
      digitalWrite(LED1,HIGH);   
      Serial.print(dNew);
      Serial.print(", ");
      Serial.print(dT);
      Serial.print(", ");
      Serial.print(tcount);
      if ((dNew != 0) && (abs(vel) < 2000)) {
        Serial.print(", ");
        Serial.print(vel,3);
      }
      Serial.println();
      tOld=tNew;
      dOld = reading;
      tcount=0;
      // delay(50);  // let LED ON be more visible
   }
  }
}
 
The I2C_T3 library works on an ATMega chip?

I did not try the i2c_t3 library, I assumed that it would not work on ATmega; that's why in the posted code i went back to the wire library, and commented out a few lines specific to i2c_t3 setup:

Code:
// #include <i2c_t3.h> // from https://github.com/nox771/i2c_t3  for Teensy 3
#include <Wire.h>  // for basic Arduino type boards

...

  Wire.begin();  // basic I2C library
  // Wire.begin(I2C_MASTER,0x00 ,I2C_PINS_18_19, I2C_PULLUP_INT, I2C_RATE_100); 
  // Wire.setOpMode(I2C_OP_MODE_ISR);

But that and the timeout delay are the only changes from the T3 code. It runs OK for a while, and then locks up if I have the delay shorter than about 15 msec, exactly like the behavior on T3. The I2C lines look just the same on the scope during operation with Seeeduino as they did with the T3, both the intended data and the unintended intermittent 5-microsecond "glitch" on the SDA line coming from the LIDAR module.

EDIT: I assume the 5-usec low pulse on SDA is unintended, because it is intermittent, and because it can cause I2C lockup with my code. However I am not an I2C expert and it is possible this is actually an intended signal from the LIDAR to indicate that it is not ready by seizing the bus with the I2C START condition (?) ...which the Wire library does not correctly handle, and the DSS Circuits library does handle (?)
 
Last edited:
Just noticed this thread. Regarding i2c_t3, if the LIDAR is generating a SDA low pulse, and if the T3 happens to try and send a command right at that time it could conceivably lock the T3 (from the T3's perspective some other master is trying to control the bus). This seems a little odd though since the glitch is so short in duration, perhaps it is confusing the T3 start/stop detection hardware.

I'm going to rework the i2c_t3 timeout system such that it will timeout if it cannot gain control of the bus. Currently the timeout only starts to work after the T3 gets control of the bus, but this situation happens enough that it needs to change. I think most hangs on i2c_t3 trace back to this bus waiting problem.
 
i too would be very interested in knowing if this can be made to work reliably.
i was planning on using the new teensy LC with the LIDAR Lite sensor.

i hope one of you finds a solution.
good luck.
 
I think there are several ways to make it work. I haven't even fixed the timeout-lockup condition, but by waiting 15 msec as mentioned above, my code has been running without issue 24/7 for a week now.
 
I think there are several ways to make it work. I haven't even fixed the timeout-lockup condition, but by waiting 15 msec as mentioned above, my code has been running without issue 24/7 for a week now.

I wish this was true for me. I am running it at 20ms intervals and I get a lockup every 5 min or so. I have resorted to quickly switching off/on the 5V supply to the teensy and lidar with a mosfet controlled by a second device (the Edison i am using to process the sensor data).
 
I got rid of the 15 ms delay by using the #include <i2c_t3.h> (v7) specific commands:

while ( nackack != 0){ nackack = Wire.endTransmission(I2C_STOP,900); if (nackack != 0){delay(1);}
}
nackack = 0;
while ( nackack == 0){ nackack = Wire.requestFrom((int)LIDARLite_ADDRESS, 2, I2C_STOP,900); if (nackack == 0){delay(1);}}

Still testing
 
This works now nicely wit fast update rates. Some delays are good to keep not to over poll the I2C bus. See the comments at the start of the coded

Code:
/*Sample code for LIDAR lite connected to Teensy 3.1. 2 April 2015
uses i2c_t3.h V7 https://forum.pjrc.com/attachment.php?attachmentid=3344&d=1421617902
Wire.endTransmission(I2C_STOP,300); is problematic and return sometimes unknown error.
Wire.beginTransmission((int)LIDARLite_ADDRESS); seems to recover from the error.


Kim Janson, www.levitezer.com
*/
#include <i2c_t3.h>

#define LIDARLite_ADDRESS 0x62 // Default I2C Address of LIDAR-Lite.
#define RegisterMeasure 0x00 // Register to write to initiate ranging.
#define MeasureValue 0x04 // Value to initiate ranging.
#define RegisterHighLowB 0x8f // Register to get both High and Low bytes in 1 call.



byte MeasureArray[2];
int LIDARreading = 0;
int LIDARreading2 = 0;
int LIDARreadingPrevious = 0;
uint8_t nackack = 100;
int32_t timer = 0;
int32_t errors = 0;


void setup()
{
Wire.begin(I2C_MASTER,0x00 ,I2C_PINS_18_19, I2C_PULLUP_INT, I2C_RATE_100);
Wire.setOpMode(I2C_OP_MODE_ISR);
Serial.begin(115200);
MeasureArray[0]=0x00; // Register to write to initiate ranging.
MeasureArray[1]=0x04; // Value to initiate ranging.
}


void loop()
{


nackack = 0;
while ( nackack == 0){ Wire.beginTransmission((int)LIDARLite_ADDRESS);
nackack = Wire.write( MeasureArray,2); if (nackack == 0 ){delay(1); Serial.print("Wire.write FAIL");} }

nackack = 100;
while ( nackack != 0){ nackack = Wire.endTransmission(I2C_STOP,900); if (nackack != 0){delay(1);
Serial.print("Wire.endTransmission 1 FAIL : "); Serial.print(nackack);} }

nackack = 0;
while ( nackack == 0){ Wire.beginTransmission((int)LIDARLite_ADDRESS);
nackack = Wire.write((int)RegisterHighLowB); if (nackack == 0){delay(1); Serial.print("Wire.write FAIL");} }
delay(1);
nackack = 100;
while ( nackack != 0){ nackack = Wire.endTransmission(I2C_STOP,300); if (nackack != 0){
delay(2);
if (nackack == 4){Wire.beginTransmission((int)LIDARLite_ADDRESS); errors=errors+1;} //recovers from unknown error
//Serial.print("Wire.endTransmission 2 FAIL : ");
//Serial.print(nackack);
//Serial.print(" ");

}}

nackack = 0;
while ( nackack == 0){ nackack = Wire.requestFrom((int)LIDARLite_ADDRESS, 2, I2C_STOP,900); if (nackack == 0){delay(1);Serial.print(" Wire.requestFrom FAIL");}}

if(2 == Wire.available())
{
LIDARreading = Wire.readByte();
LIDARreading = LIDARreading << 8; // shift high byte to be high 8 bits
LIDARreading2 = Wire.readByte();
LIDARreading |= LIDARreading2; // receive low byte as lower 8 bits

} else while(Wire.available() != 0 ) { Serial.print(" Wire.available : "); Serial.print(Wire.readByte());}

delay (1);
//if (LIDARreadingPrevious != LIDARreading) {
Serial.print(" Sample rate (ms) : ");
Serial.print(millis()-timer);
Serial.print(" LIDARreading: ");
Serial.print(LIDARreading);
Serial.print(" errors :");
Serial.println(errors);
timer=millis();
//}
LIDARreadingPrevious=LIDARreading;
}

Excample results:
Sample rate (ms) : 14 LIDARreading: 500 errors :41
Sample rate (ms) : 13 LIDARreading: 485 errors :41
Sample rate (ms) : 11 LIDARreading: 471 errors :41
Sample rate (ms) : 11 LIDARreading: 463 errors :41
Sample rate (ms) : 12 LIDARreading: 456 errors :41
Sample rate (ms) : 13 LIDARreading: 432 errors :41
Sample rate (ms) : 13 LIDARreading: 297 errors :41
Sample rate (ms) : 12 LIDARreading: 275 errors :41
Sample rate (ms) : 11 LIDARreading: 285 errors :41
Sample rate (ms) : 14 LIDARreading: 500 errors :41
Sample rate (ms) : 13 LIDARreading: 485 errors :41
Sample rate (ms) : 11 LIDARreading: 471 errors :41
Sample rate (ms) : 11 LIDARreading: 463 errors :41
Sample rate (ms) : 12 LIDARreading: 456 errors :41
Sample rate (ms) : 13 LIDARreading: 432 errors :41
Sample rate (ms) : 13 LIDARreading: 297 errors :41
Sample rate (ms) : 12 LIDARreading: 275 errors :41
Sample rate (ms) : 11 LIDARreading: 285 errors :41

Edit: but not tested much yet.

Edit2: and this hangs too, but some progress anyway. Maybe something needs to be fixed on the i2c_t3.h Wire.endTransmission?
And would be nice to know what I2C_STOP and I2C_NOSTOP actually do.

Edit3: and it seems I2C_STOP does not work if SPI.h is used :-(
 
Last edited:
I’ve been able to run my LIDAR multiple days without errors after making a couple code changes. Before the changes I could not run more than a few minutes before locking up the Teensy 3.1. Now I cannot cause any failures no matter how much I “slap” the device around.

As described in an earlier post, I modified the “Wire” library endTransmission() function. I commented out the call to i2c_wait() which is where the lockup always occurred and added inline code to perform the same function as the i2c_wait() but I also added a counter that provides a timeout after about 30 ms. When a timeout occurs I return an error code to the application. Originally I returned an error code “4” but later changed that to a unique error code I could test on at the application level, I use “99” but can be any unique value. Adding the timeout to the endTransmission() function prevented the Teensy from locking up BUT occasionally, the Wire library would be left in a state that it would no longer communicate with the LIDAR device.

By adding a unique error code “99” when the Wire library endTransmission() function times out, I can test at the application level when this error occurs. When it does, I now reinitialize the library by re-calling the Wire.begin() function and then I resume taking readings from the LIDAR. This combination of adding a timeout to the endTransmission() and then restarting the library when the error occurs seems to provide a solid workaround for me. I would be curious to hear if anyone else has tried this approach.

Ultimately I think the I2C libraries need to be enhanced to allow for these types of device errors but until then the workaround I've described allows me to use the device.
 
Last edited:
What kind of sample rates do you get, with the previous version of code (with 15 ms delay) I got solid 20 ms and no errors, with the above code mostly around 11 and 12 ms, occasionally more, but it still have some problems, especially when used together with SPI
 
I’m using the LIDAR device via a timer interrupt driven state-machine. I didn't want to tie up my application for 20 ms or so waiting on the LIDAR device each time I wanted a measurement so I wrote an interrupt driven function that runs transparently to the application. The function goes through 5 states;

enum LIDARStates
{
LIDARStateSendMeasureData,
LIDARStateSendMeasureDataAck,
LIDARStateSendHiLowB,
LIDARStateSendHiLowBAck,
LIDARStateGetDistance,
};

Each state takes less than 300 us processor time so my application is minimally affected by the slow LIDAR device. I typically set the interrupts to occur between 3 and 5 ms which results in a complete measurement taken every 18 – 25 ms. Each time a measurement is completed, the interrupt routine stores the measurement in a circular buffer and when my application needs a measurement I call a routine that returns a smoothed value from the circular buffer.

It’s really less complicated than it sounds and the CPP code is only about 150 lines long.
If you are interested I can post the code.

I’m not sure how this design would work with other devices on the I2C bus, could be problematic.
 
just FYI:
we use LIDAR sensors from here : http://www.lightware.co.za/ with teensy 3.1 with absolutely no problems using i2c, in fact we have used up to three at once on one teensy, we just give them different i2c addresses.
They give us readings of up to 50m (depending on the version) . We read them 30 times per second.

They can run off the usb powered teensy, however they give erratic range readings when they are starved of power, have never had freezing problems.
They are 5 and 3.3v tolerant.
We had them working on our arduino mega boards as well before moving across to teensy.
 
Correct they are usd prices however if you take into account the man hours spent on this forum alone, this makes us more comfortable with our decision to go with the better kit.
 
Yes, you are right, this is just very frustrating, not getting the LIDAR Lite to work high samplerates with Teensy 3.1. For me it works fine at low speeds (20 to 30 ms) but the max speed (10 to 15 ms) always hangs. What I tested the LIDAR Lite was working just fine with Arduino UNO.

Is there a way to reset the I2C communication? (using i2c_t3.h)

I get unknown errors (4) on Wire.endTransmission, often it recovers, but not always and it might be something else too causing the hang.
 
It seems indeed that there is a SDA LOW about 8 ms after the

Wire.beginTransmission(LIDARLite_ADDRESS);
Wire.write(RegisterMeasure);
Wire.write(MeasureValue);
nackack = Wire.endTransmission(I2C_STOP,1000);

Has been sent. I connected the SDA also to pin 17 and poll that after sending the MeasureValue. It looks like this is an undocumented feature that gives the reading available indication (maybe) and probably the collision with this causes the problems.

Too bad the i2c_t3.h does not always recover this. The polling method should avoid the collision. But I suppose this limits the i2c bus use only for LIDAR Lite?
 
Last edited:
I'm working on the new version of i2c_t3 library right now (currently testing and debugging). Two main things are LC support and also timeout support for a busy bus.

More specifically that means if the bus is stuck busy at the moment the START signal is sent it will cause a timeout (at least that's the plan). If that occurs I'm thinking to include a #define option which will cause it to try to unstick the Slave (this is done by toggling SCL (9 clocks max) until SDA is released), and then retrying the START command. Hopefully this will make it more robust to strange traffic like this.

I've never heard of a device using the SDA as an event flag, that's certainly not standard protocol.
 
What I tested with UNO, the I2C.h was working good, Wire.h was not and that was also the comment I received from LIDAR Lite, they like I2C.h much more.

I have been banging my head to the wall with i2c_t3.h and Teensy all too long now. need to get it working. the above method works quite good (12 to 14 ms rate), but still occasionally hangs and should get it still working with rest of my code, using SPI.h and other stuff that needs to run on 1 ms interval, so I can not really use delays.

It is good that the i2c_t3.h is now being updated, I had a look on it, but it is just beyond my skills and time I have for this.

based on my testing sendTransmission has less problems than endTransmission so I suspect finish. There was also some code about interrupt priority. I had much more problems when also SPI.h was in use.

I will now spend still some time with Teensy trying what could be archived with PWM connection and maybe using enable could help.
 
I took a closer look at your code. I think you could change a few things. First off, can you verify you are using internal pullups? If you have resistor pullups on your board you would want to set the below to I2C_PULLUP_EXT.

Code:
void setup()
{  
    Wire.begin(I2C_MASTER,0x00 ,I2C_PINS_18_19, [COLOR=#ff0000]I2C_PULLUP_INT[/COLOR], I2C_RATE_100);    
    Wire.setOpMode(I2C_OP_MODE_ISR);  [COLOR=#ff0000]<--- also this line is not needed, ISR is the default[/COLOR]
    Serial.begin(115200); 
    MeasureArray[0]=0x00; // Register to write to initiate ranging.
    MeasureArray[1]=0x04; // Value to initiate ranging.  
}

You can try running the code below. It might give you a more descriptive answer as to why the bus is hanging. The Arduino error codes aren't always very useful. I have not compiled this code, but it should do what your previous code did.

Code:
void print_i2c_status(void)
{
    switch(Wire.status())
    {
    case I2C_WAITING:  Serial.print("I2C waiting, no error\n"); break;
    case I2C_ADDR_NAK: Serial.printf("#%d : Slave addr not acknowledged\n",errors); break;
    case I2C_DATA_NAK: Serial.printf("#%d : Slave data not acknowledged\n",errors); break;
    case I2C_ARB_LOST: Serial.printf("#%d : Bus Error: Arbitration Lost\n",errors); break;
    case I2C_TIMEOUT:  Serial.printf("#%d : I2C timeout\n",errors); break;
    default:           Serial.printf("#%d : I2C busy\n",errors); break;
    }
    errors++;
}

void loop()
{
    // skip error checking this part, it is just a buffer copy, it won't fail
    Wire.beginTransmission((int)LIDARLite_ADDRESS); 
    Wire.write(MeasureArray,2);

    // this is where the error checking is important
    Wire.endTransmission(I2C_STOP,900);
    if(Wire.getError()) print_i2c_status();
    else
    {
        Wire.beginTransmission((int)LIDARLite_ADDRESS);
        Wire.write((int)RegisterHighLowB);
        Wire.endTransmission(I2C_STOP,300);
        if(Wire.getError()) print_i2c_status(); 
        else
        {
            Wire.requestFrom((int)LIDARLite_ADDRESS, 2, I2C_STOP,900);
            if(Wire.getError()) print_i2c_status(); 
            else
            {
                if(Wire.available() == 2) 
                { 
                    LIDARreading = Wire.readByte() << 8; // shift high byte to be high 8 bits 
                    LIDARreading |= Wire.readByte(); // receive low byte as lower 8 bits
                } 
                else while(Wire.available() != 0 ) { Serial.print(" Wire.available : "); Serial.print(Wire.readByte()); }
            }
        }
    }
    delay (1);
    //if (LIDARreadingPrevious != LIDARreading) { 
    Serial.print(" Sample rate (ms) : "); 
    Serial.print(millis()-timer);
    Serial.print(" LIDARreading: "); 
    Serial.print(LIDARreading);
    Serial.print(" errors :"); 
    Serial.println(errors);
    timer=millis();
    //}
    LIDARreadingPrevious=LIDARreading;
}

And would be nice to know what I2C_STOP and I2C_NOSTOP actually do.

I2C_STOP causes the command to issue a STOP at the end. This is used by the Master device to release the bus (both SDA and SCL will go high). On a single-master bus it won't really matter if you use STOP or NOSTOP, but it is good form to use STOP unless a specific command requires a RepSTART (which implies NOSTOP on the preceding command).
 
Thanks Nox771,

This is the code I am running now, sofar running ok and providing 12 to 15 ms readouts.


Code:
//by Kim Janson [url]www.levitezer.com[/url]
//2 kohm pulups to 3.3V are used, though not sure they are needed.
//on board pin 18 (SDA) and 17 are connected together and pin 17 is used for polling.
//4.7 uF capasitor on power input, not sure if it is needed.


#include <i2c_t3.h>
#include <SPI.h> //just to test including this will not cause problems, will add the code later
#define    LIDARLite_ADDRESS   0x62          // Default I2C Address of LIDAR-Lite.
#define    RegisterMeasure     0x00          // Register to write to initiate ranging.
#define    MeasureValue        0x04          // Value to initiate ranging.
#define    RegisterHighLowB    0x8f          // Register to get both High and Low bytes in 1 call.

elapsedMillis Timer1;
elapsedMillis Timer2;
boolean Flag17=LOW;
uint8_t nacCount = 0;
uint8_t nackack = 0;

void setup()
{
  //Wire.begin(); // join i2c bus
  Wire.begin(I2C_MASTER, 0, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_100, I2C_OP_MODE_DMA );
  Serial.begin(115200); 
  pinMode(17,INPUT);//SDA is connected also to pin 17 to detect glitches
  attachInterrupt(17, glitch, FALLING); 
  delay(1000); 
}

void glitch() {Flag17=HIGH;} //Set Flog17 high if a glitch is detected

void loop(){
if(nacCount==0&&nackack==0){
  nackack = 100; 
  while (nackack != 0){ 
    //Reguest reading
    Wire.beginTransmission(LIDARLite_ADDRESS);
    Wire.write(RegisterMeasure);
    Wire.write(MeasureValue);
    nackack = Wire.endTransmission(I2C_STOP,1000);
  }
 
  nackack = 100;
   
   Timer2 = 0 ;  
  //set register where to read the reading, it can not be sent before reading is ready
  Wire.beginTransmission(LIDARLite_ADDRESS);
  Wire.write(RegisterHighLowB);
  
  
  if(nackack == 100) {delay(10);} //Time to do something usefull here
 
  }
  Flag17=LOW;delay(1);
  if(Flag17==LOW){ nackack = Wire.endTransmission(I2C_NOSTOP,1000); nacCount = 0;}else{nackack=2;} //check for glitsches just before sending
  if (nackack!=0){nacCount++;Serial.print(".");} 

 
  
  if(nacCount==0&&nackack==0){ //Request LIDAR reading only if previous is sucsesfully performded
  Wire.requestFrom(LIDARLite_ADDRESS,2,I2C_STOP,1000);
                          
  int reading = Wire.readByte() ;
  reading = reading << 8;
  reading |= Wire.readByte();

  Serial.print(Timer1);
  Timer1 = 0;
  Serial.print(" Reading :");
  Serial.println(reading);
  }
}


Note: not tested much, probably this hangs too and I suspect every reading is not unique
 
Last edited:
Tested the PWM Mode of LIDAR lite, major downside is that updates at long range are slow (40 m = 4000 cm, 1 cm = 10 us => 40 000 us = 40 ms)

But to my surprise this hangs also after some time so the i2C hangs may not be totally only because of the collisions. I connected also the Power enable and perform reseting of the sensor if no updates in 50 ms. so long so good. Will try this also to I2C.

Code:
// Modified from LIDAR lite PWM excamble https://github.com/PulsedLight3D/LIDARLite_Basics/tree/master/Arduino/LIDARLite_PWM_GetDistance_ContinuousRead
//by Kim Janson www.levitezer.com
//4.7 uF capasitor on power input, not sure if it is needed.
//Pin21 PWM read, 
//Pin20 Mode PWM Low, I2C High 
//Pin2 Power enable High on, Low of

unsigned long pulse_width;
elapsedMillis Timer2;
int32_t timerPWM = 0;
boolean HighLow=LOW;
boolean PWMstatus=LOW;

void setup()
{
  Serial.begin(115200);
  pinMode(2, OUTPUT); //Power enable
  pinMode(20, OUTPUT); // Set pin 22 as trigger pin
  pinMode(21, INPUT); // Set pin 21 as monitor pin
  digitalWrite(20, LOW); // Set trigger LOW for continuous read
  digitalWrite(2, HIGH);//Turn on the LIDAR lite
  attachInterrupt(21, pulseWith, CHANGE);
}

void pulseWith() {
HighLow=digitalRead(21);
if(HighLow==HIGH){timerPWM=micros();PWMstatus=LOW;}
if(HighLow==LOW){pulse_width = micros()-timerPWM;PWMstatus=HIGH;}

} 

void loop()
{
 // pulse_width = pulseIn(21, HIGH); // Count how long the pulse is high in microseconds
  if(PWMstatus==HIGH){ //if reading ready print
        pulse_width = pulse_width/10; // 10usec = 1 cm of distance for LIDAR-Lite
        Serial.print(Timer2);
        Timer2 = 0;
        Serial.print(" Reading :");
  	Serial.println(pulse_width); // Print the distance
  PWMstatus=LOW;//wait for next HIGH to print again.
  }
  
  if(Timer2>50){ //Reset LIDAR lite if no update in given time
    digitalWrite(2,LOW); // Turn off the sensor
    delay(1);// Wait 1ms
    digitalWrite(2,HIGH); //Turn on te sensor
    delay(1);//Wait 1ms for it to turn on.
    Timer2 = 0;
    Serial.print(" Reset ");
  }
  
 delay(3);
}
 
I just noticed the DMA in your code below, try running in ISR mode if your code is almost working for you.

Code:
  Wire.begin(I2C_MASTER, 0, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_100, [COLOR=#ff0000]I2C_OP_MODE_DMA[/COLOR] );

In the v7 library the DMA mode has a lot of problems with timeout. I've spent the better part of the last two days getting DMA mode to exit cleanly when a timeout occurs. The problem is the I2C hardware can get stuck thinking the bus is busy when DMA is abruptly halted in the middle of a transfer. I think I have a working solution but it is still experimental until more people can test it out. Unfortunately there is no patch for v7, the changes are too extensive.
 
Status
Not open for further replies.
Back
Top