PDA

View Full Version : Tutorial on digital I/O, ATMega PIN/PORT/DDR D/B registers vs. ARM GPIO_PDIR / _PDOR



immortalSpirit
01-31-2013, 05:06 PM
Tutorial on digital I/O, ATMega PIN/PORT/DDR D/B registers vs. ARM GPIO_PDIR / _PDOR A/B/C/D/E registers!

OR, "How to get a fast 8-bit-wide digital read/write!"

I spent the evening figuring this out so I'd like to pass it on to you if u r interested.

My mission: read/write 8 digital I/O pins simultaneously and as fast as possible. I don't care WHICH 8 pins, I just need 8 pins. And I need *fast*.

On the ATMega based Arduino, I used PIND and PORTD, which are each 8 bit registers which read and write pins 0,1,2,3,4,5,6 and 7 packed into a single byte.

On TEENSY-3, the emulation code for PIND and PORTD is very inefficient. Indeed, it is basically 8 digital reads. The code (in avr_emulation.h) basically looks like this:

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;

That is 8 digitalReadFast's, plus 8 IFs and ORs.

The reason for this is that the actual bits corresponding to the TEENSY-3 pins are scrambled in their order. And therein lies a tale!

After a bunch of reading the "K20 Sub-Family Reference Manual" and studying the TEENSY-3 schematics, it somehow makes sense!

The ARM core has 5 registers much like the ATMel PIN/PORT registers. They are GPIOA, GPIOB, GPIOC, GPIOD, and GPIOE. Each of these supports up to 32 pins. They are *extremely* programmable, and can be mapped in whole or in part to various functions and various pins on the ARM chip.

The TEENSY 3.0 software apparently sets them up as follows:

(where: X = TEENSY-3 external pin number, Y = which GPIO port that reads and writes it, and Z = which bit of that port reads and writes it)

X Y Z
---------------
3 A 12
4 A 13
24 A 5
33 A 4
0 B 16
1 B 17
16 B 0
17 B 1
18 B 3
19 B 2
25 B 19
32 B 18
9 C 3
10 C 4
11 C 6
12 C 7
13 C 5
15 C 0
22 C 1
23 C 2
27 C 9
28 C 8
29 C 10
30 C 11
2 D 0
5 D 7
6 D 4
7 D 2
8 D 3
14 D 1
20 D 5
21 D 6
26 E 1
31 E 0

That's confusing. I'll explain the first four lines:

3 A 12
4 A 13
24 A 5
33 A 4

These say that:
GPIOA bit 12 is connected to pin 3 on the TEENSY-3 circuit board,
GPIOA bit 13 is connected to pin 4,
GPIOA bit 5 is connected to pin 24 (which is on the backside of the board), and
GPIOA bit 4 is connected to pin 33 (also on the backside of the board).

And the 5th line,
0 B 16

says that GPIOB bit 16 connects to pin 0 on the TEENSY-3.

In other words, we are using only 4 of the possible 32 bits of GPIOA, and they are connected to 4 pins of the TEENSY-3, and in scrambled order! In similar manner, GPIOB has 6 of its bits (16,17,0,1,3,2,19 and 18) connected to 6 of the TEENSY-3 external pins (0,1,16,17,18,19, and 25).

If you sort the above table in order by first column (external pin number) instead of second column you can see just how scrambled the pins are:

Teensy-3 Pin, GPIO Port, GPIO Bit #
---------------
0 B 16
1 B 17
2 D 0
3 A 12
4 A 13
5 D 7
6 D 4
7 D 2
8 D 3
9 C 3
10 C 4
11 C 6
12 C 7
13 C 5
14 D 1
15 C 0
16 B 0
17 B 1
18 B 3
19 B 2
20 D 5
21 D 6
22 C 1
23 C 2
24 A 5
25 B 19
26 E 1
27 C 9
28 C 8

How did I determine this table? Two answers: first, look at the TEENSY-3 circuit diagram: http://www.pjrc.com/teensy/schematic.html

Going down the right side of the big chip, we see:
PT C2 45 23/A9
PT C1 44 22/A8
PT D6 63 21/A7
and so on. This corresponds to the lines in my table that read:
23 C 2
22 C 1
21 D 6
(The 45,44, and 63 are irrelevant in this discussion, but are the pin numbers of the physical ARM chip. Just to further confuse you!)

So, a few bits from each of the 5 ports are being used, some more than others, and all in scrambled order!

The other way to determine this table, and corroborating my observations, is the #defines inside the core_pins.h file. Actually, that is where I started from, then noticed the schematic had the same data.

Armed with this understanding, the solution becomes apparent. Let's look just at the lines from the above table which use GPIO "D", and sort them by GPIOD bit number:

2 D 0
14 D 1
7 D 2
8 D 3
6 D 4
20 D 5
21 D 6
5 D 7

In other words, the lower 8 bits of GPIOD map to 8 pins, just like ATMega's PIND/PORTD registers, except that where PIND/PORTD map to pins 7,6,5,4,3,2,1,0 in that order, GPIOD maps to pins 5,21,20,6,8,7,14,2, in that order!

Solution:

1. connect my 8 wires to the TEENSY-3 circuit board pins labeled digital 5,21,20,6,8,7,14,2, IN THAT ORDER. The other ends of these 8 wires goes my own connector labeled 7,6,5,4,3,2,1,0.

2. Execute this statement in my code:

byte allEight = GPIOD_PDIR & 0xFF;

QED! allEight bits 0 through 7 correspond to the data on my wires 0 through 7!

Thus, by choosing this particular set of 8 pins, WE HAVE THE EXACT EQUIVALENT of what the ATMel processors call "PIND".

Note also that I could have chosen port C and gotten TWELVE consecutive pins! Executing this statement:

byte anotherEight = GPIOC_PDIR & 0xFF;

then gives us what ATMel processors call "PINB", scrambled to pins 15,22,23,9,10,13,11 and 12 in that order!

GPIOx_PDIR is the input register for port x, and GPIOx_PDOR is the output register for port x. I won't go into how one can set the direction, it is a bit more complex. Since my application only needs the speed for the read/write, I can use the normal "pinMode" calls to set the direction.

============================
I ran and tested the following code:

// input test:
byte pinTable[] = {2,14,7,8,6,20,21,5};

void setup() {
Serial.begin(0);
for (int i=0; i<8; i++) { pinMode(pinTable[i],INPUT_PULLUP); }
}

void loop() {
byte eight,prev_eight;
do {
eight = GPIOD_PDIR & 0xFF;

if (eight != prev_eight)
{
prev_eight = eight;
Serial.println(eight,HEX);
}
} while (1==1);
}

