1 | /** Function for One-Wire Neo-Pixels RGBW (GRBW) (here 16Mhz)**/
|
2 | /** Function has to be called within 5µs from last call, otherwise data is latched**/
|
3 | /** An array of 4 bytes would be more performant, but this is more human readable **/
|
4 | void LED_sendNeoPixelRGBW(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
5 | {
|
6 | uint8_t register byte; //The Data to transmit
|
7 | for(uint8_t color=0; color<4; color++)
|
8 | {
|
9 | switch(color) //If you need every tick, change r g b w to an array (GRBW!)
|
10 | {
|
11 | case 0:
|
12 | byte=g;
|
13 | break;
|
14 | case 1:
|
15 | byte=r;
|
16 | break;
|
17 | case 2:
|
18 | byte=b;
|
19 | break;
|
20 | case 3:
|
21 | byte=w;
|
22 | break;
|
23 | }
|
24 | for(uint8_t bit=0; bit<8; bit++)
|
25 | {
|
26 | //Check MSB of byte to transfer
|
27 | if((byte&0b10000000)==0) //Bit is zero //400ns +/- 150ns 6Ticks @16Mhz /3 Ticks @8Mhz
|
28 | {
|
29 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) //This is the critical section and timing is very important
|
30 | {
|
31 | asm volatile("/*T0H 400+/-150ns*/" "\n\t"
|
32 | "sbi 0x18,1 /*Set Pin High*/" "\n\t" //(PORTB|=(1<<PB1);
|
33 | "nop /*125 @16Mhz / 250ns@8Mhz*/" "\n\t"
|
34 | "nop /*187,5@16Mhz / 375ns@8Mhz*/" "\n\t"
|
35 | "nop /*250 @16Mhz / 500ns@8Mhz*/" "\n\t"
|
36 | "nop /*312,5@16Mhz / 625ns@8Mhz*/" "\n\t"
|
37 | "cbi 0x18,1 /*Set Pin Low*/"); //PORTB&=(uint8_t)(~(1<<PB1));
|
38 | }
|
39 | }
|
40 | else //Bit is one //850 +/- 150ns
|
41 | {
|
42 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) //Not so critical section, but we want fo follow timing from datasheet
|
43 | {
|
44 | asm volatile("/*T1H 850+/-150ns*/" "\n\t"
|
45 | "sbi 0x18,1 /*Set Pin High*/" "\n\t" //(PORTB|=(1<<PB1);
|
46 | "nop /*125 @16Mhz / 250ns@8Mhz*/" "\n\t"
|
47 | "nop /*187,5@16Mhz / 375ns@8Mhz*/" "\n\t"
|
48 | "nop /*250 @16Mhz / 500ns@8Mhz*/" "\n\t"
|
49 | "nop /*312,5@16Mhz / 625ns@8Mhz*/" "\n\t"
|
50 | "nop /*375 @16Mhz / 750ns@8Mhz*/" "\n\t"
|
51 | "nop /*437,5@16Mhz / 875ns@8Mhz*/" "\n\t"
|
52 | "nop /*500 @16Mhz / 1000ns@8Mhz*/" "\n\t"
|
53 | "nop /*562,5@16Mhz / 1125ns@8Mhz*/" "\n\t"
|
54 | "nop /*625 @16Mhz / 1250ns@8Mhz*/" "\n\t"
|
55 | "nop /*687,5@16Mhz / 1375ns@8Mhz*/" "\n\t"
|
56 | "nop /*750 @16Mhz / 1500ns@8Mhz*/" "\n\t"
|
57 | "cbi 0x18,1 /*Set Pin Low*/"); //PORTB&=(uint8_t)(~(1<<PB1));
|
58 | }
|
59 | }
|
60 | /*Uncritical section, just make sure that data line lowtime is long enough, here you can fire interrupts,
|
61 | but please come back within 5µs-"nops" */
|
62 | byte<<=1; //Shift left for new MSB
|
63 | asm volatile("/*T0_1L 850+/-150ns*/" "\n\t"
|
64 | "nop /* 62,5@16Mhz / 125ns@8Mhz*/" "\n\t"
|
65 | "nop /*125 @16Mhz / 250ns@8Mhz*/" "\n\t"
|
66 | "nop /*187,5@16Mhz / 375ns@8Mhz*/" "\n\t"
|
67 | "nop /*250 @16Mhz / 500ns@8Mhz*/" "\n\t"
|
68 | "nop /*312,5@16Mhz / 625ns@8Mhz*/" "\n\t"
|
69 | "nop /*375 @16Mhz / 750ns@8Mhz*/" "\n\t"
|
70 | "nop /*437,5@16Mhz / 875ns@8Mhz*/" "\n\t"
|
71 | "nop /*500 @16Mhz / 1000ns@8Mhz*/" "\n\t"
|
72 | "nop /*562,5@16Mhz / 1125ns@8Mhz*/" "\n\t");
|
73 | }
|
74 | }
|
75 | }
|