Tutorial: Muxing With the New NXP Pins Tool
Erich Styger decided to make his own tutorial for muxing with the NXP pins tool. His step-by-step instructions will give you a very thorough walkthrough of how to get it done.
Join the DZone community and get the full member experience.
Join For FreeI don’t know if it is the same for you. But for me, configuring the pins on these new ARM microcontroller is a challenge; most pins can do multiple functions, such as be used as I²C, UART or GPIO pins.
Configuring the pins ‘by hand’ is difficult, error-prone and, usually, the first thing I need to do for a new project/device. NXP developed a new tool for this task and previewed it at FTF 2016. It is available now both as web (online) and desktop (locally installed) tool. At FTF it was possible to play with an engineering release — time to get my hands on the public release. And as more and more student projects will start using that tool for their boards, I better have a tutorial for it.
Overview
The pins tool is used to configure the pins (muxing, pin assignment, electrical properties, ...). It uses a graphical user interface for this, and the output is C source and header files I can use in C/C++ applications. It does the ‘muxing’ (more about this later), and just the muxing.
Pin Muxing and Application Flow
In a typical application, the code runs out of reset, runs through the startup code (set stack pointer, initialize memory and ANSI library), then calls main() (which does pin muxing, clock configuration and driver and middleware initialization) then calls the application code:
The pins tool does one single thing: pin muxing.
The output of the pins tool is what exists today in typical Kinetis SDK V2 projects as the pin_mux.c and pin_mux.h files.
Pin Mux in SDK V2.0 Project
At FTF it was clear that the Pins tool is just the first tool of a larger set of tools, and there will be similar tools for clock configuration and driver and middleware afterward.
The device drivers (UART, SPI, USB, I²C, …) are provided by the SDK (see "First NXP Kinetis SDK Release: SDK V2.0 with Online On-Demand Package Builder") which includes middleware like FreeRTOS or the USB stack.
Comparing with Processor Expert, the Pins Tool is similar to the ‘PinSetting’ component in Processor Expert:
That Processor Expert component does pin muxing and configuration:
Muxing
So why do I need such a Pins tool? Most, if not all pins on a modern microcontroller can be used for different functionality (UART, GPIO, I²C, SPI, …). That feature is implemented on the device with a multiplexer, and the common term for doing this is called ‘muxing’ or ‘muxing the pin(s)’. That muxing is a common source of mistakes and errors because the data sheets are not always crystal clear.
For example, the MK64FN1M0VLL12 on the FRDM-K64F board has 100 pins which need to be configured:
I have seen several board designs failing with boards produced, only to find out in the software that a pin cannot be used as intended because of some side conditions. That’s why I recommend my students to do the muxing and software *first*, and then do the board layout based on the muxing.
Pins Tool
NXP showcased the new Pins Tool at FTF 2016 in Austin/TX (see FTF-DES-N1958, FTF-DES-N1960 and FTF-DES-N1957) as part of the Kinetis Expert suite of configuration tools. It exists as an online version and as a desktop application on a host (Windows, Mac, Linux). I tried out only the Windows version so far. The Web version is accessible from http://kex.nxp.com/ and the Desktop installers can be downloaded from http://www.nxp.com/ksdk.
The functionality is the same with very minor differences, e.g. for menus and file handling. Personally, I prefer the desktop version as I’m traveling by train a lot with no internet connection. And because my internet connection is not that fast, the desktop version suits better for me.
Installation
For the desktop version installers available in the download section of http://www.nxp.com/ksdk, there is an offline (around 130 MByte which includes Java runtime in case it is installed on the host) and an online (0.5 MByte) version. The difference is that the online version will fetch the installation data from the internet during installation, while the offline version has that already included.
I recommend the ‘offline’ version especially for slower internet connections. For both versions, the device data is not included in the download.
For the desktop version on Windows, both a 32bit (x86) and a 64bit (x64) version is provided. Make sure you download the one matching your host OS. There is a .pkg for Mac OS X and both dep and rpm packages for Linux (64bit).
Launching the Tool
The web version of the tool is started using the button on http://kex.nxp.com/:
For the desktop version there is a shortcut available:
Configuration
As the Kinetis SDK (see "First NXP Kinetis SDK Release: SDK V2.0 with Online On-Demand Package Builder"), the tool needs a ‘configuration’. Basically this specifies the device, package and all other needed information for the tool.
New Configuration with the Desktop Tool
Starting the Desktop tool, it asks to create a new configuration first. I can pick a board or a device/processor:
When creating a configuration for a device the first time, it downloads the data from the internet:
The device data is loaded from the internet when I’m creating a new configuration for a new device. On my Windows 7 machine the data is stored in C:\ProgramData\NXP.
A new configuration is created anytime with a menu:
Unlike the web version which works directly with the data in the cloud, configurations are stored/loaded on the disk with the desktop tool. The configurations are stored as .mex (XML) files.
New Configuration with the Web Tool
In the web version, use the ‘Tools’ menu to select Pins tool:
If using the tool the first time, it might not have configuration yet:
To create a new configuration:
Then select the device or board from the list. Optionally I can give it a different name:
The Pins tool will create code for the SDK 2.0. If I do not have the SDK yet, I need to build one first. In this tutorial I’m using the Kinetis Design Studio as IDE on Windows:
I get a notification when the new build is available:
Click on the download icon to download the file:
It will ask for a license agreement (does anyone ever read that full text?), then store the file on the disk.
I place and extract all my SDK packages into a common folder (e.g. C:\nxp\KSDK), but that’s up to you.
As I have now a configuration, I switch back to the Pins tool with the Tools menu:
Main View
This shows me the first view:
On the left: the list of pins and peripherals. In the middle is the CPU package with the routed pins, and on the right hand side the generated source code and registers information.
Menus
Source code is generated automatically in the background, but I have a menu to generate it too:
I can change the package (pin out) with the ‘Switch package’ menu, or I can use the button in the package view:
The help menu gives access to release notes and documentation resources:
Localization
Both the web and desktop tool do support multiple display languages: English and Chinese. In the web version it is a menu entry:
In the Desktop version it uses the locale of the host machine. I can force a language in the startup parameter of the executable:
-nl <language>
With <language> as:
- en: English
- zh: Chinese
There is another way changing the language by modifying the .ini file, as explained in the release notes.
Example: Muxing RGB LEDs
In the following example, I’m going to configure three pins on the FRDM-K64F board which are connected to the RGB LED. If you have a different board, then you need to check the schematics.
The one for the FRDM-K64F looks like this:
- Red LED: PTB22
- Green LED: PTE26
- Blue LED: PTB21
In the ‘Pins’ view I can filter for the pins I’m looking for:
I click on the pin check box to mux it:
As the pin has several options, I get a dialog from where I can select the GPIO function. At the end, if that muxing works out, it turns green:
The selected pin gets added to the list of routed pins:
That’s just one way to configure pins. Another way is to select the PTE26 from the Peripherals view:
Another fast way to configure a pin is to use the tabular Pins view. It is like an Excel sheet, and I can simply click on a cell to mux it:
And it is possible to export that table view in a CSV file format for Excel, using Export > Export the Pins in CSV from the Pins menu (web version) or from the File menu (Desktop version):
There is a filter check box I can use to only show the configured pins:
Because usually not all pins have interrupt capabilities, there is a filter for this too:
Similar to that, there is filter for pins which can wake up the device from low power mode:
Selecting a pin or a group of pins is highlighting it on the package so I can see where it is located:
Highlighting
I can add/remove pins by clicking on the pin or peripheral block in the package view too:
The pin gets added to the list of routed pins. As I have assigned just the pin number, I can change the settings there too. For example to assign GPIOB function to pin number 67:
The context menu allows me to change the items in the list or change the order:
The same way I can use the toolbar icons to add/remove/move items in the list:
All three LED pins are output pins, so I set the direction:
So I have them all set as output pins:
Registers View
In the registers view, I can filter for the configured registers and inspect what registers are affected. The ‘Set Value’ shows the configured value, and the ‘Reset value’ the default/out-of-reset’ one:
Sources
While I’m doing changes, it generates the code for it in the background. I can check the sources in the sources view on the right side:
Yet Another Markup Language?
One interesting thing in the generated sources are comments like this one:
/*
* TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL *****************************
PinsProfile:
- !!product 'Pins v1.0'
- !!processor 'MK64FN1M0xxx12'
- !!package 'MK64FN1M0VLL12'
- !!mcu_data 'ksdk2_0'
- !!processor_version '1.0.0'
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL ***
*/
/*
* TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL *****************************
BOARD_InitPins:
- options: {coreID: singlecore, enableClock: 'false'}
- pin_list:
- {pin_num: '66', peripheral: GPIOB, signal: 'GPIO, 20', pin_signal: PTB20/SPI2_PCS0/FB_AD31/CMP0_OUT, direction: OUTPUT}
- {pin_num: '67', peripheral: GPIOB, signal: 'GPIO, 21', pin_signal: PTB21/SPI2_SCK/FB_AD30/CMP1_OUT, direction: OUTPUT}
- {pin_num: '33', peripheral: GPIOE, signal: 'GPIO, 26', pin_signal: PTE26/ENET_1588_CLKIN/UART4_CTS_b/RTC_CLKOUT/USB_CLKIN, direction: OUTPUT}
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL ***
*/
The comment mentions YAML: a data serialization language. So the settings are stored inside the sources which is a neat way because that way the settings end up in a version control system with the source files.
And indeed, I can import source files with YAML using the Import menu:
Then I can import one or more .c files with YAML comments in it:
So all that I need to get the data imported into the Pins tool are such YAML content in source files. Which means I can pass my students pin_mux sources with YAML content, they can load it into the tool and extend/change the content with the tool and store it back. Or I could write-up a YAML generator tool which would create YAML files as input for the tool. Or NXP could give their examples with YAML content in it, and I can simply take the example source files and do my stuff with it. Up to the point to change the YAML content ‘by hand’ (e.g. to change a pin assignment) and then have the tool to create the source code for it. I think that’s a very neat way to deal with data and settings.
Clock Gate Enable
You might notice that there is some clock enable code at the start of BOARD_InitPins():
CLOCK_EnableClock(kCLOCK_PortB); /* Port B Clock Gate Control: Clock enabled */
CLOCK_EnableClock(kCLOCK_PortE); /* Port E Clock Gate Control: Clock enabled */
This can be turned off in the settings behind the menu Pins > Properties menu:
The same dialog specifies the ‘Function’ name which is shown in the ‘tab’ below for the ‘Routed Pins’ and which is used in the generated source code:
‘Functions’ are treated as independent muxing functions. The BOARD_InitPins() is the default function used by the SDK. But I can add my own functions:
I can give it my name e.g. with the ‘Rename’ context menu on the tab. One use case would be to do de-init pins and put them back to the ‘Reset’ values. For this there is a ‘Reset’ menu on a pin:
With this, I have a BOARD_DeinitPins() function which puts the values back to the reset values:
Putting Pins back to Reset Values
Using it With Kinetis Design Studio
The tool generates source files compatible with the NXP Kinetis SDK V2.0.
I can create new a new SDK v2.0 project in Kinetis Design Studio with the menu File > New > Kinetis SDK 2.x Project:
If this is the first time, I have to browse for SDK first. I select the SDK I want to use and give a name to the project:
Next, select the board or processor. With selecting a board it will pre-configure things like UART. If you want to create a minimal project, select the device from the list of processors.
The selection of drivers and RTOS depends on the needs, in this example I use ‘all drivers’ and ‘no RTOS’:
The pin muxing files are inside the ‘board’ folder:
I need to replace the pin_mux.c and pin_mux.h with the configuration files created by the Pins tool. For this, I have several options:
- copy-paste: I can select the content of the files (CTR-A to select all), then copy it (CTRL-C), and finally pasting it into the source editor view in Eclipse. Do this for the .c and .h file.
- export: Use the export menu.
To export in the web version, use the menu item in the Pins menu:
In the desktop version that function is under the File menu:
Select Export Source Files, press Next.
In the next dialog I can specify the file name:
Press Finish, and it will download a zip archive:
The archive includes both the pin_mux.h and pin_mux.c which I can use to replace the files inside my SDK V2.0 project. Additionally, it includes the .mex file which I can import again into the tool.
With the desktop version of the tool, it is even simpler: I can directly specify where the files should be stored, e.g. inside my project:
If the file(s) already exist, I will be prompted to overwrite them.
Toggling the LEDs
The new pin_mux.c and pin_mux.h only do the muxing.The muxing code get called with BOARD_InitPins() from main():
int main(void) {
/* Init board hardware. */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
/* Add your code here */
for(;;) { /* Infinite loop to avoid leaving the main function */
__asm("NOP"); /* something to use as a breakpoint stop while looping */
}
}
They do not implement the GPIO driver initialization. So I need to add code to initialize the GPIO driver and configure the pins for output:
#define LED_RED_BIT 21 /* PTB21 */
#define LED_GREEN_BIT 22 /* PTB22 */
#define LED_BLUE_BIT 26 /* PTE26 */
static const gpio_pin_config_t LED_configOutput = {
kGPIO_DigitalOutput, /* use as output pin */
1, /* initial value */
};
/*!
* @brief Initialize GPIO.
*/
static void InitGPIO(void) {
GPIO_PinInit(GPIOB, LED_RED_BIT, &LED_configOutput); /* configure PORTB21 as output */
GPIO_PinInit(GPIOB, LED_GREEN_BIT, &LED_configOutput); /* configure PORTB22 as output */
GPIO_PinInit(GPIOE, LED_BLUE_BIT, &LED_configOutput); /* configure PORTE26 as output */
}
Below is the complete code in main.c which calls the initialization and toggles the pins inside main():
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#define LED_RED_BIT 21 /* PTB21 */
#define LED_GREEN_BIT 22 /* PTB22 */
#define LED_BLUE_BIT 26 /* PTE26 */
static const gpio_pin_config_t LED_configOutput = {
kGPIO_DigitalOutput, /* use as output pin */
1, /* initial value */
};
static void InitGPIO(void) {
GPIO_PinInit(GPIOB, LED_RED_BIT, &LED_configOutput); /* configure PORTB21 as output */
GPIO_PinInit(GPIOB, LED_GREEN_BIT, &LED_configOutput); /* configure PORTB22 as output */
GPIO_PinInit(GPIOE, LED_BLUE_BIT, &LED_configOutput); /* configure PORTE26 as output */
}
/*!
* @brief Application entry point.
*/
int main(void) {
/* Init board hardware. */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
/* Add your code here */
InitGPIO();
for(;;) { /* Infinite loop to avoid leaving the main function */
GPIO_TogglePinsOutput(GPIOB, 1<<LED_RED_BIT); /* toggle RED LED */
GPIO_TogglePinsOutput(GPIOB, 1<<LED_GREEN_BIT); /* toggle GREEN LED */
GPIO_TogglePinsOutput(GPIOE, 1<<LED_BLUE_BIT); /* toggle BLUE LED */
__asm("NOP"); /* something to use as a breakpoint stop while looping */
}
}
With that, the project should compile and build just fine.
Running the program with the debugger, and it toggles the RGB LED on the board
Summary
With the Pins tool, I have now a way to configure and mux the pins with my SDK V2.0 projects. It is an easy-to-use tool, which just does that — dealing with the pins. For anyone who does not want to install the tool, there is a web-based version. Personally, I prefer the tool installed as desktop version: that way I can store it in a version control system so I have it always available.
I love the way how the tool stores and uses its data directly in the sources using YAML. This makes it simple and easy to pass muxing information around, and the settings will be automatically stored in the version control system with the YAML settings in the sources.
I hope you find that tool as useful as I do.
Happy Muxing!
Published at DZone with permission of Erich Styger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments