SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
User avatar
By roach
#11667
I'm looking into using the TWI (I2C) interface on an ATmega16. Nothing I read in the documentation explains how I'm supposed to "know" the address of the TWI slave devices. As far as I can tell, I need the device address in order to send and receive data. IT looks like, if I'm the developer, I can set the device address in code, but how do I know the addresses of external devices (such as an I2C EEPROM)?
By dext3r
#11669
usually you set it by grounding or pulling up certain address pins on the chip.

for example, look at the datasheet for, lets say a DS1624 temp sensor...

theres A0,A1,A2, and you use those to set the chips address.
User avatar
By roach
#11678
Interesting...

So that answers chapter one of my novella of questions.

Apparantly, there is also a "general call" address of 0000 000, that can be used to write data to all slaves. I'm wondering if I can't send an "Identify Yourself" command to all slaves on the bus, and have them respond somehow. I don't know how I would do this, since sending "general call" address followed by a "read" bit would have all slaves responding at the same time.

Basically, what I'm trying to avoid is having multiple instances of the same device (for example, an OpenServo) on the bus as TWI slaves, and have to code seperate firmware for each one, because the slave address is hard-coded.

I've read about, but still don't understand, the concept of a "multi-master" bus. Is this something I could use to send the abovementioned "identify yourself" command, on the "general call" address, and have each master respond with their own WR command? Slaves, then, would either ignore the command or, in the case of slaves that I haven't personally coded to understand this protocol, behave in unpredictable or undesireable ways (ie: corrupting memory, in the case of an external EEPROM, say).

In short, I2C/TWI sounds great, but I can't wrap my head around addressing slave devices without "knowing" their addresses...

As well, I'm more and more getting the feeling that TWI is not intended as a communications bus, but more of a Read/Write bus (like, for accessing memory, or other devices where this makes sense). I know I could conceivably use it as a communications bus between devices, but is this a mis-use of the architecture?
By SOI_Sentinel
#11680
Roach: looks like you hit the issue right on the head (I noticed your reply in the topic review window). TWI is meant to provide some commands to low priority devices. If you don't mind not having "plug and play" your best bet would be (for TWI slave MCUs) to set up a base I2C address and then plug them into your master one at a time and issue an address reassignment command to them. It wouldn't take too long and you'd not have to code separate firmware for each unit. It's not a bad idea anyway since each manufacturer of hardware may use a different TWI address sets and you might find your MCU's conflicting with other parts in the future.
By Kuroi Kenjin
#11682
Basically, what I'm trying to avoid is having multiple instances of the same device (for example, an OpenServo) on the bus as TWI slaves, and have to code seperate firmware for each one, because the slave address is hard-coded.
Firmware wise, you can still just have one set, but leave room to plug in addresses. For example on a I2C temperature device you could have a read temperature command be:
Code: Select all
unsigned long read_temp(unsigned int i2cAddress);
Then when you discover the addresses, in some manner, you could then store them who and what is present at each address. You could poll for a fixed number of devices, or use an extra line for an "I'm here" signal (no not very practical).
User avatar
By roach
#11688
SOI_Sentinel wrote:your best bet would be (for TWI slave MCUs) to set up a base I2C address and then plug them into your master one at a time and issue an address reassignment command to them.
Brilliant. This is probably what I'll end up doing, for slaves that I have control over (such as uCs). For other devices, like EEPROMS and such, I guess I would already know the address, based on dext3r's comment above. Slave uCs could then store the new address in on-chip EEPROM, and use that value (when available) on reset.

The only drawback would be the necessity of plugging in slaves one at a time, and having the master periodically "poll" for new slaves, then issue the "re-address" command.

Maybe it's time for a little background. I'm looking at developing an open "botstack"-type architecture for robotics. One I2C slave would be a motor controller board, another might be a Sensor I/O board, or a CF/SD board, etc, while the I2C master would be a "brain" board, coordinating and controlling the slave boards. Using SOI_Sentinel's idea, I could set base addresses based on the board type, then the master could poll each registered base address to see if a new device has been added to the bus, and reassign a new I2C address based on the device type (maintaining, of course, an internal record of slave addresses to avoid address collision).

This is, in some respects, a port and complexification of the protocol used by Pololu's serial motor controllers, which communicate over USART. Is I2C overkill? Maybe I can do this whole comms bus thing over ttl serial?

Is there some central "ICANN" of I2C address spaces? While developing, I want to make sure I won't conflict with existing devices in my selection of base addresses.

