Initial import of v2 goggles that use ws2812 rings from adafruit
[goggles] / ws2811.c
1 #include <stdint.h>
2 #include <stdbool.h>
3
4 #include "user.h"
5
6 #include "ws2811.h"
7
8 /* this holds the G R B bytes for the entire string */
9 unsigned char rgbdata[RGB_COUNT];
10
11
12 /* These values are placed in common memory so that they can be accessed
13  * quickly without a bank switch by the routines below, THIS IS IMPORTANT,
14  * it will not run properly without it */
15 volatile uint8_t rgb_sample @ 0x7B;
16 volatile uint8_t rgb_byte @ 0x7C;
17 volatile uint8_t rgb_bit @ 0x7D;
18
19 // send the whole pile of data
20 static void ws2811_send(void)
21 {
22 #asm
23     // copy the led colour array location into FSR0 for fast access
24     MOVLW HIGH _rgbdata
25     MOVWF FSR0H
26     MOVLW LOW _rgbdata
27     MOVWF FSR0L
28
29     // load next byte from array into working reg
30 ws2811_nextbyte:
31     MOVIW FSR0++
32     MOVWF _rgb_sample
33     MOVLW 8 // reset bit count
34     MOVWF _rgb_bit
35
36 ws2811_sendbit:
37     // you assume its a zero then test if its one
38 //    MOVLW 0xC0 ;11000000B
39     MOVLW 0x80 ;10000000B
40     
41     RLF _rgb_sample,f
42     BTFSC STATUS,0  // CARRY
43     //asm("MOVLW 0xF8 "); // 11111000B
44     MOVLW 0xF0      // 11110000B
45
46     BANKSEL (SSP1BUF)
47     MOVWF BANKMASK(SSP1BUF)
48
49     // any more bits
50     DECFSZ _rgb_bit,f
51     BRA ws2811_delay
52
53     // any more bytes
54     DECFSZ _rgb_byte,f
55     BRA ws2811_nextbyte
56     BRA ws2811_end
57
58 ws2811_delay:
59     NOP
60     NOP
61     NOP
62     BRA ws2811_sendbit
63
64 ws2811_end:
65
66
67 #endasm
68
69     // all done
70 }
71
72 #if _XTAL_FREQ != 32000000L
73 #error "This code requires 32MHz system clock or above"
74 #endif
75
76 void ws2811_init(void)
77 {
78     // SPI is on RA0
79     TRISAbits.TRISA0 = 0; // SDO is RA0
80     ANSELAbits.ANSA0 = 0; // not analog
81
82     // SCK (SPI Clock) is RA1
83     // SDI (SPI In) is RA2
84     APFCONbits.SDOSEL = 0; // use RA0 not RA4 for output
85
86     // at 8MHz Tclk   0 = 2 bits, 1 = 6 bits.
87     // write to SSP1BUF
88     SSP1CON1bits.SSPM = 0b0000; // SPI Master Fosc/4
89     SSP1CON1bits.SSPEN = 1; // enable MSSP
90 }
91
92 void ws2811_transmit(void)
93 {
94     rgb_byte = RGB_COUNT;
95     ws2811_send(); // send the first bit
96 }