Teensy 4.0 has no PORTC and PORTD definitions?

Status
Not open for further replies.

Utak

Active member
I'm trying to use:


#define PORTC_PDIR GPIOC_PDIR
#define PORTD_PDIR GPIOD_PDIR

But...

sketch_nov15a: In function 'void ReadLines()':
sketch_nov15a:30: error: 'GPIOD_PDIR' was not declared in this scope
#define PORTC_PDIR GPIOD_PDIR

In the Arduino IDE.

With the Teensy 3.5 this is no problem.

What can I do, or read the the ports?

Are the Ports the same like Teensy 3.5?
 
There is no such thing as PORTC and PORTD on these boards (nor Teensy 3.x), they are more specifically used for emulating an 8 bit AVR processor such as used on an Arduno Uno or Mega.

On the Teensy 3.x such as Teensy 3.5 there was software emulation of these in the files cores\teensy3\avr_emulation.h

So far this emulation has not been ported over to the T4. My guess is it might not be very hard to do the basics like PORTC and PORTD... But it might obviously be better for libraries and applications to be setup to use real things and not go through this emulation layer.

What may be more complicated is to continue to emulate things like the AVR registers for SPI...

In many cases there are already libraries that use the actual stuff on the processor.

Again note: These operations are NOT atomic. That is for example reading in from the PORTC register (PINC) the code actually does stuff like:

Code:
	inline int operator & (int val) const __attribute__((always_inline)) {
		int ret = 0;
		if ((val & (1<<0)) && digitalReadFast(14)) ret |= (1<<0);
		if ((val & (1<<1)) && digitalReadFast(15)) ret |= (1<<1);
		if ((val & (1<<2)) && digitalReadFast(16)) ret |= (1<<2);
		if ((val & (1<<3)) && digitalReadFast(17)) ret |= (1<<3);
		if ((val & (1<<4)) && digitalReadFast(18)) ret |= (1<<4);
		if ((val & (1<<5)) && digitalReadFast(19)) ret |= (1<<5);
		return ret;
	}

The output on PORTC is very simlar, the only difference is in addition it mucks with maybe the pin configuration for pull up or not to pull up.

If this becomes a major issue and Paul does not have time, I could probably take a quick look at maybe copying over the simple stuff, since this is at least the second such thread in the last few days.

Kurt
 
But... it seems

if (digitalReadFast(portPinsC[0])) ret |= (1<<0);
if (digitalReadFast(portPinsC[1])) ret |= (1<<1);
if (digitalReadFast(portPinsC[2])) ret |= (1<<2);
if (digitalReadFast(portPinsC[3])) ret |= (1<<3);
if (digitalReadFast(portPinsC[4])) ret |= (1<<4);
if (digitalReadFast(portPinsC[5])) ret |= (1<<5);
if (digitalReadFast(portPinsC[6])) ret |= (1<<6);
if (digitalReadFast(portPinsC[7])) ret |= (1<<7);

that is very slow (Teensy 4.0 800 MHz)... slower as with Teensy 3.5 with 164 Mhz.

Is there a way to read the pins faster? Very fast?

Ok...

Teensy 3.5 has "Fastes + pure code" in the Arduino IDE Board settings.
Teensy 4.0 has only "Fastes". Fastest is faster than "Fast", but I need a little bit more Digital Pin Speed.
 
But... it seems

Code:
 if (digitalReadFast(portPinsC[0])) ret |= (1<<0);
  if (digitalReadFast(portPinsC[1])) ret |= (1<<1);
  if (digitalReadFast(portPinsC[2])) ret |= (1<<2);
  if (digitalReadFast(portPinsC[3])) ret |= (1<<3);
  if (digitalReadFast(portPinsC[4])) ret |= (1<<4);
  if (digitalReadFast(portPinsC[5])) ret |= (1<<5);
  if (digitalReadFast(portPinsC[6])) ret |= (1<<6);
  if (digitalReadFast(portPinsC[7])) ret |= (1<<7);

