Sample code using GPIO?

Status
Not open for further replies.

alan856

Well-known member
Could somebody point me to a link or code sample of setting up and using GPIO functions in a Teensy 4 or earlier. I've gone over the datasheet and see the functions, but a bit unclear on how to set it up - how to specify what GPIO section and setting pins... Hoping to read a full 32 bit section and pull out 8 bits from an encoder.
 
I am not sure what you are asking for? T4 and T3.x... use the same function like pinMode and digitalWrite that are described in Arduino manual: https://www.arduino.cc/reference/en/language/functions/digital-io/pinmode/

Examples for this throughout the installation, example the blink sketch.

If you are wanting to not use the functions, you can manipulate stuff at the registers level. That is if you choose to work at that level than you need to look at reference manual, plus figure out which pins are on which IO port. Several threads about this recently. You need to configure each of these pins to be setup for GPIO input. Obviously using something like pinMode(pin, INPUT);
is the easiest way to do this. Otherwise you will need to set all of the IOMUXC setting associated with the pin to setup the signal and the pad for appropriate usage. If you are interested in this, look at the sources for pinMode.

Then you need to read the current values for the pins, like: uint32_t pin_values = GPIO6_DR;
Assuming your pins are on GPI6
 
This is what I'd like to do: "Otherwise you will need to set all of the IOMUXC setting associated with the pin to setup the signal and the pad for appropriate usage. If you are interested in this, look at the sources for pinMode.

Then you need to read the current values for the pins, like: uint32_t pin_values = GPIO6_DR;
"

Where can I find out how to setup IOMUXC?
 
You were already told: "you need to look at reference manual"... That's where all the details are.
Also you were told: "If you are interested in this, look at the sources for pinMode" [ see digital.c in the sources ]
 
But I HAVE looked at the "reference manual" - I have it all printed out and it still is not clear out to SET UP the GPIO to actually use.
 
Assuming T4.x

Chapters 9-11 of the IMXRT1060RM.pdf has all of the data.
Register names and masks are defined in imxrt.h in the core\teensy4

But with all things like this, I personally learn the most by looking at the sources.

So if it were me, I would look at what pinMode does (digital.c)

Other subsystems do their own initialize stuff, but again you need then to refer back to reference manual.
As you will see lines like: *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
TO then look to see what each of these setting mean.

Again easiest to just call pinMode...
 
Kurt - I have chapter 11 printed out - but missed 9&10 - will dig into those. And I didn't know WHERE to look for the code for pinMode was - digital.c. That will be a help too.

The IMXRT pdf is so huge and has so much stuff it is tricky to sift out the parts one needs for a given task. The GPIO section mentions the IOMUXC registers - but it wasn't clear there was a separate chapter on that. Not looking for easy - just want to get a bit of a handle on some of the finer points. If I wanted 'easy' I go with an Arduino Pro Micro or Nano! :)
Thanks for the extra info - will be a good start.
 
uTasker- many thanks for the link.

Having worked long with the simplistic Arduino world - the depth and detail available in these powerful chips is quite stunning.

Sadly - just telling a new user to "the details are in the datasheet" is like telling a new med student - "the details are in Gray's Anatomy"! There is a bit more to it than that...

The simplified Arduino IDE approach given by the Teensy platform is def a god-send for making easy use of these chips - but it would be great if there were some sort of 'bridge' documentation that could help the "junior programmer" to correlate the concepts from the simplistic Arduino world to the depth of the ARM world. I.E. - using "GPIO" pins on the simpler platforms is an 'out of the box' affair while this more advanced world one needs to do a bunch more to set them up and get them ready to use.

Lots of digging ahead! :D
 
Ahan856

First thing to remember is that the GPIO and peripherals have nothing to do with ARM. ARM delivers only the core and the rest is up to the processor chip manufacturer. GPIO control in the i.MX RT is easy except for the fact that NXP doesn't directly use GPIO naming conventions but instead refers to the GPIO to their PAD references instead. If one blends out the PAD name conversions and just thinks in GPIO names they are not really any different than the Teensy 3 board's Kinetis parts.

Unfortunately there will never be a two page tutorial that will get a junior programmer up to speed - just trying to explain the NXP PAD/GPIO naming convention take a 12 minutes video and I didn't even try a document since most would already give up trying to follow something written half way through.

I have written many documents, made a number of videos and also developed a complete simulation of the i.MX RT parts which is used by some schools and universities to help learning:
- https://www.utasker.com/docs/iMX/uTaskerV1.4_iMX.pdf (tutorial)
- https://www.utasker.com/docs/iMX/i.MX_RT_1021_uTasker.pdf i.MX RT (also valid for (1062) practical guide for those wanting to be more that script kiddies in at least understanding general things going on under the cover
- General peripherals, USB, FAT etc. documents https://www.utasker.com/docs/documentation.html
- i.MX RT playlist: https://www.youtube.com/playlist?list=PLWKlVb_MqDQEOCnsNOJO8gd3jDCwiyKKe

