I have built an I2C to LCD port expander and now I'm fighting with a modified version of the LiquidCristal library.
Before start adapting LiquidCristal to the I2c bus, I have thoroughly tested the board to be sure that it's working flawlessly.
I'm pretty sure that I will have to use the Wire library with another i2c devices at the same time than the i2c lcd,
I have choosed to not take out only the necessary i2c code from the Wire library that I need to manage the lcd, and to use the Arduino Wire library without change.
I have 2 immediate problems:
When from the modified LiquidCristaI library I call the 3 functions that I need from the Wire, the Arduino get's stuck. In the first invocation of the function that contains it.
I have used without problems the same 3 functions in sketches used to test the board.
Wire.beginTransmission(_i2c_port);
Wire.send(data);
Wire.endTransmission();
When are used inside the modified LiquidCristal, Arduino doesn't return from Wire.endTransmission() after the fist call.
I've checked with bus pirate in I2C sniffer mode and only get one i2c start condition. No more.
I need to add "#include <Wire.h>" to anywhere in the sketch to compile successfully.
No matter if I place it in top or bottom of the sketch.
No matter if I already have placed it on the library , I need to put it on the sketch anyway to compile.
In the pastebin of the sketch I've placed it on bottom.
add 1) The Wire.endTransmission() is the workhorse, the other calls just fill a buffer, if you dive into the Wire library code you see this is quite straightforward AND you will find the meaning of the returnvalue(s) of endTransmission().
add 2)
It is a known fact that if you use Wire.h in a library you also must include it in the main sketch (prefered at top, together with defines) otherwise it can't find the instance of Wire object.
Hi Rob, Thanks for take the job of reading this enormous post.
I've decided to go straight and try to find the problem using BusPirate as logic analyzer.
I have loaded the master_writer example for the Wire library.
Setup a trigger to start capture when any I2c pin changes of state.
3)Captured successfully the i2c traffic.
Event the light on the LCD goes on and of as the value of x pass 127 (the 8th pin is attached to a mosfet to drive the back-light) and go back when overflow to 0.
Doing the same with my sketch no data is captured.
My sketch and modified library sources compile correctly, call exactly the same Wire functions, no one more or one less.
But does not transmit a single clock or data in the Arduino i2c bus.
Not transmit a single bit and NEVER returns from the first Wire.EndTransmission call.
The offender code:
void LcdI2c::sendData(void){
uint8_t data=0;
for (uint8_t i=0;i<8;i++){
data |=_i2c_data*<<i;* } Wire.beginTransmission(_i2c_port); // this is 0x38 Wire.send(data); //first data sent (and last) is 0x0 Wire.endTransmission(); // Never returns from this call. } If I comment this 3 Wire lines above , and add some Serial.print everything works fine , except that the i2c bus does not transmit. The only other Wire function call in all the code is the Wire.begin in the LcdI2c constructor.
The device address is 7 bits so it might need a shift >>1 - its one of the Arduino I2C magic thingies
just give it a try
void LcdI2c::sendData(void){
uint8_t data=0;
for (uint8_t i=0;i<8;i++){
data |=_i2c_data<<i;
}
Wire.beginTransmission(_i2c_port >> 1); // shift one place to mimic 7 bits
Wire.send(data);
Wire.endTransmission();
}
Thanks again robtillaart.
The port value that I give to the library it's already in 7 bit format.
I have done a new test:
Copy the Arduino Wire library to sketchbook/libraries/LiquidCrystal2/
Replace all "LiquidCristal" references in the headers and source to "LiquidCristal2".
Add "#include <Wire.h>" at the top of LiquidCristal2.cpp file.
Add the next 3 Wire functions to the top of void LiquidCrystal2::send(uint8_t value, uint8_t mode) {
I call the constructor of the LiquidCristal2 and give that pins only to fake initialize the library.
I'm not trying to use the lcd in paralell, only give to the lib some pins not used for the i2c bus.
I know where are the i2c pins and it's the Wire library who cares about that.
I've checked the i2c port value with that pde it's the one I'm using.
The same port works perfectly if you take the wire part out off the LiquidCristal2 and put in the sketch.
Thanks again for checking.
There must be something wrong with the compiler or the arduino libraries (not 100% sure of course), because I never seen before that a "non declared function in this scope" error can be removed including the required header after the function it's called.
Maybe the libraries not where designed that you can use one inside another, and there's no other way than doing all from scratch if you don't want duplicate code everywhere.
I call the constructor of the LiquidCristal2 and give that pins only to fake initialize the library.
Why not create an appropiate constructor, with the device-id as param? (it makes it difficult for us to debug you code in this way and I dont want to download every BETA library)
You need to strip the whole library to just get this to work. Find below how it would look, should get you started. code is not tested if it will compile but I guess it is easier to debug than the 200+ lines of the modded lcd lib.