diff --git a/Cpp17AVR-package-0.0.2.tar.gz b/Cpp17AVR-package-0.0.2.tar.gz index 619200f..90668d4 100644 --- a/Cpp17AVR-package-0.0.2.tar.gz +++ b/Cpp17AVR-package-0.0.2.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ec1a3995f531c90f9b442df94d1c5fefe653a47d4035f0d303527702f24b647 -size 22401056 +oid sha256:7157245d16864645bd1a4116cdb923dece865092d5104cfe40d066e22e0b3a24 +size 22451895 diff --git a/createAnalogWriteTemplateSpecializations.sh b/createAnalogWriteTemplateSpecializations.sh new file mode 100755 index 0000000..6a8e1e1 --- /dev/null +++ b/createAnalogWriteTemplateSpecializations.sh @@ -0,0 +1,202 @@ +#!/bin/bash + +# create template code for timers to set pwm on AVRmegaxxx fro Arduino + +cat < +#endif + +template +inline +__attribute__((always_inline)) +void cbi(PTR sfr, uint8_t const bit) +{ + (_SFR_BYTE(sfr) &= ~_BV(bit)); +} +template +inline +__attribute__((always_inline)) +void sbi(PTR sfr, uint8_t const bit) +{ + (_SFR_BYTE(sfr) |= _BV(bit)); +} + +template +inline +__attribute__((always_inline)) +void digitalWrite(); + + +template +inline +__attribute__((always_inline)) +void setPWMValue(int val); + + + +// special cases taken from avr +#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) +template <> inline +__attribute__((always_inline)) +void setPWMValue(int val) +{ + sbi(TCCR0, COM00); + OCR0 = val; +} +#endif +#if defined(TCCR2) && defined(COM21) +template <> inline +__attribute__((always_inline)) +void setPWMValue(int val) +{ + sbi(TCCR2, COM21); + OCR2 = val; +} +#endif +#if defined(TCCR4A) +template <> inline +__attribute__((always_inline)) +void setPWMValue(int val) +{ + sbi(TCCR4A, COM4A1); + #if defined(COM4A0) + cbi(TCCR4A, COM4A0); + #endif + OCR4A = val; +} +#endif +#if defined(TCCR4C) && defined(COM4D1) +template <> inline +__attribute__((always_inline)) +void setPWMValue(int val) +{ + sbi(TCCR4C, COM4D1); + #if defined(COM4D0) + cbi(TCCR4C, COM4D0); + #endif + OCR4D = val; +} +#endif + +!EOF0 + +function timers() { + case "$1" in + 0) echo A B ;; + 1) echo A B C ;; + 2) echo A B ;; + 3) echo A B C ;; + 4) echo B C ;; # 4A and 4 D special cases + 5) echo A B C ;; + esac +} + +for num in 0 1 2 3 4 5 +do + for c in `timers $num ` + do + # some wrong 0 4A $D, some missing some superfluous + cat < inline +__attribute__((always_inline)) +void setPWMValue(int val) +{ + sbi(TCCR${num}A, COM${num}${c}1); + OCR${num}${c} = val; +} +#endif +!EOF +done +done + + +cat < +void setPWMValuePin(int val){ + if constexpr (digitalPinToTimer(pin) != NOT_ON_TIMER) + setPWMValue(val); + else { + if (val < 128) { + digitalWrite(); + } else { + digitalWrite(); + } + } +} + + +// to be defined in pins_arduino.h afterwards, since it depends on available timers +inline void analog_timer_turnoff(timer_values const theTimer) ; + +// make it a compile error if called with NOT_ON_TIMER + + +template inline +__attribute__((always_inline)) +void analog_timer_turnoff() ; + +template inline +__attribute__((always_inline)) +void analog_pin_to_timer_turnoff() +{ + if constexpr(digital_pin_to_timer_PS(pin) != NOT_ON_TIMER) + analog_timer_turnoff(); +} + + +#if defined(TCCR2) && defined(COM21) +template <> inline +__attribute__((always_inline)) +void analog_timer_turnoff() +{ + cbi(TCCR2, COM21); +} +#endif + +#if defined(TCCR4C) && defined(COM4D1) +template <> inline +__attribute__((always_inline)) +void analog_timer_turnoff() +{ + cbi(TCCR4C, COM4D1); +} +#endif + +!EOF2 + +function timers_to_turn_off() { + case "$1" in + 0) echo A B ;; + 1) echo A B C ;; + 2) echo A B ;; # 2 nothing is special case + 3) echo A B C ;; + 4) echo A B C ;; # 4 D special case + 5) echo A B C ;; + esac +} + + +for num in 0 1 2 3 4 5 +do + for c in `timers_to_turn_off $num ` + do + # some wrong 0 4A $D, some missing some superfluous + cat < inline +__attribute__((always_inline)) +void analog_timer_turnoff() +{ + cbi(TCCR${num}A, COM${num}${c}1); +} +#endif +!EOF +done +done + + + diff --git a/create_analog_timer_turnoff_cases.sh b/create_analog_timer_turnoff_cases.sh new file mode 100755 index 0000000..7aaad27 --- /dev/null +++ b/create_analog_timer_turnoff_cases.sh @@ -0,0 +1,24 @@ +#!/bin/bash +function timers_to_turn_off() { + case "$1" in + 0) echo A B ;; + 1) echo A B C ;; + 2) echo A B ;; + 3) echo A B C ;; + 4) echo A B C ;; + 5) echo A B C ;; + esac +} + + +for num in 0 1 2 3 4 5 +do + for c in `timers_to_turn_off $num ` + do + # some wrong 0 4A $D, some missing some superfluous + cat <(); break; +!EOF + + done +done \ No newline at end of file diff --git a/package_Cpp17AVR_index.json b/package_Cpp17AVR_index.json index babae00..91b64be 100644 --- a/package_Cpp17AVR_index.json +++ b/package_Cpp17AVR_index.json @@ -95,12 +95,12 @@ } ], "category": "Contributed", - "checksum": "SHA-256:4ec1a3995f531c90f9b442df94d1c5fefe653a47d4035f0d303527702f24b647", + "checksum": "SHA-256:7157245d16864645bd1a4116cdb923dece865092d5104cfe40d066e22e0b3a24", "help": { "online": "http://www.arduino.cc/en/Reference/HomePage" }, "name": "Cpp17 Arduino AVR Boards", - "size": "22401056", + "size": "22451895", "toolsDependencies": [ { "name": "avr-gcc", diff --git a/wsAVR/arduinoavr_dummy/.project b/wsAVR/arduinoavr_dummy/.project index 0c41399..f37279e 100644 --- a/wsAVR/arduinoavr_dummy/.project +++ b/wsAVR/arduinoavr_dummy/.project @@ -55,21 +55,6 @@ 2 virtual:/virtual - - microp - 2 - virtual:/virtual - - - robot_control - 2 - virtual:/virtual - - - robot_motor - 2 - virtual:/virtual - standard 2 @@ -130,21 +115,6 @@ 1 PARENT-3-PROJECT_LOC/ArduinoCore-avr/variants/micro/pins_arduino.h - - microp/pins_arduino.h - 1 - PARENT-3-PROJECT_LOC/ArduinoCore-avr/variants/microp/pins_arduino.h - - - robot_control/pins_arduino.h - 1 - PARENT-3-PROJECT_LOC/ArduinoCore-avr/variants/robot_control/pins_arduino.h - - - robot_motor/pins_arduino.h - 1 - PARENT-3-PROJECT_LOC/ArduinoCore-avr/variants/robot_motor/pins_arduino.h - standard/pins_arduino.h 1 @@ -340,6 +310,11 @@ 1 PARENT-3-PROJECT_LOC/ArduinoCore-avr/cores/arduino/new.h + + cores/arduino/pwm_timer_handling.h + 1 + PARENT-3-PROJECT_LOC/ArduinoCore-avr/cores/arduino/pwm_timer_handling.h + cores/arduino/wiring.c 1 @@ -355,6 +330,11 @@ 1 PARENT-3-PROJECT_LOC/ArduinoCore-avr/cores/arduino/wiring_digital.c + + cores/arduino/wiring_inline.h + 1 + PARENT-3-PROJECT_LOC/ArduinoCore-avr/cores/arduino/wiring_inline.h + cores/arduino/wiring_private.h 1 diff --git a/wsAVR/testAVRmicropinmapping/src/Test.cpp b/wsAVR/testAVRmicropinmapping/src/Test.cpp index 53cc364..60b01be 100644 --- a/wsAVR/testAVRmicropinmapping/src/Test.cpp +++ b/wsAVR/testAVRmicropinmapping/src/Test.cpp @@ -44,6 +44,13 @@ TIMER5C = 18 #define array_count_elements(arr) (sizeof(arr)/sizeof(arr[0])) namespace micro { +enum class PortType: uint8_t { + No_Port=0, PA=1, PB=2, PC=3, PD=4, PE=5, PF=6//, PG=7, PH=8, PJ=10, PK=11, PL=12 +}; +enum PinType:uint8_t { + D00, D01, D02, D03, D04, D05, D06, D07, D08, D09, D10, D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30 +}; #define PA 1 #define PB 2 #define PC 3 @@ -56,6 +63,7 @@ namespace micro { #define PK 11 #define PL 12 + const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD, // D0 - PD2 PD, // D1 - PD3 @@ -93,6 +101,20 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD, // D29 / D12 - A11 - PD6 PD, // D30 / TX Led - PD5 }; +#ifdef PB +#undef PA +#undef PB +#undef PC +#undef PD +#undef PE +#undef PF +#undef PG +#undef PH +#undef PJ +#undef PK +#undef PL +#endif + const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { _BV(2), // D0 - PD2 _BV(3), // D1 - PD3 @@ -167,11 +189,78 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER, NOT_ON_TIMER, }; +constexpr inline PortType digital_pin_to_Port_PS(uint8_t pin) noexcept { + switch(static_cast(pin)){ + case D08: case D09: case D10: case D11: case D14: case D15: case D16: case D17: case D26: case D27: case D28: + return PortType::PB; + case D05: case D13: + return PortType::PC; + case D00: case D01: case D02: case D03: case D04: case D06: case D12: case D24: case D25: case D29: case D30: + return PortType::PD; + case D07: + return PortType::PE; + case D18: case D19: case D20: case D21: case D22: case D23: + return PortType::PF; + } + return NO_PORT; +} + void testThatdigitalPinToPortProducesIdenticalResultsThatAreInTheMap() { for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_port_PGM); ++pin) ASSERT_EQUAL((int)digital_pin_to_port_PGM[pin],(int)digital_pin_to_Port_PS(pin)); } + +struct bitmask { +enum bitmask_in_byte:uint8_t { + b0=1,b1=2,b2=4,b3=8,b4=16,b5=32,b6=64,b7=128 +}; +template +static constexpr inline bool isOneOfPins(uint8_t pin){ + return (1ul << pin) & ((1ul<(pin)) + return bitmask_in_byte::b0; + if (isOneOfPins(pin)) + return bitmask_in_byte::b1; + if (isOneOfPins(pin)) + return bitmask_in_byte::b2; + if (isOneOfPins(pin)) + return bitmask_in_byte::b3; + if (isOneOfPins(pin)) + return bitmask_in_byte::b4; + if (isOneOfPins(pin)) + return bitmask_in_byte::b5; + if (isOneOfPins(pin)) + return bitmask_in_byte::b6; + if (isOneOfPins(pin)) + return bitmask_in_byte::b7; + + +// switch (static_cast(pin)) { +// case D03: case D17: case D23: +// return bitmask_in_byte::b0; +// case D02: case D15: case D22: +// return bitmask_in_byte::b1; +// case D00: case D16: +// return bitmask_in_byte::b2; +// case D01: case D14: +// return bitmask_in_byte::b3; +// case D04: case D08: case D21: case D24: case D26: +// return bitmask_in_byte::b4; +// case D09: case D20: case D27: case D30: +// return bitmask_in_byte::b5; +// case D05: case D07: case D10: case D12: case D19: case D28: case D29: +// return bitmask_in_byte::b6; +// case D06: case D11: case D13: case D18: case D25: +// return bitmask_in_byte::b7; +// } + return 0; // 0 might break code, may be, but would be better indicator. +} +}; + void testThatdigitalPinToBitmaskProducesIdenticalResultsThatAreInTheMap() { for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_bit_mask_PGM); ++pin) ASSERT_EQUAL((int)digital_pin_to_bit_mask_PGM[pin],(int)bitmask::digital_pin_to_BitMask_PS(pin)); @@ -185,9 +274,12 @@ void testThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap() { namespace uno{ // tests for uno timers *most tricky part -enum class PinType:uint8_t { +enum PinType:uint8_t { D00, D01, D02, D03, D04, D05, D06, D07, D08, D09, D10, D11, D12, D13, - A0 = PIN_A0, A1, A2, A3, A4, A5 + A0, A1, A2, A3, A4, A5, + SS=D10, MOSI=D11, MISO=D12, SCK=D12, // I2C + SDA=A4, SCL=A5, // TWI + //LED_BUILTIN=D13 }; const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { @@ -229,36 +321,336 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { }; constexpr inline uint8_t digital_pin_to_timer_PS(uint8_t const pin) noexcept { - switch (static_cast(pin)) { #if defined(__AVR_ATmega8__) - case PinType::D11: - return TIMER2;//, /* 11 */ + if (pin == PinType::D11) + return TIMER2;//, /* 11 */ -> 6 #else - case PinType::D03:/* 3 */ + if (pin == PinType::D03) // /* 3 */ -> 8 return TIMER2B; - case PinType::D05: - return TIMER0B;//, /* 5 */ - case PinType::D06: - return TIMER0A;//, /* 6 */ - case PinType::D11: - return TIMER2A;//, /* 11 */ + if (pin == PinType::D05) + return TIMER0B;//, /* 5 */ -> 2 + if (pin == PinType::D06) + return TIMER0A;//, /* 6 */ -> 1 + if (pin == PinType::D11) + return TIMER2A;//, /* 11 */ -> 7 #endif - case PinType::D09: - return TIMER1A;//, /* 9 */ - case PinType::D10: - return TIMER1B;//, /* 10 */ - default: - return NOT_ON_TIMER; - } + if (pin == PinType::D09) + return TIMER1A;//, /* 9 */ -> 3 + if (pin == PinType::D10) + return TIMER1B;//, /* 10 */ -> 4 + return NOT_ON_TIMER; + +// +// switch (static_cast(pin)) { +//#if defined(__AVR_ATmega8__) +// case PinType::D11: +// return TIMER2;//, /* 11 */ -> 6 +//#else +// case PinType::D03:// /* 3 */ -> 8 +// return TIMER2B; +// case PinType::D05: +// return TIMER0B;//, /* 5 */ -> 2 +// case PinType::D06: +// return TIMER0A;//, /* 6 */ -> 1 +// case PinType::D11: +// return TIMER2A;//, /* 11 */ -> 7 +//#endif +// case PinType::D09: +// return TIMER1A;//, /* 9 */ -> 3 +// case PinType::D10: +// return TIMER1B;//, /* 10 */ -> 4 +// default: +// return NOT_ON_TIMER; +// } } void unotestThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap() { for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_timer_PGM); ++pin) ASSERT_EQUAL((int)digital_pin_to_timer_PGM[pin],(int)digital_pin_to_timer_PS(pin)); } +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(0), /* 0, port D */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(0), /* 8, port B */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(0), /* 14, port C */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), +}; +struct bitmask { +enum bitmask_in_byte:uint8_t { + b0=1,b1=2,b2=4,b3=8,b4=16,b5=32,b6=64,b7=128 +}; +static constexpr inline uint8_t digital_pin_to_BitMask_PS(uint8_t pin) noexcept { + // benefit from regular pin bit mapping, saves space in ram, because all bad, section .rodata is copied into ram for switch statement tables + if (pin > 13) pin -=14; + else if (pin > 7) pin -= 8; + return 1u << pin; + +// switch (static_cast(pin)) { +// case PinType::D00: case PinType::D08: case PinType::A0: +// return bitmask_in_byte::b0; +// case PinType::D01: case PinType::D09: case PinType::A1: +// return bitmask_in_byte::b1; +// case PinType::D02: case PinType::D10: case PinType::A2: +// return bitmask_in_byte::b2; +// case PinType::D03: case PinType::D11: case PinType::A3: +// return bitmask_in_byte::b3; +// case PinType::D04: case PinType::D12: case PinType::A4: +// return bitmask_in_byte::b4; +// case PinType::D05: case PinType::D13: case PinType::A5: +// return bitmask_in_byte::b5; +// case PinType::D06: +// return bitmask_in_byte::b6; +// case PinType::D07: +// return bitmask_in_byte::b7; +// } +// return 0; // 0 might break code, may be, but is better indicator. +} +}; +void testThatdigitalPinToBitmaskProducesIdenticalResultsThatAreInTheMap() { + for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_bit_mask_PGM); ++pin){ + std::string msg{"pin no: "}; + msg += std::to_string(int(pin)); + ASSERT_EQUALM(msg,(int)digital_pin_to_bit_mask_PGM[pin],(int)bitmask::digital_pin_to_BitMask_PS(pin)); + + } +} +} + +namespace standardMega8{ +#define __AVR_ATmega8__ +// tests for uno timers *most tricky part +enum PinType:uint8_t { + D00, D01, D02, D03, D04, D05, D06, D07, D08, D09, D10, D11, D12, D13, + A0, A1, A2, A3, A4, A5, + SS=D10, MOSI=D11, MISO=D12, SCK=D12, // I2C + SDA=A4, SCL=A5, // TWI + //LED_BUILTIN=D13 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, /* 0 - port D */ + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, +#else + TIMER2B, +#endif + NOT_ON_TIMER, + // on the ATmega168, digital pins 5 and 6 have hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, + NOT_ON_TIMER, +#else + TIMER0B, + TIMER0A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, /* 8 - port B */ + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega8__) + TIMER2, +#else + TIMER2A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, /* 14 - port C */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +constexpr inline uint8_t digital_pin_to_timer_PS(uint8_t const pin) noexcept { +#if defined(__AVR_ATmega8__) + if (pin == PinType::D11) + return TIMER2;//, /* 11 */ -> 6 +#else + if (pin == PinType::D03) // /* 3 */ -> 8 + return TIMER2B; + if (pin == PinType::D05) + return TIMER0B;//, /* 5 */ -> 2 + if (pin == PinType::D06) + return TIMER0A;//, /* 6 */ -> 1 + if (pin == PinType::D11) + return TIMER2A;//, /* 11 */ -> 7 +#endif + if (pin == PinType::D09) + return TIMER1A;//, /* 9 */ -> 3 + if (pin == PinType::D10) + return TIMER1B;//, /* 10 */ -> 4 + return NOT_ON_TIMER; +// +// switch (static_cast(pin)) { +//#if defined(__AVR_ATmega8__) +// case PinType::D11: +// return TIMER2;//, /* 11 */ -> 6 +//#else +// case PinType::D03:// /* 3 */ -> 8 +// return TIMER2B; +// case PinType::D05: +// return TIMER0B;//, /* 5 */ -> 2 +// case PinType::D06: +// return TIMER0A;//, /* 6 */ -> 1 +// case PinType::D11: +// return TIMER2A;//, /* 11 */ -> 7 +//#endif +// case PinType::D09: +// return TIMER1A;//, /* 9 */ -> 3 +// case PinType::D10: +// return TIMER1B;//, /* 10 */ -> 4 +// default: +// return NOT_ON_TIMER; +// } +} +void testThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap() { + for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_timer_PGM); ++pin) + ASSERT_EQUAL((int)digital_pin_to_timer_PGM[pin],(int)digital_pin_to_timer_PS(pin)); +} +#undef __AVR_ATmega8__ } namespace mega{ +enum PortType: uint8_t { + No_Port=0, PA=1, PB=2, PC=3, PD=4, PE=5, PF=6, PG=7, PH=8, PI_NOTDEFINED=9, PJ=10, PK=11, PL=12 +}; +inline constexpr PortType operator++(PortType &in) { + return in=static_cast(static_cast(in)+1); +} +#define NO_PORT PortType::No_Port +constexpr inline +volatile uint8_t *port_to_mode_PS(PortType port) noexcept { + + if (port >= PortType::PA && port < PortType::PH) { // ports A to G DDR map to 0x21-0x33 +every 3 bits + return reinterpret_cast((port-PortType::PA)*3 + 1 + 0x20); + } else if (port == PortType::PH) { + return reinterpret_cast((port-PortType::PH)*3 + 1 + 0x100);//(*(volatile uint8_t *)(0x101)); + } else if (port >= PortType::PJ && port <= PortType::PL) { + return reinterpret_cast((port-PortType::PJ)*3 + 1 + 0x103);//(*(volatile uint8_t *)(0x104)); + } + return NOT_A_PORT; // nullptr +} +volatile uint8_t * getDDRPortAddress(PortType port){ +switch(port){ +case PortType::PA: return &(*(volatile uint8_t *)((0X01) + 0x20)); +case PortType::PB: return &(*(volatile uint8_t *)((0x04) + 0x20)); +case PortType::PC: return &(*(volatile uint8_t *)((0x07) + 0x20)); +case PortType::PD: return &(*(volatile uint8_t *)((0x0A) + 0x20)); +case PortType::PE: return &(*(volatile uint8_t *)((0x0D) + 0x20)); +case PortType::PF: return &(*(volatile uint8_t *)((0x10) + 0x20)); +case PortType::PG: return &(*(volatile uint8_t *)((0x13) + 0x20)); +case PortType::PH: return &(*(volatile uint8_t *)(0x101)); +case PortType::PJ: return &(*(volatile uint8_t *)(0x104)); +case PortType::PK: return &(*(volatile uint8_t *)(0x107)); +case PortType::PL: return &(*(volatile uint8_t *)(0x10A)); +default: return NOT_A_PORT; // nullptr +} +} + +void testThatComputedModeIsSameAsSwitchImplementation() { + for (PortType port=No_Port; port <= PortType::PL; ++port){ + std::string msg{"port no: "}; + msg += std::to_string(int(port)); + ASSERT_EQUALM(msg,reinterpret_cast(getDDRPortAddress(port)),reinterpret_cast(port_to_mode_PS(port))); + + } +} + +constexpr inline +volatile uint8_t *port_to_output_switch(PortType port) noexcept { + switch(port){ + case PortType::PA: return &(*(volatile uint8_t *)((0X02) + 0x20)); + case PortType::PB: return &(*(volatile uint8_t *)((0x05) + 0x20)); + case PortType::PC: return &(*(volatile uint8_t *)((0x08) + 0x20)); + case PortType::PD: return &(*(volatile uint8_t *)((0x0B) + 0x20)); + case PortType::PE: return &(*(volatile uint8_t *)((0x0E) + 0x20)); + case PortType::PF: return &(*(volatile uint8_t *)((0x11) + 0x20)); + case PortType::PG: return &(*(volatile uint8_t *)((0x14) + 0x20)); + case PortType::PH: return &(*(volatile uint8_t *)(0x102)); + case PortType::PJ: return &(*(volatile uint8_t *)(0x105)); + case PortType::PK: return &(*(volatile uint8_t *)(0x108)); + case PortType::PL: return &(*(volatile uint8_t *)(0x10B)); + default: return NOT_A_PORT; // nullptr + } +} +constexpr inline +volatile uint8_t *port_to_output_PS(PortType port) noexcept { + + if (port >= PortType::PA && port < PortType::PH) { // ports A to G DDR map to 0x21-0x33 +every 3 bits + return reinterpret_cast((port-PortType::PA)*3 + 2 + 0x20); + } else if (port == PortType::PH) { + return reinterpret_cast((port-PortType::PH)*3 + 2 + 0x100);//(*(volatile uint8_t *)(0x101)); + } else if (port >= PortType::PJ && port <= PortType::PL) { + return reinterpret_cast((port-PortType::PJ)*3 + 2 + 0x103);//(*(volatile uint8_t *)(0x104)); + } + return NOT_A_PORT; // nullptr +} + +void testThatComputedPortIsSameAsSwitchImplementation() { + for (PortType port=No_Port; port <= PortType::PL; ++port){ + std::string msg{"port no: "}; + msg += std::to_string(int(port)); + ASSERT_EQUALM(msg,reinterpret_cast(port_to_output_switch(port)),reinterpret_cast(port_to_output_PS(port))); + + } +} +constexpr inline +volatile uint8_t *port_to_input_PS(PortType port) noexcept { + if (port >= PortType::PA && port < PortType::PH) { // ports A to G DDR map to 0x21-0x33 +every 3 bits + return reinterpret_cast((port-PortType::PA)*3 + 0x20); + } else if (port == PortType::PH) { + return reinterpret_cast((port-PortType::PH)*3 + 0x100);//(*(volatile uint8_t *)(0x101)); + } else if (port >= PortType::PJ && port <= PortType::PL) { + return reinterpret_cast((port-PortType::PJ)*3 + 0x103);//(*(volatile uint8_t *)(0x104)); + } + return NOT_A_PORT; // nullptr +} +constexpr inline +volatile uint8_t *port_to_input_switch(PortType port) noexcept { + switch(port){ + case PortType::PA: return &(*(volatile uint8_t *)((0X00) + 0x20)); + case PortType::PB: return &(*(volatile uint8_t *)((0X03) + 0x20)); + case PortType::PC: return &(*(volatile uint8_t *)((0x06) + 0x20)); + case PortType::PD: return &(*(volatile uint8_t *)((0x09) + 0x20)); + case PortType::PE: return &(*(volatile uint8_t *)((0x0C) + 0x20)); + case PortType::PF: return &(*(volatile uint8_t *)((0x0F) + 0x20)); + case PortType::PG: return &(*(volatile uint8_t *)((0x12) + 0x20)); + case PortType::PH: return &(*(volatile uint8_t *)(0x100)); + case PortType::PJ: return &(*(volatile uint8_t *)(0x103)); + case PortType::PK: return &(*(volatile uint8_t *)(0x106)); + case PortType::PL: return &(*(volatile uint8_t *)(0x109)); + default: return NOT_A_PORT; // nullptr + } +} + +void testThatComputedPinIsSameAsSwitchImplementation() { + for (PortType port=No_Port; port <= PortType::PL; ++port){ + std::string msg{"port no: "}; + msg += std::to_string(int(port)); + ASSERT_EQUALM(msg,reinterpret_cast(port_to_input_switch(port)),reinterpret_cast(port_to_input_PS(port))); + + } +} + const uint8_t PROGMEM digital_pin_to_port_PGM[] = { // PORTLIST @@ -353,48 +745,83 @@ enum PinType:uint8_t { // A0=D54, A1=D55, A2=D56, A3=D57, A4=D58, A5=D59, // A6=D60, A7=D61, A8=D62, A9=D63, A10=D64, A11=D65, // A12=D66, A13=D67, A14=D68, A15=D69 +}; // Ax removed only for tests. + + +// unnecessary complex attempt at only using 8bit operations just bloating the code :-( +template +constexpr inline bool isInByte(uint8_t pin){ + constexpr uint8_t bitstart = thebyte * 8; + + return (pin >=bitstart) && (pin < (bitstart +8)); +} + +template +constexpr inline uint8_t bytebitmask(){ + constexpr uint8_t bitstart = thebyte * 8; + return ( (static_cast(isInByte(pins) << ((pins-bitstart) * isInByte(pins))))|...); +} + +static_assert(0b1010 == bytebitmask<0,D01,D03,D08,D16,D32,D24>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<1,D00,D04,D09,D11,D16,D32,D24>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<2,D00,D04,D08,D11,D17,D19,D32,D25,D27>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<3,D00,D04,D08,D11,D16,D19,D32,D25,D27>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<4,D00,D04,D08,D11,D16,D19,D33,D35,D24>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<5,D00,D04,D08,D11,D16,D19,D32,D24,D41,D43,D65>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<6,D00,D04,D08,D11,D16,D19,D32,D24,D40,D49,D51,D65>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<7,D00,D04,D08,D11,D16,D19,D32,D24,D40,D48,D57,D59,D65>(),"check if logic workds"); +static_assert(0b1010 == bytebitmask<8,D00,D04,D08,D11,D16,D19,D32,D24,D41,D43,D63,D65,D67>(),"check if logic workds"); + +template +constexpr inline bool isOneOfPinsInByte(uint8_t pin) noexcept { + constexpr uint8_t bitstart = thebyte * 8; + + return isInByte(pin)&& ((1ul << pin-bitstart ) & bytebitmask()); +} + +static_assert(isOneOfPinsInByte<0,D01,D03,D08,D16,D32,D24>(D03),"works for D01"); +static_assert(isOneOfPinsInByte<0,D03,D00,D08,D16,D32,D24>(D00),"works for D00"); + + +template +struct isPinInBytesHelper { + template + static constexpr inline bool isOneOfPins(uint8_t pin) noexcept { + return ((isOneOfPinsInByte(pin)||...)); + } + }; -#undef PA -#undef PB -#undef PC -#undef PD -#undef PE -#undef PF -#undef PG -#undef PH -#undef PJ -#undef PK -#undef PL -enum class PortType: uint8_t { - No_Port=0, PA=1, PB=2, PC=3, PD=4, PE=5, PF=6, PG=7, PH=8, PJ=10, PK=11, PL=12 -}; -#define NO_PORT PortType::No_Port -constexpr inline PortType digital_pin_to_Port_PS(uint8_t pin) noexcept { - switch(static_cast(pin)){ - case D22: case D23: case D24: case D25: case D26: case D27: case D28: case D29: +template +constexpr inline bool isOneOfPins(uint8_t pin) noexcept { + return ((pin == pins)||...); // simplest fold expression, let the compiler optimize it + + //return isPinInBytesHelper<0,1,2,3,4,5,6,7,8,9>::isOneOfPins(pin); // maximum of 72 pins on Mega +} + +constexpr inline PortType digital_pin_to_Port_PS(uint8_t const pin) noexcept { + if (pin >= D22 && pin <= D29) return PortType::PA; - case D10: case D11: case D12: case D13: case D50: case D51: case D52: case D53: + if ((pin >= D10 && pin <= D13) || (pin >= D50 && pin <= D53)) return PortType::PB; - case D30: case D31: case D32: case D33: case D34: case D35: case D36: case D37: + if (pin >= D30 && pin <= D37) return PortType::PC; - case D18: case D19: case D20: case D21: case D38: + if ((pin >= D18 && pin <= D21) || pin == D38) return PortType::PD; - case D00: case D01: case D02: case D03: case D05: + if (isOneOfPins(pin)) return PortType::PE; - case D54: case D55: case D56: case D57: case D58: case D59: case D60: case D61: + if (pin >= D54 && pin <= D61) return PortType::PF; - case D04: case D39: case D40: case D41: + if (pin == D04 || (pin >= D39 && pin <= D41)) return PortType::PG; - case D06: case D07: case D08: case D09: case D16: case D17: + if (isOneOfPins(pin)) return PortType::PH; - case D14: case D15: + if (pin == D14 || pin == D15) return PortType::PJ; - case D62: case D63: case D64: case D65: case D66: case D67: case D68: case D69: + if (pin >= D62 && pin <= D69) return PortType::PK; - case D42: case D43: case D44: case D45: case D46: case D47: case D48: case D49: + if (pin >= D42 && pin <= D49) return PortType::PL; - } return NO_PORT; } @@ -485,34 +912,34 @@ enum bitmask_in_byte:uint8_t { b0=1,b1=2,b2=4,b3=8,b4=16,b5=32,b6=64,b7=128 }; static constexpr inline uint8_t digital_pin_to_BitMask_PS(uint8_t const pin) noexcept { - switch (static_cast(pin)) { - case D00: case D15: case D17: case D21: case D22: case D37: case D41: case D49: case D53: case D54: case D62: - return bitmask_in_byte::b0; - case D01: case D14: case D16: case D20: case D23: case D36: case D40: case D48: case D52: case D55: case D63: - return bitmask_in_byte::b1; - - case D19: case D24: case D35: case D39: case D47: case D51: case D56: case D64: - return bitmask_in_byte::b2; - - case D05: case D06: case D18: case D25: case D34: case D46: case D50: case D57: case D65: - return bitmask_in_byte::b3; - - case D02: case D07: case D10: case D26: case D33: case D45: case D58: case D66: - return bitmask_in_byte::b4; - case D03: case D04: case D08: case D11: case D27: case D32: case D44: case D59: case D67: - return bitmask_in_byte::b5; - case D09: case D12: case D28: case D31: case D43: case D60: case D68: - return bitmask_in_byte::b6; - case D13: case D29: case D30: case D38: case D42: case D61: case D69: - return bitmask_in_byte::b7; - } + if( isOneOfPins(pin)) + return bitmask_in_byte::b0; + if( isOneOfPins(pin)) + return bitmask_in_byte::b1; + if( isOneOfPins(pin)) + return bitmask_in_byte::b2; + if( isOneOfPins(pin)) + return bitmask_in_byte::b3; + if( isOneOfPins(pin)) + return bitmask_in_byte::b4; + if( isOneOfPins(pin)) + return bitmask_in_byte::b5; + if( isOneOfPins(pin)) + return bitmask_in_byte::b6; + if( isOneOfPins(pin)) + return bitmask_in_byte::b7; return 0; // 0 might break code, may be, but would be better indicator. + } }; void testThatdigitalPinToBitmaskProducesIdenticalResultsThatAreInTheMap() { - for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_bit_mask_PGM); ++pin) - ASSERT_EQUAL((int)digital_pin_to_bit_mask_PGM[pin],(int)bitmask::digital_pin_to_BitMask_PS(pin)); + for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_bit_mask_PGM); ++pin){ + std::string msg{"pin is: "}; + msg += std::to_string(pin); + + ASSERT_EQUALM(msg,(int)digital_pin_to_bit_mask_PGM[pin],(int)bitmask::digital_pin_to_BitMask_PS(pin)); +} } const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { // TIMERS @@ -590,40 +1017,88 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { }; constexpr inline uint8_t digital_pin_to_timer_PS(uint8_t const pin) noexcept { - switch (static_cast(pin)) { - case D02: - return TIMER3B; - case D03: - return TIMER3C; - case D04: - return TIMER0B; - case D05: - return TIMER3A; - case D06: - return TIMER4A; - case D07: - return TIMER4B; - case D08: - return TIMER4C; - case D09: - return TIMER2B; - case D10: - return TIMER2A; - case D11: - return TIMER1A; - case D12: - return TIMER1B; - case D13: - return TIMER0A; - case D44: - return TIMER5C; - case D45: - return TIMER5B; - case D46: - return TIMER5A; - default: - return NOT_ON_TIMER; + using PT=PinType; + constexpr uint8_t timermap[] { + /* PT::D02 */ TIMER3B, + /* PT::D03 */ TIMER3C, + /* PT::D04 */ TIMER0B, + /* PT::D05 */ TIMER3A, + /* PT::D06 */ TIMER4A, + /* PT::D07 */ TIMER4B, + /* PT::D08 */ TIMER4C, + /* PT::D09 */ TIMER2B, + /* PT::D10 */ TIMER2A, + /* PT::D11 */ TIMER1A, + /* PT::D12 */ TIMER1B, + /* PT::D13 */ TIMER0A, + /* PT::D44 */ TIMER5C, + /* PT::D45 */ TIMER5B, + /* PT::D46 */ TIMER5A + }; + if (pin>=PT::D02 && pin <= PT::D13){ + return timermap[pin-PT::D02]; + } else if (pin >=PT::D44 && pin <= PT::D46){ + return timermap[pin-PT::D44 + 12]; } +// struct maptimer { +// PinType pin; +// uint8_t timer; +// }; +// constexpr maptimer timermap[] { +// { PT::D02, TIMER3B}, +// { PT::D03, TIMER3C}, +// { PT::D04, TIMER0B}, +// { PT::D05, TIMER3A}, +// { PT::D06, TIMER4A}, +// { PT::D07, TIMER4B}, +// { PT::D08, TIMER4C}, +// { PT::D09, TIMER2B}, +// { PT::D10, TIMER2A}, +// { PT::D11, TIMER1A}, +// { PT::D12, TIMER1B}, +// { PT::D13, TIMER0A}, +// { PT::D44, TIMER5C}, +// { PT::D45, TIMER5B}, +// { PT::D46, TIMER5A} +// }; +// constexpr uint8_t numberoftimers=sizeof(timermap)/sizeof(timermap[0]); +// for (uint8_t i=0; i < numberoftimers;++i) +// if (timermap[i].pin == pin) return timermap[i].timer; + return NOT_ON_TIMER; +// switch (static_cast(pin)) { +// case D02: +// return TIMER3B; +// case D03: +// return TIMER3C; +// case D04: +// return TIMER0B; +// case D05: +// return TIMER3A; +// case D06: +// return TIMER4A; +// case D07: +// return TIMER4B; +// case D08: +// return TIMER4C; +// case D09: +// return TIMER2B; +// case D10: +// return TIMER2A; +// case D11: +// return TIMER1A; +// case D12: +// return TIMER1B; +// case D13: +// return TIMER0A; +// case D44: +// return TIMER5C; +// case D45: +// return TIMER5B; +// case D46: +// return TIMER5A; +// default: +// return NOT_ON_TIMER; +// } } void testThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap() { for (uint8_t pin=0; pin < array_count_elements(digital_pin_to_timer_PGM); ++pin) @@ -643,6 +1118,11 @@ bool runAllTests(int argc, char const *argv[]) { s.push_back(CUTE(mega::testThatdigitalPinToPortProducesIdenticalResultsThatAreInTheMap)); s.push_back(CUTE(mega::testThatdigitalPinToBitmaskProducesIdenticalResultsThatAreInTheMap)); s.push_back(CUTE(mega::testThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap)); + s.push_back(CUTE(uno::testThatdigitalPinToBitmaskProducesIdenticalResultsThatAreInTheMap)); + s.push_back(CUTE(mega::testThatComputedModeIsSameAsSwitchImplementation)); + s.push_back(CUTE(mega::testThatComputedPortIsSameAsSwitchImplementation)); + s.push_back(CUTE(mega::testThatComputedPinIsSameAsSwitchImplementation)); + s.push_back(CUTE(standardMega8::testThatdigitalPinToTimerProducesIdenticalResultsThatAreInTheMap)); cute::xml_file_opener xmlfile(argc, argv); cute::xml_listener> lis(xmlfile.out); auto runner = cute::makeRunner(lis, argc, argv); diff --git a/wsAVR/testAVRmicropinmapping/testAVRmicropinmapping.xml b/wsAVR/testAVRmicropinmapping/testAVRmicropinmapping.xml index b872de6..41ddac7 100644 --- a/wsAVR/testAVRmicropinmapping/testAVRmicropinmapping.xml +++ b/wsAVR/testAVRmicropinmapping/testAVRmicropinmapping.xml @@ -1,5 +1,5 @@ - + @@ -7,5 +7,10 @@ + + + + +