Shop OBEX P1 Docs P2 Docs Learn Events
SOLVED! I2c driver weirdness that wasn't the I2C driver.. — Parallax Forums

SOLVED! I2c driver weirdness that wasn't the I2C driver..

R BaggettR Baggett Posts: 157
edited 2021-08-30 11:29 in Propeller 1

A little history:

This is for a tester for an electromechanical device that communicates by I2C.

I had this working with Basic_I2C_Driver, but I was asked to get the I2C clock to 410 Khz to match 'real world' conditions.

So I found I2C PASM driver V1.8.od. which can be set to this clock.

I fixed a little bug in the readNext routine (Line 204), adding the low bit for 'read' to the device ID. And then I don't use this routine because of the DUT's nonstandard I2C usage.

I end up using the 'arbitrary' function for reading, and it works.

Now the problem:

The i2C driver seems to go into some mode randomly, sometimes writing, sometimes reading, where it 'paces' the individual bytes about 5 mS apart!

The attached Saleae 'logic' capture has one write where this happens, and one read, with some 'normal' exchanges in between. The read at the end caused my I2C program to miss a Cnt, with the customary 54 second 'freeze'.

The ACKs seem timely, it then just waits to send the next byte...

I have increased all my stacks to ridiculous sizes, and then doubled them, to no avail.

Any ideas? perhaps a different 'driver' (Although this one seems well-written...)

I have included the .sal file in the archive

Thanks!

