diff options
Diffstat (limited to 'libraries/ws2812.c')
-rw-r--r-- | libraries/ws2812.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/libraries/ws2812.c b/libraries/ws2812.c new file mode 100644 index 0000000..41d4fb5 --- /dev/null +++ b/libraries/ws2812.c @@ -0,0 +1,125 @@ + + +/* + +# WS2812 Library for libopencm3 + +Please mind these restrictions: + +- Only usable with libopencm3 +- Newer versions of libopencm3 may be not compatibel (libopencm3 api is not stable yet) +- Just usable with a clock frequency of 80 MHz +- You have to setup the clock and gpio yourself + +*/ + + +#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 + + +void ws2812_init(ws2812_init_typedef *control_struct, uint32_t port, uint16_t pin, uint32_t array_length, uint32_t matrix_width) +{ + control_struct->gpio_port = port; + control_struct->gpio_pin = pin; + control_struct->array_length = array_length; + control_struct->matrix_width = matrix_width; + control_struct->led_array = malloc(sizeof(uint8_t[array_length][3])); + ws2812_clear_buffer(control_struct); + ws2812_send_reset(control_struct); +} + + +void ws2812_send_reset(ws2812_init_typedef *control_struct) +{ + gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); + for (int i = 0; i < NUMBER_NOPS_RESET; i++) { + __asm__("nop"); + } +} + + +void ws2812_send_zero(ws2812_init_typedef *control_struct) +{ + gpio_set(control_struct->gpio_port, control_struct->gpio_pin); + for (int i = 0; i < NUMBER_NOPS_SHORT; i++) { + __asm__("nop"); + } + gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); + for (int i = 0; i < NUMBER_NOPS_LONG; i++) { + __asm__("nop"); + } +} + + +void ws2812_send_one(ws2812_init_typedef *control_struct) +{ + gpio_set(control_struct->gpio_port, control_struct->gpio_pin); + for (int i = 0; i < NUMBER_NOPS_LONG; i++) { + __asm__("nop"); + } + gpio_clear(control_struct->gpio_port, control_struct->gpio_pin); + for (int i = 0; i < NUMBER_NOPS_SHORT; i++) { + __asm__("nop"); + } +} + + +void ws2812_send_byte(ws2812_init_typedef *control_struct, uint8_t data) +{ + for (int i=7; i>=0; i--){ + if ( (data >> i) & 0x01 ){ + ws2812_send_one(control_struct); + } + else { + ws2812_send_zero(control_struct); + } + } +} + + +void ws2812_send_led(ws2812_init_typedef *control_struct, uint8_t red, uint8_t green, uint8_t blue) +{ + ws2812_send_byte(control_struct, green); + ws2812_send_byte(control_struct, red); + ws2812_send_byte(control_struct, blue); +} + + +void ws2812_write_leds(ws2812_init_typedef *control_struct) +{ + for(uint32_t i=0; i<(control_struct->array_length); i++){ + ws2812_send_led( + control_struct, + control_struct->led_array[i][0], // red + control_struct->led_array[i][1], // green + control_struct->led_array[i][2] // blue + ); + } + ws2812_send_reset(control_struct); +} + + +void ws2812_set_array_led(ws2812_init_typedef *control_struct, uint32_t index, uint8_t red, uint8_t green, uint8_t blue) +{ + control_struct->led_array[index][0] = red; + control_struct->led_array[index][1] = green; + control_struct->led_array[index][2] = blue; +} + + +void ws2812_set_matrix_led(ws2812_init_typedef *control_struct, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) +{ + ws2812_set_array_led(control_struct, (x + y * (control_struct->matrix_width)), red, green, blue); +} + + +void ws2812_clear_buffer(ws2812_init_typedef *control_struct) +{ + for (uint32_t i=0; i<control_struct->array_length; i++){ + ws2812_set_array_led(control_struct, i, 0, 0, 0); + } +} |