With nothing touching the above program prints "FF", all ones. By connecting a jumper from ground and alternately touching it to any of the pins in the "pinTable" above, it printed a new value with the given port bit 0.

And the following program tests output. I took an LED+resistor to ground and touched the other end alternately to one of the specified pins, and within 8 seconds, when the program came around to printing that pin's number, the LED lit!

// output test:
byte pinTable[] = {2,14,7,8,6,20,21,5};

void setup() {
Serial.begin(0);
for (int i=0; i<8; i++) { pinMode(pinTable[i],OUTPUT); }
}

void loop() {
do {
for (int i=0; i<=7; i++)
{
byte b = 1<<i;
GPIOD_PDOR = b;
Serial.println(pinTable[i]);
delay(1000);
}
} while (1==1);
}

=======================
Thus, in summary:

One can use "GPIOD_PDIR" and "GPIOD_PDOR" as almost exact replacements for "PIND" and "PORTD", if you are willing to use a funny set of pins instead of a pins 0 through 7.

=======================
End of tutorial. Thanks for listening...

ZTiK.nl
01-31-2013, 06:03 PM
thank you, thank you, THANK YOU !!!!

You have given the most complete detailed and understandable explanation I have found so far...
Maybe you've seen my topic about a TFT-touchscreen (http://forum.pjrc.com/threads/16798-2-8-quot-TFT-touchscreen-Teensy-3-0?p=21203#post21203) I've been trying to connect, and this has been my main issue, except unlike you, I have been trying and testing for a few weeks now...

With your explanation I finally gotten connect the 8 control lines from the TFT to 'PORTD' now als known as 'GPIOD_PDOR' :P

I owe you a HUGE thank you (and probably a lot more), not only for fixing my problem, but mainly for sharing your knowledge in such a clear way!

ZTiK.nl
01-31-2013, 06:05 PM
P.S. I am pretty new to the subject, but I managed to update a library after reading your tutorial/guide only once
Again my compliments on how detailed it is while still being clear!

immortalSpirit
01-31-2013, 06:12 PM
You are most welcome! It is gratifying to help someone! Please make all checks out to the "Steven Swift Car Repair Fund"... :)

ZTiK.nl
01-31-2013, 06:25 PM
With guides like these, maybe rename it to the "Steven Swift New Car Fund"...
Or have O'Reilly Media sponsor you ;)

bongo
03-21-2013, 06:54 PM
Yes, thank you! I have been searching for this info for a few days, and your explanation is very clear. I made the attached image for myself as a reference, which might be helpful to others.

334

Nantonos
03-21-2013, 07:17 PM
Really nice explanation, thanks for that.

PaulStoffregen
03-21-2013, 08:47 PM
Very Nice! :)

Nantonos
03-21-2013, 09:32 PM
Yes, thank you! I have been searching for this info for a few days, and your explanation is very clear. I made the attached image for myself as a reference, which might be helpful to others.

334

Nice, but don't the pin numbers go up to 33? (Including the pins on the back).

Nantonos
03-21-2013, 09:41 PM
teensy-3 pin, gpio port, gpio bit #
---------------
0 b 16
1 b 17
2 d 0
......
26 e 1
27 c 9
28 c 8

29 c 10
30 c 11
31 e 0
32 b 18
33 a 4

bongo
04-13-2013, 07:03 PM
29 c 10
30 c 11
31 e 0
32 b 18
33 a 4

I've updated my chart with the missing pins.


387

instrumentek
02-09-2014, 02:31 AM
anyone have this info for the 2.0++?

