Fast GPIO using C++ templates. Now with port I/O.

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
igorsk
Date:
Sat May 22 22:58:38 2010 +0000
Parent:
0:f1e54c45ccaf
Child:
2:9c4a8c01862c
Commit message:

Changed in this revision

FastIO.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastIO.h	Sat May 22 22:58:38 2010 +0000
@@ -0,0 +1,100 @@
+#ifndef __FAST_IO_H
+#define __FAST_IO_H
+
+#include "mbed.h"
+
+// Super-fast DigitalOut-like class for mbed
+//   by Igor Skochinsky
+
+// pin definitions in PinNames.h start from LPC_GPIO0_BASE for P0_0 and there are 32 pins to a port (0 to 31)
+// Thus:
+// pin = LPC_GPIO0_BASE + port * 32 + bit
+// port = (pin - LPC_GPIO0_BASE) / 32
+// bit  = (pin - LPC_GPIO0_BASE) % 32
+
+#define PORTNO(pin) (((pin) - P0_0)/32)
+#define BITNO(pin)  (((pin) - P0_0)%32)
+
+// calculate the GPIO port definition for the pin
+// we rely on the fact that port structs are 0x20 bytes apart
+#define PORTDEF(pin) ((LPC_GPIO_TypeDef*)(LPC_GPIO0_BASE + PORTNO(pin)*0x20))
+
+#define PORTDEFPORT(port) ((LPC_GPIO_TypeDef*)(LPC_GPIO0_BASE + port*0x20))
+
+// calculate the mask for the pin's bit in the port
+#define PINMASK(pin) (1UL << BITNO(pin))
+
+// each port takes two PINSEL registers (8 bytes or 64 bits)
+// so there are 16 pins per PINSEL
+#define PINSELREG(pin)  (*(volatile uint32_t*)(LPC_PINCON_BASE + 4*(((pin) - P0_0)/16)))
+#define PINSELMASK(pin, v) (v << (((pin - P0_0)%16)*2) )
+
+// usage: FastOut<LED2> led2;
+// then use the same assignment operators as with DigitalOut
+template <PinName pin> class FastOut
+{
+public:
+    FastOut()
+    {
+        // set PINSEL bits to 0b00 (GPIO)
+        PINSELREG(pin) &= ~PINSELMASK(pin, 3);
+        // set FIODIR bit to 1 (output)
+        PORTDEF(pin)->FIODIR |= PINMASK(pin);
+    }
+    void write(int value)
+    { 
+        if ( value )
+            PORTDEF(pin)->FIOSET = PINMASK(pin);
+        else
+            PORTDEF(pin)->FIOCLR = PINMASK(pin);
+    } 
+    int read()
+    {
+        return PORTDEF(pin)->FIOPIN & PINMASK(pin) != 0;
+    }
+    FastOut& operator= (int value) { write(value); return *this; };
+    FastOut& operator= (FastOut& rhs) { return write(rhs.read()); };
+    operator int() { return read(); };
+};
+
+#define PINSELREG(pin)  (*(volatile uint32_t*)(LPC_PINCON_BASE + 4*(((pin) - P0_0)/16)))
+#define PINSELMASK(pin, v) (v << (((pin - P0_0)%16)*2) )
+
+// usage: FastPortOut<0> led2;
+// then use the same assignment operators as with DigitalOut
+template <enum PortName port, uint32_t mask = 0xFFFFFFFF> class FastPortOut
+{
+public:
+    FastPortOut()
+    {
+        // init pins selected by the mask
+        uint32_t pin = LPC_GPIO0_BASE + port * 32;
+        for ( uint32_t pinmask = mask; pinmask !=0; pinmask >>= 1 )
+        {
+            if ( pinmask & 1 )
+            {
+                // set PINSEL bits to 0b00 (GPIO)
+                PINSELREG(pin) &= ~PINSELMASK(pin, 3);
+                // set FIODIR bit to 1 (output)
+                PORTDEF(pin)->FIODIR |= PINMASK(pin);
+            }
+            pin++;
+        }
+    }
+    void write(int value)
+    {
+        if ( value & mask )
+            PORTDEFPORT(port)->FIOSET = value & mask;
+        if ( value & ~mask )
+            PORTDEFPORT(port)->FIOCLR = value & ~mask;
+    } 
+    int read()
+    {
+        return PORTDEFPORT(port)->FIOPIN & mask;
+    }
+    FastPortOut& operator= (int value) { write(value); return *this; };
+    FastPortOut& operator= (FastPortOut& rhs) { return write(rhs.read()); };
+    operator int() { return read(); };
+};
+
+#endif
\ No newline at end of file
--- a/main.cpp	Fri Mar 12 10:12:32 2010 +0000
+++ b/main.cpp	Sat May 22 22:58:38 2010 +0000
@@ -1,46 +1,13 @@
 #include "mbed.h"
