aboutsummaryrefslogtreecommitdiff
path: root/drivers/avr/ws2812.c
diff options
context:
space:
mode:
authorskullY <skullydazed@gmail.com>2019-08-30 11:19:03 -0700
committerskullydazed <skullydazed@users.noreply.github.com>2019-08-30 15:01:52 -0700
commitb624f32f944acdc59dcb130674c09090c5c404cb (patch)
treebc13adbba137d122d9a2c2fb2fafcbb08ac10e25 /drivers/avr/ws2812.c
parent61af76a10d00aba185b8338604171de490a13e3b (diff)
downloadqmk_firmware-b624f32f944acdc59dcb130674c09090c5c404cb.tar.gz
qmk_firmware-b624f32f944acdc59dcb130674c09090c5c404cb.zip
clang-format changes
Diffstat (limited to 'drivers/avr/ws2812.c')
-rw-r--r--drivers/avr/ws2812.c384
1 files changed, 179 insertions, 205 deletions
diff --git a/drivers/avr/ws2812.c b/drivers/avr/ws2812.c
index 7c3cb5174..0a02c6f7f 100644
--- a/drivers/avr/ws2812.c
+++ b/drivers/avr/ws2812.c
@@ -1,25 +1,25 @@
1/* 1/*
2* light weight WS2812 lib V2.0b 2 * light weight WS2812 lib V2.0b
3* 3 *
4* Controls WS2811/WS2812/WS2812B RGB-LEDs 4 * Controls WS2811/WS2812/WS2812B RGB-LEDs
5* Author: Tim (cpldcpu@gmail.com) 5 * Author: Tim (cpldcpu@gmail.com)
6* 6 *
7* Jan 18th, 2014 v2.0b Initial Version 7 * Jan 18th, 2014 v2.0b Initial Version
8* Nov 29th, 2015 v2.3 Added SK6812RGBW support 8 * Nov 29th, 2015 v2.3 Added SK6812RGBW support
9* 9 *
10* This program is free software: you can redistribute it and/or modify 10 * This program is free software: you can redistribute it and/or modify
11* it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
12* the Free Software Foundation, either version 2 of the License, or 12 * the Free Software Foundation, either version 2 of the License, or
13* (at your option) any later version. 13 * (at your option) any later version.
14* 14 *
15* This program is distributed in the hope that it will be useful, 15 * This program is distributed in the hope that it will be useful,
16* but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18* GNU General Public License for more details. 18 * GNU General Public License for more details.
19* 19 *
20* You should have received a copy of the GNU General Public License 20 * You should have received a copy of the GNU General Public License
21* along with this program. If not, see <http://www.gnu.org/licenses/>. 21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/ 22 */
23 23
24#include "ws2812.h" 24#include "ws2812.h"
25#include <avr/interrupt.h> 25#include <avr/interrupt.h>
@@ -30,44 +30,40 @@
30#if !defined(LED_ARRAY) && defined(RGB_MATRIX_ENABLE) 30#if !defined(LED_ARRAY) && defined(RGB_MATRIX_ENABLE)
31// LED color buffer 31// LED color buffer
32LED_TYPE led[DRIVER_LED_TOTAL]; 32LED_TYPE led[DRIVER_LED_TOTAL];
33 #define LED_ARRAY led 33# define LED_ARRAY led
34#endif 34#endif
35 35
36#ifdef RGBW_BB_TWI 36#ifdef RGBW_BB_TWI
37 37
38// Port for the I2C 38// Port for the I2C
39#define I2C_DDR DDRD 39# define I2C_DDR DDRD
40#define I2C_PIN PIND 40# define I2C_PIN PIND
41#define I2C_PORT PORTD 41# define I2C_PORT PORTD
42 42
43// Pins to be used in the bit banging 43// Pins to be used in the bit banging
44#define I2C_CLK 0 44# define I2C_CLK 0
45#define I2C_DAT 1 45# define I2C_DAT 1
46 46
47#define I2C_DATA_HI()\ 47# define I2C_DATA_HI() \
48I2C_DDR &= ~ (1 << I2C_DAT);\ 48 I2C_DDR &= ~(1 << I2C_DAT); \
49I2C_PORT |= (1 << I2C_DAT); 49 I2C_PORT |= (1 << I2C_DAT);
50#define I2C_DATA_LO()\ 50# define I2C_DATA_LO() \
51I2C_DDR |= (1 << I2C_DAT);\ 51 I2C_DDR |= (1 << I2C_DAT); \
52I2C_PORT &= ~ (1 << I2C_DAT); 52 I2C_PORT &= ~(1 << I2C_DAT);
53 53
54#define I2C_CLOCK_HI()\ 54# define I2C_CLOCK_HI() \
55I2C_DDR &= ~ (1 << I2C_CLK);\ 55 I2C_DDR &= ~(1 << I2C_CLK); \
56I2C_PORT |= (1 << I2C_CLK); 56 I2C_PORT |= (1 << I2C_CLK);
57#define I2C_CLOCK_LO()\ 57# define I2C_CLOCK_LO() \
58I2C_DDR |= (1 << I2C_CLK);\ 58 I2C_DDR |= (1 << I2C_CLK); \
59I2C_PORT &= ~ (1 << I2C_CLK); 59 I2C_PORT &= ~(1 << I2C_CLK);
60 60
61#define I2C_DELAY 1 61# define I2C_DELAY 1
62 62
63void I2C_WriteBit(unsigned char c) 63void I2C_WriteBit(unsigned char c) {
64{ 64 if (c > 0) {
65 if (c > 0)
66 {
67 I2C_DATA_HI(); 65 I2C_DATA_HI();
68 } 66 } else {
69 else
70 {
71 I2C_DATA_LO(); 67 I2C_DATA_LO();
72 } 68 }
73 69
@@ -77,8 +73,7 @@ void I2C_WriteBit(unsigned char c)
77 I2C_CLOCK_LO(); 73 I2C_CLOCK_LO();
78 _delay_us(I2C_DELAY); 74 _delay_us(I2C_DELAY);
79 75
80 if (c > 0) 76 if (c > 0) {
81 {
82 I2C_DATA_LO(); 77 I2C_DATA_LO();
83 } 78 }
84 79
@@ -87,9 +82,8 @@ void I2C_WriteBit(unsigned char c)
87 82
88// Inits bitbanging port, must be called before using the functions below 83// Inits bitbanging port, must be called before using the functions below
89// 84//
90void I2C_Init(void) 85void I2C_Init(void) {
91{ 86 I2C_PORT &= ~((1 << I2C_DAT) | (1 << I2C_CLK));
92 I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK));
93 87
94 I2C_CLOCK_HI(); 88 I2C_CLOCK_HI();
95 I2C_DATA_HI(); 89 I2C_DATA_HI();
@@ -99,10 +93,9 @@ void I2C_Init(void)
99 93
100// Send a START Condition 94// Send a START Condition
101// 95//
102void I2C_Start(void) 96void I2C_Start(void) {
103{
104 // set both to high at the same time 97 // set both to high at the same time
105 I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); 98 I2C_DDR &= ~((1 << I2C_DAT) | (1 << I2C_CLK));
106 _delay_us(I2C_DELAY); 99 _delay_us(I2C_DELAY);
107 100
108 I2C_DATA_LO(); 101 I2C_DATA_LO();
@@ -114,8 +107,7 @@ void I2C_Start(void)
114 107
115// Send a STOP Condition 108// Send a STOP Condition
116// 109//
117void I2C_Stop(void) 110void I2C_Stop(void) {
118{
119 I2C_CLOCK_HI(); 111 I2C_CLOCK_HI();
120 _delay_us(I2C_DELAY); 112 _delay_us(I2C_DELAY);
121 113
@@ -125,106 +117,91 @@ void I2C_Stop(void)
125 117
126// write a byte to the I2C slave device 118// write a byte to the I2C slave device
127// 119//
128unsigned char I2C_Write(unsigned char c) 120unsigned char I2C_Write(unsigned char c) {
129{ 121 for (char i = 0; i < 8; i++) {
130 for (char i = 0; i < 8; i++)
131 {
132 I2C_WriteBit(c & 128); 122 I2C_WriteBit(c & 128);
133 123
134 c <<= 1; 124 c <<= 1;
135 } 125 }
136 126
137
138 I2C_WriteBit(0); 127 I2C_WriteBit(0);
139 _delay_us(I2C_DELAY); 128 _delay_us(I2C_DELAY);
140 _delay_us(I2C_DELAY); 129 _delay_us(I2C_DELAY);
141 130
142 // _delay_us(I2C_DELAY); 131 // _delay_us(I2C_DELAY);
143 //return I2C_ReadBit(); 132 // return I2C_ReadBit();
144 return 0; 133 return 0;
145} 134}
146 135
147
148#endif 136#endif
149 137
150#ifdef RGB_MATRIX_ENABLE 138#ifdef RGB_MATRIX_ENABLE
151// Set an led in the buffer to a color 139// Set an led in the buffer to a color
152void inline ws2812_setled(int i, uint8_t r, uint8_t g, uint8_t b) 140void inline ws2812_setled(int i, uint8_t r, uint8_t g, uint8_t b) {
153{
154 led[i].r = r; 141 led[i].r = r;
155 led[i].g = g; 142 led[i].g = g;
156 led[i].b = b; 143 led[i].b = b;
157} 144}
158 145
159void ws2812_setled_all (uint8_t r, uint8_t g, uint8_t b) 146void ws2812_setled_all(uint8_t r, uint8_t g, uint8_t b) {
160{ 147 for (int i = 0; i < sizeof(led) / sizeof(led[0]); i++) {
161 for (int i = 0; i < sizeof(led)/sizeof(led[0]); i++) { 148 led[i].r = r;
162 led[i].r = r; 149 led[i].g = g;
163 led[i].g = g; 150 led[i].b = b;
164 led[i].b = b; 151 }
165 }
166} 152}
167#endif 153#endif
168 154
169// Setleds for standard RGB 155// Setleds for standard RGB
170void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) 156void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
171{ 157 // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
172 // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); 158 ws2812_setleds_pin(ledarray, leds, _BV(RGB_DI_PIN & 0xF));
173 ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF));
174} 159}
175 160
176void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) 161void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) {
177{ 162 // ws2812_DDRREG |= pinmask; // Enable DDR
178 // ws2812_DDRREG |= pinmask; // Enable DDR 163 // new universal format (DDR)
179 // new universal format (DDR) 164 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
180 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
181 165
182 ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); 166 ws2812_sendarray_mask((uint8_t *)ledarray, leds + leds + leds, pinmask);
183 _delay_us(50); 167 _delay_us(50);
184} 168}
185 169
186// Setleds for SK6812RGBW 170// Setleds for SK6812RGBW
187void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) 171void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) {
188{ 172#ifdef RGBW_BB_TWI
189
190 #ifdef RGBW_BB_TWI
191 uint8_t sreg_prev, twcr_prev; 173 uint8_t sreg_prev, twcr_prev;
192 sreg_prev=SREG; 174 sreg_prev = SREG;
193 twcr_prev=TWCR; 175 twcr_prev = TWCR;
194 cli(); 176 cli();
195 TWCR &= ~(1<<TWEN); 177 TWCR &= ~(1 << TWEN);
196 I2C_Init(); 178 I2C_Init();
197 I2C_Start(); 179 I2C_Start();
198 I2C_Write(0x84); 180 I2C_Write(0x84);
199 uint16_t datlen = leds<<2; 181 uint16_t datlen = leds << 2;
200 uint8_t curbyte; 182 uint8_t curbyte;
201 uint8_t * data = (uint8_t*)ledarray; 183 uint8_t *data = (uint8_t *)ledarray;
202 while (datlen--) { 184 while (datlen--) {
203 curbyte=*data++; 185 curbyte = *data++;
204 I2C_Write(curbyte); 186 I2C_Write(curbyte);
205 } 187 }
206 I2C_Stop(); 188 I2C_Stop();
207 SREG=sreg_prev; 189 SREG = sreg_prev;
208 TWCR=twcr_prev; 190 TWCR = twcr_prev;
209 #endif 191#endif
210
211
212 // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
213 // new universal format (DDR)
214 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
215 192
216 ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF)); 193 // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
194 // new universal format (DDR)
195 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
217 196
197 ws2812_sendarray_mask((uint8_t *)ledarray, leds << 2, _BV(RGB_DI_PIN & 0xF));
218 198
219 #ifndef RGBW_BB_TWI 199#ifndef RGBW_BB_TWI
220 _delay_us(80); 200 _delay_us(80);
221 #endif 201#endif
222} 202}
223 203
224void ws2812_sendarray(uint8_t *data,uint16_t datlen) 204void ws2812_sendarray(uint8_t *data, uint16_t datlen) { ws2812_sendarray_mask(data, datlen, _BV(RGB_DI_PIN & 0xF)); }
225{
226 ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF));
227}
228 205
229/* 206/*
230 This routine writes an array of bytes with RGB values to the Dataout pin 207 This routine writes an array of bytes with RGB values to the Dataout pin
@@ -232,136 +209,133 @@ void ws2812_sendarray(uint8_t *data,uint16_t datlen)
232*/ 209*/
233 210
234// Timing in ns 211// Timing in ns
235#define w_zeropulse 350 212#define w_zeropulse 350
236#define w_onepulse 900 213#define w_onepulse 900
237#define w_totalperiod 1250 214#define w_totalperiod 1250
238 215
239// Fixed cycles used by the inner loop 216// Fixed cycles used by the inner loop
240#define w_fixedlow 2 217#define w_fixedlow 2
241#define w_fixedhigh 4 218#define w_fixedhigh 4
242#define w_fixedtotal 8 219#define w_fixedtotal 8
243 220
244// Insert NOPs to match the timing, if possible 221// Insert NOPs to match the timing, if possible
245#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000) 222#define w_zerocycles (((F_CPU / 1000) * w_zeropulse) / 1000000)
246#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000) 223#define w_onecycles (((F_CPU / 1000) * w_onepulse + 500000) / 1000000)
247#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000) 224#define w_totalcycles (((F_CPU / 1000) * w_totalperiod + 500000) / 1000000)
248 225
249// w1 - nops between rising edge and falling edge - low 226// w1 - nops between rising edge and falling edge - low
250#define w1 (w_zerocycles-w_fixedlow) 227#define w1 (w_zerocycles - w_fixedlow)
251// w2 nops between fe low and fe high 228// w2 nops between fe low and fe high
252#define w2 (w_onecycles-w_fixedhigh-w1) 229#define w2 (w_onecycles - w_fixedhigh - w1)
253// w3 nops to complete loop 230// w3 nops to complete loop
254#define w3 (w_totalcycles-w_fixedtotal-w1-w2) 231#define w3 (w_totalcycles - w_fixedtotal - w1 - w2)
255 232
256#if w1>0 233#if w1 > 0
257 #define w1_nops w1 234# define w1_nops w1
258#else 235#else
259 #define w1_nops 0 236# define w1_nops 0
260#endif 237#endif
261 238
262// The only critical timing parameter is the minimum pulse length of the "0" 239// The only critical timing parameter is the minimum pulse length of the "0"
263// Warn or throw error if this timing can not be met with current F_CPU settings. 240// Warn or throw error if this timing can not be met with current F_CPU settings.
264#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000) 241#define w_lowtime ((w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000)
265#if w_lowtime>550 242#if w_lowtime > 550
266 #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" 243# error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
267#elif w_lowtime>450 244#elif w_lowtime > 450
268 #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." 245# warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
269 #warning "Please consider a higher clockspeed, if possible" 246# warning "Please consider a higher clockspeed, if possible"
270#endif 247#endif
271 248
272#if w2>0 249#if w2 > 0
273#define w2_nops w2 250# define w2_nops w2
274#else 251#else
275#define w2_nops 0 252# define w2_nops 0
276#endif 253#endif
277 254
278#if w3>0 255#if w3 > 0
279#define w3_nops w3 256# define w3_nops w3
280#else 257#else
281#define w3_nops 0 258# define w3_nops 0
282#endif 259#endif
283 260
284#define w_nop1 "nop \n\t" 261#define w_nop1 "nop \n\t"
285#define w_nop2 "rjmp .+0 \n\t" 262#define w_nop2 "rjmp .+0 \n\t"
286#define w_nop4 w_nop2 w_nop2 263#define w_nop4 w_nop2 w_nop2
287#define w_nop8 w_nop4 w_nop4 264#define w_nop8 w_nop4 w_nop4
288#define w_nop16 w_nop8 w_nop8 265#define w_nop16 w_nop8 w_nop8
289 266
290void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) 267void inline ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t maskhi) {
291{ 268 uint8_t curbyte, ctr, masklo;
292 uint8_t curbyte,ctr,masklo; 269 uint8_t sreg_prev;
293 uint8_t sreg_prev; 270
294 271 // masklo =~maskhi&ws2812_PORTREG;
295 // masklo =~maskhi&ws2812_PORTREG; 272 // maskhi |= ws2812_PORTREG;
296 // maskhi |= ws2812_PORTREG; 273 masklo = ~maskhi & _SFR_IO8((RGB_DI_PIN >> 4) + 2);
297 masklo =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2); 274 maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2);
298 maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2); 275 sreg_prev = SREG;
299 sreg_prev=SREG; 276 cli();
300 cli(); 277
301 278 while (datlen--) {
302 while (datlen--) { 279 curbyte = (*data++);
303 curbyte=(*data++); 280
304 281 asm volatile(" ldi %0,8 \n\t"
305 asm volatile( 282 "loop%=: \n\t"
306 " ldi %0,8 \n\t" 283 " out %2,%3 \n\t" // '1' [01] '0' [01] - re
307 "loop%=: \n\t" 284#if (w1_nops & 1)
308 " out %2,%3 \n\t" // '1' [01] '0' [01] - re 285 w_nop1
309#if (w1_nops&1)
310w_nop1
311#endif 286#endif
312#if (w1_nops&2) 287#if (w1_nops & 2)
313w_nop2 288 w_nop2
314#endif 289#endif
315#if (w1_nops&4) 290#if (w1_nops & 4)
316w_nop4 291 w_nop4
317#endif 292#endif
318#if (w1_nops&8) 293#if (w1_nops & 8)
319w_nop8 294 w_nop8
320#endif 295#endif
321#if (w1_nops&16) 296#if (w1_nops & 16)
322w_nop16 297 w_nop16
323#endif 298#endif
324 " sbrs %1,7 \n\t" // '1' [03] '0' [02] 299 " sbrs %1,7 \n\t" // '1' [03] '0' [02]
325 " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low 300 " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
326 " lsl %1 \n\t" // '1' [04] '0' [04] 301 " lsl %1 \n\t" // '1' [04] '0' [04]
327#if (w2_nops&1) 302#if (w2_nops & 1)
328 w_nop1 303 w_nop1
329#endif 304#endif
330#if (w2_nops&2) 305#if (w2_nops & 2)
331 w_nop2 306 w_nop2
332#endif 307#endif
333#if (w2_nops&4) 308#if (w2_nops & 4)
334 w_nop4 309 w_nop4
335#endif 310#endif
336#if (w2_nops&8) 311#if (w2_nops & 8)
337 w_nop8 312 w_nop8
338#endif 313#endif
339#if (w2_nops&16) 314#if (w2_nops & 16)
340 w_nop16 315 w_nop16
341#endif 316#endif
342 " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high 317 " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
343#if (w3_nops&1) 318#if (w3_nops & 1)
344w_nop1 319 w_nop1
345#endif 320#endif
346#if (w3_nops&2) 321#if (w3_nops & 2)
347w_nop2 322 w_nop2
348#endif 323#endif
349#if (w3_nops&4) 324#if (w3_nops & 4)
350w_nop4 325 w_nop4
351#endif 326#endif
352#if (w3_nops&8) 327#if (w3_nops & 8)
353w_nop8 328 w_nop8
354#endif 329#endif
355#if (w3_nops&16) 330#if (w3_nops & 16)
356w_nop16 331 w_nop16
357#endif 332#endif
358 333
359 " dec %0 \n\t" // '1' [+2] '0' [+2] 334 " dec %0 \n\t" // '1' [+2] '0' [+2]
360 " brne loop%=\n\t" // '1' [+3] '0' [+4] 335 " brne loop%=\n\t" // '1' [+3] '0' [+4]
361 : "=&d" (ctr) 336 : "=&d"(ctr)
362 : "r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo) 337 : "r"(curbyte), "I"(_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r"(maskhi), "r"(masklo));
363 ); 338 }
364 }
365 339
366 SREG=sreg_prev; 340 SREG = sreg_prev;
367} 341}