View previous topic :: View next topic |
Author |
Message |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
I2C troubles. |
Posted: Mon Aug 06, 2018 2:36 pm |
|
|
Continuing on trying to use the VL53L0X chip to do some distance measuring. I found this product: https://www.robotshop.com/media/files/pdf/tinylidar-tof-range-finder-sensor-datasheet.pdf
it claims to handle the complex API and 'dumb it all down'. Got one, giving it a go. Clock and Data lines look good on the scope, going to ground and up to about 4.3V I only read -1 for the MSB and LSB off the chip. Perhaps someone else can spy what I am missing.
Code: | #USE I2C(MASTER,I2C1, SLOW, FORCE_HW, SMBUS) |
Code: | i2c_start();
i2c_write(0x00); // reset to 0x10 address
i2c_write(0x06);
i2c_stop();
delay_ms(100);
i2c_start();
i2c_write(0x10);
i2c_write(0x4d); // set up for single read mode
i2c_write(0x53);
i2c_stop();
delay_ms(100);
i2c_start();
i2c_write(0x10);
i2c_write(0x54); // disable WDT
i2c_write(0x30);
i2c_stop();
delay_ms(100);
while(1) { // endless loop
i2c_start();
i2c_write(DISTANCE_ADDRESS);
i2c_write(0x44); // single read
msb = i2c_read();
lsb = i2c_read(0);
i2c_stop();
led_toggle();
distance_reading = msb << 8;
distance_reading = distance_reading + lsb;
distance_sum = distance_sum + distance_reading;
distance_index = distance_index + 1;
if(seconds >= 1) { // one second pasted, average data and send string via BT
seconds = 0;
if(distance_index > 0) {
distance_value = (float)((float)(distance_sum)/((float)(distance_index)));
distance_sum = 0;
distance_index = 0;
}
else {
distance_value = distance_reading;
distance_sum = 0;
distance_index = 0;
}
fprintf(USB_SERIAL,"**\t%.3f\t#\n\r",distance_value);
fprintf(USB_SERIAL,"**\t%d\t%d\t#\n\r",msb,lsb);
}
} // end endless while |
not the prettiest of code I know. I am using the default address of 0x10 for the device. That is the value of DISTANCE_ADDRESS
MPLAB 8.91
CCS PCM C Compiler, Version 5.064, xxxxx
Windows 10 |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Aug 06, 2018 2:52 pm |
|
|
OK, I know nothing about that device but...
i2c_write(0x00); // reset to 0x10 address
hmm, is this correct ?
Whenever coding, it helps to add comments to every line ,especially drivers. Costs nothing in codespace, but might help others now or you later, when you ask 'WHY did I do THAT"!??
Also run PCM P's 'I2C scanner' program ,located in the code library. It'll confirm basic, low level access to any I2C device. If it reports 'device found at 0x23' and there's only one device, you now KNOW it's true address.
Some 'camps' use the 7 bit address +R/W while CCS uses 8 bit addresses.
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Aug 06, 2018 3:05 pm |
|
|
The tinyLiDAR manual says this:
Quote: |
D Read Distance 0x44
Read distance in mm from the most recent measurement
Host -> Sensor
Send Command
0x44 {D}
Sensor -> Host
Read Response
2 bytes with MSB first
Example:
Read from distance from tinyLiDAR at default address of 0x10.
Value read was 0x0690 or 1680mm.
<10:w> 44
<10:r> 06 90
|
The 'r' and 'w' refers to the i2c r/w bit. If it's a read operation, this bit is
set = 1.
I have edited your main loop code as shown below, so that it works
according to the manual's description. I have indicated the changes
as shown in bold:
Quote: | i2c_start();
i2c_write(0x10);
i2c_write(0x44);
i2c_write(0x11);
msb = i2c_read();
lsb = i2c_read(0);
i2c_stop(); |
However, I don't actually know for certain whether they are using
7-bit or 8-bit i2c address mode. So follow Temtronic's suggestion about
checking the i2c slave address.
Last edited by PCM programmer on Mon Aug 06, 2018 3:21 pm; edited 1 time in total |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Mon Aug 06, 2018 3:19 pm |
|
|
Code: | i2c_start();
i2c_write(0x00); // reset to 0x10 address
i2c_write(0x06);
i2c_stop();
|
This probably is wrong, you need to communicate with default address.
And PCM's correction on code is probably right but I think write/read adresses are 0x20 and 0x21 since arduino uses 7 bit adressing while CCS uses 8 _________________ There is nothing you can't do if you try |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Aug 06, 2018 3:34 pm |
|
|
Got a device found at 0x20.
I will report more tomorrow. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Aug 06, 2018 3:56 pm |
|
|
tried with 0x20 for the base address, and using 0x21 for the read. still -1 reported back. I have commented allot of the code out. Done with it for today.
will try again tomorrow. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Mon Aug 06, 2018 4:14 pm |
|
|
OK, silly question.
What is the value of the I2C pullup resistors ?
Also does PCM P's program work and return with the address ?
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Aug 06, 2018 4:19 pm |
|
|
In the link that you gave for documentation, it says:
Quote: | I2C Pull-up resistors: 2x 4.7K SMD |
So it has two 4.7K pullups built-in.
When you start working on the project again, post your revised
code, so we can check if you're using the correct slave address
in all sections of the program. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Tue Aug 07, 2018 12:54 am |
|
|
0x10, is the Arduino address. 7bit. The PIC address will be 0x20, so this is right.
You are not reversing the I2C bus correctly. You need to issue a read command after a bus restart to reverse the bus...
Personally, simplify. Make a connection between the ground and clear pins for a short while, to reset the chip to factory defaults. This sets it to address 0x20, and the single step mode. Then you can use the basic code from the top of page 6 of the data sheet:
Code: |
#define LIDAR 0x20
#define WR 0
#define RD 1
while(1)
{ // endless loop
delay_ms(14); //max single read speed 75Hz
i2c_start();
i2c_write(LIDAR | WR); //we are writing
i2c_write('D'); // issue single 'distance read' command
i2c_start(); //restart
i2c_write(LIDAR | RD); //select the read address
msb = i2c_read(); //now read
lsb = i2c_read(0);
i2c_stop();
led_toggle();
//then your code to deal with this.
} // end endless while
|
Note how the I2C bus reversal is done. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Aug 07, 2018 7:34 am |
|
|
Still not working. As for pullups I am only using the 4.7K that are on the LIDAR, nothing on my control PCB. I still get -1 for MSB and LSB after doing the suggestions in this thread.
I think my hardware is good because the scanner program reported a device found at 0X20.
Code: | #use i2c(Master, sda=PIN_C4, scl=PIN_C3)
/*
*********************************************************************************************
* DEFINES
*********************************************************************************************
*/
#DEFINE LIDAR 0x20
#DEFINE RD 1
#DEFINE WR 0 |
Code: | int msb = 0;
int lsb = 0; |
Code: | delay_ms(14); //max single read speed 75Hz
i2c_start();
i2c_write(LIDAR | WR); //we are writing
i2c_write('D'); // issue single 'distance read' command
i2c_start(); //restart
i2c_write(LIDAR | RD); //select the read address
msb = i2c_read(); //now read
lsb = i2c_read(0);
i2c_stop(); |
not sure where to go now, I think it is close, but no way to really know. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Aug 07, 2018 7:45 am |
|
|
I have simplified the code down to do a simple on board LED turn on/off command 0x47.
This does not work either. Not sure why the scanner program would detect the device, and report the correct base address and simple LED control would not work. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Tue Aug 07, 2018 9:02 am |
|
|
Are you sure the internal resistors are enabled?. There are two links on the board that can be cut or made to enable the resistors.
You haven't mentioned what PIC?. On some PIC's the SMBUS option does not work. How did you have the bus setup when you were running the I2C scanner program?. Setting should be the same.
The write should work even if the PIC bus levels were set wrong.
Double check the settings you actually used for the bus scanner program. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Aug 07, 2018 9:19 am |
|
|
Yes the internal resistors are enabled. I am configured like the scanner program, that is the USE statement that is in the last post of my code. I am using 16F876 for a PIC, sorry thought I included that with the other specifics. |
|
|
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Aug 07, 2018 12:47 pm |
|
|
Just a follow up for the thread. I got the LIDAR to work. A couple of things, one there is a WDT on the board that resets after 3 seconds of no I2C bus activity. I had a really slow loop running to toggle LEDS so, disabled the WDT first thing, then I had to put the chip in single step mode before calling for a measurement. Lastly, Ttelmah's comment about needing to reset the buss is correct, had to put a i2c_stop() in front of it to keep it from hanging after a few reads. After the i2c_stop() was added, correct data flowed and no lock ups.
Isolated it down by focusing on controlling the on board LED first then expanding out. The i2c scanner code was really nice to have to verify that hardware wise, things were good. Thanks everyone. I will post some working code for the group in the next couple days and will post a new thread for this hardware in the CODE section because the datasheet does not do any PIC or CCS code examples. Here is the basic loop that worked:
Code: | delay_ms(14); //max single read speed 75Hz
i2c_start();
i2c_write(LIDAR | WR); //we are writing
i2c_write('D'); // issue single 'distance read' command
i2c_stop();
i2c_start(); //restart
i2c_write(LIDAR | RD); //select the read address
msb = i2c_read(); //now read
lsb = i2c_read(0);
i2c_stop(); |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Wed Aug 08, 2018 3:23 am |
|
|
That is quite interesting.
They don't give any actual bus timing specifications in the data. I've seen the need for a stop/start, rather than a simple restart on a few devices, but they all have delays specified between the last transmitted byte and the start (typically something like 1.5uSec), so:
Code: |
delay_ms(14); //max single read speed 75Hz
i2c_start();
i2c_write(LIDAR | WR); //we are writing
i2c_write('D'); // issue single 'distance read' command
//i2c_stop();
delay_us(2); //may also work
i2c_start(); //restart
i2c_write(LIDAR | RD); //select the read address
msb = i2c_read(); //now read
lsb = i2c_read(0);
i2c_stop();
|
May work as well.
On these it is also worth (if doing rapid sequential I2C transfers), adding a 2uSec delay after the I2C stop, since again there are problems if you do a second transaction immediately after the first.
Glad you have it working now. |
|
|
|