So if there were ever a single document to allow a junior programmer to get to grips it will likely be longer that the user's manual, so either one accepts that they don't have the time or motivation and stick with the script-kiddy stuff like most others or else one needs to accept that it can be hard out there and start studying and working. My journey (as a professional Kinetis and i.MX RT trainer and programmer) started some 9 months ago (for i.MX RT and some 9 years ago for Kinetis) and involves 8 hours a day since then and will never end until the chips become so old that no one is interested in them any more. Likely it means another 6..8 years of 8 hours days to become fully proficient with all i.MX Rt possibilities and producing videos and documents for those who still clutch to the dream that someone else will be able to magic up that two page document to make it simple for all those who doesn't really have the motivation to invest the time for themselves.

What I have done is attached a HEX file that can be loaded to a Teensy 4.0 which includes a three level OTA and serial loader solution with full AES256 level encyption and clone protection (it works on Teensy 4.0 without changing any eFUSES so can be overwritten without any issues including a number of things that can be played with (eg. it allows viewing all RAM and QSPI flash contents via USB-MSD, with file and parameter system in QSPI):
Some details - https://www.utasker.com/docs/iMX/uTaskerLoader_TestDrive.pdf

Users of the uTasker project use this as base, which can be fully simulated in Visual Studio (for easier debugging and general learning of programming and i.MX RT operations) The same program works on a number of popular i.MX RT development board so it is HW and also tool chain independent (allows IAR, MCUXpresso, VisualStudio, GCC bat file etc.).

Regards

Mark
 

Attachments

  • uTaskerCompleteImage_TEENSY4_0.zip
    179.1 KB · Views: 69
Mark - rest assured I'm well aware there is no real 'easy' route to the ARM-spec'd SoC chips. A few years ago a tried to get into some of the code available from MBED and NXP IDE kits. It was pretty daunting and I sorta... fell by the wayside. Have a couple of development boards gathering dust...

What I've been thinking of was a sort of "block-diagram-guide" that could point one to the various sections of the datasheet that were needed to use some of the various peripherals. Like a "setup guide to GPIO" or a "setup guide to UARTS"... etc. Something that might show the needed datasheet sections to study (like now I know I need to add IOMUXC details). Just sort of a "Rosetta Stone" to the 3300 pages of goodies! :) It isn't so much lack of motivation as it is not knowing which way to go first.

I also tried (before Teensy) to dig into the HAL System of drivers - and pretty much got swamped. It isn't that I don't have a good tech background - I understand the 'bits & bobs' - but it is trying to get them together that leads down a deep set of "twisty, windy passageways"! Another issue may be that for most of the (casual) things I'd like to do these chip are way overkill. I've been programming since 1976 (PDP-11 05!) and the stunning capability now available was a real challenge and was hoping to 'get into' them. A couple years ago I became aware of the Cortex M3 & M4 KNEW this was the wave of the future - and was hoping to get to use them... but I think my ship has sailed and maybe I should just stick to Teensy/Arduino stye coding.

In any case - A BIG thanks for all the details and file in your note - will be taking a look at it all. :)
 
Like a "setup guide to GPIO" or a "setup guide to UARTS"... etc.

Alan

I use macros for GPIO so that they are more or less portable between parts.
Eg. To set up a GPIO output:

#define USER_LED (PIN_GPIO_11_GPIO1_IO11) // USER_LED ('1' drives LED on)
#define INIT__LED() _CONFIG_DRIVE_PORT_OUTPUT_VALUE(1, (USER_LED), (USER_LED), (PORT_SRE_SLOW | PORT_DSE_HIGH))
#define TOGGLE_LED() _TOGGLE_PORT(1, USER_LED)
#define SET_LED_OFF() _SETBITS(1, USER_LED)
#define SET_LED_ON() _CLEARBITS(1, USER)

Behind the macros there is sometimes simple stuff and sometimes a bit more (to enable port clocks and such) and the list that i have used for the last 15 years is
https://www.utasker.com/forum/index.php?topic=1875.0

So to move to different ports basically USER_LED is redefined (possibly to suit the processor since this define is specific to an i.MX RT 1010).
In code it configures with
INIT__LED();
once and then can use the toggle, on or off macros as required.


For UARTs I use a standard interface: https://www.utasker.com/docs/uTasker/uTaskerUART.PDF
with handle = fnOpen(TYPE_TTY, FOR_I_O, &parameters);
parameters contains the port to be used, serial details and things like DMA operation or not. It thus allows run-time changing of the UART used (rather than hard coding to a physical interface) and the user doesn't need to know whether it is physically a LPUART on an i.MX RT or on a UART Kinetis etc.

