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

Thread: Reading Pins in Parallel -- Teensy 4.1

  1. #1
    Junior Member
    Join Date
    Jun 2021
    Posts
    12

    Reading Pins in Parallel -- Teensy 4.1

    Hello,

    I am looking for a fast way to read the digital pins. While there is a thread that shows it can be done, what is the exact mapping on a Teensy 4.1 to do so? i.e If I want to read 8 (or 16 or whatever) pins at a time what are they called.

    (The thread is here: https://forum.pjrc.com/threads/58377...tomically-quot)

    I am not sure how to convert the Teensy 4.1 schematic into actual pin names.

    It appears it can be done something like this:

    register uint32_t data = IMXRT_GPIO6_DIRECT

    But what does IMXRT_GPIO6_DIRECT map to? What are the names for the other groups of pins and/or where do I look?

    Thanks!

  2. #2
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Quote Originally Posted by briuz View Post
    But what does IMXRT_GPIO6_DIRECT map to?
    That's a define in the code where you copied it from in the thread you linked.
    The thread answers your main question, too, I think.

    I'd suggest to read the reference manual, too.

  3. #3
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    I'd use digitalReadFast() wherever possible.
    Its more readable and not that much slower.

  4. #4
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    15,857
    As far as the schematic it shows on one side the Teensy pin number and on the other on the MCU end shows the port and 'bit' number within the port.

    Running this sketch github.com/TeensyUser/doc/tree/master/examples/GPIO/pinList may help as it shows like this:
    Code:
    PIN   GPIOn-BITm  |  GPIOn-BITm    PIN
    ------------------|-------------------
    00  -> GPIO6-03   |   GPIO6-02  ->  01
    01  -> GPIO6-02   |   GPIO6-03  ->  00
    02  -> GPIO9-04   |   GPIO6-12  ->  24
    03  -> GPIO9-05   |   GPIO6-13  ->  25
    ...
    > and on github.com/TeensyUser/doc/wiki there may be added info to find

    They are out of order based on supporting the historical pin function where possible. So sequential MCU Port Pins are distributed based on MCU functional support.

    Note: the PORT # on the schematic IIRC are the values for LOW SPEED pin operation, but on reset the pins are placed into HIGH speed mode that shifts the port numbers upwards with an offset that will then make sense when looking at example code. The Actual Port number and association will show running the above GPIO/pinList example code.

    There are other examples that may clarify the port reading of pins - this one perhaps:
    Simultaneously-reading-8-GPIO-pins

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    10,328
    Sometimes it is hard to give one total answer to a question like this, it often depends on your needs.

    That is how fast does it have to be... Teensy is pretty fast, so even simply simulating this with reading one pin at a time may be fast enough...

    How to read schematic and figure out the pins... Note: I don't typically start off from schematic to figure which pin is which, As for most of the newer boards, I started experimenting in either Alpha or Beta mode of the boards, where Paul already generated the pin table... So had to generate tables starting from that side... Then usually generate excel document with pin information in different orders.
    Which I usually keep up at: https://github.com/KurtE/TeensyDocuments

    One page for T4.1 looks like:
    Click image for larger version. 

Name:	screenshot.jpg 
Views:	28 
Size:	381.9 KB 
ID:	27255

    I have another page with the pins in GPIO pin order. Note: my pin numbers use the port numbers in normal speed (1-5) which translate 6-9 in Defragsters. I kept mine in lower as it matches the document.

    Now how from schematic: if you look at Pin 0 you see on schematic it is connected to AD_B0_03 on IMXRT .

    Now if you look in the IMXRT1060RM.pdf file (can download from product page)... And look probably easiest place is Chapter 11 (IOMUXC) and do a search for AD_B0_03 you will find
    the register IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_03 (P477 in the version of pdf I am looking at)
    You will see in Mux Mode 5: 101 ALT5 — Select mux mode: ALT5 mux port: GPIO1_IO03 of instance: gpio1
    So this pin is GPIO1 (or 6) and Pin 3 on it...

    And it shows you all of the other things this pin can do like for a Hardware Serial port: 010 ALT2 — Select mux mode: ALT2 mux port: LPUART6_RX of instance: lpuart6

    Different ways to read multiple pins at once: The core code has code to emulate some of the AVR port registers, like I think on early AVR Arduino boards PortD was pins 0-7. The Teensy code
    has classes to emulate this. If you look at ...\teensy4\avr_emulation.h about lines starting 512...
    Like: uint8_t pins = PIND;
    Which does:
    Code:
    	operator int () const __attribute__((always_inline)) {
    		int ret = 0;
    		if (digitalReadFast(0)) ret |= (1<<0);
    		if (digitalReadFast(1)) ret |= (1<<1);
    		if (digitalReadFast(2)) ret |= (1<<2);
    		if (digitalReadFast(3)) ret |= (1<<3);
    		if (digitalReadFast(4)) ret |= (1<<4);
    		if (digitalReadFast(5)) ret |= (1<<5);
    		if (digitalReadFast(6)) ret |= (1<<6);
    		if (digitalReadFast(7)) ret |= (1<<7);
    		return ret;
    	}
    You are obviously not restricted to these pins, you could create your own similar one...

    You can take the earlier stuff and find one of the ports that has enough pins for you and read in the whole register and depending on your needs, either just use them and/or manipulate the output, depending on needs.

    Again depending on why... there may be other solutions. Example simple camera inputs, like OV7670...
    We experimented with GPIO pins, with choosing ones that we could simple manipulation of the 32 bit values.
    We also on T4.1 experimented using the CSI interface for reading in 4 bits at a time.
    On Micromod we experimented with using FlexIO for this...

    Hope some of this helps

  6. #6
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Thank you all for the answers. I am going to look into what everyone posted and will report back soon. What I am trying to do is have the Teensy read 16 address pins and 8 data pins then respond on the data pins in under 250 ns. (I am basically attempting to race the bus on a 6502 chip running at almost 2 MHz.) I believe this may be possible if the pins are read in parallel.

  7. #7
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Quote Originally Posted by briuz View Post
    Thank you all for the answers. I am going to look into what everyone posted and will report back soon. What I am trying to do is have the Teensy read 16 address pins and 8 data pins then respond on the data pins in under 250 ns. (I am basically attempting to race the bus on a 6502 chip running at almost 2 MHz.) I believe this may be possible if the pins are read in parallel.
    That's hard.
    You must remember that
    a) the Teensy has some running interrupts.
    b) interrupts get globally disabled from time to time (and get served after that-> back to a)

    both can kill the needed timing completely. The few ns you save by reading parallel are neglegtible compared to that.
    You may have to disable the interrupts yourself - > you'll loose USB communication, the systick and much more.

    It'S probably more a job for a FPGA or other additional hardware.. (Adressdecoder etc...)

  8. #8
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by defragster View Post
    As far as the schematic it shows on one side the Teensy pin number and on the other on the MCU end shows the port and 'bit' number within the port.

    Running this sketch github.com/TeensyUser/doc/tree/master/examples/GPIO/pinList may help as it shows like this:
    Code:
    PIN   GPIOn-BITm  |  GPIOn-BITm    PIN
    ------------------|-------------------
    00  -> GPIO6-03   |   GPIO6-02  ->  01
    01  -> GPIO6-02   |   GPIO6-03  ->  00
    02  -> GPIO9-04   |   GPIO6-12  ->  24
    03  -> GPIO9-05   |   GPIO6-13  ->  25
    ...
    > and on github.com/TeensyUser/doc/wiki there may be added info to find

    They are out of order based on supporting the historical pin function where possible. So sequential MCU Port Pins are distributed based on MCU functional support.

    Note: the PORT # on the schematic IIRC are the values for LOW SPEED pin operation, but on reset the pins are placed into HIGH speed mode that shifts the port numbers upwards with an offset that will then make sense when looking at example code. The Actual Port number and association will show running the above GPIO/pinList example code.

    There are other examples that may clarify the port reading of pins - this one perhaps:
    Simultaneously-reading-8-GPIO-pins

    I ran the pinlist program and got this:

    PIN GPIOn-BITm | GPIOn-BITm PIN

    ------------------|-------------------

    00 -> GPIO6-03 | GPIO6-02 -> 01
    01 -> GPIO6-02 | GPIO6-03 -> 00
    02 -> GPIO9-04 | GPIO6-12 -> 24
    03 -> GPIO9-05 | GPIO6-13 -> 25
    04 -> GPIO9-06 | GPIO6-16 -> 19
    05 -> GPIO9-08 | GPIO6-17 -> 18
    06 -> GPIO7-10 | GPIO6-18 -> 14
    07 -> GPIO7-17 | GPIO6-19 -> 15
    08 -> GPIO7-16 | GPIO6-20 -> 40
    09 -> GPIO7-11 | GPIO6-21 -> 41
    10 -> GPIO7-00 | GPIO6-22 -> 17
    11 -> GPIO7-02 | GPIO6-23 -> 16
    12 -> GPIO7-01 | GPIO6-24 -> 22
    13 -> GPIO7-03 | GPIO6-25 -> 23
    14 -> GPIO6-18 | GPIO6-26 -> 20
    15 -> GPIO6-19 | GPIO6-27 -> 21
    16 -> GPIO6-23 | GPIO6-28 -> 38
    17 -> GPIO6-22 | GPIO6-29 -> 39
    18 -> GPIO6-17 | GPIO6-30 -> 26
    19 -> GPIO6-16 | GPIO6-31 -> 27
    20 -> GPIO6-26 | GPIO7-00 -> 10
    21 -> GPIO6-27 | GPIO7-01 -> 12
    22 -> GPIO6-24 | GPIO7-02 -> 11
    23 -> GPIO6-25 | GPIO7-03 -> 13
    24 -> GPIO6-12 | GPIO7-10 -> 06
    25 -> GPIO6-13 | GPIO7-11 -> 09
    26 -> GPIO6-30 | GPIO7-12 -> 32
    27 -> GPIO6-31 | GPIO7-16 -> 08
    28 -> GPIO8-18 | GPIO7-17 -> 07
    29 -> GPIO9-31 | GPIO7-18 -> 36
    30 -> GPIO8-23 | GPIO7-19 -> 37
    31 -> GPIO8-22 | GPIO7-28 -> 35
    32 -> GPIO7-12 | GPIO7-29 -> 34
    33 -> GPIO9-07 | GPIO8-12 -> 45
    34 -> GPIO7-29 | GPIO8-13 -> 44
    35 -> GPIO7-28 | GPIO8-14 -> 43
    36 -> GPIO7-18 | GPIO8-15 -> 42
    37 -> GPIO7-19 | GPIO8-16 -> 47
    38 -> GPIO6-28 | GPIO8-17 -> 46
    39 -> GPIO6-29 | GPIO8-18 -> 28
    40 -> GPIO6-20 | GPIO8-22 -> 31
    41 -> GPIO6-21 | GPIO8-23 -> 30
    42 -> GPIO8-15 | GPIO9-04 -> 02
    43 -> GPIO8-14 | GPIO9-05 -> 03
    44 -> GPIO8-13 | GPIO9-06 -> 04
    45 -> GPIO8-12 | GPIO9-07 -> 33
    46 -> GPIO8-17 | GPIO9-08 -> 05
    47 -> GPIO8-16 | GPIO9-22 -> 51
    48 -> GPIO9-24 | GPIO9-24 -> 48
    49 -> GPIO9-27 | GPIO9-25 -> 53
    50 -> GPIO9-28 | GPIO9-26 -> 52
    51 -> GPIO9-22 | GPIO9-27 -> 49
    52 -> GPIO9-26 | GPIO9-28 -> 50
    53 -> GPIO9-25 | GPIO9-29 -> 54
    54 -> GPIO9-29 | GPIO9-31 -> 29


    If I understand correctly, pin 27, for example is the left-most (highest) bit of GPIO6.

    The Teensy 4.1 schematic for pin 27 shows AD_B1_15. On page 503 of the reference manual (revision 3) mentioned by KurtE *AD_B1_15 lists GPIO1_IO31...which would also be GPIO6_IO31.

    So, given:

    register uint32_t data = IMXRT_GPIO6_DIRECT

    Pin 27 (digital) would be the 31st bit (or left-most bit) of (uint32_t)data above.


    Thanks!

  9. #9
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    here is a sorted by (GPIO groups) outtake from core_pins.h
    the core pins I assume is the pin number given to Teensy PCB
    then GPIOx_DR is the data register
    there is also
    GPIOx_DR_SET, GPIOx_DR_CLEAR, GPIOx_DR_TOGGLE
    GPIOx_GDIR, GPIOx_PSR

    Code:
    #define CORE_PIN1_PORTREG	GPIO6_DR 2
    #define CORE_PIN0_PORTREG	GPIO6_DR 3
    #define CORE_PIN24_PORTREG	GPIO6_DR 12
    #define CORE_PIN25_PORTREG	GPIO6_DR 13
    
    // here is one continuous block of 16 bits
    // should be able to read like this
    // uint16_t addr= (GPIO6_DR & 0xFF00) / 256;
    
    #define CORE_PIN19_PORTREG	GPIO6_DR 16  0
    #define CORE_PIN18_PORTREG	GPIO6_DR 17  1
    #define CORE_PIN14_PORTREG	GPIO6_DR 18  2
    #define CORE_PIN15_PORTREG	GPIO6_DR 19  3
    #define CORE_PIN40_PORTREG	GPIO6_DR 20  4
    #define CORE_PIN41_PORTREG	GPIO6_DR 21  5
    #define CORE_PIN17_PORTREG	GPIO6_DR 22  6
    #define CORE_PIN16_PORTREG	GPIO6_DR 23  7 
    #define CORE_PIN22_PORTREG	GPIO6_DR 24  8
    #define CORE_PIN23_PORTREG	GPIO6_DR 25  9
    #define CORE_PIN20_PORTREG	GPIO6_DR 26  10
    #define CORE_PIN21_PORTREG	GPIO6_DR 27  11
    #define CORE_PIN38_PORTREG	GPIO6_DR 28  12
    #define CORE_PIN39_PORTREG	GPIO6_DR 29  13
    #define CORE_PIN26_PORTREG	GPIO6_DR 30  14
    #define CORE_PIN27_PORTREG	GPIO6_DR 31  15
    
    // by the looks of it there are not any continuous block of 8 bits
    
    #define CORE_PIN10_PORTREG	GPIO7_DR 0
    #define CORE_PIN12_PORTREG	GPIO7_DR 1
    #define CORE_PIN11_PORTREG	GPIO7_DR 2
    #define CORE_PIN13_PORTREG	GPIO7_DR 3
    #define CORE_PIN6_PORTREG	GPIO7_DR 10
    #define CORE_PIN9_PORTREG	GPIO7_DR 11
    #define CORE_PIN32_PORTREG	GPIO7_DR 12
    #define CORE_PIN8_PORTREG	GPIO7_DR 16
    #define CORE_PIN7_PORTREG	GPIO7_DR 17
    #define CORE_PIN36_PORTREG	GPIO7_DR 18
    #define CORE_PIN37_PORTREG	GPIO7_DR 19
    #define CORE_PIN35_PORTREG	GPIO7_DR 28
    #define CORE_PIN34_PORTREG	GPIO7_DR 29
    
    #define CORE_PIN45_PORTREG	GPIO8_DR 12
    #define CORE_PIN44_PORTREG	GPIO8_DR 13
    #define CORE_PIN43_PORTREG	GPIO8_DR 14
    #define CORE_PIN42_PORTREG	GPIO8_DR 15
    #define CORE_PIN47_PORTREG	GPIO8_DR 16
    #define CORE_PIN46_PORTREG	GPIO8_DR 17
    #define CORE_PIN28_PORTREG	GPIO8_DR 18
    #define CORE_PIN31_PORTREG	GPIO8_DR 22
    #define CORE_PIN30_PORTREG	GPIO8_DR 23
    
    #define CORE_PIN2_PORTREG	GPIO9_DR 4
    #define CORE_PIN3_PORTREG	GPIO9_DR 5
    #define CORE_PIN4_PORTREG	GPIO9_DR 6
    #define CORE_PIN33_PORTREG	GPIO9_DR 7
    #define CORE_PIN5_PORTREG	GPIO9_DR 8
    #define CORE_PIN51_PORTREG	GPIO9_DR 22
    #define CORE_PIN48_PORTREG	GPIO9_DR 24
    #define CORE_PIN53_PORTREG	GPIO9_DR 25
    #define CORE_PIN52_PORTREG	GPIO9_DR 26
    #define CORE_PIN49_PORTREG	GPIO9_DR 27
    #define CORE_PIN50_PORTREG	GPIO9_DR 28
    #define CORE_PIN54_PORTREG	GPIO9_DR 29
    #define CORE_PIN29_PORTREG	GPIO9_DR 31
    as you read in the comments above there is not additional 8 bits continuous
    but that can easily be solved by multiplexing the address and data using 3x 74hc245
    but think this approach will be the fastest possible

    Click image for larger version. 

