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:
21:a1dfa6c65400
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 0:d394ebd01052 1 #ifndef __FAST_IO_H
Sissors 0:d394ebd01052 2 #define __FAST_IO_H
Sissors 0:d394ebd01052 3
Sissors 0:d394ebd01052 4 #include "FastIO_LPC1768.h"
Sissors 0:d394ebd01052 5 #include "FastIO_LPC11UXX.h"
nameless129 18:c95920122b2e 6 #include "FastIO_LPC11U6X.h"
Sissors 1:85a4a54f15e3 7 #include "FastIO_LPC81X.h"
Sissors 0:d394ebd01052 8 #include "FastIO_KLXX.h"
Sissors 10:bb22a3dbedb4 9 #include "FastIO_K20D50M_KPSDK.h"
Sissors 13:0e21ffc6cb84 10 #include "FastIO_STM32F4.h"
viquiram 21:a1dfa6c65400 11 #include "FastIO_STM32L073XX.h"
Sissors 6:da3730030c07 12 #include "FastIO_NUCLEO_F030.h"
Sissors 7:1e784ae11fba 13 #include "FastIO_LPC11XX.h"
Sissors 15:e0c5a5216647 14 #include "FastIO_EFM32.h"
nameless129 19:89d6ae484a35 15 #include "FastIO_LPC43XX.h"
Sissors 20:ed72895a2402 16 #include "FastIO_NRF51822.h"
Sissors 0:d394ebd01052 17
Sissors 0:d394ebd01052 18 #ifndef INIT_PIN
Sissors 2:1a6ed4b84590 19 #warning Target is not supported by FastIO
Sissors 2:1a6ed4b84590 20 #warning Reverting to regular DigitalInOut
Sissors 2:1a6ed4b84590 21 #include "FastIO_Unsupported.h"
Sissors 0:d394ebd01052 22 #endif
Sissors 0:d394ebd01052 23
Sissors 0:d394ebd01052 24 #include "mbed.h"
Sissors 0:d394ebd01052 25
Sissors 0:d394ebd01052 26 /**
Sissors 0:d394ebd01052 27 * Faster alternative compared to regular DigitalInOut
Sissors 0:d394ebd01052 28 *
Sissors 0:d394ebd01052 29 * Except the constructor it is compatible with regular DigitalInOut.
Sissors 0:d394ebd01052 30 * Code is based on Igor Skochinsky's code (http://mbed.org/users/igorsk/code/FastIO/)
Sissors 0:d394ebd01052 31 */
Sissors 0:d394ebd01052 32 template <PinName pin> class FastInOut
Sissors 0:d394ebd01052 33 {
Sissors 0:d394ebd01052 34 public:
Sissors 0:d394ebd01052 35 /**
Sissors 0:d394ebd01052 36 * Construct new FastInOut object
Sissors 0:d394ebd01052 37 *
Sissors 0:d394ebd01052 38 * @code
Sissors 0:d394ebd01052 39 * FastInOut<LED1> led1;
Sissors 0:d394ebd01052 40 * @endcode
Sissors 0:d394ebd01052 41 *
Sissors 0:d394ebd01052 42 * No initialization is done regarding input/output mode,
Sissors 0:d394ebd01052 43 * FastIn/FastOut can be used if that is required
Sissors 0:d394ebd01052 44 *
Sissors 0:d394ebd01052 45 * @param pin pin the FastOut object should be used for
Sissors 0:d394ebd01052 46 */
Sissors 0:d394ebd01052 47 FastInOut() {
Sissors 0:d394ebd01052 48 INIT_PIN;
Sissors 0:d394ebd01052 49 }
Sissors 2:1a6ed4b84590 50
Sissors 2:1a6ed4b84590 51 ~FastInOut() {
Sissors 2:1a6ed4b84590 52 DESTROY_PIN;
Sissors 2:1a6ed4b84590 53 }
Sissors 0:d394ebd01052 54
Sissors 0:d394ebd01052 55 void write(int value) {
Sissors 0:d394ebd01052 56 if ( value )
Sissors 0:d394ebd01052 57 WRITE_PIN_SET;
Sissors 0:d394ebd01052 58 else
Sissors 0:d394ebd01052 59 WRITE_PIN_CLR;
Sissors 0:d394ebd01052 60 }
Sissors 0:d394ebd01052 61 int read() {
Sissors 0:d394ebd01052 62 return READ_PIN;
Sissors 0:d394ebd01052 63 }
Sissors 0:d394ebd01052 64
Sissors 0:d394ebd01052 65 void mode(PinMode pull) {
Sissors 0:d394ebd01052 66 SET_MODE(pull);
Sissors 0:d394ebd01052 67 }
Sissors 0:d394ebd01052 68
Sissors 0:d394ebd01052 69 void output() {
Sissors 0:d394ebd01052 70 SET_DIR_OUTPUT;
Sissors 0:d394ebd01052 71 }
Sissors 0:d394ebd01052 72
Sissors 0:d394ebd01052 73 void input() {
Sissors 0:d394ebd01052 74 SET_DIR_INPUT;
Sissors 0:d394ebd01052 75 }
Sissors 0:d394ebd01052 76
Sissors 0:d394ebd01052 77 FastInOut& operator= (int value) {
Sissors 0:d394ebd01052 78 write(value);
Sissors 0:d394ebd01052 79 return *this;
Sissors 0:d394ebd01052 80 };
Sissors 0:d394ebd01052 81 FastInOut& operator= (FastInOut& rhs) {
Sissors 0:d394ebd01052 82 return write(rhs.read());
Sissors 0:d394ebd01052 83 };
Sissors 0:d394ebd01052 84 operator int() {
Sissors 0:d394ebd01052 85 return read();
Sissors 0:d394ebd01052 86 };
Sissors 0:d394ebd01052 87
Sissors 15:e0c5a5216647 88 protected:
Sissors 0:d394ebd01052 89 fastio_vars container;
Sissors 0:d394ebd01052 90 };
Sissors 0:d394ebd01052 91
Sissors 0:d394ebd01052 92 /**
Sissors 0:d394ebd01052 93 * Faster alternative compared to regular DigitalOut
Sissors 0:d394ebd01052 94 *
Sissors 0:d394ebd01052 95 * Except the constructor it is compatible with regular DigitalOut. Aditionally all
Sissors 0:d394ebd01052 96 * functions from DigitalInOut are also available (only initialization is different)
Sissors 0:d394ebd01052 97 * Code is based on Igor Skochinsky's code (http://mbed.org/users/igorsk/code/FastIO/)
Sissors 0:d394ebd01052 98 */
Sissors 0:d394ebd01052 99 template <PinName pin, int initial = 0> class FastOut : public FastInOut<pin>
Sissors 0:d394ebd01052 100 {
Sissors 0:d394ebd01052 101 public:
Sissors 0:d394ebd01052 102 /**
Sissors 0:d394ebd01052 103 * Construct new FastOut object
Sissors 0:d394ebd01052 104 *
Sissors 0:d394ebd01052 105 * @code
Sissors 0:d394ebd01052 106 * FastOut<LED1> led1;
Sissors 0:d394ebd01052 107 * @endcode
Sissors 0:d394ebd01052 108 *
Sissors 0:d394ebd01052 109 * @param pin pin the FastOut object should be used for
Sissors 0:d394ebd01052 110 * @param initial (optional) initial state of the pin after construction: default is 0 (low)
Sissors 0:d394ebd01052 111 */
Sissors 12:973e253323c9 112 FastOut() : FastInOut<pin>::FastInOut() {
Sissors 0:d394ebd01052 113 write(initial);
Sissors 0:d394ebd01052 114 SET_DIR_OUTPUT;
Sissors 0:d394ebd01052 115 }
Sissors 0:d394ebd01052 116
Sissors 0:d394ebd01052 117 FastOut& operator= (int value) {
Sissors 0:d394ebd01052 118 this->write(value);
Sissors 0:d394ebd01052 119 return *this;
Sissors 0:d394ebd01052 120 };
Sissors 0:d394ebd01052 121 FastOut& operator= (FastOut& rhs) {
Sissors 0:d394ebd01052 122 return this->write(rhs.read());
Sissors 0:d394ebd01052 123 };
Sissors 0:d394ebd01052 124 operator int() {
Sissors 0:d394ebd01052 125 return this->read();
Sissors 0:d394ebd01052 126 };
Sissors 0:d394ebd01052 127 };
Sissors 0:d394ebd01052 128
Sissors 0:d394ebd01052 129 /**
Sissors 0:d394ebd01052 130 * Faster alternative compared to regular DigitalIn
Sissors 0:d394ebd01052 131 *
Sissors 0:d394ebd01052 132 * Except the constructor it is compatible with regular DigitalIn. Aditionally all
Sissors 0:d394ebd01052 133 * functions from DigitalInOut are also available (only initialization is different)
Sissors 0:d394ebd01052 134 * Code is based on Igor Skochinsky's code (http://mbed.org/users/igorsk/code/FastIO/)
Sissors 0:d394ebd01052 135 */
Sissors 8:b0d725519c4f 136 template <PinName pin, PinMode pinmode = PullDefault> class FastIn : public FastInOut<pin>
Sissors 0:d394ebd01052 137 {
Sissors 0:d394ebd01052 138 public:
Sissors 0:d394ebd01052 139 /**
Sissors 0:d394ebd01052 140 * Construct new FastIn object
Sissors 0:d394ebd01052 141 *
Sissors 0:d394ebd01052 142 * @code
Sissors 0:d394ebd01052 143 * FastIn<LED1> led1;
Sissors 0:d394ebd01052 144 * @endcode
Sissors 0:d394ebd01052 145 *
Sissors 0:d394ebd01052 146 * @param pin pin the FastIn object should be used for
Sissors 8:b0d725519c4f 147 * @param pinmode (optional) initial mode of the pin after construction: default is PullDefault
Sissors 0:d394ebd01052 148 */
Sissors 12:973e253323c9 149 FastIn() : FastInOut<pin>::FastInOut() {
Sissors 8:b0d725519c4f 150 SET_MODE(pinmode);
Sissors 0:d394ebd01052 151 SET_DIR_INPUT;
Sissors 0:d394ebd01052 152 }
Sissors 0:d394ebd01052 153
Sissors 0:d394ebd01052 154 FastIn& operator= (int value) {
Sissors 0:d394ebd01052 155 this->write(value);
Sissors 0:d394ebd01052 156 return *this;
Sissors 0:d394ebd01052 157 };
Sissors 0:d394ebd01052 158 FastIn& operator= (FastIn& rhs) {
Sissors 0:d394ebd01052 159 return this->write(rhs.read());
Sissors 0:d394ebd01052 160 };
Sissors 0:d394ebd01052 161 operator int() {
Sissors 0:d394ebd01052 162 return this->read();
Sissors 0:d394ebd01052 163 };
Sissors 0:d394ebd01052 164 };
Sissors 0:d394ebd01052 165
Sissors 0:d394ebd01052 166 #endif