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

Dependencies:   mbed

FastIO.h

Committer:
igorsk
Date:
2010-05-25
Revision:
4:b8e40f2a0aac
Parent:
3:8d217a0bb245

File content as of revision 4:b8e40f2a0aac:

#ifndef __FAST_IO_H
#define __FAST_IO_H

#include "mbed.h"

// Super-fast DigitalOut-like class for mbed
//   by Igor Skochinsky

// includes FastOut, FastPortOut and MaskedPortOut classes
// usage:
//   FastOut<LED2> led2;
//   FastPortOut<Port0, LED_MASK> ledport2;
//   MaskedPortOut<Port0, LED_MASK> ledport3;
//   led2 = 1;
//   ledport2 = LED_MASK;
//   ledport3 = LED_MASK;
// MaskedPortOut works the same way as FastPortOut, but it pre-sets the pin mask so that write can be done in one operation
// this makes things faster but you can't control other pins of the port, even with other classes


// 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<Port0, mask> 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)
    {
        PORTDEFPORT(port)->FIOSET = 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(); };
};

// usage: MaskedPortOut<Port0, mask> led2;
// then use the same assignment operators as with DigitalOut
template <enum PortName port, uint32_t mask = 0xFFFFFFFF> class MaskedPortOut
{
public:
    MaskedPortOut()
    {
        // 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++;
        }
        // set mask
        PORTDEFPORT(port)->FIOMASK = mask;
    }
    void write(int value)
    {
        PORTDEFPORT(port)->FIOPIN = value;
    } 
    int read()
    {
        return PORTDEFPORT(port)->FIOPIN;
    }
    MaskedPortOut& operator= (int value) { write(value); return *this; };
    MaskedPortOut& operator= (MaskedPortOut& rhs) { return write(rhs.read()); };
    operator int() { return read(); };
};

#endif