Name:	multiplexing_addr_data.png 
Views:	20 
Size:	18.8 KB 
ID:	27260

  10. #10
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    also need to mention that you have to use the
    GPIO6_GDIR to set the data directions
    i.e.
    GPIO6_GDIR &= 0x00FF; // to set pins to inputs (bit16-31)
    GPIO6_GDIR |= 0xFF00; // to set pins to outputs (bit16-31)

    and to mention that by reading the datasheet
    GPIO6_DR is used to write data to the port
    GPIO6_PSR is used to read data from the port
    i.e.
    // reading data
    uint16_t data = (GPIO6_PSR & 0xFF00) >> 16;
    // writing data (and preserve other pins data)
    GPIO6_DR = (GPIO6_DR & 0x00FF) | (data << 16);

  11. #11
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    10,328
    Other options for speed or timing may include DMA.

    Side notes with DMA is it does not work with pin in High speed mode, you have to switch them back to normal... GPIO1 instead of 6...
    More about that in other threads...

  12. #12
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by manicksan View Post
    also need to mention that you have to use the
    GPIO6_GDIR to set the data directions
    i.e.
    GPIO6_GDIR &= 0x00FF; // to set pins to inputs (bit16-31)
    GPIO6_GDIR |= 0xFF00; // to set pins to outputs (bit16-31)

    and to mention that by reading the datasheet
    GPIO6_DR is used to write data to the port
    GPIO6_PSR is used to read data from the port
    i.e.
    // reading data
    uint16_t data = (GPIO6_PSR & 0xFF00) >> 16;
    // writing data (and preserve other pins data)
    GPIO6_DR = (GPIO6_DR & 0x00FF) | (data << 16);
    I was thinking I could still set the data directions with the normal pinMode() function???

  13. #13
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    Quote Originally Posted by briuz View Post
    I was thinking I could still set the data directions with the normal pinMode() function???
    yes but that would be very slow, specially if you want to write data back to the 6502 bus
    and why not use the GDIR directly, there is no problems doing so.

  14. #14
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    You'll need additional leveshifters.

  15. #15
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by manicksan View Post
    yes but that would be very slow, specially if you want to write data back to the 6502 bus
    and why not use the GDIR directly, there is no problems doing so.
    Good point. The data line level shifters will need to be flipped quickly. Thanks for pointing it out.

  16. #16
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by Frank B View Post
    You'll need additional leveshifters.
    I've got 5 level shifters. 2 set for input to the Teensy for the address lines, 1 set for the data lines and the direction can be controlled by the Teensy, and 1 set to input to the Teensy for certain signals (such as Phi2), and 1 more that has both a chip select and direction that can be controlled by the Teensy for some other lines.

    What I screwed up on, in retrospect, is I should have figured on arranging the connections as per the GPIO0x pin registers(?) as opposed to what made the most sense by the physical wiring. But there are a couple other mistakes on the board and I have it hacked to work. I am hoping to at least prove the concept with this board then get a board made using all the lessons I learned.

  17. #17
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    606
    I did this, nice that almost all the pins are on one side
    Click image for larger version. 

