/*** Neopixels ***/
#define NPIX_PERIOD 90 // timer runs on 72 MHz, so 90 periods = 1250 ns
-#define NPIX_RESET 128 // the chip needs longer reset pulse than documented
#define NPIX_NUM_LEDS 64
+#define NPIX_RESET 6 // length of reset pulse in LED slots
+ // The chip needs longer reset pulse than documented.
#define B0 30
#define B1 60
-byte neopixel_buf[NPIX_RESET + 24*NPIX_NUM_LEDS];
+static byte neopixel_leds[NPIX_NUM_LEDS][3];
+static byte neopixel_buf[2*24];
+static uint neopixel_index;
static void neopixel_set(uint led, byte r, byte g, byte b)
{
- byte *buf = &neopixel_buf[NPIX_RESET + 24*led];
-
- for (uint m=0x80; m; m >>= 1)
- *buf++ = (g & m) ? B1 : B0;
- for (uint m=0x80; m; m >>= 1)
- *buf++ = (r & m) ? B1 : B0;
- for (uint m=0x80; m; m >>= 1)
- *buf++ = (b & m) ? B1 : B0;
+ cm_disable_interrupts();
+ neopixel_leds[led][0] = r;
+ neopixel_leds[led][1] = g;
+ neopixel_leds[led][2] = b;
+ cm_enable_interrupts();
}
-
static void neopixel_init(void)
{
for (uint i=0; i < NPIX_NUM_LEDS; i++)
neopixel_set(i, 7, 7, 7);
+ // neopixel_buf is zero-initialized, which is a start of the reset sequence
+ memset(neopixel_buf, 0, sizeof(neopixel_buf));
+ neopixel_index = NPIX_NUM_LEDS;
+
// TIM4 update is connected to DMA1 channel 7
// FIXME: Strange programming sequence as specified in manual
dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
dma_disable_peripheral_increment_mode(DMA1, 7);
+ dma_enable_half_transfer_interrupt(DMA1, 7);
+ dma_enable_transfer_complete_interrupt(DMA1, 7);
+ nvic_enable_irq(NVIC_DMA1_CHANNEL7_IRQ);
+
dma_enable_channel(DMA1, 7);
timer_set_prescaler(TIM4, 0);
timer_enable_counter(TIM4);
}
+static inline void next_led(byte *buf)
+{
+ if (neopixel_index < NPIX_NUM_LEDS) {
+ byte *led = neopixel_leds[neopixel_index++];
+ byte r = led[0], g = led[1], b = led[2];
+ for (uint m=0x80; m; m >>= 1)
+ *buf++ = (g & m) ? B1 : B0;
+ for (uint m=0x80; m; m >>= 1)
+ *buf++ = (r & m) ? B1 : B0;
+ for (uint m=0x80; m; m >>= 1)
+ *buf++ = (b & m) ? B1 : B0;
+ } else {
+ for (uint i=0; i < 24; i++)
+ *buf++ = 0;
+ neopixel_index++;
+ if (neopixel_index == NPIX_NUM_LEDS + NPIX_RESET)
+ neopixel_index = 0;
+ }
+}
+
+void dma1_channel7_isr(void)
+{
+ if (DMA1_ISR & DMA_ISR_HTIF7) {
+ // Half transfer
+ DMA1_IFCR |= DMA_IFCR_CHTIF7;
+ next_led(neopixel_buf);
+ } else if (DMA1_ISR & DMA_ISR_TCIF7) {
+ // Transfer completed
+ DMA1_IFCR |= DMA_IFCR_CTCIF7;
+ next_led(neopixel_buf + 24);
+ }
+}
+
/*** Game of Life ***/
#define LN 8