Teensy3 AVR port/pin compability macro defnition confusion.

bperrybap

Well-known member
Teensy3 has some compatibility macros for macros like:
digitalPinToPort() etc. that map pins to ports and bit masks.
While the Teensy3 compatibility macros actually will work the same
as the AVR versions,
the macro definitions are a bit confusing at first glance.

This is because of the goofy way the Arduino team did their mappings.
In their AVR definition,
digitalPinToPort(pin) returns a port table index value that is then handed to the macros:
portOutputRegister()
portInputRegister()
portModeRegister()
to get the port address.

So to get the actual port address associated with a pin when using AVR Arduino you must do:
portOutputRegister(digitalPinToPort(pin))


In the Teensy3 macros, they show every macro taking a pin argument.
While given the way the io register mapping currently works on Teensy3, that will work,
as well as when used the AVR way,
it was a bit jarring to me to see it defined this way since the portXXXRegister() macros
in AVR don't take a pin as a parameter but rather the goofy port index returned by digitalPinToPort()

So technically the definitions of digitalPinToPortReg() and digitalPinToBit()
should be:
Code:
#define digitalPinToPortReg(pin) portOutputRegister(digitalPinToPort(pin))
#define digitalPinToBit(pin) digitalPinToBitMask(pin)


Not sure how many folks really use these low level i/o interface but
for those that do, maybe a small comment and redefining the dititalPinToXX() macros above
would help to keep people from scratching their heads for a while until they figure it that it really does work.
And to keep them by using the pin number directly as the argument to the portOutputRegister() macro.

--- bill
 
So to get the actual port address associated with a pin when using AVR Arduino you must do:
portOutputRegister(digitalPinToPort(pin))

This works on Teensy, even though portOutputRegister() takes a pin number, because digitalPinToPort() is defined to just pass the pin number directly.
 
Yes, but what I meant was that the current Teensy3 definitions are technically incorrect
in that the stock Arduino AVR functions were not defined that way.
portOutputRegister()
portInputRegister()
portModeRegister()
do not take a pin number as an argument but rather a port index number returned by
digitalPinToPort()
While you can get away with passing in a pin number with Teensy3 (and it looks like perhaps AVR teensy as well)
that ends up creating non portable code.
My suggestion was to alter the macros or insert some comments to make it clearer that users should not be using the AVR API on Teensy3
in a way that would not work on the standard AVR cores.

For example, users that use
portOutputRegister(pin) on the UNO will not be happy.

So my suggestion was to redefine the macros more like:

Code:
// compatibility macros
#define digitalPinToPort(pin) (pin) // returns index for port macros
#define digitalPinToBitMask(pin) (1)
#define portOutputRegister(pinindx) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 0))
#define portSetRegister(pinindx)    ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 32))
#define portClearRegister(pinindx)  ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 64))
#define portToggleRegister(pinindx) ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 96))
#define portInputRegister(pinindx)  ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 128))
#define portModeRegister(pinindx)   ((volatile uint8_t *)(digital_pin_to_info_PGM[(pinindx)].reg + 160))
#define portConfigRegister(pinindx) ((volatile uint32_t *)(digital_pin_to_info_PGM[(pinindx)].config))


#define digitalPinToPortReg(pin) (portOutputRegister(digitalPinToPort(pin)))
#define digitalPinToBit(pin) dititalPinToBitMask(pin)

to try to steer people in the direction of portability.
It also can help insulate your users should you ever decide to change the i/o mapping in the future.
Maybe to allow doing multi bit i/o in the same register?

I have interest in multi bit i/o since I'd like to be able to do 8 bit i/o for the openGLCD library
to increase performance on teensy3. (it currently requires single bit i/o)

It's all pretty low level stuff, that most users don't use.
At least the way it is currently defined it still works
when used as defined in stock Arduino core so it's not a big deal for the non teensy
code coming into Teensy. Where it can be an issue is users that write to the Teensy macros
and take advantage of skipping a step by passing in the pin numbers directly
and then attempt to make it work on a non teensy core.


--- bill
 
Back
Top