/* * WS281x LED Strip Driver for PRU0 * Vixy's Mood Strip - 56 LEDs * * Pin: P8_11 = pr1_pru0_pru_r30_15 (Mode 6) * Alternative: P9_27 = pr1_pru0_pru_r30_5 (Mode 5) - FREE PIN! * * Shared Memory Layout (0x00010000): * [0]: num_leds (max 56) * [1]: trigger (write 1 to update) * [4-171]: LED data (56 * 3 bytes, GRB format) */ #include #include /* Use P9_27 (R30 bit 5) - it's free! */ #define LED_PIN 5 #define NUM_LEDS 56 /* WS2812 timing at 200MHz (5ns per cycle) */ #define T0H 70 /* 350ns high for 0 bit */ #define T0L 160 /* 800ns low for 0 bit */ #define T1H 140 /* 700ns high for 1 bit */ #define T1L 120 /* 600ns low for 1 bit */ /* Shared memory base */ #define SHARED_MEM 0x00010000 volatile uint8_t *shared = (volatile uint8_t *)SHARED_MEM; volatile register uint32_t __R30; static inline void delay_cycles(uint32_t cycles) { while (cycles--) { __asm(" NOP"); } } static void send_bit(uint8_t bit) { if (bit) { __R30 |= (1 << LED_PIN); delay_cycles(T1H); __R30 &= ~(1 << LED_PIN); delay_cycles(T1L); } else { __R30 |= (1 << LED_PIN); delay_cycles(T0H); __R30 &= ~(1 << LED_PIN); delay_cycles(T0L); } } static void send_byte(uint8_t byte) { for (int i = 7; i >= 0; i--) { send_bit((byte >> i) & 1); } } static void send_led(uint8_t g, uint8_t r, uint8_t b) { send_byte(g); send_byte(r); send_byte(b); } void main(void) { /* Enable OCP master port */ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; /* Clear output pin */ __R30 &= ~(1 << LED_PIN); while (1) { /* Check trigger flag */ if (shared[1] == 1) { uint8_t num = shared[0]; if (num > NUM_LEDS) num = NUM_LEDS; /* Send LED data (GRB format) */ for (int i = 0; i < num; i++) { uint8_t g = shared[4 + i * 3 + 0]; uint8_t r = shared[4 + i * 3 + 1]; uint8_t b = shared[4 + i * 3 + 2]; send_led(g, r, b); } /* Reset pulse (>50us) */ __R30 &= ~(1 << LED_PIN); delay_cycles(10000); /* Clear trigger */ shared[1] = 0; } } }