Commit | Line | Data |
---|---|---|
0f507f01 AK |
1 | /* |
2 | * LEDDriver.c | |
3 | * | |
4 | * Created on: Aug 26, 2013 | |
5 | * Author: Omri Iluz | |
6 | */ | |
e653cc19 | 7 | |
0f507f01 AK |
8 | #include "ws2812.h" |
9 | #include "stdlib.h" | |
e653cc19 AK |
10 | |
11 | #define BYTES_FOR_LED_BYTE 4 | |
12 | #define NB_COLORS 3 | |
13 | #define BYTES_FOR_LED BYTES_FOR_LED_BYTE*NB_COLORS | |
14 | #define DATA_SIZE BYTES_FOR_LED*NB_LEDS | |
15 | #define RESET_SIZE 200 | |
16 | #define PREAMBLE_SIZE 4 | |
e653cc19 | 17 | // Define the spi your LEDs are plugged to here |
0f507f01 | 18 | #define WS2812_SPI SPID2 |
e653cc19 | 19 | // Define the number of LEDs you wish to control in your LED strip |
0f507f01 | 20 | #define NB_LEDS RGBLED_NUM |
e653cc19 | 21 | |
0f507f01 | 22 | #define LED_SPIRAL 1 |
e653cc19 | 23 | |
0f507f01 | 24 | static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE]; |
e653cc19 AK |
25 | static uint8_t get_protocol_eq(uint8_t data, int pos); |
26 | ||
0f507f01 | 27 | /* |
e653cc19 AK |
28 | * This lib is meant to be used asynchronously, thus the colors contained in |
29 | * the txbuf will be sent in loop, so that the colors are always the ones you | |
30 | * put in the table (the user thus have less to worry about) | |
31 | * | |
32 | * Since the data are sent via DMA, and the call to spiSend is a blocking one, | |
33 | * the processor ressources are not used to much, if you see your program being | |
34 | * too slow, simply add a: | |
35 | * chThdSleepMilliseconds(x); | |
36 | * after the spiSend, where you increment x untill you are satisfied with your | |
37 | * program speed, another trick may be to lower this thread priority : your call | |
38 | */ | |
39 | static THD_WORKING_AREA(LEDS_THREAD_WA, 128); | |
40 | static THD_FUNCTION(ledsThread, arg) { | |
41 | (void) arg; | |
42 | while(1){ | |
0f507f01 | 43 | spiSend(&WS2812_SPI, PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE, txbuf); |
e653cc19 AK |
44 | } |
45 | } | |
e653cc19 | 46 | |
0f507f01 | 47 | static const SPIConfig spicfg = { |
26eef35f | 48 | false, |
e653cc19 | 49 | NULL, |
0f507f01 AK |
50 | PORT_WS2812, |
51 | PIN_WS2812, | |
52 | SPI_CR1_BR_1|SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz) | |
e653cc19 AK |
53 | }; |
54 | ||
0f507f01 | 55 | /* |
e653cc19 AK |
56 | * Function used to initialize the driver. |
57 | * | |
58 | * Starts by shutting off all the LEDs. | |
59 | * Then gets access on the LED_SPI driver. | |
60 | * May eventually launch an animation on the LEDs (e.g. a thread setting the | |
61 | * txbuff values) | |
62 | */ | |
63 | void leds_init(void){ | |
0f507f01 AK |
64 | /* MOSI pin*/ |
65 | palSetPadMode(PORT_WS2812, PIN_WS2812, PAL_MODE_STM32_ALTERNATE_PUSHPULL); | |
e653cc19 AK |
66 | for(int i = 0; i < RESET_SIZE; i++) |
67 | txbuf[DATA_SIZE+i] = 0x00; | |
68 | for (int i=0; i<PREAMBLE_SIZE; i++) | |
69 | txbuf[i] = 0x00; | |
0f507f01 AK |
70 | spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */ |
71 | spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */ | |
72 | spiSelect(&WS2812_SPI); /* Slave Select assertion. */ | |
e653cc19 | 73 | chThdCreateStatic(LEDS_THREAD_WA, sizeof(LEDS_THREAD_WA),NORMALPRIO, ledsThread, NULL); |
e653cc19 AK |
74 | } |
75 | ||
0f507f01 | 76 | /* |
e653cc19 AK |
77 | * As the trick here is to use the SPI to send a huge pattern of 0 and 1 to |
78 | * the ws2812b protocol, we use this helper function to translate bytes into | |
79 | * 0s and 1s for the LED (with the appropriate timing). | |
80 | */ | |
81 | static uint8_t get_protocol_eq(uint8_t data, int pos){ | |
82 | uint8_t eq = 0; | |
83 | if (data & (1 << (2*(3-pos)))) | |
84 | eq = 0b1110; | |
85 | else | |
86 | eq = 0b1000; | |
87 | if (data & (2 << (2*(3-pos)))) | |
88 | eq += 0b11100000; | |
89 | else | |
90 | eq += 0b10000000; | |
91 | return eq; | |
92 | } | |
93 | ||
0f507f01 AK |
94 | |
95 | void WS2812_init(void) { | |
96 | leds_init(); | |
e653cc19 AK |
97 | } |
98 | ||
0f507f01 AK |
99 | void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds) { |
100 | uint8_t i = 0; | |
101 | while (i < number_of_leds) { | |
102 | set_led_color_rgb(ledarray[i], i); | |
103 | i++; | |
104 | } | |
105 | } | |
106 | ||
107 | /* | |
e653cc19 AK |
108 | * If you want to set a LED's color in the RGB color space, simply call this |
109 | * function with a hsv_color containing the desired color and the index of the | |
110 | * led on the LED strip (starting from 0, the first one being the closest the | |
111 | * first plugged to the board) | |
112 | * | |
113 | * Only set the color of the LEDs through the functions given by this API | |
114 | * (unless you really know what you are doing) | |
115 | */ | |
0f507f01 | 116 | void set_led_color_rgb(LED_TYPE color, int pos){ |
e653cc19 AK |
117 | for(int j = 0; j < 4; j++) |
118 | txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + j] = get_protocol_eq(color.g, j); | |
119 | for(int j = 0; j < 4; j++) | |
120 | txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE+j] = get_protocol_eq(color.r, j); | |
121 | for(int j = 0; j < 4; j++) | |
122 | txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE*2+j] = get_protocol_eq(color.b, j); | |
123 | } | |
124 | ||
0f507f01 | 125 | void set_leds_color_rgb(LED_TYPE color){ |
e653cc19 | 126 | for(int i = 0; i < NB_LEDS; i++) |
0f507f01 | 127 | set_led_color_rgb(color, i); |
e653cc19 AK |
128 | } |
129 | ||
0f507f01 AK |
130 | |
131 | void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds) { | |
132 | ||
133 | } |