Example code using the onboard DSP, FreeRTOS, and DMA to control individually addressable LEDs (SK6812). This project has both non-audio patterns and audio syncing patterns.
Non-audio syncing patterns: https://youtu.be/5Bn3eNN9Ki0
Setup + Audio syncing patterns: https://youtu.be/zrTWR6r1QTw
The idea is to use 2 different tasks to manage the LEDs. The tasks are listed below by priority (higher numbers will preempt lower numbers). I realize they could probably all be combined into one task, but more tasks means more learning.
- Idle Task
- Does nothing
- Pattern Task
- Decides what pattern to show
- Calculates RGB color based on selected pattern
- 10ms (100 Hz)
- Refresh Task
- Refreshes the actual colors shown on the LED strip
- Initiates PWM pulse train
- 10ms (100 Hz)
- Refreshes the actual colors shown on the LED strip
Timer 2: 44.1 kHz timer for sampling audio voltage data
Timer 4: LED Data Line
Timer 12: Collects runtime statistics (task time, computation times, ...)
C4: Audio voltage data in
B6: LED Data out
D12: LED4 (GRN) - Indicates stack overflow for vCreatePattern
D13: LED3 (ORG) - Indicates stack overflow for vUpdateLedStrip
D14: LED5 (RED)
D15: LED6 (BLU)
DMA1 Stream 0: Transfer duty cycles to PWM module.
DMA2 Stream 0: Transfer ADC1->DR to buffers (used in double buffer mode).
ADC1 Channel 14: Samples audio voltage
http://socialledge.com/sjsu/index.php/FreeRTOS_Tutorial
https://www.freertos.org/a00125.html
https://cdn-shop.adafruit.com/product-files/1138/SK6812+LED+datasheet+.pdf
https://stm32f4-discovery.net/2014/10/stm32f4-fft-example/
https://www.keil.com/pack/doc/CMSIS/DSP/html/group__RealFFT.html#ga5d2ec62f3e35575eba467d09ddcd98b5
https://arm-software.github.io/CMSIS_5/DSP/html/index.html
https://www.freertos.org/FreeRTOS-Coding-Standard-and-Style-Guide.html
Use xTaskCreateStatic
to create a task with the stack in a static location
Use xTaskCreate
to create a task with the stack in a dynamic location
Use vTaskDelayUntil
to schedule task to be run again
Use uxTaskGetStackHighWaterMark
to see the highest of stack usage
Use taskENTER_CRITICAL
to disable interrupts and tasks
Use taskEXIT_CRITICAL
to re-enable interrupts and tasks
Use portTICK_PERIOD_MS
to determine period of one clock tick/cycle