summaryrefslogtreecommitdiff
path: root/libraries/ws2812.c
blob: 5fbdf6cb615d95c9b3c432e46f86d1c507e45a0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// 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);
		}
	}
}