OK Im not getting a lot of input from forum users, so I guess well just post all advances that I make along the way here. This is more for my benefit really, than anyone else. But, someone may see something that they can pop in with and make a contribution.
From my last post, to Peter J, I mention that I was struggling with the start\bit routine. I was [size=+1]over[/size] thinking the issue since I already know a device that adheres to the I2C standard for a slave will operate on front/rear I can ignore what the rear bus is doing and concentrate on just standard behavior for the start\bit routine.
With one exception, the front side of the bus has top priority.
So, the next issue is how do I detect a collision? For now, Im using this arrangement during the testing:
┌────────┐
│ │ 330
│ P ├────┐
│ R ├──────┻────────> SCK
│ O ├──────┳────────> SDA
│ P ├────┘
│ │ 330
└────────┘
So, has anyone built a multi master routine? I checked out OBEX and saw Mike Green made a spin version (very nice), and someone else made a assembly version out of it. But, the start\bit routine does not check to see if another master is using the bus at the moment So I will be flying solo on this one.
I have a multi-master object in this archive, only tested using multiple cogs on the same Prop but it performed flawlessly, however I wouldn't expect it work with scl and sda reversed, not without modification. Are you intending to have two i2c master objects running simultaneously in two different cogs, one for normal and one for reverse? If that's the case then it seems a bit of a waste, since only the forward or the reverse bus is going to be operating at any given time. My Spin-based driver shows how both forward and reversed may be accomplished in a single cog. You could even use a standard driver, start it with the normal pins for the front bus, then stop and restart it with the reverse pins for the back bus.
btw, I have discovered an actual application for this idea. The CY8C9520A is a very nifty IO expander, but it has a bit of a drawback in that it stretches the clock following every device byte, so it interferes with the Prop bootloader which drives the clock and data lines high and low. I modified my reversed-pins Spin driver further to make it open-drain compatible, and got it working on same pins as the eeprom. The CY8C9520 is the only clock-stretching slave I have experience with, but there's no reason this shouldn't work with all of 'em.
Chris
Thanks for the explanation of the state machine, but I'm afraid I'm still not getting it, and you're more than welcome to use the graphic.
btw, I have discovered an actual application for this idea. The CY8C9520A is a very nifty IO expander, but it has a bit of a drawback in that it stretches the clock following every device byte, so it interferes with the Prop bootloader which drives the clock and data lines high and low. I modified my reversed-pins Spin driver further to make it open-drain compatible, and got it working on same pins as the eeprom. The CY8C9520 is the only clock-stretching slave I have experience with, but there's no reason this shouldn't work with all of 'em.
CY8C9520 looks interesting, seems MCU based, with highish Icc.
Do you find it stretch the clock after every byte ? By how much ?
I think you are saying it does this stretch, even when not addressed itself ?
Data only says master needs support stretch, and says this re "EEPROM" [" When a 64-byte boundary is crossed in the EEPROM, the I2C clock is stretched while the device performs
an EEPROM write sequence.
If the end of available EEPROM space is reached, then further writes are responded to with a NAK."]
.... But, the start\bit routine does not check to see if another master is using the bus at the moment … So I will be flying solo on this one.
Polling always has aperture issues, so you cannot be 100% certain you catch 'other master' use.
Normally, Multimaster arbitration follows every bit, and releases when it finds PinLevel <> Expected level
Polling always has aperture issues, so you cannot be 100% certain you catch 'other master' use.
Normally, Multimaster arbitration follows every bit, and releases when it finds PinLevel <> Expected level
Yeah ... I saw that with the CAN standard ... simply lovely how the lower id number wins out over the high number device ... absolute genius ... but, I don't think I need to resort to any 'funny' techniques? Should be able to stay within I2C standard and still operate ... was just trying to 'visualize' my approach for detecting activity by another master on the bus ... haven't been able to see any other code by the 'heavy weights' on this forum regarding 'multi-master' start\bit routine.
My logic tells me that "just before 'start\bit' occurs, I should have a counter on the data_pin, detecting 'negative' edges. Any count in PHSA/B would clear PHSA/B wait (maybe 511 bit paces) and try up to two more times before 'strike three' is reached? Otherwise, seize bus as normal.
So, the 3 ways you enter this routine are:
1) The bus is 'free/idle' and not seized by this master ... both data and clock are '1' and PHSA/B is zero.
2) This master already has the bus seized (shown by DIRA) and data and clock are low.
3) The bus is in use by another master.
CY8C9520 looks interesting, seems MCU based, with highish Icc.
Do you find it stretch the clock after every byte ? By how much ?
I think you are saying it does this stretch, even when not addressed itself ?
Data only says master needs support stretch, and says this re "EEPROM" [" When a 64-byte boundary is crossed in the EEPROM, the I2C clock is stretched while the device performs
an EEPROM write sequence.
If the end of available EEPROM space is reached, then further writes are responded to with a NAK."]
Yep, it stretches after every single device ID byte, between the r/w bit and the ack bit, in order to determine who is being addressed. If it is being addressed, it continues to stretch the clocks following the register address bytes and data bytes, for both the EEPROM and the IO functions. It does not stretch clocks after it determines that some other device is being addressed.
The stretch duration varies depending on how many bytes it receives (more bytes, the longer the duration) but seems to be between 400us and 800us.
Yeah ... I saw that with the CAN standard ... simply lovely how the lower id number wins out over the high number device ... absolute genius ...
My logic tells me that "just before 'start\bit' occurs, I should have a counter on the data_pin, detecting 'negative' edges.
That reduces the aperture, but does not eliminate it entirely.
'negative' edge detect will have a few SysClks of aperture, more careful edge timing can check to 1 sysclk, but that still leaves the case where two masters fluke identical-cycle access. Both get expected-edge-time success.
In that case, the bit-by-bit check is needed to resolve & also covers masters in different Props.
idea : If you are ok this only works on same-prop masters, then maybe doing a hub access right before the Start, and using gated-timer timing, can ensure the phase-lock cannot occur,
The Hub access I think will adjust the phase of following opcodes, and they cannot then both drive the pin on same sysclk edge.
Yep, it stretches after every single device ID byte, between the r/w bit and the ack bit, in order to determine who is being addressed....
The stretch duration varies depending on how many bytes it receives (more bytes, the longer the duration) but seems to be between 400us and 800us.
Nice i2c monitor, what is that ?
Sounds like they use a (slow) MCU with software address matching & the stretch in all ID cases is going to surprise many.
Makes it look like a wait-for-scl high, is a good addition to any i2c library.
Nice i2c monitor, what is that ?
Sounds like they use a (slow) MCU with software address matching & the stretch in all ID cases is going to surprise many.
Makes it look like a wait-for-scl high, is a good addition to any i2c library.
Yeah, it is a very slow controller in that IO expander; playing with it some more I got just under 2ms of stretching in some instances. Even if it weren't interfering with the Prop bootloader, I wouldn't want something like that on a bus I was using with other devices.
Clock-stretching slaves don't really seem to be that common, and the check for scl high does slow the drivers a bit. My Spin-based push-pull (non-clock-stretch-checking) I2C driver is capable of ~28Kbps, the open-drain Spin driver which does check runs at about 20Kbps. My push-pull PASM driver is capable of 1Mbps, the open-drain version with checks is limited to ~425Kbps.
Checking will always take time, but that seems like quite a hit on the PASM case ?
Is that doing more than just waiting on SCL high ?
I'm perhaps being overcautious with the checks, or perhaps not. While my IO expander stretches the clock before the ack pulse, I know there are other devices that stretch after the ack, so two checks are necessary to ensure compatibility with all devices. And the check_stretch routine is a bit more complex due to the desire to maintain the bitrate if no stretching occurs, and to guarantee that a waitcnt won't be missed if stretching does occur.
check_stretch
test SCL_mask,ina wc ' Check for stretching
if_c jmp check_stretch_ret ' return if no stretching
mov t1,delay_target ' Loop for 1 pulse width for clock to return high
sub t1,cnt
cmps t1,#0 wc
if_nc jmp #check_stretch
waitpeq SCL_mask,SCL_mask ' Wait however long it takes for clock to return high
mov delay_target,bit_delay ' Re-establish the bitrate
add delay_target,cnt
check_stretch_ret ret
Previous versions were using this, but I abandoned it after realizing the discrepancy between the desired and actual bitrates; a setting of 400Kbps was actually sending at ~355Kbps.
waitpeq SCL_mask,SCL_mask ' test for clock-stretching
mov cnt,I2C_bit_delay ' re-establish bitrate
add cnt,cnt
waitcnt cnt,I2C_bit_delay
Previous versions were using this, but I abandoned it after realizing the discrepancy between the desired and actual bitrates; a setting of 400Kbps was actually sending at ~355Kbps.
waitpeq SCL_mask,SCL_mask ' test for clock-stretching
mov cnt,I2C_bit_delay ' re-establish bitrate
add cnt,cnt
waitcnt cnt,I2C_bit_delay
It makes sense that bit_Delay would need a tweak, as waitpeq adds to that., (and there will also be some rise time effects on large pullup values), but that should not impact (corrected) baud speeds, until you run out of wait time...
Clock-stretching slaves don't really seem to be that common, and the check for scl high does slow the drivers a bit.
I'm curious about something. What if during the time we transmit the device number (open drain), we slowed the clock rate down. Then, after receiving the acknowledge from the device, we switch to push pull in full speed? At present, you're the logical one to test this, since you have the uncommon chip.
Any thoughts? By the way, does that chip stretch the clock bit for every device number broadcast over the bus?
It makes sense that bit_Delay would need a tweak, as waitpeq adds to that., (and there will also be some rise time effects on large pullup values), but that should not impact (corrected) baud speeds, until you run out of wait time...
You're right, of course, simply checking the clock line shouldn't have resulted in that much of a difference. I realized that I was checking on the wrong side of a waitcnt in one place, fixing that boosted to max speed considerably. In examining that, I found a potentially fatal flaw where the clock might float high just before the bit delay expired and still miss the waitcnt. Here's my re-worked logic:
andn dira,SCL_mask
'check_stretch
waitcnt delay_target,bit_delay ' allow 1/4 bit width for clock to go high - an unstretched clock always manages to float high within this time, even with 10K pullups
test SCL_mask,ina wc
if_c jmp #:lower
waitpeq SCL_mask,SCL_mask ' wait for clock to go high
mov delay_target,bit_delay ' re-establish bitrate
add delay_target,cnt
:lower
waitcnt delay_target,bit_delay
It's also written in-line, eliminating the time wasted on calls and rets. The same idea is used with the read bit routines which require a couple instructions before the final waitcnt, which limits the max speed to just over 900Kbps.
I'm curious about something. What if during the time we transmit the device number (open drain), we slowed the clock rate down. Then, after receiving the acknowledge from the device, we switch to push pull in full speed? At present, you're the logical one to test this, since you have the uncommon chip.
The bitrate doesn't seem to have much, if any, affect on the duration of the clock stretching. The 20Kbps Spin driver and PASM driver running at 100Kbps (max speed for this device) both stretched the clock between 300us and 750us.
By the way, does that chip stretch the clock bit for every device number broadcast over the bus?
Yes, it stretches the clock for every device byte. If the CY8C is being addressed, it continues stretching the clocks for every byte it receives. If some other device is being addressed, say an EEPROM, the register and data bytes following the device ID are ignored by the CY8C, but the device ID always gets stretched.
This is the only clock-stretching slave I have experience with, though I know some other devices stretch the clock after the ack bit and before the 1st bit of the next byte, and I'd guess those wouldn't stretch clocks for other devices on the bus.
High-level, general-purpose drivers are tricky due to the endless variations in how manufacturers design their I2C devices. Most pressure sensors, for instance, take a device byte followed by a command byte--what would normally be a register byte--and no data bytes. The ADS1000 A/D converter likewise doesn't use registers, configuration is written immediately after the device byte. For reading, it expects the device ID with r/w bit set, after which two data bytes are clocked out. It's for these edge cases that I now include an arbitrary method in my drivers, send any number of bytes and read any number back.
... tested using multiple cogs on the same Prop but it performed flawlessly, however I wouldn't expect it work with scl and sda reversed ...
If it sticks to the bus standard, it should?
BTW, I'm curious about this snippet from Multi-Mstr\I2C start ... what are the marked lines doing?
:loop1 ' This loop allows time for the bus to float up to idle
test idle_mask,ina wc,wz
if_nc_and_nz jmp #:loop2_init
> mov cnt,target_cnt
> sub cnt,cnt
> cmps cnt,#0 wc
if_nc jmp #:loop1
jmp #main ' Abort if bus doesn't return to idle within 1/4 bit-width
I thought 'cnt' was read-only in each cog? First time I've seen it the dest.
... Tim
PS - The Manual says "CNT is a read-only pseudo-register; when used as an instructions source operand, it reads the current value of the System Counter. Do not use CNT as the destination operand; that only results in reading and modifying the shadow register whose address CNT occupies."
BTW, I'm curious about this snippet from Multi-Mstr\I2C start ... what are the marked lines doing?
:loop1 ' This loop allows time for the bus to float up to idle
test idle_mask,ina wc,wz
if_nc_and_nz jmp #:loop2_init
> mov cnt,target_cnt
> sub cnt,cnt
> cmps cnt,#0 wc
if_nc jmp #:loop1
jmp #main ' Abort if bus doesn't return to idle within 1/4 bit-width
I thought 'cnt' was read-only in each cog? First time I've seen it the dest.
... Tim
PS - The Manual says "CNT is a read-only pseudo-register; when used as an instruction’s source operand, it reads the current value of the System Counter. Do not use CNT as the destination operand; that only results in reading and modifying the shadow register whose address CNT occupies."
I think that is a 'trick' that does not make for read-able code - effectively that overlays a TMP_VAR with the shadow register.
By using the shadow register, it saves using a register elsewhere, but should really be declared with a name less lazy.
The whole CNT handling in Prop is a good argument for MACROs.
To answer the question, shadow registers are registers that can only be operated on through the destination field. In addition to cnt, there is also a shadow par and shadow ina/inb. It's not that uncommon a trick, and the code is only unreadable 'til you learn it. I like using cnt in the dest field as it's a pre-defined, aptly-named register in a role that it seems ideally suited for.
mov cnt,interval_delay
add cnt,cnt
waitcnt cnt,interval_delay
' does the same thing as
mov delay_target,interval_delay
add delay_target,cnt
waitcnt delay_target,interval_delay
I like using cnt in the dest field as it's a pre-defined, aptly-named register in a role that it seems ideally suited for.
Using the shadow register address makes sense, but using the same name is not so sensible.
add cnt,cnt
visibly doubles count, but wait, no, magical overlay use means that is not what really happens, in this special case...
Code is less maintainable and less portable across designers.
More polished would be a tool chain that pre-defined shadow registers (and also checked their misuse)
Working this Stick Adapter into the bus ... and seems to work ok? Guess I can make a board for it now ... free up my bread board.
I find the /INT does not work ... unless you send the stop bit ... then I lower the clock line and wait for the return pulse on the data line.
This is big improvement over my old stick adapter ... it had 2 timing caps and was producing results that needed scaling to each other ... a pain to calibrate.
This adapter uses the same timing cap for both axis, producing results that are 'comparable' to each other without the need for scaling.
... Tim
PS - Tried many different approaches ... but could not get original image to load ... using the schematic instead from express pc
Comments
From my last post, to Peter J, I mention that I was struggling with the start\bit routine. I was [size=+1]over[/size] thinking the issue since I already know a device that adheres to the I2C standard for a slave will operate on front/rear I can ignore what the rear bus is doing and concentrate on just standard behavior for the start\bit routine.
With one exception, the front side of the bus has top priority.
So, the next issue is how do I detect a collision? For now, Im using this arrangement during the testing:
So, has anyone built a multi master routine? I checked out OBEX and saw Mike Green made a spin version (very nice), and someone else made a assembly version out of it. But, the start\bit routine does not check to see if another master is using the bus at the moment So I will be flying solo on this one.
... Tim
btw, I have discovered an actual application for this idea. The CY8C9520A is a very nifty IO expander, but it has a bit of a drawback in that it stretches the clock following every device byte, so it interferes with the Prop bootloader which drives the clock and data lines high and low. I modified my reversed-pins Spin driver further to make it open-drain compatible, and got it working on same pins as the eeprom. The CY8C9520 is the only clock-stretching slave I have experience with, but there's no reason this shouldn't work with all of 'em.
Chris
Thanks for the explanation of the state machine, but I'm afraid I'm still not getting it, and you're more than welcome to use the graphic.
Do you find it stretch the clock after every byte ? By how much ?
I think you are saying it does this stretch, even when not addressed itself ?
Data only says master needs support stretch, and says this re "EEPROM"
[" When a 64-byte boundary is crossed in the EEPROM, the I2C clock is stretched while the device performs
an EEPROM write sequence.
If the end of available EEPROM space is reached, then further writes are responded to with a NAK."]
Normally, Multimaster arbitration follows every bit, and releases when it finds PinLevel <> Expected level
Yeah ... I saw that with the CAN standard ... simply lovely how the lower id number wins out over the high number device ... absolute genius ... but, I don't think I need to resort to any 'funny' techniques? Should be able to stay within I2C standard and still operate ... was just trying to 'visualize' my approach for detecting activity by another master on the bus ... haven't been able to see any other code by the 'heavy weights' on this forum regarding 'multi-master' start\bit routine.
My logic tells me that "just before 'start\bit' occurs, I should have a counter on the data_pin, detecting 'negative' edges. Any count in PHSA/B would clear PHSA/B wait (maybe 511 bit paces) and try up to two more times before 'strike three' is reached? Otherwise, seize bus as normal.
So, the 3 ways you enter this routine are:
1) The bus is 'free/idle' and not seized by this master ... both data and clock are '1' and PHSA/B is zero.
2) This master already has the bus seized (shown by DIRA) and data and clock are low.
3) The bus is in use by another master.
... Tim
BTW - Thanks for input.
Yep, it stretches after every single device ID byte, between the r/w bit and the ack bit, in order to determine who is being addressed. If it is being addressed, it continues to stretch the clocks following the register address bytes and data bytes, for both the EEPROM and the IO functions. It does not stretch clocks after it determines that some other device is being addressed.
The stretch duration varies depending on how many bytes it receives (more bytes, the longer the duration) but seems to be between 400us and 800us.
I2C traffic
'negative' edge detect will have a few SysClks of aperture, more careful edge timing can check to 1 sysclk, but that still leaves the case where two masters fluke identical-cycle access. Both get expected-edge-time success.
In that case, the bit-by-bit check is needed to resolve & also covers masters in different Props.
idea : If you are ok this only works on same-prop masters, then maybe doing a hub access right before the Start, and using gated-timer timing, can ensure the phase-lock cannot occur,
The Hub access I think will adjust the phase of following opcodes, and they cannot then both drive the pin on same sysclk edge.
Nice i2c monitor, what is that ?
Sounds like they use a (slow) MCU with software address matching & the stretch in all ID cases is going to surprise many.
Makes it look like a wait-for-scl high, is a good addition to any i2c library.
I'm using a Digilent Electronics Explorer board, they also have an Analog Discovery device which is more akin to a Propscope.
Yeah, it is a very slow controller in that IO expander; playing with it some more I got just under 2ms of stretching in some instances. Even if it weren't interfering with the Prop bootloader, I wouldn't want something like that on a bus I was using with other devices.
Agreed!
... Tim
Wow ... that tool you have is sweet! And the information you've provide is really helpful ... thanks ever so much.
... Tim
Is that doing more than just waiting on SCL high ?
Previous versions were using this, but I abandoned it after realizing the discrepancy between the desired and actual bitrates; a setting of 400Kbps was actually sending at ~355Kbps.
I'm curious about something. What if during the time we transmit the device number (open drain), we slowed the clock rate down. Then, after receiving the acknowledge from the device, we switch to push pull in full speed? At present, you're the logical one to test this, since you have the uncommon chip.
Any thoughts? By the way, does that chip stretch the clock bit for every device number broadcast over the bus?
... Tim
You're right, of course, simply checking the clock line shouldn't have resulted in that much of a difference. I realized that I was checking on the wrong side of a waitcnt in one place, fixing that boosted to max speed considerably. In examining that, I found a potentially fatal flaw where the clock might float high just before the bit delay expired and still miss the waitcnt. Here's my re-worked logic: It's also written in-line, eliminating the time wasted on calls and rets. The same idea is used with the read bit routines which require a couple instructions before the final waitcnt, which limits the max speed to just over 900Kbps.
The bitrate doesn't seem to have much, if any, affect on the duration of the clock stretching. The 20Kbps Spin driver and PASM driver running at 100Kbps (max speed for this device) both stretched the clock between 300us and 750us. Yes, it stretches the clock for every device byte. If the CY8C is being addressed, it continues stretching the clocks for every byte it receives. If some other device is being addressed, say an EEPROM, the register and data bytes following the device ID are ignored by the CY8C, but the device ID always gets stretched.
This is the only clock-stretching slave I have experience with, though I know some other devices stretch the clock after the ack bit and before the 1st bit of the next byte, and I'd guess those wouldn't stretch clocks for other devices on the bus.
High-level, general-purpose drivers are tricky due to the endless variations in how manufacturers design their I2C devices. Most pressure sensors, for instance, take a device byte followed by a command byte--what would normally be a register byte--and no data bytes. The ADS1000 A/D converter likewise doesn't use registers, configuration is written immediately after the device byte. For reading, it expects the device ID with r/w bit set, after which two data bytes are clocked out. It's for these edge cases that I now include an arbitrary method in my drivers, send any number of bytes and read any number back.
Wow ... I missed that!! That's precisely what I was trying to write ... and you have it written already! Thanks.
I see you tested yours in two cogs ... that was what I was going to try in my earlier post! I'm a little slow folks.
... Tim
PS - Going blind slowly
If it sticks to the bus standard, it should?
BTW, I'm curious about this snippet from Multi-Mstr\I2C start ... what are the marked lines doing?
I thought 'cnt' was read-only in each cog? First time I've seen it the dest.
... Tim
PS - The Manual says "CNT is a read-only pseudo-register; when used as an instructions source operand, it reads the current value of the System Counter. Do not use CNT as the destination operand; that only results in reading and modifying the shadow register whose address CNT occupies."
I think that is a 'trick' that does not make for read-able code - effectively that overlays a TMP_VAR with the shadow register.
By using the shadow register, it saves using a register elsewhere, but should really be declared with a name less lazy.
The whole CNT handling in Prop is a good argument for MACROs.
Using the shadow register address makes sense, but using the same name is not so sensible.
add cnt,cnt
visibly doubles count, but wait, no, magical overlay use means that is not what really happens, in this special case...
Code is less maintainable and less portable across designers.
More polished would be a tool chain that pre-defined shadow registers (and also checked their misuse)
I find the /INT does not work ... unless you send the stop bit ... then I lower the clock line and wait for the return pulse on the data line.
This is big improvement over my old stick adapter ... it had 2 timing caps and was producing results that needed scaling to each other ... a pain to calibrate.
This adapter uses the same timing cap for both axis, producing results that are 'comparable' to each other without the need for scaling.
... Tim
PS - Tried many different approaches ... but could not get original image to load ... using the schematic instead from express pc
When cnt is used in the destination, its shadow register gets used instead. It's just a way of saving a register she you're running low.
-Phil