-// Super-fast DigitalOut-like class for mbed
-//   by Igor Skochinsky
-
-// usage: FastOut<LED2> led2;
-// then use the same assignment operators as with DigitalOut
-template <PinName pin> class FastOut
-{
-// pin = LPC_GPIO0_BASE + port * 32 + bit
-// port = (pin - LPC_GPIO0_BASE) / 32
-// bit  = (pin - LPC_GPIO0_BASE) % 32
-    
-    // helper function to calculate the GPIO port definition for the pin
-    // we rely on the fact that port structs are 0x20 bytes apart
-    inline LPC_GPIO_TypeDef* portdef() { return (LPC_GPIO_TypeDef*)(LPC_GPIO0_BASE + ((pin - P0_0)/32)*0x20); };
-
-    // helper function to calculate the mask for the pin's bit in the port
-    inline uint32_t mask() { return 1UL<<((pin - LPC_GPIO0_BASE) % 32); };
 
-public:
-    FastOut()
-    {
-        // set FIODIR bit to 1 (output)
-        portdef()->FIODIR |= mask();
-    }
-    void write(int value)
-    { 
-        if ( value )
-            portdef()->FIOSET = mask();
-        else
-            portdef()->FIOCLR = mask();
-    } 
-    int read()
-    {
-        return (portdef()->FIOPIN) & mask() != 0;
-    }
-    FastOut& operator= (int value) { write(value); return *this; };
-    FastOut& operator= (FastOut& rhs) { return write(rhs.read()); };
-    operator int() { return read(); };
-};
+#include "FastIO.h"
+
+#define LED_MASK 0x07800000
 
 DigitalOut led1(LED1);
 FastOut<LED2> led2;
+PortOut ledport(Port0, LED_MASK);
+FastPortOut<Port0, LED_MASK> ledport2;
 
 Timer t;
 #define LOOPS 100000000
@@ -55,6 +22,7 @@
     }
     t.stop();
     printf("DigitalOut: %f seconds (%d ns per iteration).\n", t.read(), t.read_us()/(LOOPS/1000));
+    
     count = LOOPS;
     t.reset();
     t.start();
@@ -65,4 +33,28 @@
     }
     t.stop();
     printf("FastOut: %f seconds (%d ns per iteration).\n", t.read(), t.read_us()/(LOOPS/1000));
+
+    count = LOOPS;
+    t.reset();
+    t.start();
+    value = LED_MASK;
+    while ( count -- )
+    {
+        ledport.write(value);
+        value ^= LED_MASK;
+    }
+    t.stop();
+    printf("PortOut: %f seconds (%d ns per iteration).\n", t.read(), t.read_us()/(LOOPS/1000));
+
+    count = LOOPS;
+    t.reset();
+    t.start();
+    value = LED_MASK;
+    while ( count -- )
+    {
+        ledport2 = value;
+        value ^= LED_MASK;
+    }
+    t.stop();
+    printf("FastPortOut: %f seconds (%d ns per iteration).\n", t.read(), t.read_us()/(LOOPS/1000));
 }
--- a/mbed.bld	Fri Mar 12 10:12:32 2010 +0000
+++ b/mbed.bld	Sat May 22 22:58:38 2010 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
+http://mbed.org/users/mbed_official/code/mbed/builds/e6be4cd80aad