SX I2C Slave ASM Routines -- Winter Project :-)
![Zoot](https://forums.parallax.com/uploads/userpics/559/nW4UO23UEIWZ4.png)
I've decided to take on a small side project over the winter -- incorporating some I2C slave code into a general purpose "helper" SX -- mostly to offload some repetitive sensor and control task work from a Stamp based 'bot. I know serial is easier, but I'm a big I2C user, and it'll be nice to have some ready-to-go I2C slave code for future SX projects. Also thinking about stuff like ready-to-go IR object detectors (just hook up 8 IR/led pairs and send/read status via I2C), or manage a few motors/servos and Pings, or stuff like Jon Williams PS2 controller helper (but with I2C), etc.
I'm going to take existing I2C slave ASM code into SX/B (not actual code lines, but formatting, etc) so I can author my main program work there.
I've searched around the forums and read up a bit, but not too many folks seem to have actually posted final code from projects that use the SX an I2C slave. In any case, the attached VP is from sxlist.com, and it seems clear enough (at this point anyway). But I wondered if anyone has other (better?) examples of slave VPs and/or any comments about this VP. Has anybody used this skeleton? Comments? Tips? Traps? Working code I so don't repeat work already done?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
I'm going to take existing I2C slave ASM code into SX/B (not actual code lines, but formatting, etc) so I can author my main program work there.
I've searched around the forums and read up a bit, but not too many folks seem to have actually posted final code from projects that use the SX an I2C slave. In any case, the attached VP is from sxlist.com, and it seems clear enough (at this point anyway). But I wondered if anyone has other (better?) examples of slave VPs and/or any comments about this VP. Has anybody used this skeleton? Comments? Tips? Traps? Working code I so don't repeat work already done?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
zip
![](/plugins/FileUpload/images/file.png)
11K
Comments
Since Phillips release their licensing hold on I2C back in October of 2006, I'm surprised that I haven't seen more I2C slave implementations... I had started something actually before October 2006 based on what I knew from the I2C master side of things, but never completed it. If you are writing your own slave though, why limit yourself to 8 devices?
Here are some useful links that might help.
http://www.esacademy.com/faq/i2c/
[url=http://www.nxp.com/#/pip/pip=[pfp=41735]|pp=[v=d,t=pfp,i=41735,fi=,ps=0]]]http://www.nxp.com/#/pip/pip=[noparse]pp=[noparse][[/noparse]v=d,t=pfp,i=41735,fi=,ps=0[/url]
This is a MUST get:
http://www.nxp.com/acrobat_download/usermanuals/UM10204_3.pdf
·
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 12/13/2007 6:06:27 AM GMT
It uses an adapted version of the Ubicom I2C VP code.
The·I2C code is located in codepage 1 (and·some code in codepage 0).
I adapted the I2C code by adding two states:
·; State: i2cs_request_for_data
·;·This state tells the mainline code to supply data in the i2cs_byte register.
·;
i2cs_request_for_data
··setb·i2cs_data_needed·;1 mainline code must fill i2cs_byte and clear i2cs_data_needed
··inc·i2cs_state
··retp····;3 = 13 + 7 = 20
·; State: i2cs_waiting_for_data
·;·This state waits for the mainline routine to put some valid data in the
·;·i2cs_byte register.· This state is only reached if the master has
·;·indicated it wants more data by sending an ACK after the last byte.
·;
i2cs_waiting_for_data
··snb·i2cs_data_needed·;1 wait till mainline code has cleared i2cs_data_needed
··retp····;3 = 13 + 7 = 20
··inc·i2cs_state
··retp
These states ensure that the slave keeps the SCL line low if the master has
indicated it wants to read another byte and that byte is not readily available.
and I added an I2C broadcast command.
regards peter
Beau -- by eight, I meant, for example, eight IR led/detector pairs on one slave -- 8 detectors on one port of an SX28, 8 leds on the other port. The host would only need to send one byte (which IR LED(s) to enable) and read one byte (detector status).
I also want to do a combo of 8 pin LED PWM driver on one port, 4 servos and 2 IR/LED pairs on the other port (for a turbo Boe-bot with light display).
That said, in the interest of simplicity and getting something working, my first test project will probably be something like a simple 8 pin PWM and 8 pin digital I/O slave -- send 8 bytes via I2C and get those 8 PWM values on the pins of one port, and write/read boolean values from the 8 pins of the other port (2 bytes write/read -- 1 byte for pin dir, 1 byte for pin state). Would be a kind of combo PWMPal and general purpose I/O expander.
Since I'm kind of thinking out loud here, what do you all think about addressing and reset scenarios? For example, I have a PIC based I2C I/O expander (from another company) that lets you change the I2C slave address by sending a special command (via I2C). This works because you can write EE data on the PIC (which I can't do on the SX).
I would like to be able to burn these slaves and not have to re-burn code just to change the slave address. So that leaves me (on an SX28) with something like:
MCLR -- (optional) host reset of slave
RA.0, RA.1 -- jumpers for changing address (but only allows 4 possible addresses)
RA.2, RA.3 -- SCL, SDA
RB - I/O port
RC - I/O port
Actually, I read a datasheet for one manufacturers chip where I2C addressing with only 2 pins and jumpers was expanded by letting an address pin be pulled high, pulled low or be allowed to float, which expands the addresses to 6 with two pins. But not sure how that little trick would be handled?
Lastly, I need to more closely examine the cycle counts and times in the I2C slave routines, but I'm presuming at this point 50mhz is required? I had been hoping I could run some slaves at slower speeds, esp. given the (relatively) slow speed of I2C on the Stamps.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
and always all active, you can use dynamic address allocation. That's
what I did. It requires only 2 additional lines.
A0=SDA, A1=SCL, A2=TOKENBUSIN, A3=TOKENBUSOUT
It requires a dedicated master that supplies the first address to the first slave.
This slave increments the address and sends it to the next slave, and so on.
The last slave then sends it back to the master (although it doesn't know),
an so the master knows how many slaves there are.
Look here for sources and docs:
http://tech.groups.yahoo.com/group/synop/files/synop%20sources/
http://tech.groups.yahoo.com/group/synop/files/synop%20documentation/
regards peter
Post Edited (Peter Verkaik) : 12/13/2007 5:43:14 PM GMT
Peter -- I had thought about dynamic addressing, then you posted your code. I may try that out, but I don't think with your really super clever tokenbus -- I don't want to have to use even a single extra pin on the host.
The host controlled reset would be optional, depending on need and pin availability on the host side.
I'm going to try to develop a general purpose program template so I can burn "helper" SXes for other projects. For example, my Boe-bot is way pin strapped. Even when I add the I2C bus for external EEPROM and such, I'll be sharing SCL with a SPI clock line.
If I use dynamic addressing, I may just let the host send a special series of I2C bytes to the command register to "dynamically" change the address. In other examples, I've seen where you have to send the address change 3x in a row successfully for the change to be applied. If you were using an SX helper on a Stamp, you could have the Stamp send a new dynamic address at startup, then send subsequent operations using the new address.
Maybe a combination would be OK -- (optionally) change a base address dynamically, then set x+0...x+6 addresses within that dynamic address using jumpers. So the SX might do something like:
default address - $90 (no jumpers, no dynamic change)
-> change with jumpers - $90+0,$90+2,$90+4,$90+6
change default address dynamically via I2C command --$90, $98
-> change with jumpers e.g. $98,$9A,$9C,$9E
Actually, this begs the question of choosing a default address. $A0x is used on a lot of EE devices. $B0x, $C0x, $D0x are used on a lot of popular I2C based robotics devices made by another company (sorry, Parallax, for I2C based peripherals I need to go elsewhere :-(). It looks like you used $18 as the start address on your tokenbus project? Any particular reason?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
are not used by popular i2c devices.
Another way to use dynamic addressing, without using a tokenbus, is to make use
of a broadcast address that all slaves listen to. Via this broadcast address all
slaves receive a private I2C address. All non-assigned slaves then pull SCL low for a random time.
The slave that holds SCL low for the longest time, then accepts the private address
and does not pull SCL low on the next broadcast.
regards peter
Peter, did you think that up? Ingenious. But there's something I don't get -- how does the master know *which* device has accepted the most recently assigned address?
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
that the master reads using the individual i2c addresses, after all slaves are assigned.
That serialnumber could be just one byte.
regards peter