Comments

  • Gonna take a while for me to examine all of that, one thing that does jump out is you're using abort traps for all of the i2c calls, which are unnecessary for the PASM driver as it doesn't use aborts--were you using my Spin driver previously?
    Looks like the only object that does use aborts is the SD-MMC_FATEngine. There is an abort trap in TesterFile for capturing ErrStr, but I don't know if that captures every abort. Looks like that is running in a separate cog anyhow.

    Examining the Salae file I notice that none of the general messages are sending stop bits, which looks like it's being caused by clock stretching after the ack bit.
    I've encountered stretched clocks between the device ID and the register byte, and I've encountered them between data lsb and the ack bit, but after the Ack is a new one for me.

    Dunno if it'll solve the problem, but this should at least get it to send stop bits.

    I2C_stop
                            mov       delay_target,bit_delay                        ' SCL 
                            add       delay_target,cnt                              ' SDA 
                            or        dira,SDA_mask                                 '     0 1 2 3
                            waitcnt   delay_target,bit_delay
                            andn      dira,SCL_mask
    
                            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
                            andn      dira,SDA_mask
                            waitcnt   delay_target,bit_delay
                            waitcnt   delay_target,bit_delay
                            mov       t1,#$FF
                            wrbyte    t1,command_address                                         
    I2C_Stop_ret            ret                                                                  
    

    All 3 of the reads from $31 $60 $9F $9F seem to go okay, clock held low for ~35us after the write.
    The clock is held low for ~45us following the one read from $31 $11 $EE $9F. The device sends eleven bytes back normally, then appears to choke.
    Could it be that you're trying to read it too often?

    I noticed with my CY8C9520--the device I have that stretches clocks between the ack and data--that the clock would get stretched progressively more the more often I accessed it.

  • Chris,

    Thanks for looking at this.

    The abort traps are there because the examples included with that driver used them and it started working for me when I added them. The actual fix may have been something else, I never took a proper look at it once it began to 'work'...

    I will try the stop bit fix, (Monday...) but the timing and clock closely match the use of the device in the wild, and I have never seen this byte spacing in many hours of captures in the end application.

    What about the similar pacing on the write to $00 at the very beginning of the capture? The timing is Suspiciously similar.

  • Another option is the I2C driver that's part of FemtoBasic (or DongleBasic). It runs in its own cog and provides for non-memory devices. It can handle double buffered I/O and SPI devices and, with memory devices, can load programs and start them.

  • In case you want to have a look, I have a very simple PASM1 I2C driver (attached). It just does the basics, but seems to work well. I've deployed this in commercial products.

  • Mike, Jon

    Thanks for these!

    Both would seem to be suitable, and give me some options toward experiments to determine if the actual problem is the driver, my program, or something else...

    Mike,
    I would need to get the clock to exactly 410 KHZ in order to get the device team to not blame the tester for our actual problem. (not described here. Related to differences in actual operation after redesign due to semiconductor shortages..)
    I assume I could get this fairly minor adjustment by scaling the timing constants... right?

    Thanks again!

  • My driver needs another correction. From the Salae capture, the 1st bit of every byte after the first is short, caused by the routine only adding 1/4 bit width to re-establish the high clock after the stepper controller releases.
    This changes the bit spacing from 2.4us to just over 2us.

    A simple fix to this problem is adding another waitcnt in all of the 'check_stretches

    'check_stretch                                                                  ' some devices stretch the clock before the first bit
                            waitcnt   delay_target,bit_delay                        ' allow 1/4 bit width for clock to go high
                            test      SCL_mask,ina                wc
              if_c          jmp       #:lower1
                            waitpeq   SCL_mask,SCL_mask                             ' wait for clock to go high
                            mov       delay_target,bit_delay                        ' re-establish bitrate
                            add       delay_target,cnt
                            waitcnt   delay_target,bit_delay       ' added waitcnt
    :lower1
                            waitcnt   delay_target,bit_delay
    

    I'll be surprised if that solves the issue though. There is nothing in the driver that would cause it to change the byte spacing; it's gotta be external due to clock-stretching.
    A driver with less throughput might work better as it'll give the stepper controller more time to process.

  • Chris,

    The I2c is just for the device under test, The stepper is just step/direction.

    The team that wrote the DUTs firmware is demanding the 410 KHZ.. And these assemblies have been in hundreds of thousands of end devices for 10+ years...all at 410 KHZ.. and the ones I am using to debug this are the 'old' (Pre semiconductor shortage) units.

    The end problem doesn't have squat to do with the I2C rate IMHO, but to get the ball back over the net this time I need to clock at 410 KHZ.

    This I2C problem may ultimately be hardware, maybe my voltage converters (The famous App Note 97055 from Phillips, Which seem to perform well, I had them at a few MHZ with clean output..) or the wire length (Shorter than the final application, but fatter and not in a ribbon... etc. But I really don't think so... Nevertheless I guess I will get a 4 channel 'scope on the ins and outs of the voltage converter Monday.
    (The Sal capture is on the 5V DUT side, BTW)

    Thanks again!

  • Here's another I2C driver that you could try. I wrote pasm_i2c_driver so that it would run at higher speeds, but uses the same Spin method calls as basic_i2c_driver. The driver runs at about 400 KHz, but you can adjust DELAY_CYCLES to change the frequency.

  • Dave,

    Thanks, I can easily drop this into my earlier production code for a sanity check, as it originally used Mike's I2C object.

  • @ChrisGadd said:
    My driver needs another correction. From the Salae capture, the 1st bit of every byte after the first is short, caused by the routine only adding 1/4 bit width to re-establish the high clock after the stepper controller releases.
    This changes the bit spacing from 2.4us to just over 2us.

    A simple fix to this problem is adding another waitcnt in all of the 'check_stretches

    'check_stretch                                                                  ' some devices stretch the clock before the first bit
                            waitcnt   delay_target,bit_delay                        ' allow 1/4 bit width for clock to go high
                            test      SCL_mask,ina                wc
              if_c          jmp       #:lower1
                            waitpeq   SCL_mask,SCL_mask                             ' wait for clock to go high
                            mov       delay_target,bit_delay                        ' re-establish bitrate
                            add       delay_target,cnt
                            waitcnt   delay_target,bit_delay       ' added waitcnt
    :lower1
                            waitcnt   delay_target,bit_delay
    

    I'll be surprised if that solves the issue though. There is nothing in the driver that would cause it to change the byte spacing; it's gotta be external due to clock-stretching.
    A driver with less throughput might work better as it'll give the stepper controller more time to process.

    Chris,

    This problem turns out to be self-inflicted (As so many are...)
    I was aware that after asking the device to make a change.. (Anything other than $60 in the first byte of the writes to $31) I need to leave it alone for at least 100 mS, and added logic to accomplish this, which logic is defective... and every pacing event corresponds to this violation...

    I am attaching caps from each change for your review.

    Thanks Again!

    And Thanks again to everyone. All of these drivers are now on my short list!

  • Chris, I apologize, the caps in CG_Results were done with the original version, This one is the patched version of your driver..

Sign In or Register to comment.