//https://github.com/niteris/ArduinoSoftSpi #include #ifdef __arm__ #ifdef CORE_TEENSY //------------------------------------------------------------------------------ /** read pin value * @param[in] pin Arduino pin number * @return value read */ static inline __attribute__((always_inline)) bool fastDigitalRead(uint8_t pin) { return *portInputRegister(pin); } //------------------------------------------------------------------------------ /** Set pin value * @param[in] pin Arduino pin number * @param[in] level value to write */ static inline __attribute__((always_inline)) void fastDigitalWrite(uint8_t pin, bool value) { if (value) { *portSetRegister(pin) = 1; } else { *portClearRegister(pin) = 1; } } #else // CORE_TEENSY //------------------------------------------------------------------------------ /** read pin value * @param[in] pin Arduino pin number * @return value read */ static inline __attribute__((always_inline)) bool fastDigitalRead(uint8_t pin){ return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin; } //------------------------------------------------------------------------------ /** Set pin value * @param[in] pin Arduino pin number * @param[in] level value to write */ static inline __attribute__((always_inline)) void fastDigitalWrite(uint8_t pin, bool value){ if (value) g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin; else g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin; } #endif // CORE_TEENSY //------------------------------------------------------------------------------ inline void fastDigitalToggle(uint8_t pin) { fastDigitalWrite(pin, !fastDigitalRead(pin)); } //------------------------------------------------------------------------------ inline void fastPinMode(uint8_t pin, bool mode) {pinMode(pin, mode);} #else // __arm__ #include #include //------------------------------------------------------------------------------ /** * @class pin_map_t * @brief struct for mapping digital pins */ struct pin_map_t { volatile uint8_t* ddr; /**< address of DDR for this pin */ volatile uint8_t* pin; /**< address of PIN for this pin */ volatile uint8_t* port; /**< address of PORT for this pin */ uint8_t bit; /**< bit number for this pin */ }; //------------------------------------------------------------------------------ #if defined(__AVR_ATmega168__)\ ||defined(__AVR_ATmega168P__)\ ||defined(__AVR_ATmega328P__) // 168 and 328 Arduinos const static pin_map_t pinMap[] = { {&DDRD, &PIND, &PORTD, 0}, // D0 0 {&DDRD, &PIND, &PORTD, 1}, // D1 1 {&DDRD, &PIND, &PORTD, 2}, // D2 2 {&DDRD, &PIND, &PORTD, 3}, // D3 3 {&DDRD, &PIND, &PORTD, 4}, // D4 4 {&DDRD, &PIND, &PORTD, 5}, // D5 5 {&DDRD, &PIND, &PORTD, 6}, // D6 6 {&DDRD, &PIND, &PORTD, 7}, // D7 7 {&DDRB, &PINB, &PORTB, 0}, // B0 8 {&DDRB, &PINB, &PORTB, 1}, // B1 9 {&DDRB, &PINB, &PORTB, 2}, // B2 10 {&DDRB, &PINB, &PORTB, 3}, // B3 11 {&DDRB, &PINB, &PORTB, 4}, // B4 12 {&DDRB, &PINB, &PORTB, 5}, // B5 13 {&DDRC, &PINC, &PORTC, 0}, // C0 14 {&DDRC, &PINC, &PORTC, 1}, // C1 15 {&DDRC, &PINC, &PORTC, 2}, // C2 16 {&DDRC, &PINC, &PORTC, 3}, // C3 17 {&DDRC, &PINC, &PORTC, 4}, // C4 18 {&DDRC, &PINC, &PORTC, 5} // C5 19 }; //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega1280__)\ || defined(__AVR_ATmega2560__) // Mega static const pin_map_t pinMap[] = { {&DDRE, &PINE, &PORTE, 0}, // E0 0 {&DDRE, &PINE, &PORTE, 1}, // E1 1 {&DDRE, &PINE, &PORTE, 4}, // E4 2 {&DDRE, &PINE, &PORTE, 5}, // E5 3 {&DDRG, &PING, &PORTG, 5}, // G5 4 {&DDRE, &PINE, &PORTE, 3}, // E3 5 {&DDRH, &PINH, &PORTH, 3}, // H3 6 {&DDRH, &PINH, &PORTH, 4}, // H4 7 {&DDRH, &PINH, &PORTH, 5}, // H5 8 {&DDRH, &PINH, &PORTH, 6}, // H6 9 {&DDRB, &PINB, &PORTB, 4}, // B4 10 {&DDRB, &PINB, &PORTB, 5}, // B5 11 {&DDRB, &PINB, &PORTB, 6}, // B6 12 {&DDRB, &PINB, &PORTB, 7}, // B7 13 {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 {&DDRH, &PINH, &PORTH, 1}, // H1 16 {&DDRH, &PINH, &PORTH, 0}, // H0 17 {&DDRD, &PIND, &PORTD, 3}, // D3 18 {&DDRD, &PIND, &PORTD, 2}, // D2 19 {&DDRD, &PIND, &PORTD, 1}, // D1 20 {&DDRD, &PIND, &PORTD, 0}, // D0 21 {&DDRA, &PINA, &PORTA, 0}, // A0 22 {&DDRA, &PINA, &PORTA, 1}, // A1 23 {&DDRA, &PINA, &PORTA, 2}, // A2 24 {&DDRA, &PINA, &PORTA, 3}, // A3 25 {&DDRA, &PINA, &PORTA, 4}, // A4 26 {&DDRA, &PINA, &PORTA, 5}, // A5 27 {&DDRA, &PINA, &PORTA, 6}, // A6 28 {&DDRA, &PINA, &PORTA, 7}, // A7 29 {&DDRC, &PINC, &PORTC, 7}, // C7 30 {&DDRC, &PINC, &PORTC, 6}, // C6 31 {&DDRC, &PINC, &PORTC, 5}, // C5 32 {&DDRC, &PINC, &PORTC, 4}, // C4 33 {&DDRC, &PINC, &PORTC, 3}, // C3 34 {&DDRC, &PINC, &PORTC, 2}, // C2 35 {&DDRC, &PINC, &PORTC, 1}, // C1 36 {&DDRC, &PINC, &PORTC, 0}, // C0 37 {&DDRD, &PIND, &PORTD, 7}, // D7 38 {&DDRG, &PING, &PORTG, 2}, // G2 39 {&DDRG, &PING, &PORTG, 1}, // G1 40 {&DDRG, &PING, &PORTG, 0}, // G0 41 {&DDRL, &PINL, &PORTL, 7}, // L7 42 {&DDRL, &PINL, &PORTL, 6}, // L6 43 {&DDRL, &PINL, &PORTL, 5}, // L5 44 {&DDRL, &PINL, &PORTL, 4}, // L4 45 {&DDRL, &PINL, &PORTL, 3}, // L3 46 {&DDRL, &PINL, &PORTL, 2}, // L2 47 {&DDRL, &PINL, &PORTL, 1}, // L1 48 {&DDRL, &PINL, &PORTL, 0}, // L0 49 {&DDRB, &PINB, &PORTB, 3}, // B3 50 {&DDRB, &PINB, &PORTB, 2}, // B2 51 {&DDRB, &PINB, &PORTB, 1}, // B1 52 {&DDRB, &PINB, &PORTB, 0}, // B0 53 {&DDRF, &PINF, &PORTF, 0}, // F0 54 {&DDRF, &PINF, &PORTF, 1}, // F1 55 {&DDRF, &PINF, &PORTF, 2}, // F2 56 {&DDRF, &PINF, &PORTF, 3}, // F3 57 {&DDRF, &PINF, &PORTF, 4}, // F4 58 {&DDRF, &PINF, &PORTF, 5}, // F5 59 {&DDRF, &PINF, &PORTF, 6}, // F6 60 {&DDRF, &PINF, &PORTF, 7}, // F7 61 {&DDRK, &PINK, &PORTK, 0}, // K0 62 {&DDRK, &PINK, &PORTK, 1}, // K1 63 {&DDRK, &PINK, &PORTK, 2}, // K2 64 {&DDRK, &PINK, &PORTK, 3}, // K3 65 {&DDRK, &PINK, &PORTK, 4}, // K4 66 {&DDRK, &PINK, &PORTK, 5}, // K5 67 {&DDRK, &PINK, &PORTK, 6}, // K6 68 {&DDRK, &PINK, &PORTK, 7}, // K7 69 //pins_MIGHTYBOARD_REVE.h {&DDRG, &PING, &PORTG, 4}, // G4 70 {&DDRG, &PING, &PORTG, 3}, // G3 71 {&DDRJ, &PINJ, &PORTJ, 2}, // J2 72 {&DDRJ, &PINJ, &PORTJ, 3}, // J3 73 {&DDRJ, &PINJ, &PORTJ, 7}, // J7 74 {&DDRJ, &PINJ, &PORTJ, 4}, // J4 75 {&DDRJ, &PINJ, &PORTJ, 5}, // J5 76 {&DDRJ, &PINJ, &PORTJ, 6}, // J6 77 {&DDRE, &PINE, &PORTE, 2}, // E2 78 {&DDRE, &PINE, &PORTE, 6} // E6 79 }; //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega1284P__)\ || defined(__AVR_ATmega1284__)\ || defined(__AVR_ATmega644P__)\ || defined(__AVR_ATmega644__)\ || defined(__AVR_ATmega64__)\ || defined(__AVR_ATmega32__)\ || defined(__AVR_ATmega324__)\ || defined(__AVR_ATmega16__) #if defined(VARIANT_MIGHTY) // Mighty Layout static const pin_map_t pinMap[] = { {&DDRB, &PINB, &PORTB, 0}, // B0 0 {&DDRB, &PINB, &PORTB, 1}, // B1 1 {&DDRB, &PINB, &PORTB, 2}, // B2 2 {&DDRB, &PINB, &PORTB, 3}, // B3 3 {&DDRB, &PINB, &PORTB, 4}, // B4 4 {&DDRB, &PINB, &PORTB, 5}, // B5 5 {&DDRB, &PINB, &PORTB, 6}, // B6 6 {&DDRB, &PINB, &PORTB, 7}, // B7 7 {&DDRD, &PIND, &PORTD, 0}, // D0 8 {&DDRD, &PIND, &PORTD, 1}, // D1 9 {&DDRD, &PIND, &PORTD, 2}, // D2 10 {&DDRD, &PIND, &PORTD, 3}, // D3 11 {&DDRD, &PIND, &PORTD, 4}, // D4 12 {&DDRD, &PIND, &PORTD, 5}, // D5 13 {&DDRD, &PIND, &PORTD, 6}, // D6 14 {&DDRD, &PIND, &PORTD, 7}, // D7 15 {&DDRC, &PINC, &PORTC, 0}, // C0 16 {&DDRC, &PINC, &PORTC, 1}, // C1 17 {&DDRC, &PINC, &PORTC, 2}, // C2 18 {&DDRC, &PINC, &PORTC, 3}, // C3 19 {&DDRC, &PINC, &PORTC, 4}, // C4 20 {&DDRC, &PINC, &PORTC, 5}, // C5 21 {&DDRC, &PINC, &PORTC, 6}, // C6 22 {&DDRC, &PINC, &PORTC, 7}, // C7 23 {&DDRA, &PINA, &PORTA, 0}, // A0 24 {&DDRA, &PINA, &PORTA, 1}, // A1 25 {&DDRA, &PINA, &PORTA, 2}, // A2 26 {&DDRA, &PINA, &PORTA, 3}, // A3 27 {&DDRA, &PINA, &PORTA, 4}, // A4 28 {&DDRA, &PINA, &PORTA, 5}, // A5 29 {&DDRA, &PINA, &PORTA, 6}, // A6 30 {&DDRA, &PINA, &PORTA, 7} // A7 31 }; #elif defined(VARIANT_BOBUINO) // Bobuino Layout static const pin_map_t pinMap[] = { {&DDRD, &PIND, &PORTD, 0}, // D0 0 {&DDRD, &PIND, &PORTD, 1}, // D1 1 {&DDRD, &PIND, &PORTD, 2}, // D2 2 {&DDRD, &PIND, &PORTD, 3}, // D3 3 {&DDRB, &PINB, &PORTB, 0}, // B0 4 {&DDRB, &PINB, &PORTB, 1}, // B1 5 {&DDRB, &PINB, &PORTB, 2}, // B2 6 {&DDRB, &PINB, &PORTB, 3}, // B3 7 {&DDRD, &PIND, &PORTD, 5}, // D5 8 {&DDRD, &PIND, &PORTD, 6}, // D6 9 {&DDRB, &PINB, &PORTB, 4}, // B4 10 {&DDRB, &PINB, &PORTB, 5}, // B5 11 {&DDRB, &PINB, &PORTB, 6}, // B6 12 {&DDRB, &PINB, &PORTB, 7}, // B7 13 {&DDRA, &PINA, &PORTA, 7}, // A7 14 {&DDRA, &PINA, &PORTA, 6}, // A6 15 {&DDRA, &PINA, &PORTA, 5}, // A5 16 {&DDRA, &PINA, &PORTA, 4}, // A4 17 {&DDRA, &PINA, &PORTA, 3}, // A3 18 {&DDRA, &PINA, &PORTA, 2}, // A2 19 {&DDRA, &PINA, &PORTA, 1}, // A1 20 {&DDRA, &PINA, &PORTA, 0}, // A0 21 {&DDRC, &PINC, &PORTC, 0}, // C0 22 {&DDRC, &PINC, &PORTC, 1}, // C1 23 {&DDRC, &PINC, &PORTC, 2}, // C2 24 {&DDRC, &PINC, &PORTC, 3}, // C3 25 {&DDRC, &PINC, &PORTC, 4}, // C4 26 {&DDRC, &PINC, &PORTC, 5}, // C5 27 {&DDRC, &PINC, &PORTC, 6}, // C6 28 {&DDRC, &PINC, &PORTC, 7}, // C7 29 {&DDRD, &PIND, &PORTD, 4}, // D4 30 {&DDRD, &PIND, &PORTD, 7} // D7 31 }; #elif defined(VARIANT_STANDARD) // Standard Layout static const pin_map_t pinMap[] = { {&DDRB, &PINB, &PORTB, 0}, // B0 0 {&DDRB, &PINB, &PORTB, 1}, // B1 1 {&DDRB, &PINB, &PORTB, 2}, // B2 2 {&DDRB, &PINB, &PORTB, 3}, // B3 3 {&DDRB, &PINB, &PORTB, 4}, // B4 4 {&DDRB, &PINB, &PORTB, 5}, // B5 5 {&DDRB, &PINB, &PORTB, 6}, // B6 6 {&DDRB, &PINB, &PORTB, 7}, // B7 7 {&DDRD, &PIND, &PORTD, 0}, // D0 8 {&DDRD, &PIND, &PORTD, 1}, // D1 9 {&DDRD, &PIND, &PORTD, 2}, // D2 10 {&DDRD, &PIND, &PORTD, 3}, // D3 11 {&DDRD, &PIND, &PORTD, 4}, // D4 12 {&DDRD, &PIND, &PORTD, 5}, // D5 13 {&DDRD, &PIND, &PORTD, 6}, // D6 14 {&DDRD, &PIND, &PORTD, 7}, // D7 15 {&DDRC, &PINC, &PORTC, 0}, // C0 16 {&DDRC, &PINC, &PORTC, 1}, // C1 17 {&DDRC, &PINC, &PORTC, 2}, // C2 18 {&DDRC, &PINC, &PORTC, 3}, // C3 19 {&DDRC, &PINC, &PORTC, 4}, // C4 20 {&DDRC, &PINC, &PORTC, 5}, // C5 21 {&DDRC, &PINC, &PORTC, 6}, // C6 22 {&DDRC, &PINC, &PORTC, 7}, // C7 23 {&DDRA, &PINA, &PORTA, 7}, // A7 24 {&DDRA, &PINA, &PORTA, 6}, // A6 25 {&DDRA, &PINA, &PORTA, 5}, // A5 26 {&DDRA, &PINA, &PORTA, 4}, // A4 27 {&DDRA, &PINA, &PORTA, 3}, // A3 28 {&DDRA, &PINA, &PORTA, 2}, // A2 29 {&DDRA, &PINA, &PORTA, 1}, // A1 30 {&DDRA, &PINA, &PORTA, 0} // A0 31 }; #else // VARIANT_MIGHTY #error Undefined variant 1284, 644, 324, 64, 32 #endif // VARIANT_MIGHTY //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega32U4__) #ifdef CORE_TEENSY // Teensy 2.0 static const pin_map_t pinMap[] = { {&DDRB, &PINB, &PORTB, 0}, // B0 0 {&DDRB, &PINB, &PORTB, 1}, // B1 1 {&DDRB, &PINB, &PORTB, 2}, // B2 2 {&DDRB, &PINB, &PORTB, 3}, // B3 3 {&DDRB, &PINB, &PORTB, 7}, // B7 4 {&DDRD, &PIND, &PORTD, 0}, // D0 5 {&DDRD, &PIND, &PORTD, 1}, // D1 6 {&DDRD, &PIND, &PORTD, 2}, // D2 7 {&DDRD, &PIND, &PORTD, 3}, // D3 8 {&DDRC, &PINC, &PORTC, 6}, // C6 9 {&DDRC, &PINC, &PORTC, 7}, // C7 10 {&DDRD, &PIND, &PORTD, 6}, // D6 11 {&DDRD, &PIND, &PORTD, 7}, // D7 12 {&DDRB, &PINB, &PORTB, 4}, // B4 13 {&DDRB, &PINB, &PORTB, 5}, // B5 14 {&DDRB, &PINB, &PORTB, 6}, // B6 15 {&DDRF, &PINF, &PORTF, 7}, // F7 16 {&DDRF, &PINF, &PORTF, 6}, // F6 17 {&DDRF, &PINF, &PORTF, 5}, // F5 18 {&DDRF, &PINF, &PORTF, 4}, // F4 19 {&DDRF, &PINF, &PORTF, 1}, // F1 20 {&DDRF, &PINF, &PORTF, 0}, // F0 21 {&DDRD, &PIND, &PORTD, 4}, // D4 22 {&DDRD, &PIND, &PORTD, 5}, // D5 23 {&DDRE, &PINE, &PORTE, 6} // E6 24 }; //------------------------------------------------------------------------------ #else // CORE_TEENSY // Leonardo static const pin_map_t pinMap[] = { {&DDRD, &PIND, &PORTD, 2}, // D2 0 {&DDRD, &PIND, &PORTD, 3}, // D3 1 {&DDRD, &PIND, &PORTD, 1}, // D1 2 {&DDRD, &PIND, &PORTD, 0}, // D0 3 {&DDRD, &PIND, &PORTD, 4}, // D4 4 {&DDRC, &PINC, &PORTC, 6}, // C6 5 {&DDRD, &PIND, &PORTD, 7}, // D7 6 {&DDRE, &PINE, &PORTE, 6}, // E6 7 {&DDRB, &PINB, &PORTB, 4}, // B4 8 {&DDRB, &PINB, &PORTB, 5}, // B5 9 {&DDRB, &PINB, &PORTB, 6}, // B6 10 {&DDRB, &PINB, &PORTB, 7}, // B7 11 {&DDRD, &PIND, &PORTD, 6}, // D6 12 {&DDRC, &PINC, &PORTC, 7}, // C7 13 {&DDRB, &PINB, &PORTB, 3}, // B3 14 {&DDRB, &PINB, &PORTB, 1}, // B1 15 {&DDRB, &PINB, &PORTB, 2}, // B2 16 {&DDRB, &PINB, &PORTB, 0}, // B0 17 {&DDRF, &PINF, &PORTF, 7}, // F7 18 {&DDRF, &PINF, &PORTF, 6}, // F6 19 {&DDRF, &PINF, &PORTF, 5}, // F5 20 {&DDRF, &PINF, &PORTF, 4}, // F4 21 {&DDRF, &PINF, &PORTF, 1}, // F1 22 {&DDRF, &PINF, &PORTF, 0}, // F0 23 {&DDRD, &PIND, &PORTD, 4}, // D4 24 {&DDRD, &PIND, &PORTD, 7}, // D7 25 {&DDRB, &PINB, &PORTB, 4}, // B4 26 {&DDRB, &PINB, &PORTB, 5}, // B5 27 {&DDRB, &PINB, &PORTB, 6}, // B6 28 {&DDRD, &PIND, &PORTD, 6} // D6 29 }; #endif // CORE_TEENSY //------------------------------------------------------------------------------ #elif defined(__AVR_AT90USB646__)\ || defined(__AVR_AT90USB1286__) // Teensy++ 1.0 & 2.0 static const pin_map_t pinMap[] = { {&DDRD, &PIND, &PORTD, 0}, // D0 0 {&DDRD, &PIND, &PORTD, 1}, // D1 1 {&DDRD, &PIND, &PORTD, 2}, // D2 2 {&DDRD, &PIND, &PORTD, 3}, // D3 3 {&DDRD, &PIND, &PORTD, 4}, // D4 4 {&DDRD, &PIND, &PORTD, 5}, // D5 5 {&DDRD, &PIND, &PORTD, 6}, // D6 6 {&DDRD, &PIND, &PORTD, 7}, // D7 7 {&DDRE, &PINE, &PORTE, 0}, // E0 8 {&DDRE, &PINE, &PORTE, 1}, // E1 9 {&DDRC, &PINC, &PORTC, 0}, // C0 10 {&DDRC, &PINC, &PORTC, 1}, // C1 11 {&DDRC, &PINC, &PORTC, 2}, // C2 12 {&DDRC, &PINC, &PORTC, 3}, // C3 13 {&DDRC, &PINC, &PORTC, 4}, // C4 14 {&DDRC, &PINC, &PORTC, 5}, // C5 15 {&DDRC, &PINC, &PORTC, 6}, // C6 16 {&DDRC, &PINC, &PORTC, 7}, // C7 17 {&DDRE, &PINE, &PORTE, 6}, // E6 18 {&DDRE, &PINE, &PORTE, 7}, // E7 19 {&DDRB, &PINB, &PORTB, 0}, // B0 20 {&DDRB, &PINB, &PORTB, 1}, // B1 21 {&DDRB, &PINB, &PORTB, 2}, // B2 22 {&DDRB, &PINB, &PORTB, 3}, // B3 23 {&DDRB, &PINB, &PORTB, 4}, // B4 24 {&DDRB, &PINB, &PORTB, 5}, // B5 25 {&DDRB, &PINB, &PORTB, 6}, // B6 26 {&DDRB, &PINB, &PORTB, 7}, // B7 27 {&DDRA, &PINA, &PORTA, 0}, // A0 28 {&DDRA, &PINA, &PORTA, 1}, // A1 29 {&DDRA, &PINA, &PORTA, 2}, // A2 30 {&DDRA, &PINA, &PORTA, 3}, // A3 31 {&DDRA, &PINA, &PORTA, 4}, // A4 32 {&DDRA, &PINA, &PORTA, 5}, // A5 33 {&DDRA, &PINA, &PORTA, 6}, // A6 34 {&DDRA, &PINA, &PORTA, 7}, // A7 35 {&DDRE, &PINE, &PORTE, 4}, // E4 36 {&DDRE, &PINE, &PORTE, 5}, // E5 37 {&DDRF, &PINF, &PORTF, 0}, // F0 38 {&DDRF, &PINF, &PORTF, 1}, // F1 39 {&DDRF, &PINF, &PORTF, 2}, // F2 40 {&DDRF, &PINF, &PORTF, 3}, // F3 41 {&DDRF, &PINF, &PORTF, 4}, // F4 42 {&DDRF, &PINF, &PORTF, 5}, // F5 43 {&DDRF, &PINF, &PORTF, 6}, // F6 44 {&DDRF, &PINF, &PORTF, 7} // F7 45 }; //------------------------------------------------------------------------------ #else // CPU type #error unknown CPU type #endif // CPU type //------------------------------------------------------------------------------ /** count of pins */ static const uint8_t digitalPinCount = sizeof(pinMap)/sizeof(pin_map_t); //============================================================================== /** generate bad pin number error */ void badPinNumber(void) __attribute__((error("Pin number is too large or not a constant"))); //------------------------------------------------------------------------------ /** Check for valid pin number * @param[in] pin Number of pin to be checked. */ static inline __attribute__((always_inline)) void badPinCheck(uint8_t pin) { if (!__builtin_constant_p(pin) || pin >= digitalPinCount) { badPinNumber(); } } //------------------------------------------------------------------------------ /** fast write helper * @param[in] address I/O register address * @param[in] bit bit number to write * @param[in] level value for bit */ static inline __attribute__((always_inline)) void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) { uint8_t oldSREG; if (address > (uint8_t*)0x5F) { oldSREG = SREG; cli(); } if (level) { *address |= 1 << bit; } else { *address &= ~(1 << bit); } if (address > (uint8_t*)0x5F) { SREG = oldSREG; } } //------------------------------------------------------------------------------ /** read pin value * @param[in] pin Arduino pin number * @return value read */ static inline __attribute__((always_inline)) bool fastDigitalRead(uint8_t pin) { badPinCheck(pin); return (*pinMap[pin].pin >> pinMap[pin].bit) & 1; } //------------------------------------------------------------------------------ /** toggle a pin * @param[in] pin Arduino pin number * * If the pin is in output mode toggle the pin level. * If the pin is in input mode toggle the state of the 20K pullup. */ static inline __attribute__((always_inline)) void fastDigitalToggle(uint8_t pin) { badPinCheck(pin); if (pinMap[pin].pin > (uint8_t*)0x5F) { // must write bit to high address port *pinMap[pin].pin = 1 << pinMap[pin].bit; } else { // will compile to sbi and PIN register will not be read. *pinMap[pin].pin |= 1 << pinMap[pin].bit; } } //------------------------------------------------------------------------------ /** Set pin value * @param[in] pin Arduino pin number * @param[in] level value to write */ static inline __attribute__((always_inline)) void fastDigitalWrite(uint8_t pin, bool level) { badPinCheck(pin); fastBitWriteSafe(pinMap[pin].port, pinMap[pin].bit, level); } //------------------------------------------------------------------------------ /** set pin mode * @param[in] pin Arduino pin number * @param[in] mode if true set output mode else input mode * * fastPinMode does not enable or disable the 20K pullup for input mode. */ static inline __attribute__((always_inline)) void fastPinMode(uint8_t pin, bool mode) { badPinCheck(pin); fastBitWriteSafe(pinMap[pin].ddr, pinMap[pin].bit, mode); } #endif // __arm__ //------------------------------------------------------------------------------ /** set pin configuration * @param[in] pin Arduino pin number * @param[in] mode If true set output mode else input mode * @param[in] level If mode is output, set level high/low. * If mode is input, enable or disable the pin's 20K pullup. */ static inline __attribute__((always_inline)) void fastPinConfig(uint8_t pin, bool mode, bool level) { fastPinMode(pin, mode); fastDigitalWrite(pin, level); } //============================================================================== /** * @class DigitalPin * @brief Fast digital port I/O */ template class DigitalPin { public: //---------------------------------------------------------------------------- /** Constructor */ DigitalPin() {} //---------------------------------------------------------------------------- /** Constructor * @param[in] pinMode if true set output mode else input mode. */ explicit DigitalPin(bool pinMode) { mode(pinMode); } //---------------------------------------------------------------------------- /** Constructor * @param[in] mode If true set output mode else input mode * @param[in] level If mode is output, set level high/low. * If mode is input, enable or disable the pin's 20K pullup. */ DigitalPin(bool mode, bool level) { config(mode, level); } //---------------------------------------------------------------------------- /** Asignment operator * @param[in] value If true set the pin's level high else set the * pin's level low. * * @return This DigitalPin instance. */ inline DigitalPin & operator = (bool value) __attribute__((always_inline)) { write(value); return *this; } //---------------------------------------------------------------------------- /** Parenthesis operator * @return Pin's level */ inline operator bool () const __attribute__((always_inline)) { return read(); } //---------------------------------------------------------------------------- /** set pin configuration * @param[in] mode If true set output mode else input mode * @param[in] level If mode is output, set level high/low. * If mode is input, enable or disable the pin's 20K pullup. */ inline __attribute__((always_inline)) void config(bool mode, bool level) { fastPinConfig(PinNumber, mode, level); } //---------------------------------------------------------------------------- /** * Set pin level high if output mode or enable 20K pullup if input mode. */ inline __attribute__((always_inline)) void high() {write(true);} //---------------------------------------------------------------------------- /** * Set pin level low if output mode or disable 20K pullup if input mode. */ inline __attribute__((always_inline)) void low() {write(false);} //---------------------------------------------------------------------------- /** * Set pin mode * @param[in] pinMode if true set output mode else input mode. * * mode() does not enable or disable the 20K pullup for input mode. */ inline __attribute__((always_inline)) void mode(bool pinMode) { fastPinMode(PinNumber, pinMode); } //---------------------------------------------------------------------------- /** @return Pin's level */ inline __attribute__((always_inline)) bool read() const { return fastDigitalRead(PinNumber); } //---------------------------------------------------------------------------- /** toggle a pin * * If the pin is in output mode toggle the pin's level. * If the pin is in input mode toggle the state of the 20K pullup. */ inline __attribute__((always_inline)) void toggle() { fastDigitalToggle(PinNumber); } //---------------------------------------------------------------------------- /** Write the pin's level. * @param[in] value If true set the pin's level high else set the * pin's level low. */ inline __attribute__((always_inline)) void write(bool value) { fastDigitalWrite(PinNumber, value); } }; //------------------------------------------------------------------------------ /** Nop for timing. */ #define nop asm volatile ("nop\n\t") //------------------------------------------------------------------------------ /** Pin Mode for MISO is input.*/ const bool MISO_MODE = false; /** Pullups disabled for MISO are disabled. */ const bool MISO_LEVEL = false; /** Pin Mode for MOSI is output.*/ const bool MOSI_MODE = true; /** Pin Mode for SCK is output. */ const bool SCK_MODE = true; //------------------------------------------------------------------------------ /** * @class SoftSPI * @brief Fast software SPI. */ template class SoftSPI { public: //---------------------------------------------------------------------------- /** Initialize SoftSPI pins. */ void begin() { fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL); fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode)); fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode)); } //---------------------------------------------------------------------------- /** Soft SPI receive byte. * @return Data byte received. */ inline __attribute__((always_inline)) uint8_t receive() { uint8_t data = 0; receiveBit(7, &data); receiveBit(6, &data); receiveBit(5, &data); receiveBit(4, &data); receiveBit(3, &data); receiveBit(2, &data); receiveBit(1, &data); receiveBit(0, &data); return data; } //---------------------------------------------------------------------------- /** Soft SPI send byte. * @param[in] data Data byte to send. */ inline __attribute__((always_inline)) void send(uint8_t data) { sendBit(7, data); sendBit(6, data); sendBit(5, data); sendBit(4, data); sendBit(3, data); sendBit(2, data); sendBit(1, data); sendBit(0, data); } //---------------------------------------------------------------------------- /** Soft SPI transfer byte. * @param[in] txData Data byte to send. * @return Data byte received. */ inline __attribute__((always_inline)) uint8_t transfer(uint8_t txData) { uint8_t rxData = 0; transferBit(7, &rxData, txData); transferBit(6, &rxData, txData); transferBit(5, &rxData, txData); transferBit(4, &rxData, txData); transferBit(3, &rxData, txData); transferBit(2, &rxData, txData); transferBit(1, &rxData, txData); transferBit(0, &rxData, txData); return rxData; } private: //---------------------------------------------------------------------------- inline __attribute__((always_inline)) bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;} inline __attribute__((always_inline)) bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;} inline __attribute__((always_inline)) void receiveBit(uint8_t bit, uint8_t* data) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } nop; nop; fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); if (fastDigitalRead(MisoPin)) *data |= 1 << bit; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- inline __attribute__((always_inline)) void sendBit(uint8_t bit, uint8_t data) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } fastDigitalWrite(MosiPin, data & (1 << bit)); fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); nop; nop; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- inline __attribute__((always_inline)) void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) { if (MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); } fastDigitalWrite(MosiPin, txData & (1 << bit)); fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit; if (!MODE_CPHA(Mode)) { fastDigitalWrite(SckPin, MODE_CPOL(Mode)); } } //---------------------------------------------------------------------------- };