Regards

Mark
 
Mark - those macros are a great guide! I can get the 'sense of things' from them - will be a big help moving on. Have bookmarked your links and will be trying out the HEX code soon.

THANKS!

=Alan R.
 
Alan

Here are a few of the HW macros used for i.MX RT:

// Toggle a port with a mask eg. _TOGGLE_PORT(1, PORT1_BIT3)
//
#define _TOGGLE_PORT(ref, mask) GPIO##ref##_DR_TOGGLE = (mask)

// Read from a port with a mask eg. _READ_PORT(1, (PORT1_BIT3 | PORT1_BIT0))
//
#define _READ_PORT_MASK(ref, mask) (GPIO##ref##_PSR & (mask))

// Configure outputs, including enabling clock to specified port, and then set a value to them - this device sets the value and then drives
// eg. _CONFIG_DRIVE_PORT_OUTPUT_VALUE(1, (PORT1_BIT13), (PORT1_BIT13), (PORT_SRE_SLOW | PORT_DSE_HIGH))
//
#define _CONFIG_DRIVE_PORT_OUTPUT_VALUE(ref, pins, value, chars) fnConnectGPIO(PORT##ref, pins, (IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_GPIO | chars)); GPIO##ref##_DR = ((GPIO##ref##_DR & ~(pins)) | (value)); GPIO##ref##_GDIR |= (pins)

// Set from inputs to outputs and set a value to them - this is equivalent to _CONFIG_DRIVE_PORT_OUTPUT_VALUE on this device
//
#define _DRIVE_PORT_OUTPUT_VALUE(ref, pins, value) GPIO##ref##_DR = ((GPIO##ref##_DR & ~(pins)) | (value)); GPIO##ref##_GDIR |= (pins)

// Set from outputs to inputs eg. _FLOAT_PORT(1, LCD_BUS_BITS)
//
#define _FLOAT_PORT(ref, pins) GPIO##ref##_GDIR &= ~(pins)

// Set from inputs to outputs eg. _DRIVE_PORT_OUTPUT(1, LCD_BUS_BITS)
//
#define _DRIVE_PORT_OUTPUT(ref, pins) GPIO##ref##_GDIR |= (pins)

// Set and clear individual bits of a port eg. _SETBITS(1, (PORT1_BIT5 | PORT1_BIT19)) / _CLEARBITS(1, (PORT1_BIT5 | PORT1_BIT19))
//
#define _SETBITS(ref, pins) GPIO##ref##_DR_SET = (pins)
#define _CLEARBITS(ref, pins) GPIO##ref##_DR_CLEAR = (pins)


Unfortunately since the GPIO/PAD layout is different for various i.MX RT parts the routine fnConnectGPIO() needs to be called under the cover to do some dirty work during configuration. I have attached it as reference.

If you are serious about learning you can also subscribe to the uTasker developer's project (it is made available for free to educational establishments and hobby users who are serious about learning) and includes an i.MX RT and Teensy 4.0) simulation that allows the peripherals to be studied from the inside out.. including interrupt and DMA operations: https://www.utasker.com/iMX/Teensy_4_0.html)

Good luck

Regards

Mark
 

Attachments

  • fnConnectGPIO.c
    13.3 KB · Views: 89
Mark - I have loaded the .c file into MS Visual Studio 2019 - my primary IDE. I haven't worked with plain .c files in this environment - so will figure out where to save it. Lotta good stuff!
So how do I subscribe to the developer's project? I went to the utasker.com site and tried to join forum - but it is apparently taking no new members.

I already have a T4.1, T4, and a number of other T3's (and too many various Nano, Pro Micro Mini boards, etc). When I caught on the the "Teensy" system I got some 'for later'. When I heard of the T4 and T4.1 just HAD to get one of each - who wouldn't want a 600 MHZ mcu on their desk! :)

=A.
 
... an just a snarky "you were already told" does not help much! :mad:

Didn't mean to be snarky, you seemed to be asking for the source of information on this again having been pointed at it,
you didn't offer any concrete example of what you needed to know - code for pinMode and digitalRead/Write and the
data in core_pins.h seems to be a good basis for figuring this.
 
MarkT - Noob apologies! I FINALLY took a look at digital.c and found out that it appears "Arduino-style" ports are being implemented through Teensy GPIO port settings. !!! More of the genius of Paul and the Teensy IDE.
 
Note: Yes there is some c++ wrapper glue to emulate AVR registers, where you can use things like PORTD PIND...

BUT under the covers this translates more or less into digitalReadFast, digitalWriteFast for each logical pin... Example if your code does something like:
int d_pins = PIND;

This translates into:
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;
	}
So unless you are simply needing a quick and dirty transfer of code from an AVR based board to a teensy, I personally would recommend not going this route
 
Status
Not open for further replies.
Back
Top