Hello, I am currently trying to program a WS2812B LED matrix using output compare. There's 256 LEDs, and each LED is controlled by 24 bits. However, it has somewhat strict timing requirements, and my current code is not efficient enough. The LEDs are resetting after about half of the LEDs are lit up. I am new to programming and I am wondering if I can get some advice on how I can improve my code or improve the timing? Thank you!


#include <stdbool.h>
#include <stdint.h>
void outputBit(int value) {
if (value == 1) {
/* Pin high for approx. 0.8 us, then go low for 0.45 us */
NRF_P0->OUTSET = (1UL << 27); // Set pin to high
NRF_TIMER0->CC[0] = 6;
NRF_TIMER0->TASKS_START = 1; // Starts the clock signal
while (!(NRF_TIMER0->EVENTS_COMPARE[0])); // Wait for event to occur
NRF_TIMER0->TASKS_STOP = 1; // Starts the clock signal
NRF_TIMER0->CC[0] = 4;
NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the event
NRF_TIMER0->TASKS_START = 1; // Starts the clock signal
while (!(NRF_TIMER0->EVENTS_COMPARE[0])); // Wait for event to occur
NRF_TIMER0->TASKS_STOP = 1; // Starts the clock signal
NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the event
} else {
/* Pin high for approx. 0.35 us, then go low for 0.85 us */
NRF_P0->OUTSET = (1UL << 27); // Set pin to high
NRF_TIMER0->CC[0] = 3;
NRF_TIMER0->TASKS_START = 1; // Starts the clock signal
while (!(NRF_TIMER0->EVENTS_COMPARE[0])); // Wait for event to occur
NRF_TIMER0->TASKS_STOP = 1; // Starts the clock signal
NRF_TIMER0->CC[0] = 7;
NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the event
NRF_TIMER0->TASKS_START = 1; // Starts the clock signal
while (!(NRF_TIMER0->EVENTS_COMPARE[0])); // Wait for event to occur
NRF_TIMER0->TASKS_STOP = 1; // Starts the clock signal
NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the event
}
}
int main(void) {
NRF_P0->PIN_CNF[27] = (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
(GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
(GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
(GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
(GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
// Enable high frequency oscillator if not already enabled
if (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
}
}
NRF_TIMER0->PRESCALER = 1; // 8MHz
NRF_TIMER0->BITMODE = 0;
NRF_TIMER0->SHORTS |= (1UL << 0); // Automatically clear the count whenever an event is triggered
NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Task | (27 << GPIOTE_CONFIG_PSEL_Pos) |
(GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos);
/*Connect TIMER event to GPIOTE out task*/
NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER0->EVENTS_COMPARE[0];
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
NRF_PPI->CHENSET |= (1UL << 0);
NRF_TIMER0->EVENTS_COMPARE[0] = 0; // Clear the event
for (int i = 0; i < 6144; ++i) {
outputBit(1);
}
}