immortalSpirit
02-09-2014, 08:03 PM
If u look at the circuit diagram here: http://www.pjrc.com/teensy/schematic.html (scroll down to the 2.0 version)
you will see identifiers around the edges. For example, the top right hand corner says "ADC0 PF0 | 41 ----- F0". This means that port F bit 0 is connected to internal pin 41 (which is the ADC0), external pin (on the board) F0. (You don't care about the internal pin number, 41, ignore it). If u look at the board, you'll see "F0" painted along the edge. Indeed, from the upper left of the physical board, you'll see: "GND, B0, B1, B2, B3, B7, D0, D1,...". Those are the port and bit number, right there! Hope that helps...

instrumentek
02-09-2014, 09:10 PM
Perfect Thanks, it seems so simple now.


If u look at the circuit diagram here: http://www.pjrc.com/teensy/schematic.html (scroll down to the 2.0 version)
you will see identifiers around the edges. For example, the top right hand corner says "ADC0 PF0 | 41 ----- F0". This means that port F bit 0 is connected to internal pin 41 (which is the ADC0), external pin (on the board) F0. (You don't care about the internal pin number, 41, ignore it). If u look at the board, you'll see "F0" painted along the edge. Indeed, from the upper left of the physical board, you'll see: "GND, B0, B1, B2, B3, B7, D0, D1,...". Those are the port and bit number, right there! Hope that helps...

immortalSpirit
02-13-2014, 08:51 PM
You're welcome.:)

Nupky
07-01-2014, 05:03 PM
Thanks for the outstanding tutorial! you made the whole port manipulation thing a considerable step easier to comprehend!

I have one quick question and one possibly more difficult one. This is my first time using Port Manipulation and normally the pins are set high or low using 8-bits (B11110000) but Teensy 3.1 uses 32 bit right? does that mean you should use something like B00000000111100001111000011110000 ?


My more difficult question is about triggering multiple port registers at the same time:

I am using a 16 pin Multiplexer and I recently found out that for my project I need to trigger the 4 control pins of the multiplexer to their HIGH or LOW values at exactly the same time.

This would be fine if I had all 4 pins in the same port register (A, B, C, or D) but I don't. Mostly I need to trigger two port registers at the same time. I would rewire, but I have already made a PCB for my project, so I am wondering if there is a way to trigger multiple port registers at the same time:

e.g. PORTD = B00001010 & PORTB = B10010000

Any help with this is greatly appreciated!

immortalSpirit
07-01-2014, 05:22 PM
If I read u right, u r connecting 4 Teensy pins to your mux and want to change them simultaneously.

Do they need to be consecutive pins on the Teensy? If not, then the solution is to wire your pins non-consecutively as follows. You will have to cut the traces on your pcb and add jumper wires, can u do that?

Observe this table from my first post:

X Y Z
---------------
3 A 12
4 A 13
24 A 5
33 A 4
0 B 16
1 B 17
16 B 0
17 B 1
18 B 3
19 B 2
25 B 19
32 B 18
9 C 3
10 C 4
11 C 6
12 C 7
13 C 5
15 C 0
22 C 1
23 C 2
27 C 9
28 C 8
29 C 10
30 C 11
2 D 0
5 D 7
6 D 4
7 D 2
8 D 3
14 D 1
20 D 5
21 D 6
26 E 1
31 E 0

(Three fields are teensy pin #, port letter, port bit number, eg: teensy pin 14 is port D bit 1)

If you take these in a different order, ie, sort by columns 2 and 3, you'll see that each port A,B,C,D has many pins, more than 4 each, that u could use. For example, Port D bit 0 drives teensy pin 2, port D bit 1 drives teensy pin 14, port D bit 2 drives teensy pin 7 and port d bit 3 drives teensy pin 8. Thus, if you connect pins 2,14,7, and 8 in that order to your mux, you can change them all simultaneously using GPIOD_PDOR to set/clear port D bits 0,1,2,and 3 simultaneously setting pins 2,14,7 and 8 simultaneously. The port registers are:

PDDR: Port Data Direction Register: 0 means this bit/pin is a input, 1 means output.
PDIR: Port Data Input Register: 0/1 according to the pin's state.
(If any pin is an output it can still be read by PDIR and will simply read back the same value last output on that pin).
PDOR: Port Data Output Register: 0 sets the bit/pin to 0, 1 to 1.

The following three sub-registers are logically redundant, but save an instruction or two in some cases.

PSOR: Port Set Output Register: 0 has no effect. 1 sets the corresponding bit/pin to 1.
PCOR: Port Clear Output Register: 0 has no effect. 1 sets the corresponding bit/pin to 0.
PTOR: Port Toggle Output Register: 0 has no effect. 1 toggles the corresponding bit/pin.

Thus
GPIOD_PDOR = 0xF
sets pins 2,14,7,and 8 to 1's.
GPIOD_PDOR = 0xA // 1010 binary
sets pins 2 and 7 to 1 and 14 and 8 to 0
Etc.

Is that what u r looking for?

immortalSpirit
07-01-2014, 05:38 PM
Regarding:
e.g. PORTD = B00001010 & PORTB = B10010000

No, no way to do that. But can do two instructions back-to-back. On Teensy what u called PORTD/B is GPIOD/B_PDIR/PDOR. At 48 or 72 MHz these instructions are way less than a microsecond apart. Does your mux really need to be *that* simultaneous?

hexodin
07-03-2014, 02:38 PM
Thank you!!! I'm searching for this informantion! Now I'm praying the Teensy ++ 3 (if Paul release it someday) comes with the GPIO ordered like the beautiful Teensy ++ 2!

kito
07-03-2014, 07:09 PM
Hi immortalSpirit,

I'm newbie to tweensy and K20 chip. This post was very useful. I trying to learn more. Maybe I'm completely wrong here, but I disagree with one of the statements. The assertion that the K20 function has a feature to do IO port to pin mapping.

> The ARM core has 5 registers much like the ATMel PIN/PORT registers. They
>are GPIOA, GPIOB, GPIOC, GPIOD, and GPIOE. Each of these supports up to 32
>pins. They are *extremely* programmable, and can be mapped in whole or in
>part to various functions and various pins on the ARM chip.

I don't want to sound like I am nitpicking because I just want to learn the teensy 3.1 board.

So I read skimmed the K20 manual to see how PORTs can be mapped to pins, but it looks like they are fixed. Each pin can have alternate functions like ADC, but no IO port to pin mapping. So for example I count only 10 pins on GPIOA, and Teensy 3.1 board has less. I assume the pin brought out to the headers was purely for the alternate analog functions.

immortalSpirit
07-03-2014, 10:27 PM
Well, OK, u could be right! Seems like that's what I determined "back then" when I answered the first post here. I too merely "skimmed" the K20 manual. I'm not engaged enuf now to look at it more, but if u can find a more definitive answer, please do! And post it! Even assuming u r right, there is still then the question of why Paul S. did the PCB the way he did, since whatever the K20 pins turn out to be doesn't limit the PCB board to swizzling them into consecutive holes/pins around the edge of the board. For me, I am happy to re-swizzle them externally by connecting my 8 bit cable to what appears on to be 8 "random" pins on the tennsy, ie, not consecutive, which makes for a messy connector, but simple software. Here is a case where the cliche "There is a method to my madness" is appropriate...

PaulStoffregen
07-03-2014, 10:51 PM
there is still then the question of why Paul S. did the PCB the way he did

A lot of planning went into maximizing Arduino compatibility. A lesson learned from earlier versions of Teensy was how entrenched the Arduino Uno pinout is, even years after Arduino has released other boards with signals on different pins. For example, a LOT of tutorials on many websites, particularly Adafruit and Sparkfun, are written for the SPI signals to be pins 10, 11, 12 and 13. A tremendous effort went into studying nearly all libraries and examples that existed 2 years ago (when Teensy 3.0 was designed) and crafting a pinout that would maximize compatibility.

Even with a 4 layer PCB, routing all those pins was incredibly difficult. In the end, I believe it was worthwhile. For most advanced users, the pin arrangement doesn't matter much. But for a lot of novices, having the signals on pins that correspond to many tutorials published on other websites really makes things simpler.

defragster
05-05-2015, 07:27 PM
Came across the PORT Table (https://forum.pjrc.com/threads/17532-Tutorial-on-digital-I-O-ATMega-PIN-PORT-DDR-D-B-registers-vs-ARM-GPIO_PDIR-_PDOR?p=30625&viewfull=1#post30625) - and wondered how it applied on Teensy units 3.1 and LC and got reply below::


A lot of planning went into maximizing Arduino compatibility. ... A tremendous effort went into studying nearly all libraries and examples that existed 2 years ago (when Teensy 3.0 was designed) and crafting a pinout that would maximize compatibility.


FYI:


Looks like it's still only for Teensy 3.0 and 3.1.

Teensy-LC differs on pins 3-4 and 24-26. Of course, LC doesn't have 27-33. All the other pins have identical mapping between Teensy LC and 3.1.

Frank B
05-05-2015, 07:42 PM
@defragster, do you live here in this forum ? ;)

Its very useful to study the schematics. Perhaps you can complete the Port Table ?

defragster
05-05-2015, 08:17 PM
Its very useful to study the schematics. Perhaps you can complete the Port Table ?

From what Paul says those ports are right for the 3.0 and 3.1 and also the LC where the pins exist. I suppose the missing pins are the ones the 3.1 added?


@defragster, do you live here in this forum ? ;)

Too much (the taxes are lower ;) ) - [17 years cold-turkey after leaving work] enjoying coding again and accumulating Teensy info in case I ever start my project . . . hitting the 1.6.0 beta is the reason I unpacked my 3.1's but the distractions through 1.6.3 release fed my enormous propensity to procrastinate. Yesterday I got 10 sets M/F Machine 40 pin headers - so I should be out of excuses again.

I will repower an ILI9341 and put your code (https://forum.pjrc.com/threads/28430-Spectrum-Analyzer?p=71937&viewfull=1#post71937) to the test with the FFT code I need to get back to.

PaulStoffregen
05-05-2015, 08:50 PM
Arduino 1.6.4 is likely to release very soon too...

defragster
05-05-2015, 09:00 PM
Arduino 1.6.4 is likely to release very soon too...

The fun never ends - I just downloaded 1.23beta to install.

But after the big jumps through 1.6.2 you made 1.6.3 seem easy . . . though they have had more time to put changes in 1.6.4, are you seeing any preview of their extent?

tobalt
05-17-2015, 01:35 PM
Hello,
I am new to teensy and wondered if also 16 or 32 bit port manipulation was possible with some effort through the GPIO_PDOR registers.

It was mentioned that these are flexible. So is it possible to map 16 or even 32 of the teensy pins to one of these registers and then write all the pins in a single instruction ?

I guess this is an ultra-demanded feature, but I couldnt find a discussion about it.

keithg
05-19-2015, 01:18 AM
I am pretty novice at all this, but am converting over an mbed LPC1768 project to Teensy 3.1. It is a can/bdm project. I am in the process of wading through the code and changing it over to Teensy and am trying to get some port register stuff working for the BDM portion.

The code I am trying to figure out and port over is:

#define IN_BDM (bool)((LPC_GPIO2->FIOPIN) & (1 << 0)) // FREEZE is p26 P2.0

I think this is a macro which is checking if gpio2 is either high or low and setting a state (IN_BDM) based on that. Previously, I would

PinMode(FREEZE, INPUT);
if (digitalRead(FREEZE) == HIGH){ IN_BDM }

I really need a character by character explanation of what that macro does. I think it is reading the pin GPIO2 and bitwise anding it to (1<<0)? If so, what does that do/mean?

How do I structure this? I have defined all of portD as my BDM interface. (2,14,7,8,6,20,21,5)


// For Teensy
#define PIN_PWR 2 // power supply
#define PIN_NC 14 // connection signal
#define PIN_BERR 7 // double bus fault input - will be an input when it is working properly
#define PIN_BKPT 8 // breakpoint/serial clock
#define PIN_RESET 6 // reset signal
#define PIN_DSI 20 // data input (to ECU) signal
#define PIN_DSO 21 // data output (from ECU) signal
#define PIN_FREEZE 5 // freeze signal

EDIT: I think I got it. Now how to do 'bit-banding' writes/reads. This is also done in this project and it quite a bit beyond me. I understand in principle, but c++ practice is a bit beyond me.

keithg
05-24-2015, 04:30 PM
Can we set pin mode using GPIOx_PDIR as well? I ran across this in my adventure converting this mbed code and it appears that they use something similar. On the Teensy 3.x, do these commands work/make sense?

GPIOD_PDIR &= ~(1 << 2); // Set pin D2 as input.
...
GPIOD_PDIR |= (1 << 2); // Set pin D2 as output.

aaaaaaron
04-18-2016, 07:47 PM
Hello everyone! I happened to stumble onto this thread and realized this would be perfect for reading the HCTL-2022 quadrature decoding counter, which gives 32 bits in counts, shuffling between 4 x 8 bits. Currently I am using a teensy 3.2, and looking through its schematic found that the PIND is still the same few pins, {2,14,7,8,6,20,21,5}.

The first code did not work, so I added in normal digitalRead's to compare and see what was going on (fastcount vs. count), and everything suddenly started working, both fastcount and count were consistent. So I played around with the bytes and found that all the values were good, however everytime I comment out the digitalRead's or digitalReadFast's, fastcount goes haywire. The theoretical speed was doubled, but I only received bad data.

So, right now I have stuck to normal digitalRead's, which loops at 4.7 milliseconds (I'm trying to hit 1kHz, oh well), digitalReadFast's sometimes give me inconsistent data too. Could it be because I directly connected OE_COUNT, RST_COUNT, SEL1, SEL2 as OUTPUTs (3.3v logic to 5v device)? It works perfectly with normal digitalRead's though. The teensy GPIO's are 5v tolerant so I assume that using PIND is fine without translation.

Or could it be that the register does not "fill" itself up unless there's a digitalRead going on?

Below is a snippet of the code that uses PIND,



#define RST_COUNT 0
#define OE_COUNT 1
#define SEL1 3
#define SEL2 4

byte pinTable[] = {2,14,7,8,6,20,21,5}; //5 is D7 while 2 is D0
byte firstByte;
byte secondByte;
byte thirdByte;
byte fourthByte;

long fastcount = 0;

void setup() {
Serial.begin(115200);

for (int i=0; i<8; i++) { pinMode(pinTable[i],INPUT); } //I changed it from INPUT_PULLUP to INPUT

pinMode(SEL1, OUTPUT);
pinMode(SEL2, OUTPUT);
pinMode(RST_COUNT, OUTPUT);
pinMode(OE_COUNT, OUTPUT);

digitalWrite(RST_COUNT, HIGH);
digitalWrite(OE_COUNT, HIGH);
}

void loop() {
digitalWrite(OE_COUNT,LOW);

digitalWrite(SEL1,1);
digitalWrite(SEL2,0);
firstByte = GPIOD_PDIR & 0xFF;
fastcount = (long)firstByte;

digitalWrite(SEL1,0);
digitalWrite(SEL2,0);
secondByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(secondByte<<8);

digitalWrite(SEL1,1);
digitalWrite(SEL2,1);
thirdByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(thirdByte<<16);

digitalWrite(SEL1,0); //SEL1
digitalWrite(SEL2,1); //SEL2
fourthByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(fourthByte<<24);

digitalWrite(OE_COUNT,HIGH);

timer = micros();
Serial.print(timer);
Serial.print("\t");
Serial.print(fastcount);
Serial.println(" ");
}


Then this is the code that I used to compare between fastcount and count,


#define RST_COUNT 0
#define OE_COUNT 1
#define SEL1 3
#define SEL2 4

byte pinTable[] = {2,14,7,8,6,20,21,5}; //5 is D7 while 2 is D0
byte firstByte;
byte secondByte;
byte thirdByte;
byte fourthByte;

int encoder_array[32];
long count = 0;
long fastcount = 0;

void setup() {
Serial.begin(115200);

for (int i=0; i<8; i++) { pinMode(pinTable[i],INPUT); } //I changed it from INPUT_PULLUP to INPUT

pinMode(SEL1, OUTPUT);
pinMode(SEL2, OUTPUT);
pinMode(RST_COUNT, OUTPUT);
pinMode(OE_COUNT, OUTPUT);

digitalWrite(RST_COUNT, HIGH);
digitalWrite(OE_COUNT, HIGH);
}

void loop() {
digitalWrite(OE_COUNT,LOW);

digitalWrite(SEL1,1);
digitalWrite(SEL2,0);

encoder_array[0] = digitalRead(2); //I was trying to use digitalReadFast with the argument as a constant
encoder_array[1] = digitalRead(14);
encoder_array[2] = digitalRead(7);
encoder_array[3] = digitalRead(8);
encoder_array[4] = digitalRead(6);
encoder_array[5] = digitalRead(20);
encoder_array[6] = digitalRead(21);
encoder_array[7] = digitalRead(5);

firstByte = GPIOD_PDIR & 0xFF;
fastcount = (long)firstByte;

digitalWrite(SEL1,0);
digitalWrite(SEL2,0);

encoder_array[8] = digitalRead(2);
encoder_array[9] = digitalRead(14);
encoder_array[10] = digitalRead(7);
encoder_array[11] = digitalRead(8);
encoder_array[12] = digitalRead(6);
encoder_array[13] = digitalRead(20);
encoder_array[14] = digitalRead(21);
encoder_array[15] = digitalRead(5);

secondByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(secondByte<<8);

digitalWrite(SEL1,1);
digitalWrite(SEL2,1);

encoder_array[16] = digitalRead(2);
encoder_array[17] = digitalRead(14);
encoder_array[18] = digitalRead(7);
encoder_array[19] = digitalRead(8);
encoder_array[20] = digitalRead(6);
encoder_array[21] = digitalRead(20);
encoder_array[22] = digitalRead(21);
encoder_array[23] = digitalRead(5);

thirdByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(thirdByte<<16);

digitalWrite(SEL1,0); //SEL1
digitalWrite(SEL2,1); //SEL2

encoder_array[24] = digitalRead(2);
encoder_array[25] = digitalRead(14);
encoder_array[26] = digitalRead(7);
encoder_array[27] = digitalRead(8);
encoder_array[28] = digitalRead(6);
encoder_array[29] = digitalRead(20);
encoder_array[30] = digitalRead(21);
encoder_array[31] = digitalRead(5);

fourthByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(fourthByte<<24);

digitalWrite(OE_COUNT,HIGH);

long count = 0;
for (int i=0; i<32; i++)
{
count = count + (encoder_array[i] * (int)pow(2,i));
}

timer = micros();
Serial.print(timer);
Serial.print("\t");
Serial.print(fastcount);
Serial.print("\t");
Serial.print(count);
Serial.println(" ");
}


Sorry if the code is a mess, I was copying and pasting small pieces and rewriting some of them. So tldr:

Case 1 : PIND only, didn't work
Case 2 : PIND and digitalReadFast/digitalRead, works, but with SOME inconsistencies
Case 3 : digitalReadFast only, works, but with A LOT of inconsistencies
Case 4 : digitalRead only, works perfectly

Any insights would be greatly appreciated! In the meantime, I will use a TXS0108PWR to translate all the outputs (RST_COUNT, OE_COUNT, SEL1, SEL2) to 5V and see if the problem is still there.

Frank B
04-18-2016, 07:58 PM
Does it work with Teensy @ 24 MHZ ? If yes, perhaps the new code is too fast :)

