diff options
author | Craig Link <craigl@zillowgroup.com> | 2021-02-28 11:48:39 +0300 |
---|---|---|
committer | Craig Link <craigl@zillowgroup.com> | 2021-02-28 11:48:39 +0300 |
commit | a8a2be7513bd9bc0f9450739826453689a6823c9 (patch) | |
tree | cedc6e0dd7268ae5b1dda227e48277517e014d39 | |
parent | b779b04f36e95eb74b0f5614af4786a47ce3d02c (diff) |
optimize Ardunio Nano Every pin out to single cycle by using VPORTs
from the ATMEga4809 Datasheet - http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega4808-4809-Data-Sheet-DS40002173A.pdf
16.3.2.3 Virtual Ports
The Virtual PORT registers map the most frequently used regular PORT registers into the bit-accessible I/O space.
Writing to the Virtual PORT registers has the same effect as writing to the regular registers, but allows for memoryspecific instructions, such as bit-manipulation instructions, which are not valid for the extended I/O memory space
where the regular PORT registers reside
-rw-r--r-- | src/platforms/avr/clockless_trinket.h | 17 | ||||
-rw-r--r-- | src/platforms/avr/fastpin_avr.h | 13 |
2 files changed, 27 insertions, 3 deletions
diff --git a/src/platforms/avr/clockless_trinket.h b/src/platforms/avr/clockless_trinket.h index 971a5a71..2cfbef0d 100644 --- a/src/platforms/avr/clockless_trinket.h +++ b/src/platforms/avr/clockless_trinket.h @@ -172,7 +172,8 @@ protected: #define USE_ASM_MACROS #if defined(__AVR_ATmega4809__) -#define ASM_VAR_PORT "r" (((PORT_t*)FastPin<DATA_PIN>::port())->OUT) +// Not used - place holder so existing ASM_VARS macro can remain the same +#define ASM_VAR_PORT "r" (*FastPin<DATA_PIN>::port()) #else #define ASM_VAR_PORT "M" (FastPin<DATA_PIN>::port() - 0x20) #endif @@ -204,12 +205,24 @@ protected: [O1] "M" (RGB_BYTE1(RGB_ORDER)), \ [O2] "M" (RGB_BYTE2(RGB_ORDER)) \ : "cc" /* clobber registers */ -// Note: the code in the else in HI1/LO1 will be turned into an sts (2 cycle, 2 word) opcode + +#if defined(__AVR_ATmega4809__) + +// 1 cycle, write hi to the port +#define HI1 do {*FastPin<DATA_PIN>::port()=hi;} while(0); +// 1 cycle, write lo to the port +#define LO1 do {*FastPin<DATA_PIN>::port()=lo;} while(0); + +#else + +// Note: the code in the else in HI1/LO1 will be turned into an sts (2 cycle, 2 word) // 1 cycle, write hi to the port #define HI1 FASTLED_SLOW_CLOCK_ADJUST if((int)(FastPin<DATA_PIN>::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[hi]" ASM_VARS ); } else { *FastPin<DATA_PIN>::port()=hi; } // 1 cycle, write lo to the port #define LO1 if((int)(FastPin<DATA_PIN>::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[lo]" ASM_VARS ); } else { *FastPin<DATA_PIN>::port()=lo; } +#endif + // 2 cycles, sbrs on flipping the line to lo if we're pushing out a 0 #define QLO2(B, N) asm __volatile__("sbrs %[" #B "], " #N ASM_VARS ); LO1; // load a byte from ram into the given var with the given offset diff --git a/src/platforms/avr/fastpin_avr.h b/src/platforms/avr/fastpin_avr.h index 8087e2a2..08dcdc13 100644 --- a/src/platforms/avr/fastpin_avr.h +++ b/src/platforms/avr/fastpin_avr.h @@ -37,6 +37,7 @@ public: inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; @@ -46,15 +47,25 @@ public: /// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar /// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!) typedef volatile uint8_t & reg8_t; + #define _R(T) struct __gen_struct_ ## T #define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }}; // Register name equivalent (using flat names) -#if defined(AVR_ATtinyxy7) || defined(AVR_ATtinyxy6) || defined(AVR_ATtinyxy4) || defined(AVR_ATtinyxy2) || defined(__AVR_ATmega4809__) +#if defined(AVR_ATtinyxy7) || defined(AVR_ATtinyxy6) || defined(AVR_ATtinyxy4) || defined(AVR_ATtinyxy2) + // ATtiny series 0/1 and ATmega series 0 #define _FL_IO(L,C) _RD8(PORT ## L ## _DIR); _RD8(PORT ## L ## _OUT); _RD8(PORT ## L ## _IN); _FL_DEFINE_PORT3(L, C, _R(PORT ## L ## _OUT)); #define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(PORT ## L ## _OUT), _R(PORT ## L ## _DIR), _R(PORT ## L ## _IN)> {}; + +#elif defined(__AVR_ATmega4809__) + + +#define _FL_IO(L,C) _RD8(VPORT ## L ## _DIR); _RD8(VPORT ## L ## _OUT); _RD8(VPORT ## L ## _IN); _FL_DEFINE_PORT3(L, C, _R(VPORT ## L ## _OUT)); +#define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(VPORT ## L ## _OUT), _R(VPORT ## L ## _DIR), _R(VPORT ## L ## _IN)> {}; + #else + // Others #define _FL_IO(L,C) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); _FL_DEFINE_PORT3(L, C, _R(PORT ## L)); #define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(PORT ## L), _R(DDR ## L), _R(PIN ## L)> {}; |