Replacement for regular GPIO (DigitalIn, DigitalOut, DigitalInOut) classes which has superior speed.

Dependents:   Eavesdropper BitstreamGenerator SimpleDecimationFilter 11U68_MP3Player with TFTLCD ... more

Introduction

FastIO is a library which is largely compatible with standard mbed GPIO functions, but which provides superior speed. The code is based on Igor's earlier work (http://mbed.org/users/igorsk/notebook/fast-gpio-with-c-templates/), with three main differences: port functions are currently not available (this might change in the future), it is ported to many more targets than the original, and instead of only DigitalOut, all options from DigitalInOut are implemented.

FastIO uses a template for the pin number which is connected to the FastInOut object instead of an argument to the constructor like the regular DigitalInOut uses. The important difference between those two is that the value of a template is known by the compiler at compile time, while the supplied pin for regular DigitalInOut is only known at run-time. This allows the compiler to add more optimizations. The only limitations this introduces is that you cannot at run-time choose which pin is used (which would be an extremely rare use case).

You can start by trying out the test bench program, this should work for every supported target (you might need to update the FastIO lib):

Import programFastIO_TestBench

Testbench for FastIO

Currently the following targets are supported:

  • LPC1768
  • LPC11uXX
  • LPC11XX
  • LPC81X
  • KLXXz
  • K20D50M
  • KSDK (K22F, K64F)
  • NUCLEO F401RE/F411RE
  • NUCLEO F030R8
  • EFM32 (Gecko's)
  • NRF51822

Unsupported targets

This library has the nice feature that it also supports unsupported targets. Obviously these do not get the speed advantage of FastIO, but in case your target is not supported, it will automatically use regular DigitalInOut instead. So if you integrate it in another library it will also work on targets which are not supported by FastIO.

A warning message is printed in the compiler if it reverts back to DigitalInOut.

Performance

The main goal is to have a faster, more efficient alternative to regular mbed GPIO functions, so lets compare that. As of library version 86, the mbed library contains extra debug code that is as of yet not possible to be disabled (in the online compiler in a suitable way). This slows DigitalInOut down compared to older versions, but does not affect FastIO. This is, depending on the function, roughly a factor 2 difference: mbed version 86 is twice as slow as version 85.

Five different performance figures are measured:

  • Fixed write(pin.write(1);)
  • Variable write (pin.write(val);)
  • Reading the pin state and comparing it (if (pin.read() == 0) break;)
  • Toggling a pin using operators (pin= !pin;)
  • Switching between input and output (pin.output(); pin.input();)

While there are other use cases, these should cover the most used ones. Storing the read value is not included, but should have a fairly similar result. Just comparing it is an easy way to make sure the operation cannot be (partially) optimized away by the compiler, although it results in a longer time than what is actually used by purely the read operation. The main goal of FastIO is to have fast writing, reading, and toggling between input and output (for bidirectional lines), fast construction and mode switching is preferred, but not as important.

The following table shows the time used by fastIO, and also as percentage compared to regular DigitalInOut, this will scale with your clock frequency:

TargetFixed writeVariable writeReadOperator togglingInput/output mode
LPC1768 (96MHz)21ns (29%)78ns (68%)52ns (100%)52ns (28%)52ns (26%)
LPC11uXX (48MHz)83ns (38%)135ns (39%)208ns (60%)219ns (25%)146ns (19%)
LPC11XX (48MHz)104 ns (16%)177ns (22%)125ns (29%)240ns (18%)156ns (12%)
LPC81X (12MHz)229ns (28%)583ns (31%)583ns (100%)708ns (27%)479ns (20%)
KLXXz (48MHz)78ns (54%)146ns (78%)83ns (100%)187ns (38%)78ns (17%)
K20D50M (48MHz)135ns (41%)188ns (47%)104ns (42%)321ns (37%)156ns (17%)
KSDK (120MHz)33ns (4%)62ns (7%)42ns (14%)117ns (10%)33ns (4%)
NUCLEO F4X1RE (84MHz)24ns (27%)83ns (62%)60ns (100%)60ns (27%)60ns (5%)
NUCLEO F030R8 (48MHz)68ns (33%)115ns (36%)125ns (100%)188ns (39%)141ns (5%)
EFM32 (Wonder Gecko) (48MHz)78ns (22%)146ns (40%)188ns (64%)218ns (23%)250ns (10%)
NRF51822 (16MHz)183ns (20%)339ns (25%)372ns (40%)525ns (21%)183ns (7%)

Note that these numbers are from the specific testbench, which highly depends on which optimizations the compiler decides to make. So for your situation it can be different, for example I have seen the write speed change after changes to the read code. Mbed standard write speed also depends on the library version. Since not all targets are supported in older versions I stopped tracking that speed (was also too much effort). If you want to know the comparison for a certain library version, run the testbench on that version.

Usage

The library contains three classes you can use:

FastInOut<PinName> your_name;
FastOut<PinName, initial_state> your_name;
FastIn<PinName, initial_mode> your_name;

Initial_state is by default 0 (so output low) and is optional, initial_mode is by default PullDefault, and is optional. Some examples:

FastOut<LED1> led;             //FastOut object for LED1, will default to output low
FastIn<D5, PullUp> input;    //FastIn object for D5, with by default PullUps enabled

Contrary to regular DigitalIn/DigitalOut, FastIn/FastOut can use all functions available to DigitalInOut/FastInOut. The only difference between the three FastIO classes is the initial conditions: FastInOut doesn't set any initial conditions, and the current state of the uC will be maintained. FastOut sets it as output, either high or low, and FastIn as input, with or without pullups/pulldowns enabled. Afterwards you can change your FastIn to an output using simply .output().

For other examples you can look at the test bench code.

Committer:
Sissors
Date:
Tue Sep 20 20:41:42 2016 +0000
Revision:
22:45b32f07e790
Parent:
4:6ebbf25b9167
Fixed bug in enabling of port hardware of the F030 (via: https://developer.mbed.org/users/viquiram/)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 1:85a4a54f15e3 1 #ifdef TARGET_LPC81X
Sissors 1:85a4a54f15e3 2
Sissors 1:85a4a54f15e3 3 #include "mbed.h"
Sissors 1:85a4a54f15e3 4 #include "pinmap.h"
Sissors 1:85a4a54f15e3 5
Sissors 1:85a4a54f15e3 6 typedef struct {
Sissors 1:85a4a54f15e3 7 __I uint32_t *reg_in;
Sissors 1:85a4a54f15e3 8 uint32_t mask;
Sissors 1:85a4a54f15e3 9 } fastio_vars;
Sissors 1:85a4a54f15e3 10
Sissors 1:85a4a54f15e3 11 #define PINMASK (1 << ((int)pin & 0x1F))
Sissors 1:85a4a54f15e3 12 static void gpio_enable(void);
Sissors 1:85a4a54f15e3 13
Sissors 1:85a4a54f15e3 14 #define INIT_PIN container.mask = PINMASK; container.reg_in = &LPC_GPIO_PORT->PIN0; gpio_enable(); pin_function(pin, 0)
Sissors 2:1a6ed4b84590 15 #define DESTROY_PIN
Sissors 1:85a4a54f15e3 16
Sissors 1:85a4a54f15e3 17 #define SET_DIR_INPUT (LPC_GPIO_PORT->DIR0 &= ~PINMASK)
Sissors 1:85a4a54f15e3 18 #define SET_DIR_OUTPUT (LPC_GPIO_PORT->DIR0 |= PINMASK)
Sissors 1:85a4a54f15e3 19 #define SET_MODE(pull) (pin_mode(pin, pull))
Sissors 1:85a4a54f15e3 20
Sissors 1:85a4a54f15e3 21 #define WRITE_PIN_SET (LPC_GPIO_PORT->SET0 = PINMASK)
Sissors 1:85a4a54f15e3 22 #define WRITE_PIN_CLR (LPC_GPIO_PORT->CLR0 = PINMASK)
Sissors 1:85a4a54f15e3 23
Sissors 1:85a4a54f15e3 24 #define READ_PIN ((*container.reg_in & container.mask) ? 1 : 0)
Sissors 1:85a4a54f15e3 25
Sissors 1:85a4a54f15e3 26 static int gpio_enabled = 0;
Sissors 1:85a4a54f15e3 27 static void gpio_enable(void)
Sissors 1:85a4a54f15e3 28 {
Sissors 1:85a4a54f15e3 29 if (!gpio_enabled) {
Sissors 1:85a4a54f15e3 30 gpio_enabled = 1;
Sissors 1:85a4a54f15e3 31
Sissors 1:85a4a54f15e3 32 /* Enable AHB clock to the GPIO domain. */
Sissors 1:85a4a54f15e3 33 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
Sissors 1:85a4a54f15e3 34
Sissors 1:85a4a54f15e3 35 /* Peripheral reset control to GPIO and GPIO INT, a "1" bring it out of reset. */
Sissors 1:85a4a54f15e3 36 LPC_SYSCON->PRESETCTRL &= ~(0x1<<10);
Sissors 1:85a4a54f15e3 37 LPC_SYSCON->PRESETCTRL |= (0x1<<10);
Sissors 1:85a4a54f15e3 38 }
Sissors 1:85a4a54f15e3 39 }
Sissors 1:85a4a54f15e3 40
Sissors 1:85a4a54f15e3 41 #endif