Add 15 extra Digital I/O pins with one I2C device

I found this item on eBay and immediately bought 4 of them.

And because you can have more than 100 I2C devices on the same bus, you could theoretically control upto 1500 digital input/output devices.. if you could afford that many...
There's also one pin with PWM functionality, and this description by no means covers all of it's functions, so check it out.

http://www.byvac.co.uk/bv/bv4206.htm

Also as mentioned in a previous post, you can get small boards from the same place that control LCD modules through I2C.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1220386069

After some troubleshooting, I've found that the manual and the website present all the default ID codes as 8-bit, and they say you can only use even numbers... In Arduino the addressing is using the 7 main bits, essentially doing the same thing but when addressing them you have to shift the addresses left one bit when using them in 8-bit format.
In the manual it says the default address is 0x42, which is actually 0x21 in the 7-bit mode that "Wire.h" uses.

I'm posting the code I use to talk to the BV4206, as I think it might be useful for other newbies like myself, as it took me a few hours to figure this lot out from scratch.
This code basically just changes the default address and flashes the d0 pin on the chip (not on the Arduino).

#include "Wire.h"

void setup() {
    delay(100);
    Wire.begin();                  // set up I2C
    
    /** For BV4206 GPIO Devices **/
    //change address from default (0x21) to 0x10
    Wire.beginTransmission(0x21);  // join I2C, talk to BV4206 by id
    Wire.send(0x99);   //change address command
    Wire.send(0x10 << 1);  //new address (7 bit)
    Wire.send(0x55);  //check code - do not change
    Wire.send(0xaa);  //double check code - do not change
    Wire.send(0x21 << 1);  //current address (7 bit)
    Wire.endTransmission();      // leave I2C bus

    //set pin 0 to output mode
    Wire.beginTransmission(0x10);  // join I2C, talk to BV4206 by id
    Wire.send(0x01);   //set pin mode command
    Wire.send(0x00);  //the digital output id
    Wire.send(0x00);  //0x00=output 0x01=input
    Wire.endTransmission();      // leave I2C bus
    delay(100);
} 

void loop() {
    //set output 0 high
    Wire.beginTransmission(0x10);  // join I2C, talk to BV4206 by id
    Wire.send(0x02);   //set output command
    Wire.send(0x00);  //the digital output id
    Wire.send(0x01);  //0x01=hi 0x00=low
    Wire.endTransmission();      // leave I2C bus
    delay(100);
    
    //set output 0 low
    Wire.beginTransmission(0x10);  // join I2C, talk to BV4206 by id
    Wire.send(0x02);   //set output command
    Wire.send(0x00);  //the digital output id
    Wire.send(0x00);  //0x01=hi 0x00=low
    Wire.endTransmission();      // leave I2C bus
    delay(100);
}

as I think it might be useful for other newbies like myself,

Not only newbies, this had me going for a couple of hours with my transistor tester.

http://www.thebox.myzen.co.uk/Hardware/Transistor_Tester.html

It is because the least significant bit of the byte sent defines if it is read or write access. Every other system I have used uses that whole byte as an address with even addresses for read and odd for write access. On this system there are septate calls for read and write and so the address you have to supply, as stated, is shifted one place to the right.

It's OK when you know but this is a case of this implementation being different to every other one I have seen. Mind you I haven't seen them all. :wink:

I don't know if it was because it was built with Arduino in mind, but the BlinkM smart-led units (of which I have 4) work fine without having to shift the addresses...

It would be interesting to see what was underneath that sticker :wink:

Ok, for reference, I've also figured out how to use the BV4206 GPIO Digital Read function.

I've just got it reading a 4x4 keypad with no major issues.

    Wire.beginTransmission(0x10);  // join I2C, talk to BV4206 by id
    Wire.send(0x03);   //read command
    Wire.send(0x00);  //the digital input id
    Wire.endTransmission();      // leave I2C bus
            
    Wire.requestFrom(0x10, 1); //get byte
    byte key = Wire.receive(); //read the byte

From the read the the write functions now explained here it should be fairly straightforward to use any of the commands in the chip's manual, which is available on the website.

I'd like these groups of code put in the Arduino.cc Playground area as a more permanent reference, if anyone would kindly put it there for me :slight_smile:

Thanks

Ive got a four MCP23016-I/SP chips coming soon, to play with I2C. So will have to remember to shift over the bits after Ive set the address.

Thinks for the web site.

Had a look at the byvac.co.uk web site and thinking of ordering the BV4237 (I2C ADC + Digital Output(PWM) + RTC + Temperature) which is useful for any general purpose project.

The docs of the pcf8574 and pcf8574a datasheets show the 7 bits and R/!W. It made enough sense I could figure out how to get the test circuit working okay. I'd seen the Wire docs previously so maybe it didn't confuse me as much as I thought it would.

These devices have four address bits that are hardwired and unchangeable, three address bits that you jumper to three pins, and then the R/!W bit.

What did throw me though, I thought I ordered pcf8574 and got pcf8574a. The only difference between these are the constant value of the four hardwired address bits. And the silkscreening on some packages is very very dim, so I didn't see the problem when I made a test circuit. I had to write a loop to try all addresses...

I'm posting the code I use to talk to the BV4206, as I think it might be useful for other newbies like myself, as it took me a few hours to figure this lot out from scratch.
This code basically just changes the default address and flashes the d0 pin on the chip (not on the Arduino).

I bought two of the LCD-controllers, which I believe is the same chip as yours. However, all attempts to communicate with the controller fails. The chip works, as the LCD is displaying the controller's welcome message.

What happens is that Wire.begin(), Wire.beginTransmission(0x21) and the subsequent Wire.send()-calls seems to be successfull, but the closing Wire.endTransmission() never returns. Nothing happens on the LCD either.

I've wired the controller's SDA (pin 13) to analog 4, and SCK (pin 11) to analog 5, using a 5k6 pull-up resistor on each line. How did you wire your chip?

The only obvious thing I did differently was that I didn't use a pull-up resistor because the Arduino has built in pull-up resistors which are good enough for a handful of devices as far as I'm aware.

Try running a loop to talk to all 127 possible addresses, maybe it'll respond to an address you think it isn't programmed to.

Try running a loop to talk to all 127 possible addresses, maybe it'll respond to an address you think it isn't programmed to.

The problem is that Wire.endTransmission() never returns, so I can't use a loop. I need to reset after each call. I'm not sure if this is because I'm trying to access a non-existing device (using wrong address), or if there's some other reason.

It would be interesting to see what was underneath that sticker Wink

I removed the sticker on the LCD-driver from the same seller. All markings was ground off, but I suspect it's a PIC of some sort.

What happens is that Wire.begin(), Wire.beginTransmission(0x21) and the subsequent Wire.send()-calls seems to be successfull, but the closing Wire.endTransmission() never returns. Nothing happens on the LCD either.

Replacing the controller with another one did the trick. So now I have a 20x4 i2c LCD-display for $6 :slight_smile: I also have a few 40x2 displays I will try later.