aaaaaaron
04-19-2016, 07:17 AM
Does it work with Teensy @ 24 MHZ ? If yes, perhaps the new code is too fast :)

Hmm, it kind of defeats the purpose of running at 24MHz, I was intending to have it as fast as possible.

Update :

I found the issue (or I hope it is the issue). I had the nagging suspicion that the registers are not refreshing properly when I call them, so I removed all the digitalRead's except for one random one, just to see. And hey it works, however the speed is not very much improved from using just all digitalRead's.

PIND + 1 random digitalRead + all the other sensors, I am getting ~4.6 millisecond per loop

all digitalRead's + all the other sensors, I am getting ~4.7 millisecond per loop

is there a way to refresh the 8 bits faster, or in a more optimized way (other than manually reading one pin)?

Below is my code that I have working perfectly but not fast,



byte pinTable[] = {2,14,7,8,6,20,21,5}; //5 is D7 while 2 is D0
byte firstByte;
byte secondByte;
byte thirdByte;
byte fourthByte;

#define RST_COUNT 0
#define OE_COUNT 1
#define SEL1 3
#define SEL2 4

int encoder_array[32];
long fastcount = 0;

unsigned long timer;

void setup() {
Serial.begin(115200);
for (int i=0; i<8; i++) { pinMode(pinTable[i],INPUT); }
pinMode(SEL1,OUTPUT); //SEL1
pinMode(SEL2,OUTPUT); //SEL2
pinMode(RST_COUNT,OUTPUT); //RST_COUNT
pinMode(OE_COUNT,OUTPUT); //OE_COUNT
digitalWrite(0,HIGH); //RST COUNT
digitalWrite(1,HIGH); //OE_COUNT
}

