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

Thread: 7-bit support seems to be missing on Teensy 4

  1. #1
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528

    7-bit support seems to be missing on Teensy 4

    Received 7-bit serial data on Teensy 4 sometimes has the top bit set.

    Issue: https://github.com/PaulStoffregen/cores/issues/664
    PR: https://github.com/PaulStoffregen/cores/issues/665

  2. #2
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    It turns out that without the fix, the transmit properly sends 7-bit data, but receive still sometimes sets the 8th bit high. I need to explore more.

  3. #3
    Senior Member
    Join Date
    Feb 2015
    Location
    Finland
    Posts
    287
    I haven't checked any details (even checked the manual), but could it be related to parity checking?
    Even in no-parity modes, there could be some register flag that causes the 8th bit to be used for something similar, like framing error or such, that needs to be configured/disabled differently for 7-bit serial.

    (I'm pretty sure you are well aware of this and I'm providing nothing useful here, but I had to post just in case you hadn't thought of it yet.)

  4. #4
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    Thank you for adding that. I think it's important information to think about if one doesn't know much about the serial ports.

  5. #5
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    On my journey to understanding this better — It's been a while since I've explored this in depth (for TeensyDMX) — I think I'm re-discovering that the "data" includes everything but the start and stop bits. This means that my proposed solution, setting M7, will really cause a 6-bit data byte if there's parity. If I'm right, then my solution isn't correct. I'm closer...

  6. #6
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    @Nominal Animal I think you're right about that top bit being the parity bit. Since the serial bit stream comes in with the least significant bit first, that top bit is the last bit, which is the 8th bit in a 7-bit parity-checked format. My received data confirms this. Now onto a fix...

  7. #7
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    Okay, I think I got it. There has to be an appropriate mask depending on the mode. I updated the PR.

  8. #8
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    The same problem, I believe, exists in teensy3. I'll update the PR.

  9. #9
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    11,158
    Note: In all cases like this, it would help if showed a small sketch showing what you are trying to do:

    For example, what are you calling: SerialX.begin(...) with?

    That is, the 7-bit support that is in Teensyduino, currently always sends and receives 8 bits.
    Code:
    #define SERIAL_7E1 0x02
    #define SERIAL_7O1 0x03
    Following the standard of the 8th bit is the parity bit. Which is either Evan or Odd.
    We have the same Symbolic define as Arduino shows in https://www.arduino.cc/reference/en/.../serial/begin/

    They do have other defines that we do not have nor have we implemented.
    For example they do have do have defined, things like:
    Code:
    SERIAL_5N1
    SERIAL_6N1
    SERIAL_7N1
    Which probably the last one is what you are looking for.

    I did not look completely through your PR, but what I would expect the code to do would be, for example in the T4.x code base:
    Define: Serial_7N1 and figure out a bit for it.

    Do not change the functionality of SERIAL_7E1 or SERIAL_7O1 as they are doing what they should be doing. That is sending 8 bits with parity in upper bit.

    Instead, the code needs to change the configuration to be in 7 bit mode.
    On the Teensy 4.x you would change the LPUART Control Register (CTRL) section 49.4.1.8 Page 2865
    Look at the bit labeled: M7
    This bit is also defined in imxrt.h : #define LPUART_CTRL_M7 ((uint32_t)(1<<11))

    Setting this bit Should convert the UART to sending and receiving 7 bits. You should not have to muck with the data going in and out of the FIFO queues.

    I have not looked at the T3.x reference manuals, but I would expect similar bit defined somewhere. Assuming they support 7 bit mode.

    Hope that helps

  10. #10
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    528
    Here's a summary of what the issue was:

    Serial.read() was returning some bytes with the high bit set. It turns out that this was the parity bit. I modified the PR a short time ago to do these things:
    1. Define a mask that gets set to 0x7f if the mode is SERIAL_7E1 or SERIAL_7O1.
    2. Upon data reception, the byte is AND'ed with the appropriate mask: the 7-bit one or the default one.
    3. In an older version of the PR, I also AND'ed the output. It turns out I didn't need to do that so I removed that part. Only the received bytes need to be AND'ed with the mask.
    4. Note: I'm using a mask variable instead of if's everywhere to avoid branching if testing for 7-bit mode all the time because I think that's a little faster.

    Notes:
    In the UART and LPUART chip specs, the "data byte" includes everything except the start and stop bits. That means parity is also included in that byte. So technically, that M7 bit, if using parity, will cause a 6-bit byte plus a parity bit. i.e. setting M7 is the wrong thing to do here.

    I'm happy with the PR, so it's ready for review: https://github.com/PaulStoffregen/cores/issues/665

    Here's some simple test code:
    Code:
    void setup() {
      Serial.begin(115200);
      while (!Serial && millis() < 4000) {
        // Wait for Serial
      }
    
      Serial5.begin(19200, SERIAL_7E1);
    }
    
    void loop() {
      int c = Serial5.read();
      if (c >= 0) {
        // c &= 0x7f;  // <-- This line is needed without the fixes
        Serial.printf("c = %02xh\r\n", c);
      }
    }
    I've tested this with a 7E1 device with both a Teensy 3.2 and a Teensy 4.1. The fixes in the PR work for me and the code does not work as expected if I remove those fixes. i.e. some received bytes will have the high bit set; the value of this bit is always exactly what the parity should be.

Posting Permissions

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