diff --git a/1D_pongESP32/1D_pongESP32.ino b/1D_pongESP32/1D_pongESP32.ino index b23c168..faf74a3 100644 --- a/1D_pongESP32/1D_pongESP32.ino +++ b/1D_pongESP32/1D_pongESP32.ino @@ -15,76 +15,62 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * Adapted by Robert Köpferl 2022 to be used on ESP32 - + * no optimisation towards atmel + * */ -#include "Adafruit_NeoPixel.h" + +#include #include "notes.h" #include "pin-names.h" -//DIO -#define GPIO23 23 -#define GPIO22 22 -#define GPIO18 18 // SPI CLK -#define GPIO19 19 -#define GPIO21 21 +#define NELEM(x) (sizeof(x) / sizeof((x)[0])) -//ADIO -#define GPIO25 25 -#define GPIO26 26 -#define GPIO27 27 -#define GPIO32 32 -#define GPIO33 33 -#define GPIO34 34 -#define GPIO35 35 -#define GPIO36 36 -#define GPIO39 39 +#define PIN_WSDATA GPIO21 // LED data +#define PIN_BUT_RS GPIO35 // Right start/hit button +#define PIN_BUT_RP GPIO33 // Right power-up button +#define PIN_BUT_LS GPIO19 // Left start/hit button +#define PIN_BUT_LP GPIO18 // Left power-up button +#define PIN_SOUND GPIO32 // Buzzer output (PB1/OC1A) +#define NPIXELS 60 // Number of pixels to handle - -#define NELEM(x) (sizeof(x) / sizeof((x)[0])) - -#define PIN_WSDATA GPIO21 // LED data -#define PIN_BUT_RS GPIO35 // Right start/hit button -#define PIN_BUT_RP GPIO33 // Right power-up button -#define PIN_BUT_LS GPIO19 // Left start/hit button -#define PIN_BUT_LP GPIO18 // Left power-up button -#define PIN_SOUND GPIO32 // Buzzer output (PB1/OC1A) - -#define NPIXELS 60 // Number of pixels to handle - -#define ZONE_SIZE 7 // Bounce-back zone size -#define SHOW_LO 12 // Score dots intensity background -#define SHOW_HI 48 // Score dots intensity foreground -#define WIN_POINTS 10 // Points needed to win -#define TONE_INTERVAL 5 // Not every ball move should give a sound +#define ZONE_SIZE 7 // Bounce-back zone size +#define SHOW_LO 12 // Score dots intensity background +#define SHOW_HI 48 // Score dots intensity foreground +#define WIN_POINTS 10 // Points needed to win +#define TONE_INTERVAL 5 // Not every ball move should give a sound Adafruit_NeoPixel one_d = Adafruit_NeoPixel(NPIXELS, PIN_WSDATA, NEO_GRB | NEO_KHZ800); // Events from buttons and timers -#define EV_BUT_LS_PRESS 0x01 -#define EV_BUT_RS_PRESS 0x02 -#define EV_BUT_LP_PRESS 0x04 -#define EV_BUT_RP_PRESS 0x08 -#define EV_TIMER 0x10 -#define EV_TIMEOUT 0x20 -#define EV_TONETIMER 0x40 +#define EV_BUT_LS_PRESS 0x01 +#define EV_BUT_RS_PRESS 0x02 +#define EV_BUT_LP_PRESS 0x04 +#define EV_BUT_RP_PRESS 0x08 +#define EV_TIMER 0x10 +#define EV_TIMEOUT 0x20 +#define EV_TONETIMER 0x40 -#define TIME_DEBOUNCE 8 -#define TIME_IDLE 40 -#define TIME_START_TIMEOUT 20000 // Go idle if nothing happens -#define TIME_RESUME_TIMEOUT 7500 // Auto-fire after timeout -#define TIME_BALL_BLINK 150 -#define TIME_SPEED_MIN 10 -#define TIME_SPEED_INTERVAL 3 -#define TIME_POINT_BLINK 233 -#define TIME_WIN_BLINK 85 -#define TIME_LOCKOUT 250 // Prevent fast button-press to max. 4 times/s +#define TIME_DEBOUNCE 8 +#define TIME_IDLE 40 +#define TIME_START_TIMEOUT 20000 // Go idle if nothing happens +#define TIME_RESUME_TIMEOUT 7500 // Auto-fire after timeout +#define TIME_BALL_BLINK 150 +#define TIME_SPEED_MIN 10 +#define TIME_SPEED_INTERVAL 3 +#define TIME_POINT_BLINK 233 +#define TIME_WIN_BLINK 85 +#define TIME_LOCKOUT 250 // Prevent fast button-press to max. 4 times/s -#define TIME_TONE_SERVE 50 // Sound durations -#define TIME_TONE_BOUNCE 50 -#define TIME_TONE_MOVE 25 -#define TIME_TONE_SCORE 50 +#define TIME_TONE_SERVE 50 // Sound durations +#define TIME_TONE_BOUNCE 50 +#define TIME_TONE_MOVE 25 +#define TIME_TONE_SCORE 50 -enum { +enum +{ ST_IDLE = 0, ST_START_L, ST_START_R, @@ -100,79 +86,135 @@ enum { ST_WIN_R, }; -static uint32_t oldtime; // Previous' loop millis() value -static uint8_t thestate; // Game state +static uint32_t oldtime; // Previous' loop millis() value +static uint8_t thestate; // Game state -static uint8_t bstate_ls; // Button states +static uint8_t bstate_ls; // Button states static uint8_t bstate_rs; static uint8_t bstate_lp; static uint8_t bstate_rp; -static uint8_t debtmr_ls; // Button debounce timers +static uint8_t debtmr_ls; // Button debounce timers static uint8_t debtmr_rs; static uint8_t debtmr_lp; static uint8_t debtmr_rp; -static uint16_t timer; // General timer -static uint16_t timeout; // Timeout timer (auto-start and goto idle) -static uint16_t tonetimer; // Tone duration timer -static uint16_t lockout_l; // Lockout timer to prevent pushing too often +static uint16_t timer; // General timer +static uint16_t timeout; // Timeout timer (auto-start and goto idle) +static uint16_t tonetimer; // Tone duration timer +static uint16_t lockout_l; // Lockout timer to prevent pushing too often static uint16_t lockout_r; static uint8_t ballblinkstate; // Blinking ball at edge on/off -static uint8_t pointblinkcount; // Blinking point when a side scores -static uint8_t ballpos; // Current position of the ball -static uint16_t speed; // Time between ball moves -static uint8_t speedup; // Faster and faster replies counter -static uint8_t points_l; // Score +static uint8_t pointblinkcount; // Blinking point when a side scores +static uint8_t ballpos; // Current position of the ball +static uint16_t speed; // Time between ball moves +static uint8_t speedup; // Faster and faster replies counter +static uint8_t points_l; // Score static uint8_t points_r; -static uint8_t zone_l; // Hit back zone +static uint8_t zone_l; // Hit back zone static uint8_t zone_r; -static uint8_t boost_l; // Set if user boosted speed last round +static uint8_t boost_l; // Set if user boosted speed last round static uint8_t boost_r; -static uint8_t boosted; // Set if any user boosted until the ball reaches opposite side -static uint8_t tonecount; // Interval counter for sound during move -static uint8_t tuneidx; // Index to the running tune +static uint8_t boosted; // Set if any user boosted until the ball reaches opposite side +static uint8_t tonecount; // Interval counter for sound during move +static uint8_t tuneidx; // Index to the running tune -struct tnote { - uint8_t note; - uint16_t duration; +struct tnote +{ + uint8_t note; + uint16_t duration; }; /* Tone pitch table for 16MHz crystal */ static const uint16_t tone_pitch[NTONE_PITCH] PROGMEM = { - 61155, 57722, 54482, 51424, 48538, 45814, 43242, 40815, 38524, 36362 /* == 220Hz */, 34321, 32395, - 30577, 28860, 27240, 25711, 24268, 22906, 21620, 20407, 19261, 18180 /* == 440Hz */, 17160, 16197, - 15288, 14429, 13619, 12855, 12133, 11452, 10809, 10203, 9630, 9089 /* == 880Hz */, 8579, 8098, - 7643, 7214, 6809, 6427, 6066, 5725, 5404, 5101, 4814, 4544, 4289, 4048, - 3821, 3606, 3404, 3213, 3032, 2862, 2701, 2550, 2406, 2271, 2144, 2023, - 1910, + 61155, + 57722, + 54482, + 51424, + 48538, + 45814, + 43242, + 40815, + 38524, + 36362 /* == 220Hz */, + 34321, + 32395, + 30577, + 28860, + 27240, + 25711, + 24268, + 22906, + 21620, + 20407, + 19261, + 18180 /* == 440Hz */, + 17160, + 16197, + 15288, + 14429, + 13619, + 12855, + 12133, + 11452, + 10809, + 10203, + 9630, + 9089 /* == 880Hz */, + 8579, + 8098, + 7643, + 7214, + 6809, + 6427, + 6066, + 5725, + 5404, + 5101, + 4814, + 4544, + 4289, + 4048, + 3821, + 3606, + 3404, + 3213, + 3032, + 2862, + 2701, + 2550, + 2406, + 2271, + 2144, + 2023, + 1910, }; static const tnote tune_win[] PROGMEM = { - { NOTE_Gs6, DUR_1_16 }, - { NOTE_A6, DUR_1_16 }, - { NOTE_Gs6, DUR_1_16 }, - { NOTE_E6, DUR_1_16 }, - { NOTE_Gs6, DUR_1_16 }, - { NOTE_A6, DUR_1_16 }, - { NOTE_Gs6, DUR_1_16 }, - { NOTE_E6, DUR_1_16 }, - { 0, DUR_1_8 }, - { NOTE_D4, DUR_1_8 }, - { NOTE_D4, DUR_1_8 }, - { NOTE_B3, DUR_1_8 }, - { NOTE_E4, DUR_1_8 }, - { NOTE_D4, DUR_1_4 }, - { NOTE_B3, DUR_1_4 }, - { NOTE_D4, DUR_1_8 }, - { NOTE_D4, DUR_1_8 }, - { NOTE_B3, DUR_1_8 }, - { NOTE_E4, DUR_1_8 }, - { NOTE_D4, DUR_1_4 }, - { NOTE_B3, DUR_1_4 }, + {NOTE_Gs6, DUR_1_16}, + {NOTE_A6, DUR_1_16}, + {NOTE_Gs6, DUR_1_16}, + {NOTE_E6, DUR_1_16}, + {NOTE_Gs6, DUR_1_16}, + {NOTE_A6, DUR_1_16}, + {NOTE_Gs6, DUR_1_16}, + {NOTE_E6, DUR_1_16}, + {0, DUR_1_8}, + {NOTE_D4, DUR_1_8}, + {NOTE_D4, DUR_1_8}, + {NOTE_B3, DUR_1_8}, + {NOTE_E4, DUR_1_8}, + {NOTE_D4, DUR_1_4}, + {NOTE_B3, DUR_1_4}, + {NOTE_D4, DUR_1_8}, + {NOTE_D4, DUR_1_8}, + {NOTE_B3, DUR_1_8}, + {NOTE_E4, DUR_1_8}, + {NOTE_D4, DUR_1_4}, + {NOTE_B3, DUR_1_4}, }; -//#define sound_off() do { TCCR1A = _BV(COM1A1); /* Set clear output */ } while(0) +// #define sound_off() do { TCCR1A = _BV(COM1A1); /* Set clear output */ } while(0) void sound_off() { - // nix tun - muss erfinden + // nix tun - muss erfinden } /* @@ -181,11 +223,16 @@ void sound_off() */ static inline uint8_t button_is_down(uint8_t pin) { - switch(pin) { - case PIN_BUT_LS: return !debtmr_ls && !bstate_ls; - case PIN_BUT_RS: return !debtmr_rs && !bstate_rs; - case PIN_BUT_LP: return !debtmr_lp && !bstate_lp; - case PIN_BUT_RP: return !debtmr_rp && !bstate_rp; + switch (pin) + { + case PIN_BUT_LS: + return !debtmr_ls && !bstate_ls; + case PIN_BUT_RS: + return !debtmr_rs && !bstate_rs; + case PIN_BUT_LP: + return !debtmr_lp && !bstate_lp; + case PIN_BUT_RP: + return !debtmr_rp && !bstate_rp; } return 0; } @@ -199,17 +246,21 @@ static inline uint8_t button_is_down(uint8_t pin) */ static inline uint8_t do_debounce(uint8_t tdiff, uint8_t *bstate, uint8_t *debtmr, uint8_t pin, uint8_t ev) { - if(0 == *debtmr) { + if (0 == *debtmr) + { uint8_t state = digitalRead(pin); - if(state != *bstate) { + if (state != *bstate) + { *debtmr = TIME_DEBOUNCE; - if(!(*bstate = state)) - return ev; // Event on High-to-Low transition of input - // else - // return release_event_value + if (!(*bstate = state)) + return ev; // Event on High-to-Low transition of input + // else + // return release_event_value } - } else { - if(*debtmr >= tdiff) + } + else + { + if (*debtmr >= tdiff) *debtmr -= tdiff; else *debtmr = 0; @@ -222,13 +273,14 @@ static inline uint8_t do_debounce(uint8_t tdiff, uint8_t *bstate, uint8_t *debtm */ static inline uint8_t do_timer(uint8_t tdiff, uint16_t *tmr, uint8_t ev) { - if(0 != *tmr) { - if(*tmr >= tdiff) - *tmr -= tdiff; // Timer countdown + if (0 != *tmr) + { + if (*tmr >= tdiff) + *tmr -= tdiff; // Timer countdown else *tmr = 0; // Set event when done counting - if(0 == *tmr) + if (0 == *tmr) return ev; } return 0; @@ -240,12 +292,13 @@ static inline uint8_t do_timer(uint8_t tdiff, uint16_t *tmr, uint8_t ev) static inline void set_tone(uint16_t note, uint16_t duration) { tonetimer = duration; - if(note && note <= NTONE_PITCH) + if (note && note <= NTONE_PITCH) { - //OCR1A = pgm_read_word(&tone_pitch[note-1]); - //TCCR1A = _BV(COM1A0); /* Set toggle output */ - //TCNT1 = 0; - } else + // OCR1A = pgm_read_word(&tone_pitch[note-1]); + // TCCR1A = _BV(COM1A0); /* Set toggle output */ + // TCNT1 = 0; + } + else sound_off(); } @@ -254,12 +307,14 @@ static inline void set_tone(uint16_t note, uint16_t duration) */ static inline void tune_next() { - if(tuneidx < NELEM(tune_win)) { + if (tuneidx < NELEM(tune_win)) + { uint16_t n = pgm_read_byte(&tune_win[tuneidx].note); uint16_t d = pgm_read_word(&tune_win[tuneidx].duration); set_tone(n, d); tuneidx++; - } else + } + else set_tone(0, 0); } @@ -268,14 +323,16 @@ static inline void tune_next() */ static void draw_sides() { - for(uint8_t i = 0; i < zone_l-1; i++) { + for (uint8_t i = 0; i < zone_l - 1; i++) + { one_d.setPixelColor(i, 0, 64, 64); } one_d.setPixelColor(0, 0, 64, 64); - for(uint8_t i = 0; i < zone_r-1; i++) { - one_d.setPixelColor(NPIXELS-1-i, 0, 64, 64); + for (uint8_t i = 0; i < zone_r - 1; i++) + { + one_d.setPixelColor(NPIXELS - 1 - i, 0, 64, 64); } - one_d.setPixelColor(NPIXELS-1, 0, 64, 64); + one_d.setPixelColor(NPIXELS - 1, 0, 64, 64); } /* @@ -284,7 +341,8 @@ static void draw_sides() static void draw_ball(int8_t dir, uint8_t pos) { uint8_t c = 255; - for(uint8_t i = 0; i < 5 && pos >= 0 && pos < NPIXELS; i++) { + for (uint8_t i = 0; i < 5 && pos >= 0 && pos < NPIXELS; i++) + { one_d.setPixelColor(pos, c, c, 0); c >>= 1; pos -= dir; @@ -298,14 +356,17 @@ static void draw_course(uint8_t v) { one_d.clear(); draw_sides(); - if(v) { - for(uint8_t i = 0; i < points_l; i++) { - one_d.setPixelColor(NPIXELS/2-1-(2*i+0), v, 0, 0); - one_d.setPixelColor(NPIXELS/2-1-(2*i+1), v, 0, 0); + if (v) + { + for (uint8_t i = 0; i < points_l; i++) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * i + 0), v, 0, 0); + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * i + 1), v, 0, 0); } - for(uint8_t i = 0; i < points_r; i++) { - one_d.setPixelColor(NPIXELS/2+(2*i+0), 0, v, 0); - one_d.setPixelColor(NPIXELS/2+(2*i+1), 0, v, 0); + for (uint8_t i = 0; i < points_r; i++) + { + one_d.setPixelColor(NPIXELS / 2 + (2 * i + 0), 0, v, 0); + one_d.setPixelColor(NPIXELS / 2 + (2 * i + 1), 0, v, 0); } } } @@ -326,24 +387,27 @@ static void animate_idle_init(void) ai_state = 0; } -#define H_STEPS 1542 +#define H_STEPS 1542 static void animate_idle(void) { - switch(ai_state) { + switch (ai_state) + { case 0: case 1: case 2: case 3: /* Rainbow pattern */ - for(uint8_t i = 0; i < NPIXELS; i++) { + for (uint8_t i = 0; i < NPIXELS; i++) + { uint16_t h = ai_h + (i << 4); - if(h >= H_STEPS) + if (h >= H_STEPS) h -= H_STEPS; //*one_d.setPixelColorHsv(i, h, 255, 128); } - ai_h += H_STEPS/60; - if(ai_h >= H_STEPS) { + ai_h += H_STEPS / 60; + if (ai_h >= H_STEPS) + { ai_h -= H_STEPS; ai_pos = 0; ai_state++; @@ -354,7 +418,8 @@ static void animate_idle(void) /* Ball left-to-right */ draw_course(0); draw_ball(1, ai_pos++); - if(ai_pos >= NPIXELS) { + if (ai_pos >= NPIXELS) + { ai_state++; } break; @@ -363,7 +428,8 @@ static void animate_idle(void) /* Ball right-to-left */ draw_course(0); draw_ball(-1, --ai_pos); - if(!ai_pos) { + if (!ai_pos) + { ai_state++; } break; @@ -371,11 +437,13 @@ static void animate_idle(void) case 10: /* Score blinkenlights */ draw_course(0); - for(uint8_t i = 0; i < ai_pos; i++) { - one_d.setPixelColor(NPIXELS/2-1-i, 255, 0, 0); - one_d.setPixelColor(NPIXELS/2+i, 0, 255, 0); + for (uint8_t i = 0; i < ai_pos; i++) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - i, 255, 0, 0); + one_d.setPixelColor(NPIXELS / 2 + i, 0, 255, 0); } - if(++ai_pos >= NPIXELS/2) { + if (++ai_pos >= NPIXELS / 2) + { ai_state++; ai_pos = 0; } @@ -384,11 +452,13 @@ static void animate_idle(void) case 9: case 11: draw_course(0); - for(uint8_t i = 0; i < NPIXELS/2-ai_pos; i++) { - one_d.setPixelColor(NPIXELS/2-1-i, 255, 0, 0); - one_d.setPixelColor(NPIXELS/2+i, 0, 255, 0); + for (uint8_t i = 0; i < NPIXELS / 2 - ai_pos; i++) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - i, 255, 0, 0); + one_d.setPixelColor(NPIXELS / 2 + i, 0, 255, 0); } - if(++ai_pos >= NPIXELS/2) { + if (++ai_pos >= NPIXELS / 2) + { ai_state++; ai_pos = 0; } @@ -415,36 +485,54 @@ static uint8_t animate_win(uint8_t side) uint32_t clr; uint8_t pos; - if(side) { + if (side) + { clr = Adafruit_NeoPixel::Color(0, 255, 0); - pos = NPIXELS/2; - } else { + pos = NPIXELS / 2; + } + else + { clr = Adafruit_NeoPixel::Color(255, 0, 0); pos = 0; } one_d.clear(); - if(aw_state < 20) { - if(aw_state & 0x01) { - for(uint8_t i = 0; i < NPIXELS/2; i++) { - one_d.setPixelColor(pos+i, clr); + if (aw_state < 20) + { + if (aw_state & 0x01) + { + for (uint8_t i = 0; i < NPIXELS / 2; i++) + { + one_d.setPixelColor(pos + i, clr); } } - } else if(aw_state < 50) { - for(uint8_t i = 0; i < aw_state - 20; i++) { - one_d.setPixelColor(pos+i, clr); + } + else if (aw_state < 50) + { + for (uint8_t i = 0; i < aw_state - 20; i++) + { + one_d.setPixelColor(pos + i, clr); } - } else if(aw_state < 80) { - for(uint8_t i = aw_state - 50; i < NPIXELS/2; i++) { - one_d.setPixelColor(pos+i, clr); + } + else if (aw_state < 80) + { + for (uint8_t i = aw_state - 50; i < NPIXELS / 2; i++) + { + one_d.setPixelColor(pos + i, clr); } - } else if(aw_state < 110) { - for(uint8_t i = 0; i < aw_state - 80; i++) { - one_d.setPixelColor(NPIXELS/2-1-i+pos, clr); + } + else if (aw_state < 110) + { + for (uint8_t i = 0; i < aw_state - 80; i++) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - i + pos, clr); } - } else if(aw_state < 140) { - for(uint8_t i = aw_state - 110; i < NPIXELS/2; i++) { - one_d.setPixelColor(NPIXELS/2-1-i+pos, clr); + } + else if (aw_state < 140) + { + for (uint8_t i = aw_state - 110; i < NPIXELS / 2; i++) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - i + pos, clr); } } one_d.show(); @@ -456,14 +544,15 @@ static uint8_t animate_win(uint8_t side) */ static uint8_t is_game_state(uint8_t s) { - switch(s) { - case ST_MOVE_LR: // If you press too soon + switch (s) + { + case ST_MOVE_LR: // If you press too soon case ST_MOVE_RL: - case ST_ZONE_R: // In the zone + case ST_ZONE_R: // In the zone case ST_ZONE_L: - case ST_POINT_L: // Just got a point, delay resume + case ST_POINT_L: // Just got a point, delay resume case ST_POINT_R: - case ST_WIN_R: // Delay to activate the win sequence + case ST_WIN_R: // Delay to activate the win sequence case ST_WIN_L: return 1; default: @@ -476,11 +565,11 @@ static uint8_t is_game_state(uint8_t s) */ static inline void speed_to_timer() { - if(boosted) + if (boosted) timer = speed * 3 / 4; else timer = speed; - if(timer < 2) + if (timer < 2) timer = 2; } @@ -493,7 +582,8 @@ static inline void speed_to_timer() static void set_state(uint8_t newstate) { /* State exit actions */ - switch(thestate) { + switch (thestate) + { case ST_IDLE: case ST_WIN_L: case ST_WIN_R: @@ -509,23 +599,23 @@ static void set_state(uint8_t newstate) case ST_RESUME_L: ballpos = 0; /* Serve speed not too fast */ - speed = TIME_SPEED_MIN + 5*TIME_SPEED_INTERVAL; + speed = TIME_SPEED_MIN + 5 * TIME_SPEED_INTERVAL; speedup = 0; break; case ST_START_R: case ST_POINT_R: case ST_RESUME_R: - ballpos = NPIXELS-1; + ballpos = NPIXELS - 1; /* Serve speed not too fast */ - speed = TIME_SPEED_MIN + 5*TIME_SPEED_INTERVAL; + speed = TIME_SPEED_MIN + 5 * TIME_SPEED_INTERVAL; speedup = 0; break; case ST_ZONE_L: /* Calculate the speed for the return */ speed = TIME_SPEED_MIN + TIME_SPEED_INTERVAL * ballpos; - if(++speedup / 2 >= speed) + if (++speedup / 2 >= speed) speed = 2; else speed -= speedup / 2; @@ -534,8 +624,8 @@ static void set_state(uint8_t newstate) case ST_ZONE_R: /* Calculate the speed for the return */ - speed = TIME_SPEED_MIN + TIME_SPEED_INTERVAL * (NPIXELS-1 - ballpos); - if(++speedup / 2 >= speed) + speed = TIME_SPEED_MIN + TIME_SPEED_INTERVAL * (NPIXELS - 1 - ballpos); + if (++speedup / 2 >= speed) speed = 2; else speed -= speedup / 2; @@ -545,7 +635,8 @@ static void set_state(uint8_t newstate) thestate = newstate; /* State entry actions */ - switch(thestate) { + switch (thestate) + { case ST_IDLE: boost_l = boost_r = 0; zone_l = zone_r = ZONE_SIZE; @@ -560,7 +651,7 @@ static void set_state(uint8_t newstate) timer = TIME_BALL_BLINK; timeout = TIME_START_TIMEOUT; ballblinkstate = 0; - ballpos = thestate == ST_START_L ? 0 : NPIXELS-1; + ballpos = thestate == ST_START_L ? 0 : NPIXELS - 1; break; case ST_MOVE_LR: @@ -573,17 +664,17 @@ static void set_state(uint8_t newstate) case ST_POINT_R: pointblinkcount = 7; /* Recover the zone next round */ - if(!boost_l && zone_l < ZONE_SIZE) + if (!boost_l && zone_l < ZONE_SIZE) zone_l++; - if(!boost_r && zone_r < ZONE_SIZE) + if (!boost_r && zone_r < ZONE_SIZE) zone_r++; timer = TIME_POINT_BLINK; - if(boost_l) + if (boost_l) boost_l--; - if(boost_r) + if (boost_r) boost_r--; // Ensure we get to the score display before continuing - lockout_l = lockout_r = TIME_LOCKOUT; + lockout_l = lockout_r = TIME_LOCKOUT; break; case ST_RESUME_L: @@ -598,7 +689,7 @@ static void set_state(uint8_t newstate) case ST_WIN_L: case ST_WIN_R: // Ensure we get to the winner display before continuing - lockout_l = lockout_r = 2 * TIME_LOCKOUT; + lockout_l = lockout_r = 2 * TIME_LOCKOUT; animate_win_init(); timer = TIME_WIN_BLINK; tuneidx = 0; @@ -612,7 +703,7 @@ static void set_state(uint8_t newstate) */ void setup() { - //PORTB = PORTC = PORTD = 0xff; // Enable all pull-ups so we don't have undef inputs hanging + // PORTB = PORTC = PORTD = 0xff; // Enable all pull-ups so we don't have undef inputs hanging pinMode(PIN_BUT_LS, INPUT_PULLUP); pinMode(PIN_BUT_RS, INPUT_PULLUP); @@ -621,25 +712,26 @@ void setup() digitalWrite(PIN_SOUND, 0); pinMode(PIN_SOUND, OUTPUT); - one_d.begin(); // Setup IO - one_d.setBrightness(60); - one_d.setPixelColor(6, one_d.Color(200,200,0)); - one_d.show(); // All leds off + one_d.begin(); // Setup IO + // Test rob + one_d.setBrightness(60); + one_d.setPixelColor(6, one_d.Color(200, 200, 0)); + one_d.show(); // All leds off thestate = ST_IDLE; - set_state(ST_IDLE); // To run both exit and entry actions + set_state(ST_IDLE); // To run both exit and entry actions /* * Setup sound hardware with Timer1 manually. The disabled interrupts * in the pixel-update causes interference in the timing resulting in * clicks in the sound output. */ - /* geht nicht bei ESP32 - müsen was eigenes finden - TCCR1A = 0; - TCCR1B = _BV(WGM12) | _BV(CS10); - OCR1A = NOTE_C4; // Just a value - TCNT1 = 0; - */ + /* geht nicht bei ESP32 - müsen was eigenes finden + TCCR1A = 0; + TCCR1B = _BV(WGM12) | _BV(CS10); + OCR1A = NOTE_C4; // Just a value + TCNT1 = 0; + */ } /* @@ -648,16 +740,18 @@ void setup() * - Handle timing and generate events * - Run the game's state machine */ -#define chk_ev(ev) (events & (ev)) +#define chk_ev(ev) (events & (ev)) +/// @brief Main loop void loop() { - uint32_t now; - uint8_t tdiff = (now = millis()) - oldtime; + uint32_t now = millis(); + uint8_t tdiff = now - oldtime; uint8_t events = 0; /* Handle buttons and timers on (just about) every millisecond */ - if(tdiff) { + if (tdiff > 0) + { oldtime = now; events |= do_debounce(tdiff, &bstate_ls, &debtmr_ls, PIN_BUT_LS, EV_BUT_LS_PRESS); events |= do_debounce(tdiff, &bstate_rs, &debtmr_rs, PIN_BUT_RS, EV_BUT_RS_PRESS); @@ -670,28 +764,35 @@ void loop() do_timer(tdiff, &lockout_r, 0); } - if(is_game_state(thestate)) { + if (is_game_state(thestate)) + { // If the lockout timer is running, squash the button event - if(lockout_l) + if (lockout_l) events &= ~EV_BUT_LS_PRESS; - if(lockout_r) + if (lockout_r) events &= ~EV_BUT_RS_PRESS; } // A button press activates the lockout timer - if(chk_ev(EV_BUT_LS_PRESS)) + if (chk_ev(EV_BUT_LS_PRESS)) lockout_l = TIME_LOCKOUT; - if(chk_ev(EV_BUT_RS_PRESS)) + if (chk_ev(EV_BUT_RS_PRESS)) lockout_r = TIME_LOCKOUT; - switch(thestate) { + switch (thestate) + { // Nothing to do case ST_IDLE: - if(chk_ev(EV_BUT_LS_PRESS)) { + if (chk_ev(EV_BUT_LS_PRESS)) + { set_state(ST_START_L); - } else if(chk_ev(EV_BUT_RS_PRESS)) { + } + else if (chk_ev(EV_BUT_RS_PRESS)) + { set_state(ST_START_R); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_IDLE; animate_idle(); } @@ -699,13 +800,18 @@ void loop() // Game is started, waiting for left player to serve the ball case ST_START_L: - if(chk_ev(EV_BUT_LS_PRESS)) { + if (chk_ev(EV_BUT_LS_PRESS)) + { set_state(ST_MOVE_LR); - } else if(chk_ev(EV_TIMEOUT)) { + } + else if (chk_ev(EV_TIMEOUT)) + { set_state(ST_IDLE); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_BALL_BLINK; - if(ballblinkstate) + if (ballblinkstate) one_d.setPixelColor(ballpos, 255, 128, 0); else one_d.setPixelColor(ballpos, 0, 0, 0); @@ -716,13 +822,18 @@ void loop() // Game is started, waiting for right player to serve the ball case ST_START_R: - if(chk_ev(EV_BUT_RS_PRESS)) { + if (chk_ev(EV_BUT_RS_PRESS)) + { set_state(ST_MOVE_RL); - } else if(chk_ev(EV_TIMEOUT)) { + } + else if (chk_ev(EV_TIMEOUT)) + { set_state(ST_IDLE); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_BALL_BLINK; - if(ballblinkstate) + if (ballblinkstate) one_d.setPixelColor(ballpos, 255, 128, 0); else one_d.setPixelColor(ballpos, 0, 0, 0); @@ -733,8 +844,10 @@ void loop() // Ball is moving left-to-right outside the playback zone case ST_MOVE_LR: - if(chk_ev(EV_TIMER)) { - if(!--tonecount) { + if (chk_ev(EV_TIMER)) + { + if (!--tonecount) + { set_tone(NOTE_G4, TIME_TONE_MOVE); tonecount = TONE_INTERVAL; } @@ -743,15 +856,17 @@ void loop() draw_ball(1, ballpos); one_d.show(); ballpos++; - if(NPIXELS-1 - ballpos <= zone_r) + if (NPIXELS - 1 - ballpos <= zone_r) set_state(ST_ZONE_R); } break; // Ball is moving right-to-left outside the playback zone case ST_MOVE_RL: - if(chk_ev(EV_TIMER)) { - if(!--tonecount) { + if (chk_ev(EV_TIMER)) + { + if (!--tonecount) + { set_tone(NOTE_G4, TIME_TONE_MOVE); tonecount = TONE_INTERVAL; } @@ -760,31 +875,38 @@ void loop() draw_ball(-1, ballpos); one_d.show(); ballpos--; - if(ballpos <= zone_l) + if (ballpos <= zone_l) set_state(ST_ZONE_L); } break; // Ball is in the left playback zone, waiting for hit/score case ST_ZONE_L: - if(chk_ev(EV_BUT_LS_PRESS)) { + if (chk_ev(EV_BUT_LS_PRESS)) + { set_tone(NOTE_G3, TIME_TONE_BOUNCE); set_state(ST_MOVE_LR); // Changing speed is done after the state-change's exit/entry action - if(zone_l > 1 && button_is_down(PIN_BUT_LP)) { + if (zone_l > 1 && button_is_down(PIN_BUT_LP)) + { zone_l--; boosted = 1; speed_to_timer(); boost_l++; } - } else if(chk_ev(EV_TIMER)) { - if(!ballpos) { + } + else if (chk_ev(EV_TIMER)) + { + if (!ballpos) + { set_tone(NOTE_C5, TIME_TONE_SCORE); - if(++points_r >= WIN_POINTS) + if (++points_r >= WIN_POINTS) set_state(ST_WIN_R); else set_state(ST_POINT_R); - } else { + } + else + { speed_to_timer(); ballpos--; } @@ -796,24 +918,31 @@ void loop() // Ball is in the right playback zone, waiting for hit/score case ST_ZONE_R: - if(chk_ev(EV_BUT_RS_PRESS)) { + if (chk_ev(EV_BUT_RS_PRESS)) + { set_tone(NOTE_G3, TIME_TONE_BOUNCE); set_state(ST_MOVE_RL); // Changing speed is done after the state-change's exit/entry action - if(zone_r > 1 && button_is_down(PIN_BUT_RP)) { + if (zone_r > 1 && button_is_down(PIN_BUT_RP)) + { zone_r--; speed_to_timer(); boosted = 1; boost_r++; } - } else if(chk_ev(EV_TIMER)) { - if(ballpos == NPIXELS-1) { + } + else if (chk_ev(EV_TIMER)) + { + if (ballpos == NPIXELS - 1) + { set_tone(NOTE_C5, TIME_TONE_SCORE); - if(++points_l >= WIN_POINTS) + if (++points_l >= WIN_POINTS) set_state(ST_WIN_L); else set_state(ST_POINT_L); - } else { + } + else + { speed_to_timer(); ballpos++; } @@ -825,52 +954,67 @@ void loop() // Left player scored, animate point case ST_POINT_L: - if(chk_ev(EV_BUT_LS_PRESS)) { + if (chk_ev(EV_BUT_LS_PRESS)) + { set_state(ST_RESUME_L); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_POINT_BLINK; draw_course(SHOW_HI); - if(!(pointblinkcount & 0x01)) { - one_d.setPixelColor(NPIXELS/2-1-(2*(points_l-1)+0), 0, 0, 0); - one_d.setPixelColor(NPIXELS/2-1-(2*(points_l-1)+1), 0, 0, 0); - } else { - one_d.setPixelColor(NPIXELS/2-1-(2*(points_l-1)+0), 255, 0, 0); - one_d.setPixelColor(NPIXELS/2-1-(2*(points_l-1)+1), 255, 0, 0); + if (!(pointblinkcount & 0x01)) + { + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * (points_l - 1) + 0), 0, 0, 0); + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * (points_l - 1) + 1), 0, 0, 0); + } + else + { + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * (points_l - 1) + 0), 255, 0, 0); + one_d.setPixelColor(NPIXELS / 2 - 1 - (2 * (points_l - 1) + 1), 255, 0, 0); } one_d.show(); - if(!--pointblinkcount) + if (!--pointblinkcount) set_state(ST_RESUME_L); } break; // Right player scored, animate point case ST_POINT_R: - if(chk_ev(EV_BUT_RS_PRESS)) { + if (chk_ev(EV_BUT_RS_PRESS)) + { set_state(ST_RESUME_R); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_POINT_BLINK; draw_course(SHOW_HI); - if(!(pointblinkcount & 0x01)) { - one_d.setPixelColor(NPIXELS/2+(2*(points_r-1)+0), 0, 0, 0); - one_d.setPixelColor(NPIXELS/2+(2*(points_r-1)+1), 0, 0, 0); - } else { - one_d.setPixelColor(NPIXELS/2+(2*(points_r-1)+0), 0, 255, 0); - one_d.setPixelColor(NPIXELS/2+(2*(points_r-1)+1), 0, 255, 0); + if (!(pointblinkcount & 0x01)) + { + one_d.setPixelColor(NPIXELS / 2 + (2 * (points_r - 1) + 0), 0, 0, 0); + one_d.setPixelColor(NPIXELS / 2 + (2 * (points_r - 1) + 1), 0, 0, 0); + } + else + { + one_d.setPixelColor(NPIXELS / 2 + (2 * (points_r - 1) + 0), 0, 255, 0); + one_d.setPixelColor(NPIXELS / 2 + (2 * (points_r - 1) + 1), 0, 255, 0); } one_d.show(); - if(!--pointblinkcount) + if (!--pointblinkcount) set_state(ST_RESUME_R); } break; // Left player previously scored and must serve again (or timeout to auto-serve) case ST_RESUME_L: - if(chk_ev(EV_BUT_LS_PRESS | EV_TIMEOUT)) { + if (chk_ev(EV_BUT_LS_PRESS | EV_TIMEOUT)) + { set_state(ST_MOVE_LR); set_tone(NOTE_F3, TIME_TONE_SERVE); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_BALL_BLINK; - if(ballblinkstate) + if (ballblinkstate) one_d.setPixelColor(ballpos, 255, 128, 0); else one_d.setPixelColor(ballpos, 0, 0, 0); @@ -881,12 +1025,15 @@ void loop() // Right player previously scored and must serve again (or timeout to auto-serve) case ST_RESUME_R: - if(chk_ev(EV_BUT_RS_PRESS | EV_TIMEOUT)) { + if (chk_ev(EV_BUT_RS_PRESS | EV_TIMEOUT)) + { set_state(ST_MOVE_RL); set_tone(NOTE_F3, TIME_TONE_SERVE); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_BALL_BLINK; - if(ballblinkstate) + if (ballblinkstate) one_d.setPixelColor(ballpos, 255, 128, 0); else one_d.setPixelColor(ballpos, 0, 0, 0); @@ -898,17 +1045,23 @@ void loop() // A player won the game, animate the winning side case ST_WIN_L: case ST_WIN_R: - if(chk_ev(EV_TONETIMER)) { - events &= ~EV_TONETIMER; // Remove the event so we don't get messed up with a set_tone(0, 0) below call + if (chk_ev(EV_TONETIMER)) + { + events &= ~EV_TONETIMER; // Remove the event so we don't get messed up with a set_tone(0, 0) below call tune_next(); } - if(chk_ev(EV_BUT_LS_PRESS)) { + if (chk_ev(EV_BUT_LS_PRESS)) + { set_state(ST_START_L); - } else if(chk_ev(EV_BUT_RS_PRESS)) { + } + else if (chk_ev(EV_BUT_RS_PRESS)) + { set_state(ST_START_R); - } else if(chk_ev(EV_TIMER)) { + } + else if (chk_ev(EV_TIMER)) + { timer = TIME_WIN_BLINK; - if(!animate_win(thestate == ST_WIN_R)) + if (!animate_win(thestate == ST_WIN_R)) set_state(ST_IDLE); } break; @@ -921,9 +1074,8 @@ void loop() /* The sound timer is async to the rest */ /* Alternative is to handle it in each and every state */ - if(chk_ev(EV_TONETIMER)) + if (chk_ev(EV_TONETIMER)) set_tone(0, 0); - } // vim: syn=cpp diff --git a/1D_pongESP32/Adafruit_NeoPixel.cpp b/1D_pongESP32/Adafruit_NeoPixel.cpp deleted file mode 100644 index 7abfc1a..0000000 --- a/1D_pongESP32/Adafruit_NeoPixel.cpp +++ /dev/null @@ -1,1096 +0,0 @@ -/*------------------------------------------------------------------------- - Arduino library to control a wide variety of WS2811- and WS2812-based RGB - LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. - Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega - MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide - output on PORTB and PORTD, while 16 MHz chips can handle most output pins - (possible exception with upper PORT registers on the Arduino Mega). - - Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, - contributions by PJRC and other members of the open source community. - - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing products - from Adafruit! - - ------------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - NeoPixel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with NeoPixel. If not, see - . - -------------------------------------------------------------------------*/ - -#include "Adafruit_NeoPixel.h" - -Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : - numLEDs(n), numBytes(n * 3), pin(p), brightness(0), - pixels(NULL), type(t), endTime(0) -#ifdef __AVR__ - ,port(portOutputRegister(digitalPinToPort(p))), - pinMask(digitalPinToBitMask(p)) -#endif -{ - if((pixels = (uint8_t *)malloc(numBytes))) { - memset(pixels, 0, numBytes); - } - if(t & NEO_GRB) { // GRB vs RGB; might add others if needed - rOffset = 1; - gOffset = 0; - bOffset = 2; - } else if (t & NEO_BRG) { - rOffset = 1; - gOffset = 2; - bOffset = 0; - } else { - rOffset = 0; - gOffset = 1; - bOffset = 2; - } - -} - -Adafruit_NeoPixel::~Adafruit_NeoPixel() { - if(pixels) free(pixels); - pinMode(pin, INPUT); -} - -void Adafruit_NeoPixel::begin(void) { - digitalWrite(pin, LOW); - pinMode(pin, OUTPUT); -} - -void Adafruit_NeoPixel::show(void) { - - if(!pixels) return; - - // Data latch = 50+ microsecond pause in the output stream. Rather than - // put a delay at the end of the function, the ending time is noted and - // the function will simply hold off (if needed) on issuing the - // subsequent round of data until the latch time has elapsed. This - // allows the mainline code to start generating the next frame of data - // rather than stalling for the latch. - while(!canShow()); - // endTime is a private member (rather than global var) so that mutliple - // instances on different pins can be quickly issued in succession (each - // instance doesn't delay the next). - - // In order to make this code runtime-configurable to work with any pin, - // SBI/CBI instructions are eschewed in favor of full PORT writes via the - // OUT or ST instructions. It relies on two facts: that peripheral - // functions (such as PWM) take precedence on output pins, so our PORT- - // wide writes won't interfere, and that interrupts are globally disabled - // while data is being issued to the LEDs, so no other code will be - // accessing the PORT. The code takes an initial 'snapshot' of the PORT - // state, computes 'pin high' and 'pin low' values, and writes these back - // to the PORT register as needed. - - noInterrupts(); // Need 100% focus on instruction timing - -#ifdef __AVR__ - - volatile uint16_t - i = numBytes; // Loop counter - volatile uint8_t - *ptr = pixels, // Pointer to next byte - b = *ptr++, // Current byte value - hi, // PORT w/output bit set high - lo; // PORT w/output bit set low - - // Hand-tuned assembly code issues data to the LED drivers at a specific - // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) - // for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The - // datastream timing for the LED drivers allows a little wiggle room each - // way (listed in the datasheets), so the conditions for compiling each - // case are set up for a range of frequencies rather than just the exact - // 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on - // devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based - // on the datasheet figures and have not been extensively tested outside - // the canonical 8/12/16 MHz speeds; there's no guarantee these will work - // close to the extremes (or possibly they could be pushed further). - // Keep in mind only one CPU speed case actually gets compiled; the - // resulting program isn't as massive as it might look from source here. - -// 8 MHz(ish) AVR --------------------------------------------------------- -#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) - -#ifdef NEO_KHZ400 - if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream -#endif - - volatile uint8_t n1, n2 = 0; // First, next bits out - - // Squeezing an 800 KHz stream out of an 8 MHz chip requires code - // specific to each PORT register. At present this is only written - // to work with pins on PORTD or PORTB, the most likely use case -- - // this covers all the pins on the Adafruit Flora and the bulk of - // digital pins on the Arduino Pro 8 MHz (keep in mind, this code - // doesn't even get compiled for 16 MHz boards like the Uno, Mega, - // Leonardo, etc., so don't bother extending this out of hand). - // Additional PORTs could be added if you really need them, just - // duplicate the else and loop and change the PORT. Each add'l - // PORT will require about 150(ish) bytes of program space. - - // 10 instruction clocks per bit: HHxxxxxLLL - // OUT instructions: ^ ^ ^ (T=0,2,7) - -#ifdef PORTD // PORTD isn't present on ATtiny85, etc. - - if(port == &PORTD) { - - hi = PORTD | pinMask; - lo = PORTD & ~pinMask; - n1 = lo; - if(b & 0x80) n1 = hi; - - // Dirty trick: RJMPs proceeding to the next instruction are used - // to delay two clock cycles in one instruction word (rather than - // using two NOPs). This was necessary in order to squeeze the - // loop down to exactly 64 words -- the maximum possible for a - // relative branch. - - asm volatile( - "headD:" "\n\t" // Clk Pseudocode - // Bit 7: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 6: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 5: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 4: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 3: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 2: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 1: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "brne headD" "\n" // 2 while(i) (Z flag set above) - : [byte] "+r" (b), - [n1] "+r" (n1), - [n2] "+r" (n2), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - } else if(port == &PORTB) { - -#endif // PORTD - - // Same as above, just switched to PORTB and stripped of comments. - hi = PORTB | pinMask; - lo = PORTB & ~pinMask; - n1 = lo; - if(b & 0x80) n1 = hi; - - asm volatile( - "headB:" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 6" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 5" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 4" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 3" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 2" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 1" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 0" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "brne headB" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef PORTD - } // endif PORTB -#endif - -#ifdef NEO_KHZ400 - } else { // end 800 KHz, do 400 KHz - - // Timing is more relaxed; unrolling the inner loop for each bit is - // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out - // of need but just to trim the code size down a little. - // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical - // to the 800-on-16 code later -- the hi/lo timing between WS2811 and - // WS2812 is not simply a 2:1 scale! - - // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,4,10) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "dec %[bit]" "\n\t" // 1 bit-- (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); - } -#endif - -// 12 MHz(ish) AVR -------------------------------------------------------- -#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) - -#ifdef NEO_KHZ400 - if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream -#endif - - // In the 12 MHz case, an optimized 800 KHz datastream (no dead time - // between bytes) requires a PORT-specific loop similar to the 8 MHz - // code (but a little more relaxed in this case). - - // 15 instruction clocks per bit: HHHHxxxxxxLLLLL - // OUT instructions: ^ ^ ^ (T=0,4,10) - - volatile uint8_t next; - -#ifdef PORTD - - if(port == &PORTD) { - - hi = PORTD | pinMask; - lo = PORTD & ~pinMask; - next = lo; - if(b & 0x80) next = hi; - - // Don't "optimize" the OUT calls into the bitTime subroutine; - // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! - asm volatile( - "headD:" "\n\t" // (T = 0) - "out %[port], %[hi]" "\n\t" // (T = 1) - "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 6 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 5 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 4 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 3 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 2 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 1 - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) - "rjmp .+0" "\n\t" // 2 nop nop (T = 3) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) - "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) - "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) - "rjmp doneD" "\n\t" - "bitTimeD:" "\n\t" // nop nop nop (T = 4) - "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) - "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "ret" "\n\t" // 4 nop nop nop nop (T = 15) - "doneD:" "\n" - : [byte] "+r" (b), - [next] "+r" (next), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - } else if(port == &PORTB) { - -#endif // PORTD - - hi = PORTB | pinMask; - lo = PORTB & ~pinMask; - next = lo; - if(b & 0x80) next = hi; - - // Same as above, just set for PORTB & stripped of comments - asm volatile( - "headB:" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port] , %[hi]" "\n\t" - "rjmp .+0" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "out %[port] , %[next]" "\n\t" - "mov %[next] , %[lo]" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[next] , %[hi]" "\n\t" - "nop" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "brne headB" "\n\t" - "rjmp doneB" "\n\t" - "bitTimeB:" "\n\t" - "out %[port], %[next]" "\n\t" - "mov %[next], %[lo]" "\n\t" - "rol %[byte]" "\n\t" - "sbrc %[byte], 7" "\n\t" - "mov %[next], %[hi]" "\n\t" - "nop" "\n\t" - "out %[port], %[lo]" "\n\t" - "ret" "\n\t" - "doneB:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef PORTD - } -#endif - -#ifdef NEO_KHZ400 - } else { // 400 KHz - - // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,6,15) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head30:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) - "rjmp .+0" "\n\t" // 2 nop nop (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "nop" "\n\t" // 1 nop (T = 15) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) - "rjmp .+0" "\n\t" // 2 nop nop (T = 19) - "dec %[bit]" "\n\t" // 1 bit-- (T = 20) - "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) - "rjmp .+0" "\n\t" // 2 nop nop (T = 24) - "rjmp .+0" "\n\t" // 2 nop nop (T = 26) - "rjmp .+0" "\n\t" // 2 nop nop (T = 28) - "rjmp head30" "\n\t" // 2 -> head30 (next bit out) - "nextbyte30:" "\n\t" // (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) - "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); - } -#endif - -// 16 MHz(ish) AVR -------------------------------------------------------- -#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) - -#ifdef NEO_KHZ400 - if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream -#endif - - // WS2811 and WS2812 have different hi/lo duty cycles; this is - // similar but NOT an exact copy of the prior 400-on-8 code. - - // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL - // ST instructions: ^ ^ ^ (T=0,5,13) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "dec %[bit]" "\n\t" // 1 bit-- (T = 5) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - -#ifdef NEO_KHZ400 - } else { // 400 KHz - - // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. - - // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL - // ST instructions: ^ ^ ^ (T=0,8,20) - - volatile uint8_t next, bit; - - hi = *port | pinMask; - lo = *port & ~pinMask; - next = lo; - bit = 8; - - asm volatile( - "head40:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "rjmp .+0" "\n\t" // 2 nop nop (T = 8) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp .+0" "\n\t" // 2 nop nop (T = 20) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) - "dec %[bit]" "\n\t" // 1 bit-- (T = 25) - "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) - "nop" "\n\t" // 1 nop (T = 28) - "rjmp .+0" "\n\t" // 2 nop nop (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "rjmp .+0" "\n\t" // 2 nop nop (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "rjmp .+0" "\n\t" // 2 nop nop (T = 38) - "rjmp head40" "\n\t" // 2 -> head40 (next bit out) - "nextbyte40:" "\n\t" // (T = 27) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) - "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - } -#endif - -#else - #error "CPU SPEED NOT SUPPORTED" -#endif - -#elif defined(__arm__) - -#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 -#define CYCLES_800_T0H (F_CPU / 4000000) -#define CYCLES_800_T1H (F_CPU / 1250000) -#define CYCLES_800 (F_CPU / 800000) -#define CYCLES_400_T0H (F_CPU / 2000000) -#define CYCLES_400_T1H (F_CPU / 833333) -#define CYCLES_400 (F_CPU / 400000) - - uint8_t *p = pixels, - *end = p + numBytes, pix, mask; - volatile uint8_t *set = portSetRegister(pin), - *clr = portClearRegister(pin); - uint32_t cyc; - - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - -#ifdef NEO_KHZ400 - if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream -#endif - cyc = ARM_DWT_CYCCNT + CYCLES_800; - while(p < end) { - pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); - cyc = ARM_DWT_CYCCNT; - *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); - } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); - } - *clr = 1; - } - } - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); -#ifdef NEO_KHZ400 - } else { // 400 kHz bitstream - cyc = ARM_DWT_CYCCNT + CYCLES_400; - while(p < end) { - pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - cyc = ARM_DWT_CYCCNT; - *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); - } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); - } - *clr = 1; - } - } - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - } -#endif - - - - - -#elif defined(__MKL26Z64__) // Teensy-LC - -#if F_CPU == 48000000 - uint8_t *p = pixels, - pix, count, dly, - bitmask = digitalPinToBitMask(pin); - volatile uint8_t *reg = portSetRegister(pin); - uint32_t num = numBytes; - asm volatile( - "L%=_begin:" "\n\t" - "ldrb %[pix], [%[p], #0]" "\n\t" - "lsl %[pix], #24" "\n\t" - "movs %[count], #7" "\n\t" - "L%=_loop:" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_loop_one" "\n\t" - "L%=_loop_zero:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0L" "\n\t" - "b L%=_next" "\n\t" - "L%=_loop_one:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_next:" "\n\t" - "sub %[count], #1" "\n\t" - "bne L%=_loop" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_last_one" "\n\t" - "L%=_last_zero:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_last_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #10" "\n\t" - "L%=_last_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0L" "\n\t" - "b L%=_repeat" "\n\t" - "L%=_last_one:" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_last_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #1" "\n\t" - "L%=_last_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_repeat:" "\n\t" - "add %[p], #1" "\n\t" - "sub %[num], #1" "\n\t" - "bne L%=_begin" "\n\t" - "L%=_done:" "\n\t" - : [p] "+r" (p), - [pix] "=&r" (pix), - [count] "=&r" (count), - [dly] "=&r" (dly), - [num] "+r" (num) - : [bitmask] "r" (bitmask), - [reg] "r" (reg) - ); -#else -#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" -#endif - - -#else // Arduino Due - - #define SCALE VARIANT_MCK / 2UL / 1000000UL - #define INST (2UL * F_CPU / VARIANT_MCK) - #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) - #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) - - int pinMask, time0, time1, period, t; - Pio *port; - volatile WoReg *portSet, *portClear, *timeValue, *timeReset; - uint8_t *p, *end, pix, mask; - - pmc_set_writeprotect(false); - pmc_enable_periph_clk((uint32_t)TC3_IRQn); - TC_Configure(TC1, 0, - TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); - TC_Start(TC1, 0); - - pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into - port = g_APinDescription[pin].pPort; // declarations above. Want to - portSet = &(port->PIO_SODR); // burn a few cycles after - portClear = &(port->PIO_CODR); // starting timer to minimize - timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. - timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); - p = pixels; - end = p + numBytes; - pix = *p++; - mask = 0x80; - -#ifdef NEO_KHZ400 - if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream -#endif - time0 = TIME_800_0; - time1 = TIME_800_1; - period = PERIOD_800; -#ifdef NEO_KHZ400 - } else { // 400 KHz bitstream - time0 = TIME_400_0; - time1 = TIME_400_1; - period = PERIOD_400; - } -#endif - - for(t = time0;; t = time0) { - if(pix & mask) t = time1; - while(*timeValue < period); - *portSet = pinMask; - *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; - while(*timeValue < t); - *portClear = pinMask; - if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes - if(p >= end) break; // idle time to minimize inter-byte delays. - pix = *p++; - mask = 0x80; - } - } - while(*timeValue < period); // Wait for last bit - TC_Stop(TC1, 0); - -#endif // end Arduino Due - -#endif // end Architecture select - - /* XXX - * Setting 60 pixels takes 1.8ms, which means we lose a timer interrupt. - * Compensate some of the "lost" time here to be slightly better at - * real-time. - */ - extern volatile unsigned long timer0_millis; - timer0_millis++; - - interrupts(); - endTime = micros(); // Save EOD time for latch on next call -} - -// Set the output pin number -void Adafruit_NeoPixel::setPin(uint8_t p) { - pinMode(pin, INPUT); - pin = p; - pinMode(p, OUTPUT); - digitalWrite(p, LOW); -#ifdef __AVR__ - port = portOutputRegister(digitalPinToPort(p)); - pinMask = digitalPinToBitMask(p); -#endif -} - -// Set pixel color from separate R,G,B components: -void Adafruit_NeoPixel::setPixelColor( - uint16_t n, uint8_t r, uint8_t g, uint8_t b) { - if(n < numLEDs) { - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - uint8_t *p = &pixels[n * 3]; - p[rOffset] = r; - p[gOffset] = g; - p[bOffset] = b; - } -} - -// Set pixel color from 'packed' 32-bit RGB color: -void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { - if(n < numLEDs) { - uint8_t - r = (uint8_t)(c >> 16), - g = (uint8_t)(c >> 8), - b = (uint8_t)c; - if(brightness) { // See notes in setBrightness() - r = (r * brightness) >> 8; - g = (g * brightness) >> 8; - b = (b * brightness) >> 8; - } - uint8_t *p = &pixels[n * 3]; - p[rOffset] = r; - p[gOffset] = g; - p[bOffset] = b; - } -} -/* ------------------------------------------------------------------------------- - HSV to RGB conversion ------------------------------------------------------------------------------- - H [0..1541] angle 0 == 0deg, 1541 < 360deg - sextants: [0..256], [257..513], [514..770], [771..1027], [1028..1284], [1285..1541] - 8-bit(+1) per sextant - ~0.2335 degrees per count - This is the highest resolution possible with 8 bit target colors and is already - slightly higher than necessay (max resolution is ~6 * 256). However, using the - current setup makes calculation a lot easier by using 8-bit shifts. - S [0..255] - V [0..255] -*/ -static inline void hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) -{ - uint16_t frac = h; - - if(!s) - s++; /* This fixes border case, marked !! below */ - if(h < 257) { - frac -= 0; - *r = v; - *g = (v * (uint8_t)(~((s * (256-frac)) >> 8))) >> 8; - *b = (v * (uint8_t)(~s + 1)) >> 8; - } else if(h < 514) { - frac -= 257; - *r = (v * (uint8_t)(~((s * frac) >> 8))) >> 8; - *g = v; - *b = (v * (uint8_t)(~s + 1)) >> 8; - } else if(h < 771) { - frac -= 514; - *r = (v * (uint8_t)(~s + 1)) >> 8; - *g = v; - *b = (v * (uint8_t)(~((s * (256-frac)) >> 8))) >> 8; - } else if(h < 1028) { - frac -= 771; - *r = (v * (uint8_t)(~s + 1)) >> 8; - *g = (v * (uint8_t)(~((s * frac) >> 8))) >> 8; - *b = v; - } else if(h < 1285) { - frac -= 1028; - *r = (v * (uint8_t)(~((s * (256-frac)) >> 8))) >> 8; - *g = (v * (uint8_t)(~s + 1)) >> 8; - *b = v; - } else { - frac -= 1285; - *r = v; - *g = (v * (uint8_t)(~s + 1)) >> 8; - *b = (v * (uint8_t)(~((s * frac) >> 8))) >> 8; - } -} - -void Adafruit_NeoPixel::setPixelColorHsv(uint16_t n, uint16_t h, uint8_t s, uint8_t v) { - uint8_t r, g, b; - hsv_to_rgb(h, s, v, &r, &g, &b); - setPixelColor(n, r, g, b); -} - -// Convert separate R,G,B into packed 32-bit RGB color. -// Packed format is always RGB, regardless of LED strand color order. -uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { - return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; -} - -// Query color from previously-set pixel (returns packed 32-bit RGB value) -uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { - if(n >= numLEDs) { - // Out of bounds, return no color. - return 0; - } - uint8_t *p = &pixels[n * 3]; - uint32_t c = ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; - // Adjust this back up to the true color, as setting a pixel color will - // scale it back down again. - if(brightness) { // See notes in setBrightness() - //Cast the color to a byte array - uint8_t * c_ptr =reinterpret_cast(&c); - c_ptr[0] = (c_ptr[0] << 8)/brightness; - c_ptr[1] = (c_ptr[1] << 8)/brightness; - c_ptr[2] = (c_ptr[2] << 8)/brightness; - } - return c; // Pixel # is out of bounds -} - -// Returns pointer to pixels[] array. Pixel data is stored in device- -// native format and is not translated here. Application will need to be -// aware whether pixels are RGB vs. GRB and handle colors appropriately. -uint8_t *Adafruit_NeoPixel::getPixels(void) const { - return pixels; -} - -uint16_t Adafruit_NeoPixel::numPixels(void) const { - return numLEDs; -} - -// Adjust output brightness; 0=darkest (off), 255=brightest. This does -// NOT immediately affect what's currently displayed on the LEDs. The -// next call to show() will refresh the LEDs at this level. However, -// this process is potentially "lossy," especially when increasing -// brightness. The tight timing in the WS2811/WS2812 code means there -// aren't enough free cycles to perform this scaling on the fly as data -// is issued. So we make a pass through the existing color data in RAM -// and scale it (subsequent graphics commands also work at this -// brightness level). If there's a significant step up in brightness, -// the limited number of steps (quantization) in the old data will be -// quite visible in the re-scaled version. For a non-destructive -// change, you'll need to re-render the full strip data. C'est la vie. -void Adafruit_NeoPixel::setBrightness(uint8_t b) { - // Stored brightness value is different than what's passed. - // This simplifies the actual scaling math later, allowing a fast - // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, - // adding 1 here may (intentionally) roll over...so 0 = max brightness - // (color values are interpreted literally; no scaling), 1 = min - // brightness (off), 255 = just below max brightness. - uint8_t newBrightness = b + 1; - if(newBrightness != brightness) { // Compare against prior value - // Brightness has changed -- re-scale existing data in RAM - uint8_t c, - *ptr = pixels, - oldBrightness = brightness - 1; // De-wrap old brightness value - uint16_t scale; - if(oldBrightness == 0) scale = 0; // Avoid /0 - else if(b == 255) scale = 65535 / oldBrightness; - else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; - for(uint16_t i=0; i> 8; - } - brightness = newBrightness; - } -} - -//Return the brightness value -uint8_t Adafruit_NeoPixel::getBrightness(void) const { - return brightness - 1; -} - -void Adafruit_NeoPixel::clear() { - memset(pixels, 0, numBytes); -} - diff --git a/1D_pongESP32/Adafruit_NeoPixel.h b/1D_pongESP32/Adafruit_NeoPixel.h deleted file mode 100644 index d53da1f..0000000 --- a/1D_pongESP32/Adafruit_NeoPixel.h +++ /dev/null @@ -1,97 +0,0 @@ -/*-------------------------------------------------------------------- - This file is part of the Adafruit NeoPixel library. - - NeoPixel is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - NeoPixel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with NeoPixel. If not, see - . - --------------------------------------------------------------------*/ - -#ifndef ADAFRUIT_NEOPIXEL_H -#define ADAFRUIT_NEOPIXEL_H - -#if (ARDUINO >= 100) -#include -#else -#include -#include -#endif - -// 'type' flags for LED pixels (third parameter to constructor): -#define NEO_RGB 0x00 // Wired for RGB data order -#define NEO_GRB 0x01 // Wired for GRB data order -#define NEO_BRG 0x04 - -#define NEO_COLMASK 0x01 -#define NEO_KHZ800 0x02 // 800 KHz datastream -#define NEO_SPDMASK 0x02 -// Trinket flash space is tight, v1 NeoPixels aren't handled by default. -// Remove the ifndef/endif to add support -- but code will be bigger. -// Conversely, can comment out the #defines to save space on other MCUs. -#ifndef __AVR_ATtiny85__ -#define NEO_KHZ400 0x00 // 400 KHz datastream -#endif - -class Adafruit_NeoPixel -{ - -public: - // Constructor: number of LEDs, pin number, LED type - Adafruit_NeoPixel(uint16_t n, uint8_t p = 6, uint8_t t = NEO_GRB + NEO_KHZ800); - ~Adafruit_NeoPixel(); - - void - begin(void), - show(void), - setPin(uint8_t p), - setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), - setPixelColor(uint16_t n, uint32_t c), - setPixelColorHsv(uint16_t n, uint16_t h, uint8_t s, uint8_t v), - setBrightness(uint8_t), - clear(); - uint8_t - * - getPixels(void) const, - getBrightness(void) const; - uint16_t - numPixels(void) const; - static uint32_t - Color(uint8_t r, uint8_t g, uint8_t b); - uint32_t - getPixelColor(uint16_t n) const; - inline bool - canShow(void) { return (micros() - endTime) >= 50L; } - -private: - const uint16_t - numLEDs, // Number of RGB LEDs in strip - numBytes; // Size of 'pixels' buffer below - uint8_t - pin, // Output pin number - brightness, - *pixels, // Holds LED color values (3 bytes each) - rOffset, // Index of red byte within each 3-byte pixel - gOffset, // Index of green byte - bOffset; // Index of blue byte - const uint8_t - type; // Pixel flags (400 vs 800 KHz, RGB vs GRB color) - uint32_t - endTime; // Latch timing reference -#ifdef __AVR__ - const volatile uint8_t - *port; // Output PORT register - uint8_t - pinMask; // Output PORT bitmask -#endif -}; - -#endif // ADAFRUIT_NEOPIXEL_H diff --git a/1D_pongESP32/pin-names.h b/1D_pongESP32/pin-names.h index 8ccd563..0bd6b00 100644 --- a/1D_pongESP32/pin-names.h +++ b/1D_pongESP32/pin-names.h @@ -5,7 +5,7 @@ #define GPIO22 22 #define GPIO18 18 // SPI CLK #define GPIO19 19 -#define GPIO21 21 +#define GPIO21 21 // guter LED-out pin //ADIO #define GPIO25 25