mcp23017 (i2c) example code?
Does anyone have some mcp23017 code I can look at? It's getting late and the datasheet is becoming blurry.
Maybe tomorrow I'll wake up and find that some kind soul has posted some code to get me started.
Being inexperienced in the ways of i2c, I just need to be pointed in the right direction.
Maybe tomorrow I'll wake up and find that some kind soul has posted some code to get me started.
Being inexperienced in the ways of i2c, I just need to be pointed in the right direction.
Comments
A search in the Obex search for MCP23017 comes up blank, as does a number of other searches for chips like this (including the SPI variants).
Spin or Pasm or both would be fine. Searches on Google come up with Duane Johnson's Femtobasic driver but Spin/Pasm would be better!
mpark - did you end up getting some code working?
I'm not looking to use every feature on these chips - in fact all I really want to do is either output some bytes, or input some bytes. I'm intrigued by this chip as it can share the I2C bus which is already used by the eeprom, and hence effectively it can give you more I/O pins on the propeller without actually using any more propeller pins. Cunning!
Any help would be most appreciated.
Simple answer - use Jonny Mac's code which works perfectly. Is this one maybe for the Obex?
Addit - a little demo using two MCP23017 chips. These are $1.20 each at Futurlec, so for $2.40 you can have another 32 I/O pins for the propeller chip.
PUB MCP23017_Out_Long(n) ' send out a long to two MCP23017 chips ' chips share the I2c bus with the eeprom. Pin 18 reset high, pin 19 and 20 = NC, A0-1-2 on first chip all low ' and on second chip A0 is high. The chips can be run from 3 or 5V (useful for level translation) ' gives a propeller another 32 input and output pins. Futurlec sell these chips for $1.20. DIP28 narrow package. ' if using sockets and can't source 28 pin sockets, use two 14 pin ones. ' use johnny macs code, the io codes are different for the 23016 and 23017 mcp23017.start(i2cSCL,i2cSDA,%000) ' clock, data, address of chip (2 chips, either 000 or 001) mcp23017.cfg_dira(%00000000) ' 0 = output, 1=input mcp23017.wr_gpioa(n & %11111111) ' output low byte mcp23017.cfg_dirb(%00000000) ' 0 = output, 1=input mcp23017.wr_gpiob(n >> 8) ' second lowest byte mcp23017.stop ' stop this chip mcp23017.start(i2cSCL,i2cSDA,%001) ' clock, data, address of second chip mcp23017.cfg_dira(%00000000) ' 0 = output, 1=input mcp23017.wr_gpioa(n >> 16) ' output second high byte mcp23017.cfg_dirb(%00000000) ' 0 = output, 1=input mcp23017.wr_gpiob(n >> 24) ' output high byte mcp23017.stop
the object itself:
pub cfg_iocon(outbits) '' Write value to IOCON i2c.start i2c.write(slaveid) i2c.write(IOCON) i2c.write(outbits) i2c.stop pub cfg_gpinta(outbits) '' Write value to GPINTENA i2c.start i2c.write(slaveid) i2c.write(GPINTENA) i2c.write(outbits) i2c.stop pub cfg_gpintb(outbits) '' Write value to GPINTENB i2c.start i2c.write(slaveid) i2c.write(GPINTENB) i2c.write(outbits) i2c.stop
Here is my test code to run it with int on change.
''This code block uses a modified version of Jon "JonnyMac" McPhalen's MCP23017 object -added cfg_iocon, cfg_gpinta and cfg_gpintb OBJ mcp1 : "jm_mcp23017_2" mcp2 : "jm_mcp23017_2" CON _clkmode = xtal1 + pll16x ' Feedback and PLL multiplier _xinfreq = 5_000_000 ' External oscillator = 5 MHz VAR long temp PUB Main ' Main method dira[2]:=0 'set address port to input dira[3]:=1 'set address port to output ' Setup Chip 1 mcp1.start(0,1,0) ' scl=0, sda=1, address=0 mcp1.cfg_iocon(%0100_0100) ' turn on open drain ints, and mirroring mcp1.cfg_gpintb(%1111_1111) ' turn on int on change for pina 0-7 on portb mcp1.cfg_dira(0) ' group a configure for outputs mcp1.cfg_pola(0) ' group a normal polarity mcp1.cfg_pua(1) ' group a pullup enabled mcp1.cfg_dirb(1) ' group b configure for inputs mcp1.cfg_polb(1) ' group b normal polarity 0=normal, 1=inverted mcp1.cfg_pub(1) ' group b pullup enabled ' Setup Chip 2 mcp2.start(0,1,1) ' scl=0, sda=1, address=0 mcp2.cfg_iocon(%0100_0100) ' turn on open drain ints, and mirroring mcp2.cfg_gpintb(%1111_1111) ' turn on int on change for pina 0-7 on portb mcp2.cfg_dira(0) ' group a configure for outputs mcp2.cfg_pola(0) ' group a normal polarity mcp2.cfg_pua(1) ' group a pullup enabled mcp2.cfg_dirb(1) ' group b configure for inputs mcp2.cfg_polb(1) ' group b normal polarity 0=normal, 1=inverted mcp2.cfg_pub(1) ' group b pullup enabled repeat ' Endless loop temp:=ina[2] if temp==0 mcp1.wr_gpioa(mcp1.rd_gpiob) ' read input and send to output mcp2.wr_gpioa(mcp2.rd_gpiob) ' read input and send to output outa[3]:=1 waitcnt(clkfreq / 10 + cnt) else outa[3]:=0
The test code used a circuit with two MCP23017's on a PPDB. Each MCP23017 had port B set up as in input with port A set up as an output. I used a pushbutton switch on the board for the input, and a LED on the board for the output. I used the interrupt pin bussed off of both MCP23017's to trigger the reads and writes to the chips. This keeps from having to poll continuously and tie up the I2C port with messages. Finally, I just had an LED to turn on with the interrupt so that I could see that. This circuit is not really practical (although it may be), but I wanted to use all the features of the chips. It also may be handy to have each chip capable of 8 inputs and 8 outputs, versus having to have one chip as an input and one as an output.
Again, thanks for the object, this was a great help. Hopefully this code may help someone else use them as well.
{MCP23017 16bit general purpose I/O expander ┌──────┬┬─────┐ GPB0─[│1 28│]─GPA7 GPB1─[│2 27│]─GPA6 GPB2─[│3 26│]─GPA5 GPB3─[│4 M 25│]─GPA4 GPB4─[│5 C 24│]─GPA3 GPB5─[│6 P 23│]─GPA2 GPB6─[│7 2 22│]─GPA1 GPB7─[│8 3 21│]─GPA0 VDD──[│9 0 20│]──INTA VSS──[│10 1 19│]──INTB NC───[│11 7 18│]──RESET (active low) SCL──[│12 17│]──A2  SDA─[│13 16│]──A1 ─(I2C address pins) NC───[│14 15│]──A0  └─────────────┘ } CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 SCL = 0 ' Connect to propeller pin 0 SDA = 1 ' Connect to propeller pin 1 ' A2 A1 A0<<<(I2C address pins)must be Biased to VSS="0" or VDD="1" ' └┐│┌┘ MCP_ID = 00_0011 ' I2C address for MCP23017 VAR byte Abits byte Ainbits byte Bbits byte Binbits OBJ GPIO : "jm_mcp23017" PUB Init | counter, count GPIO.start(SCL,SDA,MCP_ID) waitcnt(clkfreq / 2 + cnt) 'All_Output HalfIn_HalfOut PUB All_Output GPIO.cfg_dira(00_0000) ' Configure all eight pins of PortA to output. GPIO.cfg_dirb(00_0000) ' Configure all eight pins of PortB to output. Abits := 01_0101 ' Set PortA bit pattern Bbits := 01_0101 ' Set PortB bit pattern repeat GPIO.wr_gpioa(Abits) ' Write eight bits to PortA GPIO.wr_gpiob(Bbits) ' Write eight bits to PortB waitcnt(clkfreq / 2 + cnt) GPIO.wr_gpioa(!Abits) ' Flip bits with Not(!) GPIO.wr_gpiob(!Bbits) waitcnt(clkfreq / 2 + cnt) PUB HalfIn_HalfOut GPIO.cfg_dira(11_1111) ' Configure all eight pins of PortA to inputs. GPIO.cfg_dirb(00_0000) ' Configure all eight pins of PortB to output. GPIO.cfg_pola(11_1111) ' Invert Polarity of all eight pins of PortA ' ( for Pull_up resistors on PPDB push buttons.) repeat Ainbits := GPIO.rd_gpioa ' Read the eight bits from PortA into the Ainbits variable GPIO.wr_gpiob(Ainbits) ' Write the eight bit Ainbits variable to PortB waitcnt(clkfreq / 16 + cnt)
EDIT: it's amazing what the forum software can do to code...don't cut and paste the above, unless you add the percent signs and missing zeros.. sigh...I like the MCP23017, seems like it will be handy for reading switches and such.
Purchased from the 'OldBitCollector'( http://www.propellerpowered.us/) himself.
They are large, and do take some real estate investment...
Thanks for sharing your code fixmax,
MCP23017_Demo_MyWay - Archive [Date 2013.07.26 Time 09.34].zip
-Tommy