// vim: tabstop=4 shiftwidth=4 noexpandtab /* Documentation is in ws2812.h */ #include "ws2812.h" #define NUMBER_NOPS_RESET 1080 // > 50 µs --> 60 µs (to be sure) = 4320 cycles @ 72 MHz = 1080 nops #define NUMBER_NOPS_LONG 16 // 0.9 µs = 64.8 cycles @ 72 MHz = 16.2 nops --> 11.1 ns timing error #define NUMBER_NOPS_SHORT 6 // 0.35 µs = 25.2 cycles @ 72 MHz = 6.3 nops --> 16.7 ns timing error // public API functions: void ws2812_init(WS2812_ARRAY *control_struct, uint32_t port, uint16_t pin, uint8_t *buffer_ptr, uint32_t array_length) { control_struct->gpio_port = port; control_struct->gpio_pin = pin; control_struct->array_buffer = buffer_ptr; control_struct->array_length = array_length; ws2812_clear_buffer(control_struct); ws2812_send_reset(control_struct); ws2812_write_buffer_to_leds(control_struct); } void ws2812_clear_buffer(WS2812_ARRAY *control_struct) { for (uint32_t i=0; i<(control_struct->array_length*3); i++){ control_struct->array_buffer[i] = 0x00; } } void ws2812_write_buffer_to_leds(WS2812_ARRAY *control_struct) { for (uint32_t i=0; i<(control_struct->array_length); i++) { ws2812_send_byte(control_struct, control_struct->array_buffer[i*3+1]); // green first ws2812_send_byte(control_struct, control_struct->array_buffer[i*3+0]); // red second ws2812_send_byte(control_struct, control_struct->array_buffer[i*3+2]); // blue third } ws2812_send_reset(control_struct); } // internal functions: void ws2812_send_reset(WS2812_ARRAY *control_struct) { gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); for (uint16_t i = 0; i < NUMBER_NOPS_RESET; i++) { __asm__("nop"); } } void ws2812_send_zero(WS2812_ARRAY *control_struct) { gpio_set(control_struct->gpio_port, control_struct->gpio_pin); for (uint8_t i = 0; i < NUMBER_NOPS_SHORT; i++) { __asm__("nop"); } gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); for (uint8_t i = 0; i < NUMBER_NOPS_LONG; i++) { __asm__("nop"); } } void ws2812_send_one(WS2812_ARRAY *control_struct) { gpio_set(control_struct->gpio_port, control_struct->gpio_pin); for (uint8_t i = 0; i < NUMBER_NOPS_LONG; i++) { __asm__("nop"); } gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); for (uint8_t i = 0; i < NUMBER_NOPS_SHORT; i++) { __asm__("nop"); } } void ws2812_send_byte(WS2812_ARRAY *control_struct, uint8_t data) { for (int8_t i=7; i>=0; i--){ if ( (data >> i) & 0x01 ){ ws2812_send_one(control_struct); } else { ws2812_send_zero(control_struct); } } }