ws2812.pio
概要
Raspberry pi pico SDK にある ws2812.pio のデータフォーマットを調べたのでその記録。
背景
Raspberry pi pico の PIO (Programmable Input/Output block) ペリフェラルを使用すると WS2812B RGB LED strip を制御しやすい (pico-sdk にサンプルが含まれる) ことが分かったので試してみました。ただデータフォーマットが分かりにくかったので確認したことを記録しておきます。
コード修正
オリジナルの ws2812_parallel は32本のLEDストリップを制御できるのですが、そこまで必要としないので4本に修正します。(この修正でデータフォーマットが変化します)
※実際には3本のLEDストリップで十分なのですが、4本にすると生データが4bit区切りになって扱いやすいので4本としています
オリジナル
.wrap_target
out x, 32
mov pins, !null [2]
mov pins, x [2]
mov pins, null [2]
.wrap
修正後
.wrap_target
out x, 4
mov pins, !null [2]
mov pins, x [2]
mov pins, null [2]
.wrap
データフォーマット
ws2812
ws2812 は RGB モード と RGBW モード の2種類が選択できますが、どちらも 32bit が 1LED に対応します。RGB モードの場合は W7~W0 を 0 にしておけば問題ありません。
Format:
[G7(MSB)][G6]..[G0][R7][R6]..[R0][B7][B6]..[B0][W7][W6]..[W0]
サンプルコード (LED の指令値が pio_packet にこのフォーマットで格納されます)
uint offset0 = pio_add_program(pio0, &ws2812_program);
auto sm0 = pio_claim_unused_sm(pio0, true);
ws2812_program_init(pio0, sm0, offset0, WS2812_SIGNAL0_PIN, 800000, false);
dma_channel_config dma0_conf = dma_channel_get_default_config(DMA0);
channel_config_set_dreq(&dma0_conf, pio_get_dreq(pio0, sm0, true));
channel_config_set_transfer_data_size(&dma0_conf, DMA_SIZE_32);
channel_config_set_read_increment(&dma0_conf, true);
dma_channel_configure(DMA0, &dma0_conf, &pio0->txf[sm0], NULL, NUM_OF_LEDs, false);
// Refresh LEDs
uint32_t pio_packet[NUM_OF_LEDs];
/* Fill pio_packet here */
dma_channel_set_read_addr(DMA0, (void*)pio_packet, true);
ws2812_parallel (修正版)
ws2812_parallel は 4本の LED strip を制御できる関係で、ws2812 とは異なり、データのインタリーブとビットスワップが必要になります。また 96bit がストリップあたり 1LED (4ストリップで合計 4LED) に対応します。なお 4ストリップにつながる GPIO は連番である必要があります。
Format:
[STRIP3-G0(MSB)][STRIP2-G0][STRIP1-G0][STRIP0-G0][STRIP3-G1][STRIP2-G1][STRIP1-G1][STRIP0-G1] … [STRIP3-G7][STRIP2-G7][STRIP1-G7][STRIP0-G7]
[STRIP3-R0][STRIP2-R0][STRIP1-R0][STRIP0-R0][STRIP3-R1][STRIP2-R1][STRIP1-R1][STRIP0-R1] … [STRIP3-R7][STRIP2-R7][STRIP1-R7][STRIP0-R7]
[STRIP3-B0][STRIP2-B0][STRIP1-B0][STRIP0-B0][STRIP3-B1][STRIP2-B1][STRIP1-B1][STRIP0-B1] … [STRIP3-B7][STRIP2-B7][STRIP1-B7][STRIP0-B7]
サンプルコード (LED の指令値が pio_packet にこのフォーマットで格納されます)
uint offset0 = pio_add_program(pio0, &ws2812_parallel_program);
auto sm0 = pio_claim_unused_sm(pio0, true);
ws2812_parallel_program_init(pio0, sm0, offset0, WS2812_SIGNAL0_PIN, 4, 800000);
dma_channel_config dma0_conf = dma_channel_get_default_config(DMA0);
channel_config_set_dreq(&dma0_conf, pio_get_dreq(pio0, sm0, true));
channel_config_set_transfer_data_size(&dma0_conf, DMA_SIZE_32);
channel_config_set_read_increment(&dma0_conf, true);
dma_channel_configure(DMA0, &dma0_conf, &pio0->txf[sm0], NULL, 3*NUM_OF_LEDs, false);
// Refresh LEDs
uint32_t pio_packet[3*NUM_OF_LEDs];
/* Fill pio_packet here */
dma_channel_set_read_addr(DMA0, (void*)pio_packet, true);