Forum Rule: Always post complete source code & details to reproduce any issue!
Page 27 of 27 FirstFirst ... 17 25 26 27
Results 651 to 674 of 674

Thread: New I2C library for Teensy3

  1. #651
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Also to anyone following this thread - in regards to Teensy4:

    I was offered a T4 beta board back when it started, but I could not accept as I did not have the requisite time to work on a library port.

    I have now obtained a couple of the retail boards, and although I still lack time, I will probably attempt a port as I can get to it. I have not reviewed Wire code on T4 to know how different it is, but I did read something about it using a FIFO, so my guess is the ISR code would be different enough to warrant a new lib (eg. i2c_t4). I am uncertain of interest level, if any, so any comments would be helpful.

  2. #652
    Senior Member
    Join Date
    Jun 2015
    Posts
    231
    Hi nox771,

    Thanks for getting back on this.

    Before I waste any of your time trying to help me - as I could be trying to achieve the impossible here.
    Would you expect your library to help increase the speed/performance of sending & displaying text to 8 x i2c displays?

    I have now managed to get the "spoof (wire/ic2_t3) " method to compile, but I'm not really seeing much difference performance wise.

    I know there are limitations with this protocol - but not sure what your library is offering versus the std Wire lib.
    As per a post on another thread - I'm seeing a cascading/domino effect when sending the text updates.

    I'm not a software person, so don't really understand most of this stuff.
    Just someone who manages to fumble his way through with the help of forums like this.

    Thanks

  3. #653
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by bossredman View Post
    Hi nox771,

    Thanks for getting back on this.

    Before I waste any of your time trying to help me - as I could be trying to achieve the impossible here.
    Would you expect your library to help increase the speed/performance of sending & displaying text to 8 x i2c displays?

    I have now managed to get the "spoof (wire/ic2_t3) " method to compile, but I'm not really seeing much difference performance wise.

    I know there are limitations with this protocol - but not sure what your library is offering versus the std Wire lib.
    As per a post on another thread - I'm seeing a cascading/domino effect when sending the text updates.

    I'm not a software person, so don't really understand most of this stuff.
    Just someone who manages to fumble his way through with the help of forums like this.

    Thanks
    It depends. Mostly any speedup will depend on the slave device and if it will respond well to faster than normal I2C speeds. I've gotten faster than normal communication working on something like a SSD1306 I2C display (like the cheap ones on ebay: https://www.ebay.com/sch/i.html?_nkw...06+i2c&_sop=12 ). In that case IIRC it can help with refresh speeds.

    If you are using standard default settings (100kHz/400kHz), then you will likely see the same performance as Wire, as that is what it uses, so it does require specifying something above normal rates.

    Also there are other indirect ways to improve performance. Typical Wire is a blocking interface. Such that the program halts and waits for communication to complete. For i2c_t3 you can background transfers. So in that case you can load the buffer, start the transfer, then continue to a foreground task while it transfers in the background. Most recent releases also support a Master callback that can call a given function when the background transfer completes, so you do not need to monitor it. These are capabilities above and beyond what the standard Wire library will offer. You can check the "basic_master_callback" example for further information on that.

    Note the library linked in post #1 in this thread is obsolete. You should grab the latest one from GitHub (currently v11.0). Due to updated forum rules I can no longer edit the top post to maintain it, so GitHub is the main location now.

  4. #654
    Senior Member
    Join Date
    Jun 2015
    Posts
    231
    Quote Originally Posted by nox771 View Post
    Note the library linked in post #1 in this thread is obsolete. You should grab the latest one from GitHub (currently v11.0). Due to updated forum rules I can no longer edit the top post to maintain it, so GitHub is the main location now.
    Thanks.

    I picked up v11.0 already. It's the only 1 I've tried.

  5. #655
    Senior Member
    Join Date
    Jun 2015
    Posts
    231
    The Digole displays come with their own library for sending data (text, shapes etc) to them.
    So apart from the include for wire.h - all commands for sending the data are Digole specific commands.
    I'm don't directly interact with the Wire libray & commands - I guess that is done indirectly via the Digole Library.

    I just add these statements for each Display & then create an array listing each instance :
    Code:
    DigoleSerialDisp mydisp1(&Wire, '\x27'); 
    DigoleSerialDisp mydisp2(&Wire, '\x28'); 
    ...
    DigoleSerialDisp mydisp8(&Wire, '\x34'); 
    
    mydisp[8] = {mydisp1, mydisp2, ... mydisp8};
    This lets me easily loop each Display & send the data as required.

    Apart from what this statement is actually doing
    Code:
    DigoleSerialDisp mydisp1(&Wire, '\x27');
    I'm able to mostly understand the above.
    But I think I'm just not smart enough to figure out how to make changes to use Master Callbacks etc.

  6. #656
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by bossredman View Post
    The Digole displays come with their own library for sending data (text, shapes etc) to them.
    So apart from the include for wire.h - all commands for sending the data are Digole specific commands.
    I'm don't directly interact with the Wire libray & commands - I guess that is done indirectly via the Digole Library.
    ...
    You'll have to supply a link to your library you are using. Other than that it is guessing. Using google I can see a DigoleSerial.h lib at:
    https://github.com/phalpern/Thermost...DigoleSerial.h

    That one has a very generic init for I2C config:
    Code:
    _myWire->begin();
    That may be giving you a 100kHz clock, which is standard for Arduino.

    A simple option is to use your init code as-is, then insert a Wire command to adjust the clock:
    Code:
    DigoleSerialDisp mydisp1(&Wire, '\x27'); 
    DigoleSerialDisp mydisp2(&Wire, '\x28'); 
    ...
    DigoleSerialDisp mydisp8(&Wire, '\x34'); 
    Wire.setClock(200000);  // 200kHz
    ...
    ...
    Add that, test it, and see if it works. Then increase it and try again: 400000 = 400kHz, 600000 == 600kHz, 800000 = 800kHz, and so on.

    i2c_t3 lib will quantize the number to the nearest legal value, so you can use any number you like. Most T3 parts can run up to 3000000 = 3MHz. Recent T3.5/3.6 can do higher.

    At some point it will fail and the screen will get garbage or something, then you can back it off.

    Edit: Forgot to mention, high speeds are also limited by the pullup resistor value. If the R-value on the bus is too high the pullups will be slow and it will limit your speeds. Refer to this link:
    http://dsscircuits.com/articles/86-a...l-up-resistors

  7. #657
    Senior Member
    Join Date
    Apr 2013
    Posts
    142
    Hello nox771,

    is it possible to modify/add an modified version of void i2c_t3::resetBus_(struct i2cStruct* i2c, uint8_t bus) to create an clock stretching for slave mode?

  8. #658
    Quote Originally Posted by nox771 View Post
    I am uncertain of interest level, if any, so any comments would be helpful.
    I would definitely be interested.

  9. #659
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by Markus_L811 View Post
    Hello nox771,
    is it possible to modify/add an modified version of void i2c_t3::resetBus_(struct i2cStruct* i2c, uint8_t bus) to create an clock stretching for slave mode?
    I don't quite follow your question. On Master-side the resetBus function will take I2C off the pins for a moment, manually send some clocks down SCL to release any stuck slaves, and then reconnect I2C. In this case you are talking about having a slave swap I2C off the pin and then holding SCL low for some time?

    I'm not sure if it would work. It would only be possible between bytes, after bit9 and before bit1. But SCL might go high before the slave could switch to pulling it low (not seamless). If it were embedded in the Slave ISR it might be fast enough. But trying to change I2C pin inside the ISR in order to enable manual control would be quite odd. Hard to say, it would require experimentation.

  10. #660
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by wcalvert View Post
    I would definitely be interested.
    Thanks for the feedback. I'll probably investigate it, but I have no idea when I could get something out.

  11. #661
    Senior Member
    Join Date
    Apr 2013
    Posts
    142
    Quote Originally Posted by nox771 View Post
    In this case you are talking about having a slave swap I2C off the pin and then holding SCL low for some time?

    I'm not sure if it would work. It would only be possible between bytes, after bit9 and before bit1. But SCL might go high before the slave could switch to pulling it low (not seamless). If it were embedded in the Slave ISR it might be fast enough. But trying to change I2C pin inside the ISR in order to enable manual control would be quite odd. Hard to say, it would require experimentation.
    Click image for larger version. 

Name:	i2c_clock_stretching.png 
Views:	6 
Size:	8.7 KB 
ID:	17262

    Yes this was what I have in mind

  12. #662
    Senior Member
    Join Date
    Apr 2013
    Posts
    142
    Looks like an can't edit my post.

    Technically the picture is wrong, after IC-bus specification and user manual Rev. 6

    3.1.9 Clock stretching
    Clock stretching pauses a transaction by holding the SCL line LOW. The transaction
    cannot continue until the line is released HIGH again. Clock stretching is optional and in
    fact, most slave devices do not include an SCL driver so they are unable to stretch the
    clock.
    On the byte level, a device may be able to receive bytes of data at a fast rate, but needs
    more time to store a received byte or prepare another byte to be transmitted. Slaves can
    then hold the SCL line LOW after reception and acknowledgment of a byte
    to force the
    master into a wait state until the slave is ready for the next byte transfer in a type of
    handshake procedure.
    On the bit level, a device such as a microcontroller with or without limited hardware for the
    I2C-bus, can slow down the bus clock by extending each clock LOW period. The speed of
    any master is adapted to the internal operating rate of this device.
    In Hs-mode, this handshake feature can only be used on byte level.

    So after the ACK the Slave can hold the SCL line LOW, I was thinking about this:

    Code:
    void i2c_t3::stretchClock_(struct i2cStruct* i2c, uint8_t bus)
    {
        uint8_t scl = i2c->currentSCL;
        uint8_t sda = i2c->currentSDA;
    
        // change pin mux to digital I/O
        pinMode(sda,((i2c->currentPullup == I2C_PULLUP_EXT) ? INPUT : INPUT_PULLUP));
        digitalWrite(scl,LOW);
        pinMode(scl,OUTPUT);
    
        //Do what ever I want inside the sketch and after it go back in IC Mode
    
        // reconfigure pins for I2C
        pinConfigure_(i2c, bus, scl, sda, i2c->currentPullup, 0, 0);
    
        // reset config and status
        if(*(i2c->S) & 0x7F) // reset config if any residual status bits are set
        {
            *(i2c->C1) = 0x00; // disable I2C, intr disabled
            delayMicroseconds(5);
            *(i2c->C1) = I2C_C1_IICEN; // enable I2C, intr disabled, Rx mode
            delayMicroseconds(5);
        }
        i2c->currentStatus = I2C_WAITING;
    }

  13. #663
    Senior Member
    Join Date
    Jun 2015
    Posts
    231
    Quote Originally Posted by nox771 View Post
    You'll have to supply a link to your library you are using. Other than that it is guessing. Using google I can see a DigoleSerial.h lib at:
    http://"https://github.com/phalpern/...igoleSerial.h"
    Hi sorry for slow response.
    Believe I got the library from here:
    https://www.digole.com/forum.php?topicID=1

    I had already tried various values for Wire.setClock - nothing seemed to make a difference - to the naked eye at least.

    Edit: Forgot to mention, high speeds are also limited by the pullup resistor value. If the R-value on the bus is too high the pullups will be slow and it will limit your speeds. Refer to this link:
    http://dsscircuits.com/articles/86-a...l-up-resistors
    Tried both 4k7 & 2k7 so far - again no noticeable difference.

    The only thing I have seen make a slight difference was changing the Font.
    The displays come with 4 "built-in" fonts but I been using a custom Font (Bold) which can be written direct to the display.
    Flipping back one the std fonts seemed to improve things a touch

  14. #664
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by Markus_L811 View Post
    So after the ACK the Slave can hold the SCL line LOW, I was thinking about this:

    Code:
    void i2c_t3::stretchClock_(struct i2cStruct* i2c, uint8_t bus)
    {
        uint8_t scl = i2c->currentSCL;
        uint8_t sda = i2c->currentSDA;
    
        // change pin mux to digital I/O
        pinMode(sda,((i2c->currentPullup == I2C_PULLUP_EXT) ? INPUT : INPUT_PULLUP));
        digitalWrite(scl,LOW);
        pinMode(scl,OUTPUT);
    
        //Do what ever I want inside the sketch and after it go back in IC Mode
    
        // reconfigure pins for I2C
        pinConfigure_(i2c, bus, scl, sda, i2c->currentPullup, 0, 0);
    
        // reset config and status
        if(*(i2c->S) & 0x7F) // reset config if any residual status bits are set
        {
            *(i2c->C1) = 0x00; // disable I2C, intr disabled
            delayMicroseconds(5);
            *(i2c->C1) = I2C_C1_IICEN; // enable I2C, intr disabled, Rx mode
            delayMicroseconds(5);
        }
        i2c->currentStatus = I2C_WAITING;
    }
    It's an interesting idea, but I suspect it is a bit more complex than it seems. On the Slave end, the code would run as part of the ISR. The code you show has elements that seem right, but overall it seems off. It would need to work similar to the onReceive() callback.

    In a generic sense it would be more like a per-byte callback, as opposed to onReceive(), which is an end-of-message callback. But the experimental/weird part is that IIRC there is no mechanism to force pin state on the I2C peripheral (I might be wrong, its been a long time since I read the docs). So that only leaves doing the pinConfigure swap as you show, which might work, as long as the I2C bus doesn't change its state while the peripheral is disconnected, and it otherwise remains oblivious to the pin change.

    I'll think about it, but it will be some time before I could really get into it. If you manage to get something to work then let me know, I would be interested.

  15. #665
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by bossredman View Post
    Hi sorry for slow response.
    Believe I got the library from here:
    https://www.digole.com/forum.php?topicID=1

    I had already tried various values for Wire.setClock - nothing seemed to make a difference - to the naked eye at least.

    Tried both 4k7 & 2k7 so far - again no noticeable difference.

    The only thing I have seen make a slight difference was changing the Font.
    The displays come with 4 "built-in" fonts but I been using a custom Font (Bold) which can be written direct to the display.
    Flipping back one the std fonts seemed to improve things a touch
    I'm not sure what else to suggest. Other displays I've used generally scale with transmit speed (but they were graphical, so I2C was the bottleneck for moving frame data). Perhaps that display has a processor that controls/limits the speed.

    Another possibility is that the host program is sending at a constant rate - in other words, the data itself is communicated faster, but the frame-to-frame speed is constant. I've seen this situation before, where frames were sent at a fixed rate, and even if the data was faster, the host would just idle until the next frame interval.

  16. #666
    Sorry if this has been covered elsewhere in this thread. (I did search for it!)

    I'm seeing delays on the I2C bus between each part of a command. I'll explain with an example. First, the code snippet (from the master):

    Code:
    Wire.beginTransmission(addr);
    Wire.write(cmd_byte);
    Wire.endTransmission(I2C_NOSTOP);
    Wire.requestFrom(addr, 2, I2C_STOP, 500000);
    Wire.read();
    Wire.read();
    What I'm seeing on the bus is:

    1) Send address with R/W bit low
    2) 0.3 ms delay with SCL low
    3) Send cmd_byte
    4) 1 ms delay with SCL low
    5) Send address with R/W bit high
    6) 1 ms delay with SCL low
    7) Receive first byte
    8) 0.9 ms delay with SCL low
    9) Receive second byte

    (I can't seem to upload an image of the bus capture, for whatever reason.)

    Is the master responsible for some (or all) of those delays? I wonder if that could confuse the slave? I know clock stretching is a possibility, but it seems like that wouldn't account for every delay in this sequence.

    Assuming these delays are caused by the master, is there anything I can do about them?

  17. #667
    Senior Member
    Join Date
    Apr 2013
    Posts
    142
    Quote Originally Posted by nox771 View Post
    It's an interesting idea, but I suspect it is a bit more complex than it seems. On the Slave end, the code would run as part of the ISR. The code you show has elements that seem right, but overall it seems off. It would need to work similar to the onReceive() callback.

    In a generic sense it would be more like a per-byte callback, as opposed to onReceive(), which is an end-of-message callback. But the experimental/weird part is that IIRC there is no mechanism to force pin state on the I2C peripheral (I might be wrong, its been a long time since I read the docs). So that only leaves doing the pinConfigure swap as you show, which might work, as long as the I2C bus doesn't change its state while the peripheral is disconnected, and it otherwise remains oblivious to the pin change.

    I'll think about it, but it will be some time before I could really get into it. If you manage to get something to work then let me know, I would be interested.
    I will make some Tests soon, I have an SHT31-D who supports SCL-Stretching, the does support i2c_t3 SCL-Streching?

    See some Interesting about it there https://forum.pjrc.com/threads/25768...n-for-Teensy-3

  18. #668
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by markb View Post
    Sorry if this has been covered elsewhere in this thread. (I did search for it!)

    I'm seeing delays on the I2C bus between each part of a command. I'll explain with an example. First, the code snippet (from the master):

    Code:
    Wire.beginTransmission(addr);
    Wire.write(cmd_byte);
    Wire.endTransmission(I2C_NOSTOP);
    Wire.requestFrom(addr, 2, I2C_STOP, 500000);
    Wire.read();
    Wire.read();
    What I'm seeing on the bus is:

    1) Send address with R/W bit low
    2) 0.3 ms delay with SCL low
    3) Send cmd_byte
    4) 1 ms delay with SCL low
    5) Send address with R/W bit high
    6) 1 ms delay with SCL low
    7) Receive first byte
    8) 0.9 ms delay with SCL low
    9) Receive second byte

    (I can't seem to upload an image of the bus capture, for whatever reason.)

    Is the master responsible for some (or all) of those delays? I wonder if that could confuse the slave? I know clock stretching is a possibility, but it seems like that wouldn't account for every delay in this sequence.

    Assuming these delays are caused by the master, is there anything I can do about them?
    Those delays should not be caused by the Master. Ignoring the SCL delay, when the bytes transmit, what is the SCL toggle speed? That would be the Master-side clock.

    I'm not sure why the hold times with SCL low would occur. Perhaps try getting the Master to talk to a different Slave device. Also make sure the pullups are correct (although if they were not you probably would not get any data).

    Also list what is the Wire.begin() statement.

  19. #669
    Quote Originally Posted by nox771 View Post
    Those delays should not be caused by the Master. Ignoring the SCL delay, when the bytes transmit, what is the SCL toggle speed? That would be the Master-side clock.

    I'm not sure why the hold times with SCL low would occur. Perhaps try getting the Master to talk to a different Slave device. Also make sure the pullups are correct (although if they were not you probably would not get any data).

    Also list what is the Wire.begin() statement.
    The begin statement is this:

    Code:
    Wire.begin(I2C_MASTER, 0x01, I2C_PINS_18_19, I2C_PULLUP_EXT, 100000);
    I measured 5 us high and 5us low on SCL, when it's not delayed. That matches the clock speed I setup in the begin statement. I used 4.7k pullup resistors.

    The slave responds to some commands, and not others. I was thinking the delay might be responsible for that, but at this point, I'm pretty sure the delay isn't interfering with anything. Still, it seems like more delays than there should be.

  20. #670
    Senior Member
    Join Date
    Mar 2013
    Location
    Austin TX
    Posts
    425
    Quote Originally Posted by markb View Post
    The begin statement is this:

    Code:
    Wire.begin(I2C_MASTER, 0x01, I2C_PINS_18_19, I2C_PULLUP_EXT, 100000);
    I measured 5 us high and 5us low on SCL, when it's not delayed. That matches the clock speed I setup in the begin statement. I used 4.7k pullup resistors.

    The slave responds to some commands, and not others. I was thinking the delay might be responsible for that, but at this point, I'm pretty sure the delay isn't interfering with anything. Still, it seems like more delays than there should be.
    The 5us high/low is correct for 100kHz rate. 4.7k is a good value. It really looks like Slave clock stretching, but that is quite a long duration. I'm not sure why it would not respond to some commands. If you have a different Slave, particularly a different device type, I would suggest trying that to see if the bus behaves better, or at least differently. That would isolate the problem to that particular Slave device. What is it exactly, does it have a datasheet?

  21. #671
    Quote Originally Posted by nox771 View Post
    The 5us high/low is correct for 100kHz rate. 4.7k is a good value. It really looks like Slave clock stretching, but that is quite a long duration. I'm not sure why it would not respond to some commands. If you have a different Slave, particularly a different device type, I would suggest trying that to see if the bus behaves better, or at least differently. That would isolate the problem to that particular Slave device. What is it exactly, does it have a datasheet?
    It's a power supply that speaks PMBus. I bought it used, and expected it to follow the datasheet, but the manufacturer tells me it was customized and probably had those commands disabled in firmware. So I'm pretty sure at this point the delay I see on the bus has nothing to do with the lack of response from those commands.

    When I get a chance, I'll test it out with another Teensy as slave, and see if there are still delays or not.

  22. #672
    Senior Member
    Join Date
    Nov 2012
    Location
    Salt Lake City, UT, USA
    Posts
    276
    We have a library to talk PMBus to an Artesyn LCM300 supply. It works well. I'm on the road for a few days but will see if I can post a link to that here. You should monitor the slave response... Is there an ACK to your request? Check all the possible exceptions. I2c_t3 is awesome for that. We added a library to keep a strict of exception counters and we can run many millions of messages, even billions, with no errors. I'll see if I can also post a link to that code. We also have PMBus test code. Good luck

  23. #673
    Junior Member
    Join Date
    Aug 2019
    Posts
    1
    Related issue that I've just dealt with. With a system that is running a Teensy LC as a slave (main loop runs background work, I2C handled by ISRs), Teensy 3.6 as a master (100 kHz) - that we experienced a SCL-low hang by the slave, occurring in the middle of a byte transfer to master rather than the typical timing issue at the end of one. All the signals are picture perfect for I2C. Very intermittent issue, perhaps once every 30 min to 2-3 hours.

    We tried a number of the suggested mechanisms to recover from this, to no effect. In the end, we resorted to using a spare GPIO to monitor the SCL line; when the main loop sees it hung for longer than expected, a new library function is called to disable the I2C hardware module and effectively reinitialize the I2C. This clears the hang; the application on the master side is forgiving enough to just ignore the momentary loss of the slave.

    I'm working to extricate this into a minimum code / library set that I can share and anybody with an LC and 3.6 can reproduce. I'll be working to determine if this is something that be fixed in a cleaner way or if its a fundamental issue with the hardware.

  24. #674
    Senior Member
    Join Date
    Nov 2012
    Location
    Salt Lake City, UT, USA
    Posts
    276

    Link to LCM300 PMBus library

    Here is the code we wrote and which is heavily tested and in use in multiple field installations: GitHub Systronix LCM300 library with the usual disclaimers that it might not work for your needs etc. We have some extensive error tracking and logging and there are notes about that in the linked libraries. Also some simple examples which print basic info from the supply and actually led to some surprises: the supply actually differs from its spec in regard to many message details. For one, the vendor in the supply is "Emerson"; they never changed that when Artesyn purchased them. And sadly PMBus got mired in patent disputes - see the links in readme. So it never reached its potential acceptance in the market and is unlikely to be adopted more widely than it is now. Still, for the price (about $125 is what we last paid at 50-ish units) for 300 watts it is IMO a good deal.
    Last edited by bboyes; 09-03-2019 at 09:25 PM. Reason: forgot forum doesn't use markdown style links

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •