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

Thread: Strange GPIO Port Behaviour

  1. #1
    Junior Member
    Join Date
    Jun 2019
    Posts
    10

    Strange GPIO Port Behaviour (Teensy 3.6)

    Hi all.

    I am working on some code that reads a 16 bit address using 16 of the GPIO pins. I want these reads to be fast and as close to atomic as possible, therefore I am using the GPIO ports directly. However, when I read the address bits from the ports I get different results than if I use digitalReadFast for each pin and shift the bits.

    Using this great post as a guide https://forum.pjrc.com/threads/17532...PIO_PDIR-_PDOR along with the code documentation in core_pins.h I have chosen GPIO port C for the first 12 bits of the address and port B for the highest 4 bits. This is nice because the bits for the ranges I mention are contiguous, and makes read/write code fairly simple.

    Here is how I am testing this (currently only testing first 12 bits from port C):

    Code:
    // A0 - A11 maps to GPIO port C (bits 0 - 11) . A12 - A15 maps to GPIO port B (bits 0 - 3)
    #define A0  15
    #define A1  22
    #define A2  23
    #define A3  9
    #define A4  10
    #define A5  13
    #define A6  11
    #define A7  12
    #define A8  28
    #define A9  27
    #define A10 29
    #define A11 30
    #define A12 16
    #define A13 17
    #define A14 19
    #define A15 18
    
    static inline void setAddressMode(uint8_t mode)
    {
      pinMode(A0, mode);
      pinMode(A1, mode);
      // ... do this for all the pins
    }
    
    // traditional address access
    static inline uint16_t getAddr()
    {
      uint16_t addr = 0;
      addr |= (digitalReadFast(A0));
      addr |= (digitalReadFast(A1) << 1);
      addr |= (digitalReadFast(A2) << 2);
      addr |= (digitalReadFast(A3) << 3);
      addr |= (digitalReadFast(A4) << 4);
      addr |= (digitalReadFast(A5) << 5);
      addr |= (digitalReadFast(A6) << 6);
      addr |= (digitalReadFast(A7) << 7);
      addr |= (digitalReadFast(A8) << 8);
      addr |= (digitalReadFast(A9) << 9);
      addr |= (digitalReadFast(A10) << 10);
      addr |= (digitalReadFast(A11) << 11);
    
      //addr |= (digitalReadFast(A12) << 12);
      //addr |= (digitalReadFast(A13) << 13);
      //addr |= (digitalReadFast(A14) << 14);
      //addr |= (digitalReadFast(A15) << 15);
    
      return addr;
    }
    
    void setup()
    {
      setAddressMode(INPUT);  // set A0 - A15 to INPUT
      Serial.begin(250000);
    }
    
    void loop()
    {
      Serial.begin(250000);
      while (1)
      {
        // currently just testing the lower 12 bits from the c register
        uint32_t cPortInput = GPIOC_PDIR;
        uint16_t addr = getAddr();
    
        Serial.println(addr, BIN);
        Serial.println(cPortInput , BIN);
        Serial.println("x");
      }
      Serial.end();
    }
    With the above code, I get the following output:

    100001101
    1101
    x
    100011110
    11110
    x



    I am really not sure how this can be. A8 is clearly high active when using the traditional method, but it is low when reading the C port register directly. I would expect the cPortInput to match addr exactly in this test condition.

    Would love to hear thoughts and suggestions.

    Thanks.
    Last edited by KurtE; 09-10-2020 at 06:04 PM. Reason: code tag

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,917
    Might help to know what Teensy you are trying this on?

  3. #3
    Junior Member
    Join Date
    Jun 2019
    Posts
    10
    Sorry that's my bad, tagged the page but forgot to put it in the title (updated).

    Testing on a 3.6.

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,917
    If that is really the code you are running, I wonder about:
    Code:
    static inline void setAddressMode(uint8_t mode)
    {
      pinMode(A0, mode);
      pinMode(A1, mode);
      // ... do this for all the pins
    }
    Did you do it for all the pins?

  5. #5
    Junior Member
    Join Date
    Jun 2019
    Posts
    10
    Quote Originally Posted by KurtE View Post
    If that is really the code you are running, I wonder about:
    Code:
    static inline void setAddressMode(uint8_t mode)
    {
      pinMode(A0, mode);
      pinMode(A1, mode);
      // ... do this for all the pins
    }
    Did you do it for all the pins?
    Yep, all pins. Code omitted for brevity. I've triple checked that code and I know its all good. The fact that getAddr works as intended is proof of that.

    I just don't get what I am seeing when I print the register directly.

  6. #6
    The Arduino style pin names A0- map to Teensy ports in strange ways. From the schematic they appear spread across all of the GPIO ports. Certainly not all on GPIOC.

  7. #7
    Junior Member
    Join Date
    Jun 2019
    Posts
    10
    Thanks for the reply, but I am fully aware of this. If you look at my code you can see that I am using all pins from the c register, apart from the last 4 bit, but I am not testing those in this code.

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,049
    Quote Originally Posted by Jay8ee View Post
    Code omitted for brevity.
    Please do not omit code.

    In trying to make reading your code easier, you're erecting a huge barrier for any of us to *run* your code.

  9. #9
    Senior Member
    Join Date
    Aug 2013
    Location
    Gothenburg, Sweden
    Posts
    336
    Teensy 3.2 and 3.6 have different mappings for PTC8. According to the schematics at https://www.pjrc.com/teensy/schematic.html

    On 3.2 PTC8 is indeed Arduino pin 28
    On 3.6 PTC8 is mapped to Arduino pin number 35, and pin 28 is connected to PTA16

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    7,917
    The problem is your data pin numbers are WRONG...
    This one works...
    Code:
    // A0 - A11 maps to GPIO port C (bits 0 - 11) . A12 - A15 maps to GPIO port B (bits 0 - 3)
    #define A0  15  // C0
    #define A1  22  // c1
    #define A2  23  //c2
    #define A3  9   // C3
    #define A4  10  // C4
    #define A5  13  // C5
    #define A6  11  //C6
    #define A7  12  // C7
    #define A8  35  // C8 28 A16
    #define A9  36  // C9   27 A15
    #define A10 37  // C10  29
    #define A11 38  // C11 30
    #define A12 16
    #define A13 17
    #define A14 19
    #define A15 18
    
    static inline void setAddressMode(uint8_t mode)
    {
      pinMode(A0, mode);
      pinMode(A1, mode);
      pinMode(A2, mode);
      pinMode(A3, mode);
      pinMode(A4, mode);
      pinMode(A5, mode);
      pinMode(A6, mode);
      pinMode(A7, mode);
      pinMode(A8, mode);
      pinMode(A9, mode);
      pinMode(A10, mode);
      pinMode(A11, mode);
      // ... do this for all the pins
    }
    
    // traditional address access
    static inline uint16_t getAddr()
    {
      uint16_t addr = 0;
      addr |= (digitalReadFast(A0));
      addr |= (digitalReadFast(A1) << 1);
      addr |= (digitalReadFast(A2) << 2);
      addr |= (digitalReadFast(A3) << 3);
      addr |= (digitalReadFast(A4) << 4);
      addr |= (digitalReadFast(A5) << 5);
      addr |= (digitalReadFast(A6) << 6);
      addr |= (digitalReadFast(A7) << 7);
      addr |= (digitalReadFast(A8) << 8);
      addr |= (digitalReadFast(A9) << 9);
      addr |= (digitalReadFast(A10) << 10);
      addr |= (digitalReadFast(A11) << 11);
    
      //addr |= (digitalReadFast(A12) << 12);
      //addr |= (digitalReadFast(A13) << 13);
      //addr |= (digitalReadFast(A14) << 14);
      //addr |= (digitalReadFast(A15) << 15);
    
      return addr;
    }
    
    void setup()
    {
      setAddressMode(INPUT_PULLDOWN);  // set A0 - A15 to INPUT
      Serial.begin(250000);
    }
    
    void loop()
    {
      Serial.begin(250000);
      while (1)
      {
        // currently just testing the lower 12 bits from the c register
        uint32_t cPortInput = GPIOC_PDIR;
        uint16_t addr = getAddr();
    
        Serial.println(addr, BIN);
        Serial.println(cPortInput , BIN);
        Serial.println("x");
        delay(100);
      }
      Serial.end();
    }
    Note: I used INPUT_PULLDOWN as I did not have anything attached to pins, so did not want them floating...

    Here is off one of my Excel document pages:
    Click image for larger version. 

Name:	screenshot.jpg 
Views:	15 
Size:	113.5 KB 
ID:	21690

  11. #11
    Junior Member
    Join Date
    Jun 2019
    Posts
    10
    Thanks, working as expected with those changes.

    Also, that excel is great. Thanks for sharing.

Tags for this Thread

Posting Permissions

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