/*----------------------------------------------------------------------------*/ /* Ambilight Project : Arduino Uno Board with WS2801/WS2812B LED Strip Arduino Pin Connection - Mode 0 (1 wire) : Data Out Pin 6 - Mode 1 (3 wire : spi mode = 0, clk = 2Mhz) : Data Out Pin 11 Clock Out Pin 13 Connect to Board : H/W Serial (USB, ttyACM, Baud 1000000N81) Dev Board : ODROID-C2 WS2812B Spec : - Max Current : 60mA per 1 Cell (Max bright) - Data Transfer : 800Khz Serial(1 wire) Communication(1.25us) WS2801 Spec : - Max Current : 120mA per 1 Cell (Max bright) - Data Transfer : 2Mhz Serial(3 wire : spi mode) Communication Use Library : Install Arduino Library folder - Adafruit_NeoPixel : https://github.com/adafruit/Adafruit_NeoPixel - Git clone : https://github.com/adafruit/Adafruit_NeoPixel.git Protocol : Receive : HEADER[4] + (num_of_leds in HEADER) * 3 bytes Transceive : 'N' (Ack for Data received) Header Information 'o', 'd', num of leds(1byte), check sum(1byte) Check Sum Information HEADER[3] = 0; HEADER[3] ^= HEADER[0]; HEADER[3] ^= HEADER[1]; HEADER[3] ^= HEADER[2]; Serial Data send time : 10us/byte (Buad : 1000000 bps) SPI Data send time : 5us/byte (SCKL : 2000000 Hz) 1 wire data send time : 12.5us/byte (Freq : 800000 Hz) Hardkernel Co.,Ltd (2016/10/11) */ /*----------------------------------------------------------------------------*/ /* Include Adafruit NeoPixel library */ #include #include /*----------------------------------------------------------------------------*/ /* Data Out PIN */ #define DOUT_PIN 6 #define MAX_LEDS 256 #define SERIAL_BAUD 1000000 #define HEADER_SIZE 4 /* Use LED type define */ #define LED_WS2801 #define LED_WS2812B #define TIMEOUT_MSEC 1000 /*----------------------------------------------------------------------------*/ /* LED color data struct */ struct led_data_t { uint8_t b; uint8_t g; uint8_t r; }; /*----------------------------------------------------------------------------*/ /* Create 'leds' object to drive LEDs */ Adafruit_NeoPixel leds = Adafruit_NeoPixel(MAX_LEDS, DOUT_PIN, NEO_GRB + NEO_KHZ800); /* Serial Data Receive buffer */ uint8_t SerialBuffer[sizeof(led_data_t) * MAX_LEDS]; /*----------------------------------------------------------------------------*/ void setup() { /* H/W Serial Init */ Serial.begin(SERIAL_BAUD); /* SPI Port Init for WS2801 LED, 80kbytes/sec */ SPI.setBitOrder(MSBFIRST); /* SPI Clock = 16 Mhz / 8 = 2 Mhz, 200kbytes/sec */ SPI.setClockDivider(SPI_CLOCK_DIV8); SPI.setDataMode(SPI_MODE0); SPI.begin(); SPCR |= _BV(MSTR); SPCR &= ~_BV(SPIE); SPSR; for(int i = 0; i < MAX_LEDS * sizeof(led_data_t); i++) SPI.transfer(0x00); /* NeoPixel Lib Init for WS2812B */ leds.begin(); leds.clear(); leds.show(); } /*----------------------------------------------------------------------------*/ uint8_t check_timeout(unsigned long current_time) { static unsigned long prev_time; unsigned long diff_time; if (current_time) { diff_time = current_time - prev_time; if (diff_time > TIMEOUT_MSEC) { prev_time = millis(); Serial.write("N"); return 1; } return 0; } prev_time = millis(); return 0; } /*----------------------------------------------------------------------------*/ uint16_t check_header() { uint8_t header[4] = {0, }; uint16_t rx_cnt = 0; /* start time check */ check_timeout(0); while(true) { if (Serial.available()) { header[rx_cnt++] = Serial.read(); if (rx_cnt >= HEADER_SIZE) { if ((header[0] == 'o') && (header[1] == 'd')) { uint8_t check_sum = 0; check_sum ^= header[0]; check_sum ^= header[1]; check_sum ^= header[2]; /* Return num of leds */ if (check_sum == header[3]) return (uint16_t)header[2]; } rx_cnt -= 1; header[0] = header[1]; header[1] = header[2]; header[2] = header[3]; } } else check_timeout(millis()); } } /*----------------------------------------------------------------------------*/ void loop() { uint16_t rx_cnt, recv_data_size; while(true) { timeout_data: recv_data_size = check_header() * sizeof(led_data_t); /* rx buffer pointer init */ rx_cnt = 0; /* start time check */ check_timeout(0); while(true) { if (Serial.available()) SerialBuffer[rx_cnt++] = Serial.read(); else if (check_timeout(millis())) goto timeout_data; if (rx_cnt >= recv_data_size) break; } #if defined(LED_WS2801) /* WS2801 LED Update */ for (rx_cnt = 0; rx_cnt < recv_data_size; rx_cnt ++) SPI.transfer(SerialBuffer[rx_cnt]); #endif #if defined(LED_WS2812B) /* WS2812B LED Update */ recv_data_size /= sizeof(led_data_t); led_data_t *led_data = (led_data_t *)&SerialBuffer[0]; for (rx_cnt = 0; rx_cnt < recv_data_size; rx_cnt++) leds.setPixelColor(rx_cnt, leds.Color(led_data[rx_cnt].r, led_data[rx_cnt].g, led_data[rx_cnt].b)); leds.show(); #endif /* Ack Send for Data Received */ Serial.print("N"); } } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/