Initial commit: PRU LED firmware and HTTP service
- Combined PRU0 firmware for both mood (56 LED) and jaw (24 LED) strips - Uses P9_27 and P9_25 (free pins, not HDMI locked) - Python HTTP service on port 8765 - Named states: idle, listening, responding, pleasure, thinking, playful, commanding, love, sleep - Setup scripts for fresh BBB deployment Built with love by Vixy 🦊💜
This commit is contained in:
94
pru/ws281x_pru0.c
Normal file
94
pru/ws281x_pru0.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <pru_cfg.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user