X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=tinyboard.git;a=blobdiff_plain;f=projects%2Frgb-led-string%2Fmain.c;h=bd923612f57f30dd0cba6093daaf2e02894caee2;hp=4c82f48b8f2bed6b97f3c74e471495b60aec8d56;hb=5013d75921e37f1df3034f0d2ed39ddecb718d67;hpb=616f20d134e94462b5920a2f93be54cdb9fe74e0 diff --git a/projects/rgb-led-string/main.c b/projects/rgb-led-string/main.c index 4c82f48..bd92361 100644 --- a/projects/rgb-led-string/main.c +++ b/projects/rgb-led-string/main.c @@ -4,17 +4,290 @@ #include "rgbstring.h" +static unsigned char jiffies; + +// #define CHRISTMAS_TREE 1 + +#define rgb_return(r, g, b) do { send_rgb((r), (g), (b)); return 1; } while(0) + +#define VERT_SIZE 47 + +/* RNG from ADC noise */ +static unsigned char rand_pool[8], rand_pool_off, prev_bit, rand_pool_out; + +static void init_rng() +{ + ADCSRA |= _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1); // enable, clk/64 + ADMUX = _BV(REFS1) | _BV(MUX0) | _BV(MUX3); // 1.1V, PB5:PB5, gain 20 + DIDR0 = _BV(ADC0D); + ADCSRA |= _BV(ADIE) | _BV(ADSC); + rand_pool_off = 0; + prev_bit = 0; +} + +static unsigned char rand() { + unsigned char rv = 0; + + rv = rand_pool[rand_pool_out]; + rand_pool_out++; + if (rand_pool_out >= sizeof(rand_pool)) + rand_pool_out = 0; + + return rv; +} + +ISR(ADC_vect) { + ADCSRA |= _BV(ADSC); + if ((rand_pool_off & 1) == 0) { // first bit of the pair + prev_bit = ADCW & 1; + rand_pool_off++; + } else { + unsigned char bit = ADCW & 1; + if (bit == prev_bit) { // whitening fail: try again + rand_pool_off--; + return; + } + + if (bit) { + rand_pool[rand_pool_off >> 4] + ^= 1 << ((rand_pool_off >> 1) & 7); + } + + rand_pool_off++; + if (rand_pool_off >= 16*sizeof(rand_pool)) + rand_pool_off = 0; + } +} + +/* up and down running stars at the beginning/end of the strip */ +static unsigned char updown_star, updown_star0, updown_down, updown_bright; + +static void updown_star_init() +{ + updown_star0 = 0; + updown_down = 1; +} + +static void updown_star_frame() +{ + if (updown_star0 == 0) { + updown_star0 = STRIP_SIZE-VERT_SIZE-8; + updown_down = 0; + } else if (updown_star0 == STRIP_SIZE + 8) { + updown_star0 = VERT_SIZE+7; + updown_down = 1; + } else if (updown_star0 <= VERT_SIZE + 8) { + updown_star0--; + } else if (updown_star0 >= STRIP_SIZE-VERT_SIZE-8) { + updown_star0++; + } + + if (updown_down && updown_star0 < 8) { + updown_star = 0; + updown_bright = 1 << updown_star0; + } else if (updown_down) { + updown_star = updown_star0 - 8; + updown_bright = 128; + } else if (updown_star0 < STRIP_SIZE-VERT_SIZE) { + updown_star = STRIP_SIZE-VERT_SIZE; + updown_bright = 1 << (STRIP_SIZE-VERT_SIZE-updown_star0); + } else { + updown_star = updown_star0; + updown_bright = 1; + } +} + +static unsigned char updown_star_pixel(unsigned char pos) +{ + if (pos >= VERT_SIZE && pos < STRIP_SIZE-VERT_SIZE) + return 0; + + if (pos == updown_star) { + send_rgb(updown_bright, updown_bright, updown_bright); + if (updown_down) { + updown_bright >>= 1; + if (updown_bright) + updown_star++; + } else { + updown_bright <<= 1; + if (updown_bright) + updown_star++; + } + return 1; + } + + return 0; +} + +/* down running stars at the beginning/end of the strip */ +static unsigned char down_star, down_star0, down_bright; + +static void down_star_init() +{ + down_star0 = STRIP_SIZE; +} + +static void down_star_frame() +{ + if (down_star0 == 0) { + down_star0 = STRIP_SIZE; + } else { + down_star0--; + } + + if (down_star0 < 8) { + down_star = 0; + down_bright = 1 << down_star0; + } else { + down_star = down_star0; + down_bright = 128; + } +} + +static unsigned char down_star_pixel(unsigned char pos) +{ + if (pos == down_star) { + send_rgb(down_bright, down_bright, down_bright); + down_bright >>= 1; + if (down_bright) + down_star++; + return 1; + } + + return 0; +} + +/* middle stars */ + +static unsigned char midstar_pos0, midstar_pos, midstar_bright, midstar_color; + +static void midstar_init() +{ + midstar_pos0 = STRIP_SIZE/2; + midstar_color = 0; +} + +static unsigned int slow_dim[] = { + 255, 182, 130, 92, 66, 47, 33, 24, 17, 12, 8, 6, 4, 3, 2, 1, +}; + +static void midstar_frame() +{ + unsigned char phase = (jiffies) & 0x1F; + + midstar_bright = phase & 0x10 ? slow_dim[phase & 0x0F] + : slow_dim[15-(phase & 0x0F)]; + + if (!phase) { + unsigned char c = rand(); +#ifdef CHRISTMAS_TREE + midstar_pos0 = 2 + (c % (STRIP_SIZE - 4)); +#else + midstar_pos0 -= 2 + VERT_SIZE; + midstar_pos0 += 16 + (c & 0x1F); + midstar_pos0 &= 0x3F; + midstar_pos0 += 2 + VERT_SIZE; +#endif + midstar_color += 1 + (c & 0xC0 ? 0 : 1); + } + + midstar_pos = midstar_pos0 - 2; +} + +static unsigned char midstar_pixel(unsigned char pos) +{ + unsigned char dim; + + if (pos != midstar_pos) + return 0; + + if (pos > midstar_pos0) { + dim = pos - midstar_pos0; + if (dim < 2) + midstar_pos++; + } else { + dim = midstar_pos0 - pos; + midstar_pos++; + } + + dim = midstar_bright >> 2*dim; + if (dim >= 2) { + switch (midstar_color & 0x7) { + case 0: send_rgb(dim, 0, 0); break; // red + case 1: send_rgb(dim, dim, dim); break; // white + case 2: send_rgb(0, dim, 0); break; // green + case 3: send_rgb(dim, 0, dim); break; // violet + case 4: send_rgb(dim, dim >> 2, 0); break; // yellow/orange + case 5: send_rgb(0, dim, dim >> 2); break; // cyan + case 6: send_rgb(0, 0, dim); break; // blue + case 7: send_rgb(dim, dim, 0); break; // yellow + } + + return 1; + } else { + return 0; + } +} + +static void background(unsigned char pos) +{ +#ifdef CHRISTMAS_TREE + switch ((pos >> 4) & 3) { + case 0: if (pos & 1) send_rgb(7, 0, 0); else send_rgb(0, 7, 0); + break; + case 1: if (pos & 1) send_rgb(0, 0, 7); else send_rgb(7, 7, 7); + break; + case 2: if (pos & 1) send_rgb(7, 0, 7); else send_rgb(0, 7, 5); + break; + case 3: if (pos & 1) send_rgb(7, 5, 0); else send_rgb(7, 7, 7); + break; + } +#else + send_rgb(0, 0, 7); +#endif +} + int main(void) { init_log(); + init_rng(); + init_serial(); - log_set_state(3); + _delay_ms(3000/8); // wait for a bit and then increase the CPU clock + CLKPR = _BV(CLKPCE); + CLKPR = 0; + + sei(); + +#ifdef CHRISTMAS_TREE + down_star_init(); +#else + updown_star_init(); +#endif + midstar_init(); - DDRB |= _BV(PB2); while (1) { - PORTB |= _BV( PB2 ); - _delay_ms(200); - PORTB &=~ _BV( PB2 ); - _delay_ms(200); + unsigned char i; + + ++jiffies; + +#ifdef CHRISTMAS_TREE + down_star_frame(); +#else + updown_star_frame(); +#endif + midstar_frame(); + + for (i = 0; i < STRIP_SIZE; i++) { +#ifdef CHRISTMAS_TREE + if (down_star_pixel(i)) continue; +#else + if (updown_star_pixel(i)) continue; +#endif + if (midstar_pixel(i)) continue; + background(i); + } + end_frame(); + _delay_ms(30); } }