Skip to content

Instantly share code, notes, and snippets.

@stnolting

stnolting/main.c

Created Feb 26, 2021
Embed
What would you like to do?
test program for the WS2812 hardware interface
// WS2812 LED hardware interface test
// channel 0: 12-LED RGB NEOpixel (24-bit) ring
// channel 1: 8-LED RGBW NEOpixel (32-bit) strip
#include <neorv32.h>
// The hardware interface is implemented as NEORV32 "custom functions subsystem (CFS)"
// CFS_REG_0 is the control register
// CFS_REG_1 is the data transmit register
#define WS2812_CONTROL (CFS_REG_0)
#define WS2812_DATA (CFS_REG_1)
// control register bits
#define WS2812_CT_ENABLE (0) // 1-bit enable flag (r/w)
#define WS2812_CT_MODE (1) // 1-bit mode flag (r/w)
#define WS2812_CT_PRSC (2) // 3-bit prescaler select (r/w)
#define WS2812_CT_CHMASK (5) // 4-bit value (r/w)
#define WS2812_CT_T_TOTAL (10) // 5-bit value (r/w)
#define WS2812_CT_T_T0HIGH (15) // 5-bit value (r/w)
#define WS2812_CT_T_T1HIGH (20) // 5-bit value (r/w)
#define WS2812_CT_BUSY (31) // 1-bit busy flag (r/-)
// configuration
#define UART_BAUD_RATE (19200)
#define NUM_LEDS_CH0 (8)
#define NUM_LEDS_CH1 (12)
// prototypes
void send_data(uint32_t channel, uint32_t mode, uint32_t data);
int main() {
// capture all exceptions and give debug info via UART
// this is not required, but keeps us safe
neorv32_rte_setup();
// init UART0 at default baud rate, no parity bits, no hw flow control
neorv32_uart0_setup(UART_BAUD_RATE, 0, 0);
neorv32_uart0_print("WS2812 LED test\n");
// initialize LED driver module
WS2812_CONTROL = 0; // reset
// static configuration for f_cpu = 100MHz
uint32_t ctrl = 0;
ctrl |= 0b1 << WS2812_CT_ENABLE; // enable ws2812 hardware module
ctrl |= 0b0 << WS2812_CT_MODE; // mode (0=24-bit, 1=32-bit)
ctrl |= 0b010 << WS2812_CT_PRSC; // prsc = 2 -> f_clk = f_cpu/8 -> T_clk = 80ns
ctrl |= 0b01111 << WS2812_CT_T_TOTAL; // T_total = T_clk * 15 = 1.2us
ctrl |= 0b00100 << WS2812_CT_T_T0HIGH; // T_0_high = T_clk * 4 = 0.32us
ctrl |= 0b01001 << WS2812_CT_T_T1HIGH; // T_1_high = T_clk * 9 = 0.72us
WS2812_CONTROL = ctrl;
// clear all LEDs
neorv32_uart0_print("Clearing LEDs...\n");
int i;
for (i=0; i<(NUM_LEDS_CH0+NUM_LEDS_CH1); i++) { // just send a lot of zeros to both channels
send_data(1, 1, 0);
send_data(0, 0, 0);
}
neorv32_cpu_delay_ms(1000);
neorv32_uart0_print("Starting animation.\n");
int led_id_ch0 = 0, flash_position = 0, flash_direction = -1;
int led_id_ch1 = 0, circle_position = 0;
uint32_t circle_color = 0x00000004;
while (1) {
// RGBW LEDs: knight rider!
if ((flash_position == (NUM_LEDS_CH0-1)) || (flash_position == 0)) {
flash_direction = -flash_direction;
}
for (led_id_ch0=0; led_id_ch0<NUM_LEDS_CH0; led_id_ch0++) {
if (led_id_ch0 == flash_position) {
send_data(1, 1, 0x00000004); // warm white dot
}
else {
send_data(1, 1, 0); // LED off
}
}
flash_position += flash_direction;
// RGB LEDs: turning circle, changes color after each completed cycle
if (circle_position == (NUM_LEDS_CH1-1)) {
circle_position = 0;
circle_color = (circle_color << 8) | ((circle_color >> 16) & 0xff);
}
else {
circle_position++;
}
for (led_id_ch1=0; led_id_ch1<NUM_LEDS_CH1; led_id_ch1++) {
if (led_id_ch1 == circle_position) {
send_data(0, 0, circle_color);
}
else {
send_data(0, 0, 0); // LED off
}
}
// delay between frames; also used to "send" ws2812.reset command
neorv32_cpu_delay_ms(100);
}
return 0;
}
void send_data(uint32_t channel, uint32_t mode, uint32_t data) {
uint32_t channel_int = channel & 3; // new channel select
uint32_t mode_int = mode & 1; // RGB (24-bit) or RGBW (32-bit) mode
while(WS2812_CONTROL & (1 << WS2812_CT_BUSY)); // polling (FIXME!): wait for busy flag to clear
uint32_t ctrl = WS2812_CONTROL;
ctrl &= ~(0b1111 << WS2812_CT_CHMASK); // clear current channel selection
ctrl &= ~(0b1 << WS2812_CT_MODE); // clear current mode
ctrl |= (0b1 << (channel_int + WS2812_CT_CHMASK)); // set new channel enable
ctrl |= (mode_int << WS2812_CT_MODE); // set new mode
WS2812_CONTROL = ctrl;
WS2812_DATA = data; // send new LED data
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment