Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

Thread: LPUART RX and TX interrupts priority

  1. #1
    Junior Member
    Join Date
    Feb 2020
    Posts
    14

    LPUART RX and TX interrupts priority

    I use a teensy 4 and I wanted to know if there is a way that in an LPUART output that the RX has a priority on the TX.
    Example if the TX sends data and that suddenly the RX receives data the TX stops transmitting its data.

    Thank you in advance

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,081
    Hardware should be capable of independent simultaneous and bidirectional Rx and Tx.

    4 byte FIFO on both - they will interrupt to service IIRC at 2 bytes

  3. #3
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    I communicate with a Nextion screen, but I don't use the nextion library, because there are several bugs.
    I process by myself the data that enter and exit the Uart port.
    I send periodically the display values and for the reception I use Serial.event and then process the data.
    See my example below.
    When I transmit it looks like the incoming data processing is not working, it looks like the TX is taking all the space.
    When I remove the transmit data section from my program the receive data works.

    Transmit section:

    Code:
    if((millis() - Timer_print) > 500)
      {
        Serial3.print("CurrentVal.val="+String(Current)+"\xFF\xFF\xFF");
        Serial3.print("ProcessorVal.val="+String(int(InternalTemperature.readTemperatureC()*100))+"\xFF\xFF\xFF");
        Timer_print - millis();
      }
    Reception section:

    Code:
    void serialEvent3()
    {
       if(dfd.length()>9) dfd="";
       if(dfd.endsWith(endChar)) dfd="";
       if(Serial3.available())
       {
         dfd += char(Serial3.read());
    
         /*** Value reading ***/
         if((String(dfd.substring(0,3))=="val") & (dfd.length() == 9))
         {
           Value.charByte[0]=char(dfd[5]);
           Value.charByte[1]=char(dfd[6]);
           Value.charByte[2]=char(dfd[7]);
           Value.charByte[3]=char(dfd[8]);
           SettingSel=String(dfd.substring(3,5)).toInt();
           switch (SettingSel)
           {
             case 1:
               SensorTapValue=Value.valLong;
             break;
    
             case 2:
               InstPickupValue=Value.valLong;
             break;
    
             case 3:
               ShortPickupValue=Value.valLong;
             break;
    
             case 4:
               ShortDelayValue=Value.valLong;
             break;
    
             case 5:
               LongPickupValue=Value.valLong;
             break;
    
             case 6:
               LongDelayValue = Value.valLong;
             break;
    
             case 7:
               GRNPickupValue=Value.valLong;
             break;
    
             case 8:
               GRNDelayValue = Value.valLong;
             break;
    
             case 9:
               CurrentSetPointValue = Value.valLong;
             break;
    
             case 10:
               PickupSelValue = Value.valLong;
             break;
    
             case 11:
               Kp = Value.valLong;
             break;
    
             case 12:
               Ki = Value.valLong;
             break;
    
             case 13:
               Kd = Value.valLong;
             break;
    
             case 14:
               ManualOut = Value.valLong;
             break;
    
             case 15:
               // = Value.valLong;
             break;
    
             case 16:
               // = Value.valLong;
             break;
           }
           dfd="";
         } 
         
         /*** Page reading ***/
         if((String(dfd.substring(0,3))=="pag") & (dfd.length() == 9))
         {
          
           Value.charByte[0]=char(dfd[5]);
           Value.charByte[1]=char(dfd[6]);
           Value.charByte[2]=char(dfd[7]);
           Value.charByte[3]=char(dfd[8]);
           CurrentPage=Value.valLong;
           dfd="";
         } 
    
         /*** Button reading ***/
         if((String(dfd.substring(0,3))=="but") & (dfd.length() == 9))
         {
           Value.charByte[0]=char(dfd[5]);
           Value.charByte[1]=char(dfd[6]);
           Value.charByte[2]=char(dfd[7]);
           Value.charByte[3]=char(dfd[8]);
           Button=Value.valLong;
           dfd="";
         } 
       }
    }
    Last edited by KurtE; 08-15-2021 at 12:56 PM. Reason: Code Tags

  4. #4
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    In the Serialevent I would have to figure out if it's an RX or a TX, but I don't know how.

  5. #5
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,081
    serialEvent only trigger on incoming bytes available?

  6. #6
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    Trig on serialevent, trig on rx or tx interrupts…..

    Teensy T3 has two different interrupts when I look at the interrupts list vector.

    T3 interrupts list have:
    USART1_RX_vect
    USART1_TX_vect


    T4 interrupts list have:
    IRQ_LPUART1


    Is there any way to differentiate which of the two interrupts for T4.

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,743
    What serial baud rate are you using to/from the Nextion?

    Pete

  8. #8
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    Serial baud 115200

  9. #9
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,081
    Quote Originally Posted by defragster View Post
    serialEvent only trigger on incoming bytes available?
    Should have added: serialEvent() is not interrupt based. It is just called on any loop() exit, delay() or call to yield(). It is called inline with the sketch code.

    If loop() is running without large work loads it can cycle 100K or 5M times per second easily. At 115K baud the UART data won't wait too long for attention.

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,743
    Try changing the beginning of serialEvent3 from this:
    Code:
    if(dfd.length()>9) dfd="";
    if(dfd.endsWith(endChar)) dfd="";
    if(Serial3.available())
    {
    dfd += char(Serial3.read());
    To this:
    Code:
      while(Serial3.available() > 0) {
        dfd += char(Serial3.read());
        if((dfd.length() > 9) || dfd.endsWith(endChar)) {
          dfd="";
        }
    There may be (many?) more than one character available, but you only handle one on each call to serialEvent3. This might speed things up by using "while" instead of "if" which will make it handle all available characters before returning from the function.
    The first two "if"s you had would be executed on every call to serialEvent but there's no point testing them every time. There can only be a change after you've added another character to dfd.

    A baud rate of 115K baud shouldn't be difficult for a 600MHz processor to handle unless you are doing a lot of processing that prevents yield() being called frequently enough. We can't tell if that is the case from the snippets you've posted.

    Pete
    [EDIT] I've just modified my code to use "while(Serial.available() > 0)" instead of "while(Serial.available())" just in case available can return a negative number as an indication of an error.
    Last edited by el_supremo; 08-15-2021 at 02:30 AM.

  11. #11
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,564
    Sorry,

    I have not fully followed everything in this thread.

    Hope you don't mind - I added the code tags to earlier post to make it easier to read.

    Simple notes and many have been mentioned. Like el_supremos comments about processing multiple characters.

    But the other half of this may also be with the TX side of things:
    That is if the code is doing a lot of: Serial3.print(....) which outputs a lot of data, such that it fills the default software queue, the Serial.print code will wait until there is room made available in the queue to complete the write, before it will return.
    So for example, the default queue size is I believe 40. So if you ask to output lets says 80 bytes, the code will wait for about 40 characters to be output over the serial port before the call will complete.... Actually probably about 35-36 bytes to transfer as per the hardware fifo...

    Note: the underlying code does call yield while waiting for queue space....

    Now if it is the case it is waiting for serial to output, you can always try increasing the size of the TX buffer. We added a method to serial to add a secondary buffer.

    So your setup code could have something like:

    // in global memory area...
    uint8_t serial3_extra_buffer[512];

    In setup:
    Serial3.addMemoryForWrite(serial3_extra_buffer, sizeof(serial3_extra_buffer));

    And see if that helps... Note: could put up in DMAMEM either by the keyword or malloc...

  12. #12
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    defragster….

    ok....I didn't know that serialevent was a routine.
    And yes....actually I have the same process in another much bigger program and my program works.
    is there any way to differentiate an RX from a TX.
    If in my serialevent I could differentiate RX from TX I think my program would work.
    Or if there is a way to make an interrupt on the RX only I think it would work too.

  13. #13
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    KurtE…..

    I am really not an expert in programming, what do you mean with…

    "Note: could put up in DMAMEM either by the keyword or malloc... "

    How to do that

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    25,060
    It's been a while since I've looked at the code, but my recollection is serialEvent() only gets called as data is received.

    Of course you can receive or transmit data from your serialEvent() function. But you should not expect serialEvent() to be called as the data you've previously transmitted with Serial3.write() or Serial3.print() is actually leaving the chip.

    We might be able to help you better if you would attempt to explain what you're trying to accomplish and tell us specifically what is not working. Often people make a mistake when asking technical questions where they only say what they believe is wrong, but they neglect to say specifically what behavior is actually observed. We can answer specific narrowly focused questions, like how serialEvent works, but without understanding what your program tries to do and without a clear picture of specifically what is going wrong, we can't do much to help resolve the larger problem.

  15. #15
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,564
    Quote Originally Posted by Ian Larouche View Post
    KurtE…..

    I am really not an expert in programming, what do you mean with…

    "Note: could put up in DMAMEM either by the keyword or malloc... "

    How to do that
    Remember the T4 (and the other T4.x) boards have a few memory sections as you can see on the product page:
    https://www.pjrc.com/store/teensy40.html#memory

    If you have a small program that is not using a lot of memory you don't need to worry about it at all. The default memory is the fastest memory on the chip.
    However there is whole other 512KB of memory on the board, which you can gain access through typically in two different ways:

    In the above you example I mentioned, you could change the memory defined like: DMAMEM uint8_t serial3_extra_buffer[512];
    And that variable will have an address in that other memory region. Note: things allocated like this can not be initialized. That is you can not do things like: DMAMEM char mystring[] = "ABCD";

    Another way you can use memory out of this region is using a memory allocate function like malloc or new

    like:

    Code:
    uint8_t *serial3_buffer;
    ...
    void setup() {
    ...
        serial3_buffer = (uint8_t *)malloc(512);
        Serial3.addMemoryForWrite(serial3_buffer, 512);
    ...
    Warning typed on the fly ... so probably typos... Also I would typically check to make sure malloc succeeded... That is did not return a null pointer.

  16. #16
    Junior Member
    Join Date
    Feb 2020
    Posts
    14
    Quote Originally Posted by KurtE View Post
    Remember the T4 (and the other T4.x) boards have a few memory sections as you can see on the product page:
    https://www.pjrc.com/store/teensy40.html#memory

    If you have a small program that is not using a lot of memory you don't need to worry about it at all. The default memory is the fastest memory on the chip.
    However there is whole other 512KB of memory on the board, which you can gain access through typically in two different ways:

    In the above you example I mentioned, you could change the memory defined like: DMAMEM uint8_t serial3_extra_buffer[512];
    And that variable will have an address in that other memory region. Note: things allocated like this can not be initialized. That is you can not do things like: DMAMEM char mystring[] = "ABCD";

    Another way you can use memory out of this region is using a memory allocate function like malloc or new

    like:

    Code:
    uint8_t *serial3_buffer;
    ...
    void setup() {
    ...
        serial3_buffer = (uint8_t *)malloc(512);
        Serial3.addMemoryForWrite(serial3_buffer, 512);
    ...
    Warning typed on the fly ... so probably typos... Also I would typically check to make sure malloc succeeded... That is did not return a null pointer.
    I tried this way and it works now.
    Thank you very much everyone for your help, it is really appreciated

Posting Permissions

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