void loop() {
long fastcount = 0;

digitalWrite(1,LOW); //OE_COUNT

digitalWrite(3,1);
digitalWrite(4,0);

encoder_array[0] = digitalRead(2); //{2,14,7,8,6,20,21,5} **leaving this random read to refresh the 8 bits
// encoder_array[1] = digitalRead(14);
// encoder_array[2] = digitalRead(7);
// encoder_array[3] = digitalRead(8);
// encoder_array[4] = digitalRead(6);
// encoder_array[5] = digitalRead(20);
// encoder_array[6] = digitalRead(21);
// encoder_array[7] = digitalRead(5);

firstByte = GPIOD_PDIR & 0xFF;
fastcount = (long)firstByte;

digitalWrite(3,0);
digitalWrite(4,0);

encoder_array[8] = digitalRead(2); //**leaving this random read to refresh the 8 bits
// encoder_array[9] = digitalRead(14);
// encoder_array[10] = digitalRead(7);
// encoder_array[11] = digitalRead(8);
// encoder_array[12] = digitalRead(6);
// encoder_array[13] = digitalRead(20);
// encoder_array[14] = digitalRead(21);
// encoder_array[15] = digitalRead(5);

secondByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(secondByte<<8);

digitalWrite(3,1);
digitalWrite(4,1);

encoder_array[16] = digitalRead(2); //**leaving this random read to refresh the 8 bits
// encoder_array[17] = digitalRead(14);
// encoder_array[18] = digitalRead(7);
// encoder_array[19] = digitalRead(8);
// encoder_array[20] = digitalRead(6);
// encoder_array[21] = digitalRead(20);
// encoder_array[22] = digitalRead(21);
// encoder_array[23] = digitalRead(5);

thirdByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(thirdByte<<16);

digitalWrite(3,0); //SEL1
digitalWrite(4,1); //SEL2

encoder_array[24] = digitalRead(2); //**leaving this random read to refresh the 8 bits
// encoder_array[25] = digitalRead(14);
// encoder_array[26] = digitalRead(7);
// encoder_array[27] = digitalRead(8);
// encoder_array[28] = digitalRead(6);
// encoder_array[29] = digitalRead(20);
// encoder_array[30] = digitalRead(21);
// encoder_array[31] = digitalRead(5);

fourthByte = GPIOD_PDIR & 0xFF;
fastcount |= (long)(fourthByte<<24);

digitalWrite(1,HIGH); //OE_COUNT

timer = micros();
Serial.print(timer);
Serial.print("\t");
Serial.print(fastcount);
}

Frank B
04-19-2016, 07:22 AM
Hmm, it kind of defeats the purpose of running at 24MHz, I was intending to have it as fast as possible.
I know, but this test would help to know wether it is a speed issue or not. It takes some seconds only....
If it is a speed-issue, a delayMicroseconds(1) would help, too.... then, you could try shorter delays, and insert some asm volatile ("nop").

aaaaaaron
04-19-2016, 08:51 AM
I know, but this test would help to know wether it is a speed issue or not. It takes some seconds only....
If it is a speed-issue, a delayMicroseconds(1) would help, too.... then, you could try shorter delays, and insert some asm volatile ("nop").

Oh my god, it works! Thank you so much, Frank! I see, so what you meant by the code being too fast, would be that the decoder couldn't keep up!

Now it runs at ~2.7 milliseconds :D

defragster
04-27-2016, 04:59 PM
I've updated my chart with the missing pins.


387

@bongo - (old post - but good work) - is the chart source in excel? Can you post this? Editing for LC might be nice, also to add the 'function' of the primary SPI/I2C/Serial type pins so the info would be in one place.

joaquin
10-26-2016, 03:00 PM
I made an account just to say thanks.
It would have been so annoying going through the datasheet until that WTF moment.
I discovered that the PINx registers were emulated because you can't assign as you would in AVR likeso DDRA=0x0F|1<<6. It throws an error. I hope the guys on PJRC put together a better pin register access tutorial, because I think that pin register emulation is pointless, and direct access to pins is critical.

Frank B
10-26-2016, 03:15 PM
I made an account just to say thanks.
It would have been so annoying going through the datasheet until that WTF moment.
I discovered that the PINx registers were emulated because you can't assign as you would in AVR likeso DDRA=0x0F|1<<6. It throws an error. I hope the guys on PJRC put together a better pin register access tutorial, because I think that pin register emulation is pointless, and direct access to pins is critical.

Best is, to take a look at the Datasheet.
It can tell more than every tutorial.

joaquin
10-27-2016, 06:21 AM
you are right, though, the arduino platform will imply that many of us will be trying to make things while not yet very caable of understandong the datasheets. ..
btw, i made a sheet with the pin maps, here
https://docs.google.com/spreadsheets/d/1eNFDcwB1zd58UtyyYf6wSAXn47VMJZGjQmyyU6nU4MU/edit?usp=drive_web

immortalSpirit
10-27-2016, 06:38 AM
Joaquin, you most definitely CAN access the PINx registers just like in AVR. Except that they are named "GPIOx_PDIR" instead of "PINx". This is just a symbol error, not a missing piece of hardware! Using them invokes no overhead, they are direct hardware registers just as their AVR namesakes.

