Another i2c assembly driver
Still working on code for a new board (Manta) and needed an assembly i2c driver...
Found some in OBEX, but I couldn't figure out how to adapt them for what I needed.
So, wrote a new one.
This one is pretty generic, but also has code for these specific chips:
LSM9DS0 - a nine degree of freedom mems with gyro, accelerometer and compass
TSC2003 - touchscreen chip used in my 4.3" and 3.5" LCD boards
PCA9554 - I/O expander
DS1339 - RTC clock
But, I think it can be fairly easily adapted to interface to other chips as well.
This demo of the driver is for an improved version of the PTP2 board for 3.5" touchscreen.
The old one was slow to start because used Spin to initialize the LCD over I2C.
Switching to assembly makes startup much faster.
Another nice feature is that the touchscreen math is now done in assembly.
This makes the touchscreen response much faster.
PTP2_Paint_Rev2 - Archive [Date 2015.05.15 Time 09.09].zip
Found some in OBEX, but I couldn't figure out how to adapt them for what I needed.
So, wrote a new one.
This one is pretty generic, but also has code for these specific chips:
LSM9DS0 - a nine degree of freedom mems with gyro, accelerometer and compass
TSC2003 - touchscreen chip used in my 4.3" and 3.5" LCD boards
PCA9554 - I/O expander
DS1339 - RTC clock
But, I think it can be fairly easily adapted to interface to other chips as well.
This demo of the driver is for an improved version of the PTP2 board for 3.5" touchscreen.
The old one was slow to start because used Spin to initialize the LCD over I2C.
Switching to assembly makes startup much faster.
Another nice feature is that the touchscreen math is now done in assembly.
This makes the touchscreen response much faster.
PTP2_Paint_Rev2 - Archive [Date 2015.05.15 Time 09.09].zip


Comments
My boards are like the Parallax ones, with just one pull up.
That's one of the problems I had trying other codes in OBEX.
The only Parallax boards I'm aware of without pull-ups on both lines are the Demo Board and the Propeller Professional Development Board. All the rest have pull-ups on both.
So, I guess I could do it Jon's way.
Still, if somebody is desperate for pins, they might think about using SCL after boot up.
Plus, this way is compatible with older boards with just the one pullup.
You're right, but -- technically -- I'm pretty sure that driving SCL violates the I2C spec. I'm very fastidious with my designs; every one of them has proper bypass caps and pull-ups on the I2C lines, even if some example circuits do not.
People appreciate that! I had to write my own a long time back because I could not use the ones that drove SCL and ignored the possibility of clock stretch. Many other uC based devices do it and it took me a long time to figure out a weird intermittent problem because of that.
Can multiple cogs use your driver by properly using locks?
This 9DOF chip puts out sample data at pretty high rates, you have to take care, if you don't want to miss any data, like in IMU usage
Here is an elementary shell for the MCP3428. It seems to work just fine, Saleae protocol decoder likes it.
{MCP3428 Demo} CON 'Belonging to main _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 Slv3428=%11010000 'slave address #0, ACK, NAK VAR byte D3428[34] 'data returned from 3428 Long cog 'data returned from starting i2c cog byte WriteSlvA[2] 'two bytes for writing: Slave address and Configuration Byte' byte ReadSlvA 'one byte for reading: slave address ORred with read bit OBJ pst : "parallax serial terminal" i2c : "jm_i2c_fast" PUB main pst.Start (115_200) 'start up ser terminal pst.str(String("hello, world ")) 'runs in cog 1 pst.NewLine waitcnt(clkfreq/10+cnt) cog := i2c.setup(400_000) pst.str(String("Value from i2c.setup: ")) pst.hex(cog,8) pst.NewLine waitcnt(clkfreq/10+cnt) cog := i2c.present(Slv3428) pst.str(String("Value from i2c.present ")) pst.hex(cog,8) pst.NewLine waitcnt(clkfreq/10+cnt) WriteSlvA[0] := Slv3428 'slave address WriteSlvA[1] := %0_00_1_00_00 'configuration byte template ReadSlvA := Slv3428 | 1 'set read bit repeat Read3428(1) 'read from channel 1 pst.str(string("Channel 1: ")) pst.bin(D3428[0],8) pst.char(" ") pst.bin(D3428[1],8) pst.char(" ") pst.bin(D3428[2],8) Read3428(3) 'and now channel 3 pst.str(string(" Channel 3: ")) pst.bin(D3428[0],8) pst.char(" ") pst.bin(D3428[1],8) pst.char(" ") pst.bin(D3428[2],8) pst.newline waitcnt(clkfreq+cnt) PUB Read3428(Channel) 'read specified channel (1..4) WriteSlvA[1] := %00010000 | ((Channel-1) << 5) 'insert channelnumber i2c.start i2c.pwrite(@WriteSlvA,2) 'set configuration register repeat i2c.start 'restart i2c.pwrite(@ReadSlvA,1) ' 'issue read command i2c.pread(@d3428, 3, NAK) 'dataHi, dataLo, Config i2c.stop until (D3428[2] & $80) == 0 're-read until conversion is complete return