| 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 | } |