Teensy 4.1 : GPIO config is NOT glitch free

tjaekel

Well-known member
The library functions for Teensy 4.1 GPIOs, e.g. in "digital.c" do NOT support a glitch free configuration.

Use Case
I want to generate an nRES signal (low active, inactive is high) for an external board.
If I reset the MCU, e.g. via software, as a command, BTW: I do via:

Code:
  ////NVIC_SystemReset();     //CMSIS files do not work!
  SCB_AIRCR = 0x05FA0004;

the nRES signal (GPIO output) generates a low pulse glitch (and resets also the external board).

Reason
When you reset MCU - all signals, GPIOs, become floating, until they are configured again, here as Output.
But it is NOT POSSIBLE to set the GPIO output register BEFORE you configure GPIO as output.
Due to fact that output register is reset (has value 0), a GPIO config for output generates a tiny low pulse before GPIO is set to high (as inactive), a glitch.

The function
Code:
void digitalWrite(uint8_t pin, uint8_t val)
which sets the GPIO output value (low or high), can ONLY be called AFTER GPIO is set to output:

This generates a transition from (MCU reset) value low to high (set as default inactive in a subsequent function call).
This happens on every MCU reset and resets also my external board - even you have a pull-up there in order to deal with the floating signal during reset.

If you do this - which FAILS completely:
Code:
digitalWrite(2, arduino::HIGH);
pinMode(2, arduino::OUTPUT);
it does not set the GPIO output register - instead: it uses the value as pull-up or pull-down config value for an input (pin is still an input when this call is done).
You do not have any support to preset the output register for GPIO before you bring it into output mode.

Solution
Create a new function which has this code:

Code:
void GPIO_setOutValue(uint8_t pin, uint8_t val)
{
	const struct digital_pin_bitband_and_config_table_struct *p;
	uint32_t mask;

	if (pin >= CORE_NUM_DIGITAL) return;
	p = digital_pin_to_info_PGM + pin;
	mask = p->mask;
	{
		// pin is configured for output mode
		if (val) {
			*(p->reg + 0x21) = mask; // set register
		} else {
			*(p->reg + 0x22) = mask; // clear register
		}
  }
}

Now you SHOULD do:
Code:
  //configure nRES output signal
  GPIO_setOutValue(2, arduino::HIGH);
  pinMode(2, arduino::OUTPUT);
  //drive high as default
  ////digitalWrite(2, arduino::HIGH);

With an external pull-up (internal does not help, it does not work), this signal is now glitch free.

Why the LIB functions are not coded in a way that you can set GPIO output before you enable as output?
(this would be professional and the right way to do, common "standard" for me)
 
Why the LIB functions are not coded in a way that you can set GPIO output before you enable as output?
(this would be professional and the right way to do, common "standard" for me)

tjaekel:

I did not write the underlying GPIO code, so I can only guess. However, having used GPIO extensively in many of my Teensy projects, my guess would be that those routines are most likely written with speed and/or consistency across multiple Teensy products as the primary objective. Your suggested routine would add additional time to every GPIO call, which would be highly unacceptable in some applications. You are always free (as you have done) to incorporate your own unique functions, which are locally optimized to satisfy the specific requirements of your application. However, your suggested function may not be as generally applicable as you may think, and certainly is no more or less professional than any other approach (including the standard GPIO support). Just to point out an alternative that you may not have considered, you could also have added a hardware inverter after the GPIO signal that you are using, and thereby, the default LOW value of the GPIO pin would no longer force a reset on your unique hardware !! There are always multiple solutions to every problem. It's both your task and your obligation to find the best solution in your particular case. By your own description, you have successfully made a choice to add new firmware functionality which uniquely solves your particular problem.

Mark J Culross
KD5RXT
 
Last edited:
Yes, that's a good call - the pull up code is there to maintain compatibility with original AVR hardware behaviour, but missed this case - I wonder if this has bitten others? I think the fix is one-line.

One way to contribute (if you have experience driving git) is to clone a copy the Teensy core library and create a PR with a suggested fix:

https://github.com/PaulStoffregen/cores, see teensy4/digital.c

If not I'm sure someone else will - I don't think there's much risk of breaking existing code with this, its important the semantics match other microcontroller chips!
 
Back
Top