Igor Skochinsky
/
FastIO
Fast GPIO using C++ templates. Now with port I/O.
FastIO.h@4:b8e40f2a0aac, 2010-05-25 (annotated)
- Committer:
- igorsk
- Date:
- Tue May 25 08:35:39 2010 +0000
- Revision:
- 4:b8e40f2a0aac
- Parent:
- 3:8d217a0bb245
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
igorsk | 1:8064f8b8cf82 | 1 | #ifndef __FAST_IO_H |
igorsk | 1:8064f8b8cf82 | 2 | #define __FAST_IO_H |
igorsk | 1:8064f8b8cf82 | 3 | |
igorsk | 1:8064f8b8cf82 | 4 | #include "mbed.h" |
igorsk | 1:8064f8b8cf82 | 5 | |
igorsk | 1:8064f8b8cf82 | 6 | // Super-fast DigitalOut-like class for mbed |
igorsk | 1:8064f8b8cf82 | 7 | // by Igor Skochinsky |
igorsk | 1:8064f8b8cf82 | 8 | |
igorsk | 3:8d217a0bb245 | 9 | // includes FastOut, FastPortOut and MaskedPortOut classes |
igorsk | 3:8d217a0bb245 | 10 | // usage: |
igorsk | 3:8d217a0bb245 | 11 | // FastOut<LED2> led2; |
igorsk | 3:8d217a0bb245 | 12 | // FastPortOut<Port0, LED_MASK> ledport2; |
igorsk | 3:8d217a0bb245 | 13 | // MaskedPortOut<Port0, LED_MASK> ledport3; |
igorsk | 3:8d217a0bb245 | 14 | // led2 = 1; |
igorsk | 3:8d217a0bb245 | 15 | // ledport2 = LED_MASK; |
igorsk | 3:8d217a0bb245 | 16 | // ledport3 = LED_MASK; |
igorsk | 3:8d217a0bb245 | 17 | // MaskedPortOut works the same way as FastPortOut, but it pre-sets the pin mask so that write can be done in one operation |
igorsk | 3:8d217a0bb245 | 18 | // this makes things faster but you can't control other pins of the port, even with other classes |
igorsk | 3:8d217a0bb245 | 19 | |
igorsk | 3:8d217a0bb245 | 20 | |
igorsk | 1:8064f8b8cf82 | 21 | // pin definitions in PinNames.h start from LPC_GPIO0_BASE for P0_0 and there are 32 pins to a port (0 to 31) |
igorsk | 1:8064f8b8cf82 | 22 | // Thus: |
igorsk | 1:8064f8b8cf82 | 23 | // pin = LPC_GPIO0_BASE + port * 32 + bit |
igorsk | 1:8064f8b8cf82 | 24 | // port = (pin - LPC_GPIO0_BASE) / 32 |
igorsk | 1:8064f8b8cf82 | 25 | // bit = (pin - LPC_GPIO0_BASE) % 32 |
igorsk | 1:8064f8b8cf82 | 26 | |
igorsk | 1:8064f8b8cf82 | 27 | #define PORTNO(pin) (((pin) - P0_0)/32) |
igorsk | 1:8064f8b8cf82 | 28 | #define BITNO(pin) (((pin) - P0_0)%32) |
igorsk | 1:8064f8b8cf82 | 29 | |
igorsk | 1:8064f8b8cf82 | 30 | // calculate the GPIO port definition for the pin |
igorsk | 1:8064f8b8cf82 | 31 | // we rely on the fact that port structs are 0x20 bytes apart |
igorsk | 1:8064f8b8cf82 | 32 | #define PORTDEF(pin) ((LPC_GPIO_TypeDef*)(LPC_GPIO0_BASE + PORTNO(pin)*0x20)) |
igorsk | 1:8064f8b8cf82 | 33 | |
igorsk | 1:8064f8b8cf82 | 34 | #define PORTDEFPORT(port) ((LPC_GPIO_TypeDef*)(LPC_GPIO0_BASE + port*0x20)) |
igorsk | 1:8064f8b8cf82 | 35 | |
igorsk | 1:8064f8b8cf82 | 36 | // calculate the mask for the pin's bit in the port |
igorsk | 1:8064f8b8cf82 | 37 | #define PINMASK(pin) (1UL << BITNO(pin)) |
igorsk | 1:8064f8b8cf82 | 38 | |
igorsk | 1:8064f8b8cf82 | 39 | // each port takes two PINSEL registers (8 bytes or 64 bits) |
igorsk | 1:8064f8b8cf82 | 40 | // so there are 16 pins per PINSEL |
igorsk | 1:8064f8b8cf82 | 41 | #define PINSELREG(pin) (*(volatile uint32_t*)(LPC_PINCON_BASE + 4*(((pin) - P0_0)/16))) |
igorsk | 1:8064f8b8cf82 | 42 | #define PINSELMASK(pin, v) (v << (((pin - P0_0)%16)*2) ) |
igorsk | 1:8064f8b8cf82 | 43 | |
igorsk | 1:8064f8b8cf82 | 44 | // usage: FastOut<LED2> led2; |
igorsk | 1:8064f8b8cf82 | 45 | // then use the same assignment operators as with DigitalOut |
igorsk | 1:8064f8b8cf82 | 46 | template <PinName pin> class FastOut |
igorsk | 1:8064f8b8cf82 | 47 | { |
igorsk | 1:8064f8b8cf82 | 48 | public: |
igorsk | 1:8064f8b8cf82 | 49 | FastOut() |
igorsk | 1:8064f8b8cf82 | 50 | { |
igorsk | 1:8064f8b8cf82 | 51 | // set PINSEL bits to 0b00 (GPIO) |
igorsk | 1:8064f8b8cf82 | 52 | PINSELREG(pin) &= ~PINSELMASK(pin, 3); |
igorsk | 1:8064f8b8cf82 | 53 | // set FIODIR bit to 1 (output) |
igorsk | 1:8064f8b8cf82 | 54 | PORTDEF(pin)->FIODIR |= PINMASK(pin); |
igorsk | 1:8064f8b8cf82 | 55 | } |
igorsk | 1:8064f8b8cf82 | 56 | void write(int value) |
igorsk | 1:8064f8b8cf82 | 57 | { |
igorsk | 1:8064f8b8cf82 | 58 | if ( value ) |
igorsk | 1:8064f8b8cf82 | 59 | PORTDEF(pin)->FIOSET = PINMASK(pin); |
igorsk | 1:8064f8b8cf82 | 60 | else |
igorsk | 1:8064f8b8cf82 | 61 | PORTDEF(pin)->FIOCLR = PINMASK(pin); |
igorsk | 1:8064f8b8cf82 | 62 | } |
igorsk | 1:8064f8b8cf82 | 63 | int read() |
igorsk | 1:8064f8b8cf82 | 64 | { |
igorsk | 1:8064f8b8cf82 | 65 | return PORTDEF(pin)->FIOPIN & PINMASK(pin) != 0; |
igorsk | 1:8064f8b8cf82 | 66 | } |
igorsk | 1:8064f8b8cf82 | 67 | FastOut& operator= (int value) { write(value); return *this; }; |
igorsk | 1:8064f8b8cf82 | 68 | FastOut& operator= (FastOut& rhs) { return write(rhs.read()); }; |
igorsk | 1:8064f8b8cf82 | 69 | operator int() { return read(); }; |
igorsk | 1:8064f8b8cf82 | 70 | }; |
igorsk | 1:8064f8b8cf82 | 71 | |
igorsk | 1:8064f8b8cf82 | 72 | #define PINSELREG(pin) (*(volatile uint32_t*)(LPC_PINCON_BASE + 4*(((pin) - P0_0)/16))) |
igorsk | 1:8064f8b8cf82 | 73 | #define PINSELMASK(pin, v) (v << (((pin - P0_0)%16)*2) ) |
igorsk | 1:8064f8b8cf82 | 74 | |
igorsk | 3:8d217a0bb245 | 75 | // usage: FastPortOut<Port0, mask> led2; |
igorsk | 1:8064f8b8cf82 | 76 | // then use the same assignment operators as with DigitalOut |
igorsk | 1:8064f8b8cf82 | 77 | template <enum PortName port, uint32_t mask = 0xFFFFFFFF> class FastPortOut |
igorsk | 1:8064f8b8cf82 | 78 | { |
igorsk | 1:8064f8b8cf82 | 79 | public: |
igorsk | 1:8064f8b8cf82 | 80 | FastPortOut() |
igorsk | 1:8064f8b8cf82 | 81 | { |
igorsk | 1:8064f8b8cf82 | 82 | // init pins selected by the mask |
igorsk | 1:8064f8b8cf82 | 83 | uint32_t pin = LPC_GPIO0_BASE + port * 32; |
igorsk | 1:8064f8b8cf82 | 84 | for ( uint32_t pinmask = mask; pinmask !=0; pinmask >>= 1 ) |
igorsk | 1:8064f8b8cf82 | 85 | { |
igorsk | 1:8064f8b8cf82 | 86 | if ( pinmask & 1 ) |
igorsk | 1:8064f8b8cf82 | 87 | { |
igorsk | 1:8064f8b8cf82 | 88 | // set PINSEL bits to 0b00 (GPIO) |
igorsk | 1:8064f8b8cf82 | 89 | PINSELREG(pin) &= ~PINSELMASK(pin, 3); |
igorsk | 1:8064f8b8cf82 | 90 | // set FIODIR bit to 1 (output) |
igorsk | 1:8064f8b8cf82 | 91 | PORTDEF(pin)->FIODIR |= PINMASK(pin); |
igorsk | 1:8064f8b8cf82 | 92 | } |
igorsk | 1:8064f8b8cf82 | 93 | pin++; |
igorsk | 1:8064f8b8cf82 | 94 | } |
igorsk | 1:8064f8b8cf82 | 95 | } |
igorsk | 1:8064f8b8cf82 | 96 | void write(int value) |
igorsk | 1:8064f8b8cf82 | 97 | { |
igorsk | 2:9c4a8c01862c | 98 | PORTDEFPORT(port)->FIOSET = value & mask; |
igorsk | 4:b8e40f2a0aac | 99 | PORTDEFPORT(port)->FIOCLR = ~value & mask; |
igorsk | 1:8064f8b8cf82 | 100 | } |
igorsk | 1:8064f8b8cf82 | 101 | int read() |
igorsk | 1:8064f8b8cf82 | 102 | { |
igorsk | 1:8064f8b8cf82 | 103 | return PORTDEFPORT(port)->FIOPIN & mask; |
igorsk | 1:8064f8b8cf82 | 104 | } |
igorsk | 1:8064f8b8cf82 | 105 | FastPortOut& operator= (int value) { write(value); return *this; }; |
igorsk | 1:8064f8b8cf82 | 106 | FastPortOut& operator= (FastPortOut& rhs) { return write(rhs.read()); }; |
igorsk | 1:8064f8b8cf82 | 107 | operator int() { return read(); }; |
igorsk | 1:8064f8b8cf82 | 108 | }; |
igorsk | 1:8064f8b8cf82 | 109 | |
igorsk | 3:8d217a0bb245 | 110 | // usage: MaskedPortOut<Port0, mask> led2; |
igorsk | 3:8d217a0bb245 | 111 | // then use the same assignment operators as with DigitalOut |
igorsk | 3:8d217a0bb245 | 112 | template <enum PortName port, uint32_t mask = 0xFFFFFFFF> class MaskedPortOut |
igorsk | 3:8d217a0bb245 | 113 | { |
igorsk | 3:8d217a0bb245 | 114 | public: |
igorsk | 3:8d217a0bb245 | 115 | MaskedPortOut() |
igorsk | 3:8d217a0bb245 | 116 | { |
igorsk | 3:8d217a0bb245 | 117 | // init pins selected by the mask |
igorsk | 3:8d217a0bb245 | 118 | uint32_t pin = LPC_GPIO0_BASE + port * 32; |
igorsk | 3:8d217a0bb245 | 119 | for ( uint32_t pinmask = mask; pinmask !=0; pinmask >>= 1 ) |
igorsk | 3:8d217a0bb245 | 120 | { |
igorsk | 3:8d217a0bb245 | 121 | if ( pinmask & 1 ) |
igorsk | 3:8d217a0bb245 | 122 | { |
igorsk | 3:8d217a0bb245 | 123 | // set PINSEL bits to 0b00 (GPIO) |
igorsk | 3:8d217a0bb245 | 124 | PINSELREG(pin) &= ~PINSELMASK(pin, 3); |
igorsk | 3:8d217a0bb245 | 125 | // set FIODIR bit to 1 (output) |
igorsk | 3:8d217a0bb245 | 126 | PORTDEF(pin)->FIODIR |= PINMASK(pin); |
igorsk | 3:8d217a0bb245 | 127 | } |
igorsk | 3:8d217a0bb245 | 128 | pin++; |
igorsk | 3:8d217a0bb245 | 129 | } |
igorsk | 3:8d217a0bb245 | 130 | // set mask |
igorsk | 3:8d217a0bb245 | 131 | PORTDEFPORT(port)->FIOMASK = mask; |
igorsk | 3:8d217a0bb245 | 132 | } |
igorsk | 3:8d217a0bb245 | 133 | void write(int value) |
igorsk | 3:8d217a0bb245 | 134 | { |
igorsk | 3:8d217a0bb245 | 135 | PORTDEFPORT(port)->FIOPIN = value; |
igorsk | 3:8d217a0bb245 | 136 | } |
igorsk | 3:8d217a0bb245 | 137 | int read() |
igorsk | 3:8d217a0bb245 | 138 | { |
igorsk | 3:8d217a0bb245 | 139 | return PORTDEFPORT(port)->FIOPIN; |
igorsk | 3:8d217a0bb245 | 140 | } |
igorsk | 3:8d217a0bb245 | 141 | MaskedPortOut& operator= (int value) { write(value); return *this; }; |
igorsk | 3:8d217a0bb245 | 142 | MaskedPortOut& operator= (MaskedPortOut& rhs) { return write(rhs.read()); }; |
igorsk | 3:8d217a0bb245 | 143 | operator int() { return read(); }; |
igorsk | 3:8d217a0bb245 | 144 | }; |
igorsk | 3:8d217a0bb245 | 145 | |
igorsk | 1:8064f8b8cf82 | 146 | #endif |