**caveat: I'm just getting started in microcontroller programming, so if I've said something really stupid, feel free to point it out :D
By Kuroi Kenjin
#11692
Ah the info for what base address goes with what device? The only info I could find on that is purchasing and registering products with Philips (I think that's who "owns" the I2C standards).... but I couldn't find much info on the device classes.

If you're using PIC to PIC (or board to board) communication, you probably would just want to roll your own.

Using I2C for a botstack doesn't seem overkill at all. I think it's perfect. In fact, I've already been planning out to use I2C for a modular bench supply (non isolated DC/DC converter cards with a common front end, my website has more on the current train of thought for the ramping up to a full design spec). My solution is in the card connectors, so I have a hardwired address per module and polling on power up for enumeration.
By SOI_Sentinel
#11696
Glad you like it roach. It should work well, just set up the system to poll the bus about once a second per address range and you should have no problems.

Your original "plug them together and let them sort themselves out" method would have needed something as complex as CAN. I'm working on a stack for that on and off(I need the higher bandwidth, cable length, and noise immunity). CAN is message based, so it's up to the clients on the bus to determine if the message applies to them or not. And there's no master-slave relationship in the base technology, although that can be implemented in higher orders. Plus it has on the fly arbitration for bus collisions, so no worries about too many talking at once :) The downfall is that to implement this system it takes a lot more planning, especially if you want to have it expandable in the future. And more hardware.

Interesting design Kuroi. That should work quite well for you, as you also have a few extra IO and more space than Roach :)
User avatar
By roach
#11700
So here's another stupid question: What is the difference between an I2C Master, and a slave? Is a slave not allowed to set a START/STOP condition? I'm still a little fuzzy on the details...
By SOI_Sentinel
#11702
The slave can't send a start/stop condition. The master generates the clock. Other than replying with data, the two conditions that the slave can do (that I remember) is "stretch" the clock line (needs more time IIRC) and send an acknowledgement. Normal 7 bit address operation is master sends a 7 bit address plus the read/write bit. The slave acks. If read is sent, the next byte from the master is the register address. Slave acks. Slave then sends the data back. Write goes the same way, except the master transmits the data at the third byte. The stop condition is sent. There might be another start condition in there somewhere (I'm working off memory here). Some devices allow multi-byte sends and recieves, such as 16 bit register data.
User avatar
By roach
#11704
Does clock-stretching happen in hardware on AVRs?
User avatar
By roach
#11730
Since the TWI address range is only 0x07 to 0x70 (excluding reserved addresses, enumerated here, It probably wouldn't take too long for a master to "poll" the entire address range, basically sending a START, SLA+R, STOP for each address, and check the ACK bit on the address byte to see if there's a device responding at that address.

After reading the data sheet a couple of times over, there are still some unanswered questions in my mind...

It seems like the only difference between a Master and a Slave on the bus, is that a master cannot be directly addressed. Seems like whatever device initiates a START condition automatically becomes a master (in a multi-master system). Nothing prevents a slave from initiating a START condition. Is this correct?

If so, the only problem here is that, in order for built-in arbitration to occur, all transmissions must contain the same number of data packets, which kind of sucks.

The datasheet makes several references to something called "Wired-ANDing" of the SCL line. Does this mean putting a transistor on the SCL line to ensure the clock signals match up (ie: smallest HI period, longest LOW period)? The datasheet doesn't make clear whether this is done internally to the AVR, or if I need to do this myself.

Some vocab: What is a "slew-rate limiter"?

The datasheet says that internal pullups on the TWI pins can be enabled by setting the right DDR and PORT values for those pins, and that "in some systems", this can remove the need for external pullups on the TWI lines. It's that "in some systems" that worries me. What is the value of these internal pullups? Come to that, what values do I need for pullups on these lines? I can't find the current draw requirements for TWI anywhere (maybe I'm asking the wrong question here...).

Although this is not explicitly stated in the datasheet, it looks like, when the last data byte is sent from a slave to a master (during a SLA read operation), the slave will signal this is the last byte by following up with a NACK. Is this part of the protocol?
By transcendentnb2
#11881
Hey Roach, I actually just started messing around with the TWI on the (get this) ATMega16 too. I just have one lonly EEPROM that I can read/write to, but it's enough to get an idea of what's going on.

Anyway, I setup a polling loop in my code and it has a very very short response time (addresses from 0x00 to 0x7F). It does pretty much what you say, but you can get away with not sending a STOP all the time since you're doing multiple starts.
It seems like the only difference between a Master and a Slave on the bus, is that a master cannot be directly addressed. Seems like whatever device initiates a START condition automatically becomes a master (in a multi-master system). Nothing prevents a slave from initiating a START condition. Is this correct?
From my understanding, you are correct, but in multi-master systems the other masters switch to slave mode so they *can* be addressed by the current master. I'm assuming it's in the I2C standard written by Philips that slaves must not send start conditions (nothing *prevents* them, but it's just assumed everyone is playing nice). I haven't read much into multiple Master systems, though.

I didn't worry about the Wired-ANDing and everything works fine for me, but I'm not doing mult-master busses.

About the pull-up resistors, you should probably just use your own. The internal I/O pull up resistors are between 20k and 50k. You'd only want to use that high of a resistor value on very slow clocks (maybe 10KHz or less). Any higher than 100KHz and you'll probably want 5k to 2k. I'm running my bus at 400KHz and using 2.2K external pull-up resistors. The resistor value has to do with the required slew rate. Too high of a resistor for high frequencies could cause the slew rate to be too low.

The slew rate is the rate of change in the output between voltage levels. Sometimes slew rate limiters are places in order to conform to certian signal specifications (so it won't change too fast).
Although this is not explicitly stated in the datasheet, it looks like, when the last data byte is sent from a slave to a master (during a SLA read operation), the slave will signal this is the last byte by following up with a NACK. Is this part of the protocol?
All depends on the device. The EEPROM that I'm dealing with doesn't send any ACK/NACK after sending a data packet. It simply waits for the master to send an ACK and it'll output the next byte.

Here's the actual specification, BTW. Haven't read through it yet though: http://www.semiconductors.philips.com/a ... 340011.pdf
User avatar
By roach
#11891
Thanks for the response, tran! I'm bookmarking this thread fer sure!