Getting started - Photon + I2C + Understanding Addressing

Hey folks, I am a software guy new to the hardware side of things and trying to learn my way around combining the two. Any help would be much appreciated.

I am working on a project to drive some LEDs under my cabinets with Photon. I can write the code logic no problem once I understand the addressing of how to get the logic to the pins/memory. I am using this device - PCA-9532 and a photon power shield. I am ultimately wanting to send PWM to the 9532. Here is the 9532 datasheet.

Below is a a sample code set. I understand the begin and end parts but the comments combined with the write functions are confusing the heck out of me. Could someone help walk me through what is doing what here and how I could have derived it from the data sheet? I know this is asking quite a bit but kind of lost here and if I can figure out one of these I figure I can get the rest too.

Basically what are each of the writes doing and how should I have figured it out from the datasheet? Are they sending a value or am I supposed to put a value in there and the current hex is an address?

What does a frequency prescaler of (0x01) mean/do?
How does Wire.write(0x4B) mean blink for .5 secs?
etc…?

Thanks a million. Sorry for the oh-so-beginner questions.

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select frequency prescaler 0 register
  Wire.write(0x01);
  // Period of blink = 0.5 sec
  Wire.write(0x4B);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select pulse width modulation 0 register
  Wire.write(0x02);
  // Duty cycle = 50
  Wire.write(0x80);
  // Stop I2C Transmission
  Wire.endTransmission();

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select LED selector register
  Wire.write(0x05);
  // Output set to Blinking at PWM0
  Wire.write(0xAA);
  // Stop I2C Transmission
  Wire.endTransmission();

Before answering your actual question, have you considered Neopixels instead of “dumb” LEDs?

@ScruffR, not in a ton of detail but they seemed like they were more for complex/artsy type of work and didn’t put off nearly as much light in the color (cool white) that I wanted. Plus this is an awesome way for me to get more familiar with this stuff because I really do want to get good at this. I love it and I can do the code just gotta figure out how to merge the code and the hardware. :slight_smile:

Thanks.

Adafruit carries Neopixels with true Cool White LED’s in them along with the RGB leds. The good news is that there is a library ready to go with the Photon and Electrons which makes things much easier.

The are dead easy to use with the lib, even several hundreds of them with one pin, but even a few of them are painfully bright too :sunglasses:

And about the meaning of the registers it’s best to have a look at the actual datasheet of the controller chip (page 7ff)

Page 13 does give you walk through how to set up a blink with a detailed description of each step.

Perfect! I’m almost following the walkthrough on page 13.

Questions are still:
What are the symbols in I2C-bus column? Such as C0h for address with A0 to A2 = LOW?
I can’t use the symbols like “BLINK” and “PWM0” or anything, right? I have to select the address and then send the bits, right?

Below is my attempt at the example on pg. 13 with comments in case someone else finds it useful someday.

#define Addr 0x60
Wire.begin();
delay(300);
Wire.beginTransmission(Addr);
//Select Prescaler 0 Register
Wire.write(0x01);
//Write 151 to signify period to 1 second) 0x97 = 151 
Wire.write(0x97);
Wire.endTransmission();
/*...begin
Select binary 010 using hex 0x02*/
Wire.write(0x02);
//Set PWM0 Duty Cycle value = 25% of total = 256/4 = 64 = 0x40
Wire.write(0x40);
/*...end*/
/*...begin*/
/*Select LED0 to LED3 to ON. not including all begin/ends anymore*/
/* Select LED0 Register */
Wire.write(0x05);
/*Write ON (01) for each bit of each LED in this register to send ON to LED*/
/* write 01010101 (0x55) to send ON to each LED in LS0*/
Wire.write(0x55);
/*...end*/

/* Write PWM0 values (10) for LED 4-5 and 
PWM1 (11) Values for LED 6-7 (10101111) = (0xAF) */
/* begin/ends assumed */
/* select LS1 */
Wire.write(0x06);
/* write PWM0 for 4-5 and PWM1 for 6-7 */
Wire.write(0xAA);

C0h is the same as 0xC0 - it’s just another way to mark HEX numbers.
C0h = 0xC0 = 0b11000000

But if you feel more comfortable with decimal notation (e.g. for the duty cycle) you can still use that too

  Wire.write(64);  // exactly the same as Wire.write(0x40)

It’s just easier to picture the bits when using HEX (0x..) and don’t want to use BIN (0b........)

1 Like

C0h is the code (in hex, that's what the h is) that you need to send to address a particular slave, in this case, one whose address is 0 (A0, A1, and A2 all zero). If you look at 6.1 Device Address in the data sheet, you will see that the register has a fixed part, the 7th and 8th bits, that are set to 1; that would equal 192 or C0 in hex.

I can't use the symbols like "BLINK" and "PWM0" or anything, right? I have to select the address and then send the bits, right?

That is correct.

1 Like

Thanks guys. Makes sense. I’m used to JAVA and Scala where we never look at bits (almost never). takes some getting used to.

Below is a simplified program that looks like it’s working.
LED Register 0 - On
LED Register 1 - On via PWM at 25%

Obviously I can set case statements and what not from here to change actions based on some variable.

Thanks so much for your help.

void loop()
{
  //BLINK LEDS
  //Set 1 second period for prescaler0
  writePreScaler("0x01", "0x97");
  //Turn all LEDs on for LED Register 0
  writeValsToLED("0x05", "0x55");


  //PWM LEDs
  //Set max blink rate for prescaler1
  writePreScaler("0x02", "0x00")
  //Set Duty Cycle to PWM1 Register to 25%
  writePWM("0x04", "0x40")
  //Send PWM val to all LEDs on LED Register 1
  writeValsToLED("0x06", "0xFF")

  delay(500);
}

void writePreScaler(String preScaleReg, String blinkHex) {
  Wire.beginTransmission(Addr);
  Wire.write(preScaleReg);
  Wire.write(blinkHex);
  Wire.endTransmission();
}

void writeValsToLED(String ledReg, String ledVal) {
  Wire.beginTransmission(Addr);
  Wire.write(ledreg);
  Wire.write(ledVal);
  Wire.endTransmission();
}

One more question,

Should I be able to see the ON from LED Register 0 via a voltmeter from those out (1 to ground 1 to, say PIN0)?

On the PWM, should I be getting an average reading in Vs of approx 25% of output voltage? or does it work like that with volt meters? Trying to test outputs before I stick LEDs on there.

On/Off you should be able to measure with a V-meter, but PWM is a bit more tricky - depending on the quality of your meter and the PWM periode you may be able to get a “stable” reading or not.
PWM is best measured with an oscillograph.

1 Like

Gotcha, that makes sense.

I also came to realize that I don’t actually need that board at all. I wound up just plugging my photon directly into the PWM LED Amp’s PWM input control and viola.

I couldn’t make the data get to the LED Amp through the board, either I’m not pulling something up or down correctly or I am not communicating/addressing the boards correctly.