Name:	GPIO6_mapping16bits.png 
Views:	16 
Size:	102.9 KB 
ID:	27261

  18. #18
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by Frank B View Post
    That's hard.
    You must remember that
    a) the Teensy has some running interrupts.
    b) interrupts get globally disabled from time to time (and get served after that-> back to a)

    both can kill the needed timing completely. The few ns you save by reading parallel are neglegtible compared to that.
    You may have to disable the interrupts yourself - > you'll loose USB communication, the systick and much more.

    It'S probably more a job for a FPGA or other additional hardware.. (Adressdecoder etc...)
    I wasn't thinking about the interrupts...

    Many times this is done by an FPGA but somebody created a cartridge called the UNO Cart that uses a micro controller.

    I was originally thinking of having the Teensy manage a parallel SRAM chip that was loaded by the Teensy but then decided to try a Teensy alone as someone else got a micro-controller to race the bus in a project called "UNO Cart".

  19. #19
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by manicksan View Post
    I did this, nice that almost all the pins are on one side
    Click image for larger version. 

Name:	GPIO6_mapping16bits.png 
Views:	16 
Size:	102.9 KB 
ID:	27261
    Perfect! That looks something like what I'd end up with.

    I am concerned now about interrupts as I was was planning on eventually using the USB communication too.

  20. #20
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by Frank B View Post
    That's hard.
    You must remember that
    a) the Teensy has some running interrupts.
    b) interrupts get globally disabled from time to time (and get served after that-> back to a)

    both can kill the needed timing completely. The few ns you save by reading parallel are neglegtible compared to that.
    You may have to disable the interrupts yourself - > you'll loose USB communication, the systick and much more.

    It'S probably more a job for a FPGA or other additional hardware.. (Adressdecoder etc...)


    Maybe use a CPLD and a memory chip with the Teensy on the back-end to load and save from SD cards, load other memory features, etc.

  21. #21
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Might be still possible without, with some careful planning...

  22. #22
    Senior Member
    Join Date
    Apr 2014
    Location
    -
    Posts
    9,756
    Another aproach would be to emulate the 6502+RAM on the Teensy So, all timing would be in your hand, you could still use the rest of the hardware...

  23. #23
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Quote Originally Posted by Frank B View Post
    Another aproach would be to emulate the 6502+RAM on the Teensy So, all timing would be in your hand, you could still use the rest of the hardware...
    I've seen where that was done. But it wouldn't be a good idea in this case.

  24. #24
    Junior Member
    Join Date
    Jun 2021
    Posts
    12
    Thanks for the great support! I decided to do things differently and include memory and a CPLD as well as a Teensy 4.1. The CPLD will decode and act as a register so the 6502 can communicate with the Teensy. I'll solve the loading and interfacing issues with software. I will, however, read the pins in parallel, like we discussed in this thread, so as to speed up communication.

Posting Permissions

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