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

Thread: T4.0 Hardware Serial Questions: FIFOs & Buffer Sizes, etc.

  1. #1

    T4.0 Hardware Serial Questions: FIFOs & Buffer Sizes, etc.

    Hi! I have some noob-ish questions about the Teensy 4.0 UARTS and the associated hardwareserial.cpp code.

    HW Configuration
    Multiple, identical custom PCBs using Teensy 4.0 as an MCU module, all connected with a RS-485 serial bus using a custom protocol (some similarities to DMX-512).
    One board is configured as a bus master, the rest are receive-only slaves. I'm using this RS-485 transceiver (https://www.maxlinear.com/ds/sp3070e-sp3078e.pdf) which supports up to 128 nodes. Here's a photo of the board (just to make this post more visually interesting):
    Click image for larger version. 

Name:	IMG_0622.jpg 
Views:	10 
Size:	197.8 KB 
ID:	19873

    Operational Concept
    The master will transmit a small number of variable-length packets at a fixed cycle rate of 33 Hz (~30ms). The slaves will use the receive time of the first byte of the first packet in a cycle to synchronize their processing. The target data rate is 250 Kbps (40 us per byte). The master will cap the per-cycle transmit data quantity at about 380 bytes, which takes about 15ms or half of the cycle time. The slave devices will use the "sync" condition (1st byte received) to trigger their time-critical processing, and after that's done they will read and process the serial data received during that cycle. That's non-time-critical, as long as they finish before the start of the next cycle. This data is used to configure the synchronous processing in the following cycle.

    Hardware Questions
    I've seen conflicting information about the hardware buffers/FIFOs supported by the T4 processor. The RT1060 family reference manual seems to say that all 8 of the UARTs have only a 1 byte receive buffer, but elsewhere I've see multiple people say that two of the UARTs have a 4-byte FIFO (or 8-byte). That's somewhat important to me, as it relates to the software questions below. Which is correct?

    Software Questions
    I'd like to use Serial.available() to poll for the sync condition, but defer reading any of the data (other than maybe the first one or two bytes) until later in the cycle. The implies that the software receive buffer in hardwareserial.cpp must be at least 380 bytes. If I'm looking at the correct version on GitHub ( don't know where to find the version #), it looks like the receive buffer is hardcoded to 64 bytes.

    I've see other posts talking about modifying hardwareserial.cpp to change the buffer sizes, but I had a hard time following the discussion and recommendations. Can someone please lay it out for me a little more clearly (assuming this is a reasonable thing to do)? It may be a little more challenging because I'm using Visual Studio Code with PlatformIO (MacOS), not the normal Arduino IDE. Also, I'm I'm not very familiar with C++ (only C) or the details of the board-specific build process.

    If it's correct that the T4 UARTs have a 1-deep receive buffer, I assume that Serial.available() will return a non-zero value pretty much immediately upon receipt of the first byte. Is that correct? But...if it DID have a deeper FIFO, is it true that an interrupt wouldn't be triggered until the FIFO was full, or at some (configurable?) high-water mark? And then, is there a configurable IDLE timeout that will trigger in interrupt even if the high-water mark isn't reached? Just curious.

    I'm also curious why the rx/tx buffer sizes aren't configurable except by re-compiling. This seems like a reasonable parameter for Serial.begin() or something similar. Not whining.

    Sorry for being long-winded. Thanks for any help you can provide.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,011
    Quote Originally Posted by Aerokeith View Post
    I've seen conflicting information about the hardware buffers/FIFOs supported by the T4 processor. The RT1060 family reference manual seems to say that all 8 of the UARTs have only a 1 byte receive buffer, but elsewhere I've see multiple people say that two of the UARTs have a 4-byte FIFO (or 8-byte). That's somewhat important to me, as it relates to the software questions below. Which is correct?
    All the serial ports have 4 byte FIFO.


    I'm also curious why the rx/tx buffer sizes aren't configurable except by re-compiling.
    Partly because the API to configure them was proposed but never fully decided by Arduino. But mostly because nobody has put the time into making it runtime configurable (as still efficient).

  3. #3
    Hi Paul! Thanks very much for responding so quickly. I understand that you're very busy, so hopefully some other forum members can fill in the rest of the details.

    4-byte FIFO's are good as long as I can confirm when interrupts will occur as a function of FIFO fill level (or IDLE period). If Serial.available() doesn't report any received data until the 4th byte, that's fine as long as it's repeatable.

    Just out of curiosity, maybe someone can point out to me how I mis-read the processor reference manual. I see no mention of FIFOs (maybe it's wrong?).

    FYI, so far I really like the T4 and the strong community behind it. I just switched from the Sparkfun Pro Micro, and I plan to stick with the T4 (and successors) for a long time.

  4. #4
    Senior Member
    Join Date
    Sep 2015
    Posts
    108
    There's an addStorageForRead() method on the HW serial ports which looked like it was appending onto the incoming buffer, but maybe it's not implemented, or Paul probably would have mentioned it?
    Last edited by ecurtz; 04-27-2020 at 03:44 AM. Reason: Paul replied with better info

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,011
    Quote Originally Posted by Aerokeith View Post
    Just out of curiosity, maybe someone can point out to me how I mis-read the processor reference manual. I see no mention of FIFOs (maybe it's wrong?).
    NXP's reference manual can be quite a challenge to read.

    Here are key parts about the UART FIFOs.

    page 2834:
    Click image for larger version. 

Name:	fifo1.png 
Views:	18 
Size:	86.8 KB 
ID:	19874

    page 2856:
    Click image for larger version. 

Name:	fifo2.png 
Views:	16 
Size:	39.7 KB 
ID:	19875

    Also see the documentation about the FIFO control registers, on pages 2874 to 2879 (in Rev 2, 12/2019 - the page numbers change in each rev)

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    12,675
    Not sure if the 'protocol' to be used has a STOP state and transition like UART Serial.

    I posted code some time back - enabling an interrupt on the STOP>START transition. The interrupt disables itself {so it doesn't trigger on data bits } and records the time - this was a GPS message ideally to sync time.

    The message can be received/processed and the interrupt enabled before the next start time as described to be ready to the next cycle.

    That would eliminate the need for polling and give relatively consistent results

    Looking at sources there is code like this: { ..\hardware\teensy\avr\cores\teensy4\HardwareSeria l1.cpp }
    Code:
    #ifndef SERIAL1_TX_BUFFER_SIZE
    #define SERIAL1_TX_BUFFER_SIZE     64 // number of outgoing bytes to buffer
    #endif
    #ifndef SERIAL1_RX_BUFFER_SIZE
    #define SERIAL1_RX_BUFFER_SIZE     64 // number of incoming bytes to buffer
    #endif
    So if during the build those items are 'defined' with alternate values in advance they will be used.

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,890
    Quote Originally Posted by ecurtz View Post
    There's an addStorageForRead() method on the HW serial ports which looked like it was appending onto the incoming buffer, but maybe it's not implemented, or Paul probably would have mentioned it?
    Actually this is implemented for T4 (and T4.1), but not for T3.x and LC.... Actually I had a version (https://github.com/KurtE/cores/tree/unified-serial) for these that like the T4 used one class to do this, but we never integrated it in... But I then started from that for the T4 version.

  8. #8
    Thanks everyone! It sounds like there are two different methods to expand the RX buffer size:

    1. #define SERIAL1_RX_BUFFER_SIZE <Size> before the #include "hardwareserial1.h"

    2. Call Serial1.addStorageForRead(&buffer, bufLength)

    The second method sounds more straightforward, so I'll try that first.

    Mystery solved on the NXP manual: Paul quoted from Rev 2 and I was looking at Rev 1 (which doesn't say anything about the FIFOs). Both revs are on the PJRC site, but I was using an (outdated) link from Sparkfun, where I purchased my first Teensy 4.0.

    So I'm happy I don't have to recompile any libraries. I think I'm good to go!

  9. #9
    Thanks for the suggestion on synchronization (and on the buffer size). Sounds like the interrupt approach would work for me, but I don't need that level of timing accuracy. Also, the slaves will have nothing else left to do at the end of a cycle, so polling isn't a problem. But I'll keep it on mind in case this doesn't work out...

Posting Permissions

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