I want to connect a temperature/humidity sensor to the Imp. I do not want to bitbang, and when I saw
Hugo say “SHT2x would be less of a problem as we have that code on an imp”, I went looking for a board with SHT21 (I am not equipped nor skilled for SMT work). Found one at LiquidWare (the same, I think, as the ModernDevice one). (Ended up costing more than an Imp and an April Impee :()
I am new to the Imp, and know nothing about i2c, so please forgive the dumb questions
Hardware questions:
Supply voltage. SHT21 datasheet specifies supply voltage as min=2.1, typical=3.0, max=3.6, but LiquidWare (and ModernDevice) page specifies input voltage as +5 and says: “Board is 5V tolerant, allowing sensor to run from a 5V supply on Arduino I/O pins”. So, do I have to power it from the 5V, or is 3.3V good?
Pull-up resistors. Imp documentation says: “external pull-ups are required, it is not possible to enable the internal pull-ups when pins are used for I2C.” I do not see any difference with or without pull-ups, probably because the board I am using has them. Is there a way to find out for sure?
Software questions:
Address. Although i2cdetect on a Raspberry Pi shows the sensor at address 0x40, I need to shift the address to the left when using the sensor on an Imp. That is not clear from the Imp documentation (hint), but was addressed multiple times on the Imp forums. The question is - since Imp firmware does not process the address, do I need to specify the read bit as a part of address when calling i2c.read() (|1 to the base address)), or is this done for me?
Command and sub address. SHT21 datasheet describes how to trigger measurement of temperature (with “hold master”) - send a “command” 1110’0011 (looks like 0xE3 to me). Imp documentation for the i2c.write() says: “first two characters of the string are typically used as the MSB and LSB of the sub address”. If the “command” that I need to send is part of the data, and not the “sub address”, how do I indicate to the Imp not to send any sub address? If the “command” is actually the “sub address” (and then I do not need to send any data), how do I indicate to the Imp to send one byte and not two?
This is embarrassing, but since I have no clue about i2c and its terminology, I resorted to experimenting with sending various values for the “sub address”. Some of the values allowed me to read something off the sensor, but only two of them coincide with commands listed in the SHT21 datasheet.
What am I doing wrong?!
Status codes. Imp documentation for i2c.write() says: “On completion 0 is returned for success or -1 for an error condition.” I saw other values: -13 when i2c was not configured; -2 when i2c address is wrong; -3 and -4. Is there any documentation for these?
There’s no schematic for the board, but I believe I can see an LDO and a couple of level-translating FETs on the board. Given how little current the SHT21 takes, you’re likely fine running at at 3.3v input - the LDO will drop out a little but the chip has a very wide supply range. The level translators won’t do any harm at the same voltage on both sides.
I think the liquidware board has pull-ups on it already, from the photo.
SW:
The bottom bit is set automatically on a read
The I2C protocol doesn’t differentiate between written bytes; if the I2C device is expecting two byte subaddress, it’ll take the first two bytes after address on a write transaction as subaddress, and the rest as data. If the device only expects one byte subaddress it’ll take the first byte then the rest will be data. In the case of the SHT21, it has no subaddresses - the byte is just the command.
In general I hate devices that clock stretch (because every I2C master I’ve ever used has issues with doing it right) so I’d use the non-hold mode.
Something like this should work (assuming you’re using pins 8 & 9):
`// initiate temperature conversion, no bus hold
hardware.i2c89.write(0x80, “\xf3”);
// wait for conversion, 14 bits = 85ms
imp.sleep(0.085);
// read temperature
local t_raw = hardware.i2c89.read(0x80, “”, 2);
if (t_raw != null) {
// print it raw
server.log(format(“read %02x %02x
”, t_raw[0], t_raw[1]);
// convert it
local t = -46.85 + 175.72 * ((t_raw[0]<<8) | (t_raw[1]&0xfc))/65535.0;
server.log(format(“temperature %fC”, t));
} else {
server.error(“i2c read error”);
}
`
Status codes. Yes, there’s more info there as you noticed… but this isn’t documented as yet. I’ll see what we can do
(also note that the datasheet linked from the liquidware website is very very old and out of date; it has the wrong parameters for processing the data returned from the chip - google to find at least a 2010 version!)
The hold mode seemed like a good idea at the time: datasheet suggests polling for the no-hold commands… But your suggestion (with wait) works great!
Thanks for the datasheet tip: the latest I found is from 2010, and the conversion parameters are different! Did the hardware change? Did they make mistake in the original version of the datasheet? Why does LiquidWare site link to an obsolete and incorrect document? Does it really matter?
Weirdly, the temperature as reported by the sensor was very low (-20C), but after power down/up, it is now correct. I guess I wrote something to the sensor during my experiments…
Polling might save you 20ms (ISTR typical conversion time was 65ms) but sleeping is a lot simpler.
The 2009 datasheet was likely from a very early revision, maybe an engineering sample, of the part. They probably hadn’t finished tuning the performance; come 2010 they had the final production stuff and updated the datasheet to match.
You almost certainly have the production chip. You could always ask liquidware to update their website, it’s probably just an oversight.