that is very slow (Teensy 4.0 800 MHz)... slower as with Teensy 3.5 with 164 Mhz.
Sometimes code fragments like the above it is hard to know what the code will compile to without having any idea of some of your definitions.
That is if you look at the code fragment: digitalReadFast(portPinsC[1])
How is portPinsC[1] defined as?

What I ask is digitalReadFast is setup that IF the pin number passed in was a built in constant, than the compiler reduces all of the code down to something real simple:

Code:
uint8_t digitalRead(uint8_t pin);
static inline uint8_t digitalReadFast(uint8_t pin) __attribute__((always_inline, unused));
static inline uint8_t digitalReadFast(uint8_t pin)
{
	if (__builtin_constant_p(pin)) {
		if (pin == 0) {
			return (CORE_PIN0_PINREG & CORE_PIN0_BITMASK) ? 1 : 0;
		} else if (pin == 1) {
			return (CORE_PIN1_PINREG & CORE_PIN1_BITMASK) ? 1 : 0;
		} else if (pin == 2) {
			return (CORE_PIN2_PINREG & CORE_PIN2_BITMASK) ? 1 : 0;
		} else if (pin == 3) {
			return (CORE_PIN3_PINREG & CORE_PIN3_BITMASK) ? 1 : 0;
		} else if (pin == 4) {
			return (CORE_PIN4_PINREG & CORE_PIN4_BITMASK) ? 1 : 0;
		} else if (pin == 5) {
			return (CORE_PIN5_PINREG & CORE_PIN5_BITMASK) ? 1 : 0;
		} else if (pin == 6) {
...
So the compiler with optimizer if you call it with a constant like 0,
The code will be reduced to: CORE_PIN0_PINREG & CORE_PIN0_BITMASK) ? 1 : 0;

However if it is not a constant that the compiler can not deduce at compile time:
Then it will reduce to: return (*portInputRegister(pin) & digitalPinToBitMask(pin)) ? 1 : 0;
So it will have to do two macros, both which index into an array with the pin number and then extract either the address of the register or the mask. So again more code.

So again I don't know fully all of the details on how the compiler decides if __builtin_constant_p

For example if your array is setup: as const uint8_t portPinsC[] = {0, 1, 2, 3, 4, 5, 6, 7};

Then hopefully it will deduce the constants...
 
More informations as I expected :) Thank you very much. It seems that this forum is much better than the most. Less haters.


Here is the definition:

uint8_t portPinsD[pinCountC] = {1, 4, 2, 22, 5, 6, 7, 8};


I will do some tests tomorrow.
 
I had to rewrite a lot of fast code that was using GPIOC_PDIR, GPIOD_PDOR etc from Teensy 3.6 when I moved to the 4.0. Using individual digitalreadfasts wasn't an option since I needed the fastest-possible reads in parallel. Unfortunately it's really a pain that there's not a full, in-orderbyte worth of pins available on a single GPIO bank in the T4, but you can work around it if you're creative with your board designs and your coding.

Check the programming manual for the processor (linked from pjrc.com) for the gory details. I ended up with these defs in my project:
#define COMMAND_BUS_DATAREG GPIO7_DR
#define COMMAND_BUS_SETREG GPIO7_DR_SET
#define COMMAND_BUS_CLRREG GPIO7_DR_CLEAR
#define CE_BUS_SETREG GPIO7_DR_SET
#define CE_BUS_CLRREG GPIO7_DR_CLEAR
#define DATA_BUS_DATAREG GPIO6_DR
#define DATA_BUS_SETREG GPIO6_DR_SET
#define DATA_BUS_CLRREG GPIO6_DR_CLEAR
#define DATA_BUS_INPUTREG GPIO6_PSR

They're obviously application-specific, but you can see the important registers you'll need -- things like GPIO6_DR (which is physically tied to the same pins as GPIO1, but faster, if I understand it all right) work similarly to what the T3.6 would have called GPIOD_PDOR. Since the pins you'll want are NOT going to be bits 0 thru 7 on those 32 bit registers you have to do creative programming to read the various values you need without too much overhead.
 
Wow nice. I will definitely test this too.

Yes, the Teensy 4.0 is a little bit more complicated to handle. I also miss the very nice 5V tolerant Digital Pins very much.
 
Again it is sort of interesting.

There is some on another thread this morning on someone who was able to read in 8 bits on very specific pins, but had to do some shifting and masking.....
https://forum.pjrc.com/threads/5837...tomically-quot?p=221412&viewfull=1#post221412

Again @Utak, you could try to see differences in speed with your current stuff, and then simply changing your pin definitions:
Code:
const uint8_t portPinsD[pinCountC] = {1, 4, 2, 22, 5, 6, 7, 8};
Also assuming this is in the same code area that calls digitalReadFast

Also as noted in other thread: T4 processor can only read/write 32 bits to port registers, so will never have a way to read 8 or 16 bits from the register. That is a limitation of the underlying processor.

I will probably have a hacked up version of the PORTC/PORTD avr emulation later. For a first round for testing, will probably less optimize it on the DDR registers than the T3.x, will see.
But again the code still boils down to calling digitalReadFast...


FYI @Paul is discussing a larger version of the T4 with more pins... You can always add suggestions on what they should be, in the thread:
https://forum.pjrc.com/threads/5802...pothetical-larger-Teensy4?p=220669#post220669
 
@Paul and others.

I just did a PR with a pass of the code that appears to work at least in limited tested for PORTC/B/D AVR register emulations.
If anyone is interested Code is up at: https://github.com/KurtE/cores/tree/t4_avr_registers
PR: https://github.com/PaulStoffregen/cores/pull/404

I ran simple test case:
Code:
void setup()
{
  while (!Serial && millis() < 5000) ; // wait up to 5 seconds.
  Serial.begin(115200);
  Serial.println("Quick test to see if AVR emulation works ag all");
  // Quick and dirty test
  // PORTD Pins 0-7
  // PORTB Pins 8-13
  // PORTC Pins 14-19
  DDRD = 0xff;  // All Outputs;
  DDRB = 0;     // All Inputs
  DDRC = 0;     // All Inputs
}

uint8_t counter = 0;
void loop()
{
  PORTD = counter;
  Serial.printf("Count: %x, B:%x C:%x\n", counter, (uint8_t)PINB, (uint8_t)PINC);
  counter++;
  delay(250);
  if (Serial.available()) {
    while (Serial.read() != -1) ;
    Serial.println("Paused:");
    while (Serial1.read() == -1) ;
    while (Serial.read() != -1) ;
  }
}
Ran jumper wires from 0-7 to 8-15, and B: properly showed the lower 6 bits C: showed the upper 2 bits (on it's lower 2 bits).
Note: Found bug in T3.x version as well, which is fixed in this PR as well.

Did not test any of the PU setting stuff... But this can hopefully get some of you limping along.

But again want to stress: This is not atomic! (Nor was it on T3.x)... It again uses digitalWriteFast and digitalReadFast for each pin which do reduce down to a couple of instructions...
 
Question: pinModeFast is not available anymore?

Don't see it any any of the Teensy sources? That is I did a search in Sublime text at the directory where Teensyduino is installed and only see any hits in the library openGLCD
 
If you look at the second post in that thread:
Nevermind- I'm officially stupid. :-/ My code was using a 'pinModeFast' ad-hoc modification to the library that I did myself a few months ago, as described here. I just forgot about it. https://forum.pjrc.com/threads/28735...ll=1#post75044
The only other thing is that it was only applicable to the T3.1 and probably will still work for the T3.2. No similar function exists for the T4
 
Thanks. Ok, no fast pinMode :)

Finally I had success reading pins at 800Mhz and finished my project.

It would have been nice if I had more possibilities, so i had to delete some features, but at least it wasn't a complete failure ;-)

... and it seems, 800 Mhz is not enough. The slow Pin read speed (and also the slow pinMode) is very critical.
 
Status
Not open for further replies.
Back
Top