Wherever you had "PINA" use "GPIOA_PDIR". PDIR = Port Data Input Register.
Likewise use GPIOA_PDDR instead of DDR. ("Port data direction register)
and use GPIOA_PDOR instead of PORTA. ("Port data output register)

The purpose of my first post, which started this thread, was to show the pin ordering. For example, see this code snippet, adopted from that post:

// byte pinTable[] = {2,14,7,8,6,20,21,5};
for (int i=0; i<=7; i++)
{
GPIOD_PDOR = 1<<i;
delay(1000);
}

This sets each of 8 pins high, sequentially 1 second apart. What is different about GPIOD_PDOR as compared to AVR's PORTD is that on the AVR the 8 pins would probably be found on the board in sequential order, whereas on the teensy, they are pins 2,14,7,8,6 etc in that (funny) order.

Hope that helps clarify.

joaquin
11-09-2016, 05:55 PM
Hope that helps clarify.
Hey! thanks for the answer. Indeed I understand. Now I have two questions
- Why was the decision of scrambling the ports taken? It probably brought a lot of trouble in the making of the libraries
- Why immortalSpirit said that changing data registers is more complex?

*edit*
I just happened to have an older teensy at reach, which happens to have an atmel microcontroller, so the pin mapping probably was to keep the same footprint. Am I right?

immortalSpirit
11-09-2016, 07:56 PM
Yes, all the teensy's have kept similar/same ordering, but then that just defers the question to why the 1st version was scrambled. In the final analysis, you'd have to ask Paul.

If u look at the ATMEGA 832 chip, used by Arduino Uno and others, the pins are much more orderly. The Teensy's are based on the ARM Cortex-M4 and if you google it's pinout you'll see it is itself quite scrambled.

I didn't spend a lot of time looking at it, but the ARM Cortex manual shows what appears to be a fantastic level of programmability on the ports, and it may be that with more research one could do more unscrambling. You are getting pretty low-level and affecting timer ports and internal signals and all kinds of stuff that is sensitive and tricky. I wouldn't mess with it and I'm guessing neither would Paul. There is just not much need to care, except in a few cases which I guess to be rare.

I suspect that the problem isn't had by many people. I suspect that most libraries, for portability, probably use the slower digitalRead() and digitalWrite() functions. By "slower" we are just talking about a few microseconds, which is kinda sorta silly to worry about for *most* cases.

In your own case, Joaquin, it was merely a matter of using a different register than the one you expected. The technical capability was still there, just in a harder-to-find place.

For the rest of us, the "big" problem is not electrical or technical in any way, it is merely "neatness" on a breadboard. If we have say an 8-bit parallel cable, the Arduino Uno will connect them all in a nice "pretty" row of jumpers, whereas the teensy jumpers will end in a tangle of crossed wires. I would say, for most projects, this is a trivial concern. I've attached a pix of one of my breadboards. One end of the jumper cable is "pretty", the other is "messy". That is not a terrible price to pay! :-)

8750

Michael Ward
11-09-2016, 08:10 PM
This from Paul in an earlier discussion:

A lot of planning went into maximizing Arduino compatibility. A lesson learned from earlier versions of Teensy was how entrenched the Arduino Uno pinout is, even years after Arduino has released other boards with signals on different pins. For example, a LOT of tutorials on many websites, particularly Adafruit and Sparkfun, are written for the SPI signals to be pins 10, 11, 12 and 13. A tremendous effort went into studying nearly all libraries and examples that existed 2 years ago (when Teensy 3.0 was designed) and crafting a pinout that would maximize compatibility.

Even with a 4 layer PCB, routing all those pins was incredibly difficult. In the end, I believe it was worthwhile. For most advanced users, the pin arrangement doesn't matter much. But for a lot of novices, having the signals on pins that correspond to many tutorials published on other websites really makes things simpler.
https://forum.pjrc.com/threads/17532-Tutorial-on-digital-I-O-ATMega-PIN-PORT-DDR-D-B-registers-vs-ARM-GPIO_PDIR-_PDOR?p=21228&viewfull=1#post21228
--Michael

Edit: DOH! Had bookmarked this and just now realized it's earlier in this same thread...
--M

LERAY
07-04-2017, 03:01 PM
PIN 13 (LED) has a different behaviour due to the LED capacitor. So 8 bits register C is not available. Register A is not completely available (A0 A1 A2 A" already used by memory) and B is not available because PTB6 is don't exist. Would it be possible to design a Teensy with 3 really available 8 bits ports ?

Revalogics
07-04-2017, 03:22 PM
LED capacitor? Never heard of that. Is that the capacitance formed by the depletion region between the N and P junctions, or is it a physical capacitor included within the LED package?

Revalogics
07-04-2017, 03:28 PM
About pins changing states at the exact same moment, why don't you try using transparent latches like HEF40373 or 74HCT573 (D-type Flip-flops with Output latches)? You input your parallel data, and latch it, and unlatch it, on and on, and you get simultaneous bus bits state changes. I think the downside of this is more on about speed issues.

LERAY
07-04-2017, 04:07 PM
About pins changing states at the exact same moment, why don't you try using transparent latches like HEF40373 or 74HCT573 (D-type Flip-flops with Output latches)? You input your parallel data, and latch it, and unlatch it, on and on, and you get simultaneous bus bits state changes. I think the downside of this is more on about speed issues.

Obviously, time response is different on PIN 13 (LED) (PTC5) than on any other Pin. I'am using this pin (and the others ones PTC0 1 2 3 4 for 6 74HCT138 controls. All are running fine, but the PTC5 is never instantly changed. Fortunately, I can do another tasks before putting PTC5 HIGH. Otherwise, the 138 don't run correctly. (The 5 other HCT138 controlled by PTC0 1 2 3 4 are running fine. So there is obviously a different behaviour on PIN 13. So I would like to have really 3 complete registers (on new Teensy), fast 8 bits registers A B C without LED, which could be controlled on upper pins such as PTX11, 12, 13, and so on ... But not on bits 0 to 7. Thanks a lot.

Revalogics
07-04-2017, 04:14 PM
I replaced the LED in my Teensy 3.6 from orange to white - white has higher forward voltage than orange so it loads less to pin 13 compared to orange LED. The voltage may be ramping because of low current capability of Teensy ports. This hasn't been an issue for me though, maybe because of the replacement I did.

LERAY
07-04-2017, 04:21 PM
Thanks, Paul, but for me it's a critical issue. Fortunately, I'am using a software artefact in order to control my entries correctly. You can see my board here :
http://pascal.leray.free.fr/web_org/ki6x8x8_midi_usb.jpg
It's a 6 keyboard and Pedalboard MIDI/USB controller.
where you can see the 6 74HCT138; The last one at the right side of the board is controlled by PTC5.
from the web page :
http://pascal.leray.free.fr/web_org/org_en.html
Best regards
Pascal

PaulStoffregen
07-04-2017, 07:26 PM
time response is different on PIN 13 (LED) (PTC5) than on any other Pin.

Can you provide a small but complete program to demonstrate the problem? Will it work if I just run your program on a Teensy 3.2 here and use my oscilloscope to view the waveforms on pin 13 and up to 3 other pins? Or does the problem only occur when Teensy is soldered to your PCB?

I have a 4 channel scope with 200 MHz bandwidth available for viewing the waveforms from whatever code you post. But until you post a complete program I can run here on a Teensy 3.2, there's little I can do other than guess. Even then, from these 2 message, I simply do not have guesses. I need to actually see the problem. Please post a complete program which I can copy and paste into Arduino and run on a Teensy 3.2 here.

LERAY
07-07-2017, 07:32 PM
I tested with my oscilloscope this simple program : It appears that the LEDPIN decay is not so fast as for other pins. Moreover, there are important Gibbs phenomenon (oscillations) for Low to High and High to Low state. These oscillations don't exist onn other pin. Here is a simple program for testing :

//TEST LEDPIN versus OTHER PINS
const int ledPin = 13;
const int Pin14 = 14;

void setup() {
// put your setup code here, to run once:
pinMode(ledPin, OUTPUT);
pinMode(Pin14, OUTPUT);
}

void loop()
{
// put your main code here, to run repeatedly:
digitalWrite(ledPin,HIGH);
digitalWrite(Pin14,HIGH);
delayMicroseconds(1);
digitalWrite(ledPin,LOW);
digitalWrite(Pin14,LOW);
delayMicroseconds(2);
}

PaulStoffregen
08-18-2017, 01:52 PM
The slower pin fall time is due to the extra load on the pin from the orange LED and 470 ohm resistor.

I ran a test here. I can see the different fall times on my scope. If I connect a LED and resistor to pin 14, it becomes the same as pin 13. Without the LED, I see about 9 ns. With the LED it looks like about 15 ns.

PaulStoffregen
08-18-2017, 02:01 PM
I should mention, by default pinMode() turns on the slew rate limiting feature. If you turn this off, the transitions are much faster. I measured just now. It is approx 3 ns, with or without the LED.

However, with the scope probes connected using ordinary ground clips, I also see quite a lot of ringing and cross-talk. These are common issues with very fast rise and fall times. They are the reason the pins have the slew rate limit feature, and why it's turned on by default.

If you want to run without the slew rate limit for maximum speed (and extra noise issues), this is the code:



void setup() {
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
// Turn off slew rate limit, for maximum speed
// CAUTION: noise and cross-talk problems can be
// much worse when slew rate limiting is disabled
CORE_PIN13_CONFIG &= ~PORT_PCR_SRE;
CORE_PIN14_CONFIG &= ~PORT_PCR_SRE;
}

void loop() {
digitalWrite(13, HIGH);
digitalWrite(14, HIGH);
delayMicroseconds(1);
digitalWrite(13, LOW);
digitalWrite(14, LOW);
delayMicroseconds(2);
}

LERAY
08-18-2017, 04:09 PM
Thanks for your reply, Paul. Of course, this little difference is due to the 470 Ohms resistor and the LED.
(Light capacitive effect). But sufficient to induce problems for very fast real time professionnal uses.

So I need contiguous, very fast 8 bits INPUTS and OUTPUTS. Without LED on these pins.

Maybe would it be great to design a new TEENSY with : 2 x 8 bits contiguous INPUT-OUTPUT registers (registers C and D for example); and the rest (say registers A or B) for addresses.
As a classic microprocessor.
And without any LED please ! Thanks ! (Or connected to an unused pin such as PTB19 for example)
Because the C and D registers are the only ones which are available on the output pins of the MK20P64 chips.

I'm ready to design free of charge such a PCB if 2 layers only are necessary.

Best regards,

Pascal

LERAY
08-18-2017, 04:11 PM
You can watch all the PCB I designed for real Pipe organ and for digital organs here :
http://pascal.leray.free.fr/web_org/org_en.html

Pascal

defragster
08-18-2017, 08:55 PM
... So I need contiguous, very fast 8 bits INPUTS and OUTPUTS. Without LED on these pins.

Maybe would it be great to design a new TEENSY with : 2 x 8 bits contiguous INPUT-OUTPUT registers (registers C and D for example); and the rest (say registers A or B) for addresses.
As a classic microprocessor.
And without any LED please ! Thanks ! (Or connected to an unused pin such as PTB19 for example)
Because the C and D registers are the only ones which are available on the output pins of the MK20P64 chips.


Doing that would break the Arduino ( hardware/software ) interchangeability of Teensy PJRC works to provide.

There is a design On OSH you could rework by changing the pin placement routing and redefining 'LED_BUILTIN': Teensy 3.2 DIY Reference Board (https://www.oshpark.com/shared_projects/d3J03Zeb)

Other pointers probably on the Forum and around and this one recently linked: building-your-own-custom-teensy/ (http://www.appfruits.com/2015/03/building-your-own-custom-teensy/)

Or - if the LED were pulled off - a PCB BreakoutBoard could be designed to route the signals to a linear row of edge pins: Teensy 3.2 Breakout Board (https://www.oshpark.com/shared_projects/Gnvbt7io). Something like that also has solderable castellated pads on the underside to bring out those bottom side pins.

FrankB has shared designs (https://oshpark.com/profiles/FrankB) that pull out those bottom pins - that might suggest an easier way to repurpose by grabbing the desired port pins and routing them in a similar way without the need for a whole new Teensy - just a small PCB.

PaulStoffregen
08-18-2017, 10:12 PM
I'm ready to design free of charge such a PCB if 2 layers only are necessary.


PJRC sells bootloader chips, specifically so you can design your own Teensy-compatible board with the features you need.

https://www.pjrc.com/store/ic_mkl02.html

Just to be clear, PJRC is not going to make another board for your project. You need to do this.

StanfordEE
01-11-2019, 09:48 PM
I've updated my chart with the missing pins.


387

After much frustration, I manually mapped Port B and it does not correspond to the chart exactly. In my application, with several libraries at play, pin25 simply did not respond (always read as HIGH) but (interestingly) digitalReadFast(25) *did* work, so my work-around was this:

temp1 = GPIOB_PDIR; //Bits are out of order compared to published mapping. Tested by grounding each, serial port output.
vReal[SampleIndex] = (((temp1 & 0x00030000)>>12)+((temp1 & 0x00000800)>>5)+(temp1 & 0x0000000F))+(digitalReadFast(25)<<7);

I am getting just shy of 1 MB/s transfer rate (some jitter, solid at 2 us rather than 1 us interrupt rate), but I cannot figure out how to work around the pin 25 issue. The main reason for this post is to warn that one of the pins (32) does not appear to be the internal 32-bit port digit suggested.

I could go on, but using ports is difficult due to the morass of Arduino legacy libraries and "commonly used pins." While there seem some on the forum who insist that "ports are useless" or "going fast is a meaningless metric," there are those of us in education and research who do want to do that, and the CPU can handle it - the bottleneck is getting data in fast enough.

I will try again to reach PJRC directly, but I'm curious if I/we put up the funding, would someone design a "Teensy 3.6 Pro" that had maybe two rows of pins on each edge and had at least one port "uncontaminated" and available, pins in order, for "us people."

By the way, the other thing some folks tend to say on this forum is "time to step up to professional embedded systems tools." I've used those, and while they are great, I respectfully disagree. The benefit of the Arduino/Teensy approach is massively broad access (great as an educator) and much, much faster prototyping in most cases due to the huge base of code/libraries/hardware. This is particularly true for creatives, who want to try ideas quickly rather than getting bogged down in the details.

We are trying to straddle these two points of view. One of the current projects is a touch-screen GUI, Teensy 3.6/Gameduino 3 (GPU-equipped) FFT analyzer for teaching. It's solid at 60 dB SNR and 100 ks/s using just the Teensy's ADC's and has a DDS synthesizer (tracking generator) running concurrently). The port issue came up trying to interface a lovely 8-bit flash ADC, as the code runs at tantalizingly close to 1 Ms/s. Imagine a $100, 500 kHz, all floating-point FFT analyzer with commented, educational code. I think it's going to be very cool.

Snippet of video here on Vimeo: https://vimeo.com/310882403

Every day I thank PJRC for bringing this kind of compute power to the community!!!

StanfordEE
01-22-2019, 03:48 AM
Upper bits of Port C are incorrect in the posted mapping. It is like this:

Port C Teensy Pin Notes
12..31 NONE
11 38
10 37
9 36
8 35
7 12
6 11
5 13 LED pin
4 10
3 9
2 23
1 22
0 15

LAtimes
02-02-2019, 03:16 PM
Pins 24 and above are on different GPIO ports between Teensy 3.2 and Teensy 3.5/3.6. For 3.5/3.6, here is a table of pin numbers to port/bit number, and also a table of ports A-E to pin numbers. It is color-coded by pin location (front/back) and port number. I also attached the spreadsheet for reference.

15811
15812

PatMaximum
02-13-2019, 09:26 AM
Have been using (on a MEGA):-

PORTA = PORTA & B11000000;
PORTA = PORTA | _muxpin; //The project is migrating to a Teensy 3.5 so

GPIOB_PDOR = GPIOB_PDOR & B11000000;
GPIOB_PDOR = GPIOB_PDOR | _muxpin;

Seems logical, however.. How do I point _muxpin at GPIOB bits 16-21 instead?

PatMaximum
02-14-2019, 02:51 AM
How do I point _muxpin at GPIOB bits 16-21 instead?

Never mind, the 'Scope tells me that I've got it sorted..