Initial Release
This commit is contained in:
15
pio/apa102/CMakeLists.txt
Normal file
15
pio/apa102/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
add_executable(pio_apa102)
|
||||
|
||||
pico_generate_pio_header(pio_apa102 ${CMAKE_CURRENT_LIST_DIR}/apa102.pio)
|
||||
|
||||
target_sources(pio_apa102 PRIVATE apa102.c)
|
||||
|
||||
target_link_libraries(pio_apa102 PRIVATE
|
||||
pico_stdlib
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
pico_add_extra_outputs(pio_apa102)
|
||||
|
||||
# add url via pico_set_program_url
|
||||
example_auto_set_url(pio_apa102)
|
||||
69
pio/apa102/apa102.c
Normal file
69
pio/apa102/apa102.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "apa102.pio.h"
|
||||
|
||||
#define PIN_CLK 2
|
||||
#define PIN_DIN 3
|
||||
|
||||
#define N_LEDS 150
|
||||
#define SERIAL_FREQ (5 * 1000 * 1000)
|
||||
|
||||
// Global brightness value 0->31
|
||||
#define BRIGHTNESS 16
|
||||
|
||||
void put_start_frame(PIO pio, uint sm) {
|
||||
pio_sm_put_blocking(pio, sm, 0u);
|
||||
}
|
||||
|
||||
void put_end_frame(PIO pio, uint sm) {
|
||||
pio_sm_put_blocking(pio, sm, ~0u);
|
||||
}
|
||||
|
||||
void put_rgb888(PIO pio, uint sm, uint8_t r, uint8_t g, uint8_t b) {
|
||||
pio_sm_put_blocking(pio, sm,
|
||||
0x7 << 29 | // magic
|
||||
(BRIGHTNESS & 0x1f) << 24 | // global brightness parameter
|
||||
(uint32_t) b << 16 |
|
||||
(uint32_t) g << 8 |
|
||||
(uint32_t) r << 0
|
||||
);
|
||||
}
|
||||
|
||||
#define TABLE_SIZE (1 << 8)
|
||||
uint8_t wave_table[TABLE_SIZE];
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
PIO pio = pio0;
|
||||
uint sm = 0;
|
||||
uint offset = pio_add_program(pio, &apa102_mini_program);
|
||||
apa102_mini_program_init(pio, sm, offset, SERIAL_FREQ, PIN_CLK, PIN_DIN);
|
||||
|
||||
for (int i = 0; i < TABLE_SIZE; ++i)
|
||||
wave_table[i] = powf(sinf(i * M_PI / TABLE_SIZE), 5.f) * 255;
|
||||
|
||||
uint t = 0;
|
||||
while (true) {
|
||||
put_start_frame(pio, sm);
|
||||
for (int i = 0; i < N_LEDS; ++i) {
|
||||
put_rgb888(pio, sm,
|
||||
wave_table[(i + t) % TABLE_SIZE],
|
||||
wave_table[(2 * i + 3 * 2) % TABLE_SIZE],
|
||||
wave_table[(3 * i + 4 * t) % TABLE_SIZE]
|
||||
);
|
||||
}
|
||||
put_end_frame(pio, sm);
|
||||
sleep_ms(10);
|
||||
++t;
|
||||
}
|
||||
}
|
||||
89
pio/apa102/apa102.pio
Normal file
89
pio/apa102/apa102.pio
Normal file
@@ -0,0 +1,89 @@
|
||||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program apa102_mini
|
||||
.side_set 1
|
||||
|
||||
; This is really just a TX-only SPI. CLK is side-set pin 0, DIN is OUT pin 0.
|
||||
; Autopull enabled, threshold 32.
|
||||
;
|
||||
; Every word (32 bits) written to the FIFO will be shifted out in its entirety, MSB-first.
|
||||
|
||||
out pins, 1 side 0 ; Stall here when no data (still asserts clock low)
|
||||
nop side 1
|
||||
|
||||
% c-sdk {
|
||||
#include "hardware/clocks.h"
|
||||
static inline void apa102_mini_program_init(PIO pio, uint sm, uint offset,
|
||||
uint baud, uint pin_clk, uint pin_din) {
|
||||
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_clk) | (1u << pin_din));
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, ~0u, (1u << pin_clk) | (1u << pin_din));
|
||||
pio_gpio_init(pio, pin_clk);
|
||||
pio_gpio_init(pio, pin_din);
|
||||
|
||||
pio_sm_config c = apa102_mini_program_get_default_config(offset);
|
||||
sm_config_set_out_pins(&c, pin_din, 1);
|
||||
sm_config_set_sideset_pins(&c, pin_clk);
|
||||
// Shift to right, autopull with threshold 32
|
||||
sm_config_set_out_shift(&c, false, true, 32);
|
||||
// Deeper FIFO as we're not doing any RX
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
// We transmit 1 bit every 2 execution cycles
|
||||
float div = (float)clock_get_hz(clk_sys) / (2 * baud);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
%}
|
||||
|
||||
.program apa102_rgb555
|
||||
|
||||
; Alternative program to unpack two RGB555 pixels from a FIFO word and transmit.
|
||||
; This makes it easier to DMA large buffers without processor involvement.
|
||||
|
||||
; OSR: shift to right
|
||||
; ISR: shift to right
|
||||
|
||||
; To set brightness, set ISR to bit-reverse of 5-bit brightness,
|
||||
; followed by 111. (00...00_b0b1b2b3b4_111)
|
||||
|
||||
; DMA pixel format is 0RRRRRGGGGGBBBBB x2 (15 bpp, 2px per FIFO word)
|
||||
|
||||
; APA102 command structure:
|
||||
; increasing time ---->>
|
||||
; | byte 3 | byte 2 | byte 1 | byte 0 |
|
||||
; |7 0|7 0|7 0|7 0|
|
||||
; -------------------------------------
|
||||
; Pixel |111bbbbb|BBBBBBBB|GGGGGGGG|RRRRRRRR|
|
||||
; Start Frame |00000000|00000000|00000000|00000000|
|
||||
; Stop Frame |11111111|11111111|11111111|11111111|
|
||||
|
||||
.wrap_target
|
||||
public pixel_out:
|
||||
; pixel_out formats an APA102 colour command in the ISR.
|
||||
; bit_run shifts 32 bits out of the ISR, with clock.
|
||||
pull ifempty
|
||||
set x, 2
|
||||
colour_loop:
|
||||
in osr, 5
|
||||
out null, 5
|
||||
in null, 3
|
||||
jmp x-- colour_loop
|
||||
in y, 8
|
||||
mov isr, ::isr ; reverse for msb-first wire order
|
||||
out null, 1
|
||||
public bit_run:
|
||||
; in isr, n rotates ISR by n bits (right rotation only)
|
||||
; Use this to perform out shifts from ISR, via mov pins
|
||||
set x, 31
|
||||
bit_out:
|
||||
set pins, 0
|
||||
mov pins, isr [6]
|
||||
set pins, 1
|
||||
in isr, 1 [6]
|
||||
jmp x-- bit_out
|
||||
.wrap
|
||||
Reference in New Issue
Block a user