I am trying to write a library for the PCA9636 IC. It is a 16-channel PWM LED driver. I have found libraries for this chip but they are either not compiling for my board (Zero) or they plain just don't work. I am rather new to programming I2C and using the Wire library, so I am quite stuck.
As far as I can tell, I can successfully write to a register. At the same time I am trying to verify this by reading from a register that I just wrote to but this is where I am stuck. My code so far:
#include <Wire.h>
//MODE registers 1 & 2
const int MODE1 = 0x00;
const int MODE2 = 0x01;
//LEDOUT registers 1 - 4
const int LEDOUT0 = 0x14;
const int LEDOUT1 = 0x15;
const int LEDOUT2 = 0x16;
const int LEDOUT3 = 0x17;
//PWM register of output 0
const int PWM0 = 0x02;
void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
byte mode = B11111111; //this is the value I set MODE1 and MODE2 registers to
byte sendvalue = 100; //this is the value I am setting the PWM0 register to
//Send stuff
Wire.beginTransmission(0x28);
Wire.write(MODE1);
Wire.write(mode);
Wire.endTransmission();
Wire.beginTransmission(0x28);
Wire.write(MODE2);
Wire.write(mode);
Wire.endTransmission();
Wire.beginTransmission(0x28);
Wire.write(PWM0);
Wire.write(sendvalue);
Wire.endTransmission();
//Recieve stuff
Wire.beginTransmission(0x28);
Wire.write(PWM0);
Wire.endTransmission(false); //false gives me the ReSTART condition I need (check datasheet attachment)
Wire.requestFrom(0x28, 1);
byte recieved = Wire.read();
Wire.endTransmission();
Serial.println(recieved, BIN);
}
All I am getting on the serial monitor is 0s. I attached relevant datasheet info, sorry I don't know how to embed it in the post...
Can someone please tell me what I am doing wrong? Thanks for any help!
PS: I have a Open Logic Sniffer attached to my I2C bus, in case it could be useful for debugging.
Well, I wish I could But really I am saying this because I can see all the ACKs in my trace (logic sniffer). Even for the read procedure the trace looks exactly like in the datasheet, it's just always transmitting 0s on any register I try to read...
I have tried it without the closing endTranmission() but the result is the same in the serial monitor and trace. I'm guessing that the I2C bus just doesn't care about a random STOP condition?
I have also swapped the IC to a new one (both are new in that sense) but the results also stay the same...
gcjr:
doesn't the ACK, pulling the line low, confirm that the chip is responding?
I guess so...? I'm really a newb when it comes to I2C...
Again, all my verification comes from the I2C protocol analyzer in the LogicSniffer where everything looks alright. But then again, all I read from any register is 0s and all outputs are constantly HIGH regardless of what I write to any register. So I am turning in a circle...
Okay, partial success!! If I use the all-call address 0x70 instead of the hardware wired (and I2C scanner confirmed) address 0x28 it actually works. Confusing but better!
Okay, so I have the chip going by now by simply setting a different address. Some confusion went on.
First of all, my thought-to-be address of 0x28 didn't actually represent the hardware wired I2C address for the chip. My wired address was 0x00 which seems to be a sort of catch-all I2C address. That's why that partially worked. But took me a while to realize.
At the same time, I also discovered this: When I remove ALL I2C devices from my bus - literally just "empty" wires on my breadboard then - I2C scanner still shows me 0x28 address to be available and responding. I don't really understand why but for my system here, it's a fact.
So, after discovering all of this, I could make it work. If anybody has any clue as to why I am seeing this address on my bus, please let me know
At the same time, I also discovered this: When I remove ALL I2C devices from my bus - literally just "empty" wires on my breadboard then - I2C scanner still shows me 0x28 address to be available and responding.
by this you mean the acknowledge is being pulled low?
are there pull-up resistors on your clk and data pins? bus capacitance can hold a bus line to the state it was previously driven to.
my thought-to-be address of 0x28 didn't actually represent the hardware wired I2C address for the chip. My wired address was 0x00
what do you by wired address?
in order to you more than one of these chips, there are often address pins that can be pull-up/low to add an offset to the base address.
I didn't check electronically if anything is being pulled low while I2C scanner was running. I just repeat what it tells me in the serial monitor, where it finds the 0x28 address. I am assuming it wouldn't report that address if it wouldn't respond. But yeah, didn't check if any lines are being pulled low.
There is pull-up resistors on both SDA and SCL lines. I have designed I2C busses before, just never had to program them Signals look very good on an oscilloscope.
Wired address : The PCA9635 has 7 pins to be configured high or low as the I2C address. That's what I meant. Out of laziness I set them all to 0s to start with. That would have made it 0x00 but that address was never shown to me, maybe because it is "reserved" or so...?
Ah, it's nice to see that this not only confuses me. Also I find the datasheet rather thin with information...
gcjr:
did i read the datasheet correctly, that there are 7 hardware address pin? if so, doesn't this mean they fully specify the address.
Yes, it does. I have written about this in my previous answer.
gcjr:
where did you get 0x28 from?
Well, this is what I am pondering about. Again, my Arduino finds this address with no I2C devices attached to a working I2C bus. It almost feels like it's finding itself or something.
gcjr:
isn't your code simply printing the "received" value. is there a way to check for an I2C error?
As I said, I have a logic sniffer attached, so I can analyse the I2C communication. While I was communicating with that 0x28 address, everything looked fine on that analysis.
sherzaad:
sorry did not read all your post but can you confirm how the address pins are connected.
there is an example in the datasheet to show how you can set the device I2C address
Dear Sherzaad, everything is working already. Thank you.
gfvalvo:
Post the code for the exact scanner you're using, there are several of them floating around out there.
Confirm that when you run the scanner nothing is connected to the SDA / SCL pins except for pullup resistors of the proper value.
You may have stated this already, but I didn't see it scanning through the posts -- state which Arduino board you're using.
Code:
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// https://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, November 27, 2015.
// Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
I use an Arduino Zero (did not state it yet, sorry)
//edit: There is a original Arduino Motor Shield attached to my Arduino during this whole time. But it doesn't contain any I2C components - thought I'd mention it though.