I2C sensor with WiPy2
I'm trying to read a VL6180x distance sensor with my WiPy2.
The WiPy detects the sensor and can read stuff from it, but the results doesn't really make sense.
According to the datasheet, register 0 should contain a model ID = 0xB4. The first time I read it I get the correct value, but if I keep reading it after that I get random values. If I reboot the sensor, I can read the correct value again one time. The same thing goes for all other registers I've tried to read.
The code I use to read:
from machine import I2C i2c = I2C(0, I2C.MASTER) i2c.readfrom_mem(0x29, 0, 1)
The sensor is on a breakout board with a voltage regulator, and there's nothing wrong with it, because if I connect it to an Arduino and do the same thing, it works perfectly. I've tried both to have the sensor connected directly to the WiPy, running it on 3.3V, and via a levelshifter, running it on 5V.
I have also tried different baudrates, but with no change.
What am I doing wrong?
@jasontimmins Hi , I dont know i suppose is not very hard ... try to find similar conversions for other sensors from Adafruit i2c mode and apply to pycom microphyton ...
Or maybe u should try to use i2c workflow from @iotmaker and rest of code and registers from Adafruit
The single difference that i see is the i2c addressing mode.
I dont know Python programming ...
If u have any result pls share :)
@chumelnicu This looks like a great library but I'm struggling to convert it to work on the Pycom device. Python is not my strong point. How different are Adafruit and Pycom devices?
Yes thats a bug i have on the code, have not dig into it yet on how to fix it.. But if you figure it out, please share :)
@iotmaker Thanks, that's got it working. I think I was missing...
It's now sitting here telling me how far my ceiling is above my desk!.. ~1690mm :-)
I see a distance reading on 20mm quite often (30% of the time), why do you suppose that would be?
This is my full code
just clean it up hehe
from machine import UART from time import sleep_ms from network import Sigfox from machine import I2C import socket import pycom import re import binascii import ubinascii from machine import Pin import ustruct import time VL53L0X_REG_IDENTIFICATION_MODEL_ID=0xc0 VL53L0X_REG_IDENTIFICATION_REVISION_ID=0xc2 VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD= 0x50 VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD=0x70 VL53L0X_REG_SYSRANGE_START=0x00 VL53L0X_REG_RESULT_INTERRUPT_STATUS=0x13 VL53L0X_REG_RESULT_RANGE_STATUS=0x14 sensor= 0x29#I2C Address ### Sigfox Stuff sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ2) # create a Sigfox socket s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW) # print Sigfox Device ID print("Sigfox ID") print(binascii.hexlify(sigfox.id())) # print Sigfox PAC number print("Sigfox PAC") print(binascii.hexlify(sigfox.pac())) # make the socket blocking s.setblocking(True) # configure it as uplink only s.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False) #Sigfox Stuff pycom.heartbeat(False) ##RGB Colors red=0xff0000 yellow=0xffff00 green=0x00ff00 blue=0x0000ff cyan=0x00feff purple=0xc442a1 orange=0xff8b55 dark=0x000000 def ledtoggle(color): pycom.rgbled(color) sleep_ms(50) pycom.rgbled(dark) sleep_ms(50) def i2c_w(reg,val): i2c.writeto_mem(sensor,reg,bytes([val]))##Put device on standby mode sleep_ms(1) ## address 0x1D i2c = I2C(0) # create on bus 0 i2c = I2C(0, I2C.MASTER) # create and init as a master i2c.init(I2C.MASTER, baudrate=400000) # init as a master sleep_ms(30) print("I2C Scan for devices") print(i2c.scan()) print("Revision ID ") print(i2c.readfrom_mem(sensor,VL53L0X_REG_IDENTIFICATION_REVISION_ID,1)) print("") print("Device ID ") print(i2c.readfrom_mem(sensor,VL53L0X_REG_IDENTIFICATION_MODEL_ID,1)) print("") print("Pre Range config Period") print(i2c.readfrom_mem(sensor,VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,1)) print("") print("Final Period") print(i2c.readfrom_mem(sensor,VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,1)) sleep_ms(30) print("") cnt=0 val=0 a=0 while True: #print("Start Measuerment") i2c_w(VL53L0X_REG_SYSRANGE_START, 0x02) while (cnt < 100): #1 second waiting time max val=i2c.readfrom_mem(sensor,VL53L0X_REG_RESULT_RANGE_STATUS,1) if val==64: cnt=200 cnt=cnt+1 sleep_ms(30) datasensor=i2c.readfrom_mem(sensor,0x14,12)#Read sensor data distance=datasensor*256+datasensor#combine integers #print("distance") print(distance) if 100<=distance<=200: print('Sending Sigfox') s.send(bytes([datasensor, datasensor, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255])) ledtoggle(blue) ledtoggle(blue) ledtoggle(blue) ledtoggle(blue) print("By law it will sleep 20 seconds") time.sleep(20) ledtoggle(green) # for x in range(0,12): # print(datasensor[x]) # # print(datasensor) # print(datasensor) # print(datasensor) # print("") sleep_ms(1000)```
@iotmaker Thanks for your code for the VL53L0X distance sensor. I've got the same configuration here and, although I can read the various registers you mention (Revision ID, Device ID, etc), I can't actually get a distance from the thing. VL53L0X_REG_RESULT_RANGE_STATUS is zero all the time and your 'distance' code gives zero too.
This looks like a fairly complex device, am I missing some kind of initialisation procedure?
@sesamproductions Did u manage to read VL53LX0 in long distance mode?
I did asked him if he managed to read the VL53L0X in long range mode (that mean 200cm)
@iotmaker Hi , did u read distance using vl53l0x with this code? Wrking and long distance too? i mean 200cm?
@iotmaker Hello , can u tell me please what is maximum distance range?
Great! Now I'm starting to understand this a bit!
I can read and write stuff using @robert-hh's suggestions, and the sensor seem to output correct data. Now I just have to modify my library with new read/write methods.
Thanks a lot for the help!
@SesamProductions I'm afraid I don't have any more information on that library. But smbus is just the I2C library for whatever hardware platform it was written for. You should be able to substitute pycom's I2C functions readfrom_mem and writeto_mem for b.read_byte_data and b.write_byte_data, respectively. But note, I've never actually tried to access 16-bit addresses using pycom's I2C functions. If they don't work, please do submit a bug report, and in that case, you should be able to accomplish the same thing using the writeto and readfrom method that @robert-hh suggested earlier.
@SesamProductions For writing to a register, just append the data for the register to the address in a single write.
About @iotmaker's comment. The VL53L0X device he uses requires just an 1 byte address just like the memory devices.
Thanks for the suggestions!
YES! That is working! Thank you! I can now read data from registers in a controller way.
Unfortunately I'm now very confused about this. If the writeto function is used to tell the device what register I want to read, how do I write things to the registers? For instance to tell the device I want it to start measuring range.
To me it looks like you're doing the exakt same thing I'm doing, and according to the short datasheet I found for your sensor, it should work similar to mine.
So why yours is working and mine is not is definitely beyond me.
When I've tried the sensor on the Arduino I've used the Adafruit library your linked code seem to be a python port of. I had myself not found that python version, so what I've done is my own python port of the Adafruit Arduino library. The problem is that in order to deal with all the complexities of the sensor and initialize it, I need to be able to read and write to registers, which is the part that isn't working.
The python-version you're linking to is using a module called smbus to deal with everything I'm having problems with. Where do I get that from? I didn't find any links for that on the github page, and
import smbusis not working on my WiPy. Where you using it on a WiPy, or some other Pycom device?
I had not heard about smbus before and a quick google for it seem to indicate it's a different, but fairly similar, protocol than i2c. Was there a reason for using smbus instead of the builtin i2c?
I have it working like this
VL53L0X_REG_IDENTIFICATION_MODEL_ID=0xc0 VL53L0X_REG_IDENTIFICATION_REVISION_ID=0xc2 VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD= 0x50 VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD=0x70 VL53L0X_REG_SYSRANGE_START=0x00 VL53L0X_REG_RESULT_INTERRUPT_STATUS=0x13 VL53L0X_REG_RESULT_RANGE_STATUS=0x14 sensor= 0x29#I2C Address print("Revision ID ") print(i2c.readfrom_mem(sensor,VL53L0X_REG_IDENTIFICATION_REVISION_ID,1)) print("") print("Device ID ") print(i2c.readfrom_mem(sensor,VL53L0X_REG_IDENTIFICATION_MODEL_ID,1)) print("") print("Pre Range config Period") print(i2c.readfrom_mem(sensor,VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,1)) print("") print("Final Period") print(i2c.readfrom_mem(sensor,VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,1)) #To read first check the status val=i2c.readfrom_mem(sensor,VL53L0X_REG_RESULT_RANGE_STATUS,1) #if val is equal to 64 then it read the distance #read the value datasensor=i2c.readfrom_mem(sensor,0x14,12)#Read sensor data distance=datasensor*256+datasensor#combine integers
I have it working on the VL53L0X hope it helps
@SesamProductions From the spec, I assume that the sequence should be:
i2c.writeto(0x29, b'\x00\x00') i2c.readfrom(0x29, 1)
The address for a read is a two byte value.
Yes, this is a fairly complex device that requires a lot of initialization (although I would think reading back the model ID could be done without init, but who knows). We used this driver: https://github.com/luciengaitskell/python-adafruit-vl6180x/blob/master/i2c/vl6180x.py
We've since moved on from using this sensor (it's a very interesting device, but it did not work well in our particular application), but I had no problem communicating with it. In fact, the only problems I've ever had with I2C on any pycom device was with the lack of clock stretching support on the software-based I2C (and now that hardware-based I2C is supported, that's no longer a problem).