From 2e37c2bff2ef9f1a9c22acaff05e4581b14057e2 Mon Sep 17 00:00:00 2001 From: andryblack Date: Sat, 26 Oct 2024 15:14:33 +0300 Subject: [PATCH] [rp] pio: make initialization code more close to pio program --- examples/rp_pico/pio_ws2812/main.cpp | 71 +--------------- examples/rp_pico/pio_ws2812/ws2812.pio.hpp | 96 ++++++++++++++++++++++ src/modm/platform/pio/rp/pio_asm.hpp | 28 ++++--- src/modm/platform/pio/rp/pio_sm.hpp | 51 +++++++----- 4 files changed, 146 insertions(+), 100 deletions(-) create mode 100644 examples/rp_pico/pio_ws2812/ws2812.pio.hpp diff --git a/examples/rp_pico/pio_ws2812/main.cpp b/examples/rp_pico/pio_ws2812/main.cpp index b03920beff..846c1d1028 100644 --- a/examples/rp_pico/pio_ws2812/main.cpp +++ b/examples/rp_pico/pio_ws2812/main.cpp @@ -11,62 +11,9 @@ // ---------------------------------------------------------------------------- #include +#include "ws2812.pio.hpp" using namespace Board; -/* from https://github.com/raspberrypi/pico-examples/blob/master/pio/ws2812/ws2812.pio */ - -// constants WS2812 -// static constexpr uint32_t T0H = 350; // ns -// static constexpr uint32_t T0L = 800; -// static constexpr uint32_t T1H = 700; -// static constexpr uint32_t T1L = 600; - -// constants WS2812B -static constexpr uint32_t T0H = 400; // ns -static constexpr uint32_t T0L = 850; -static constexpr uint32_t T1H = 850; -static constexpr uint32_t T1L = 400; - -static constexpr uint32_t TimeScale = 50; - -static constexpr uint32_t TH_Common = T0H/TimeScale; -static constexpr uint32_t TH_Add = (T1H-T0H)/TimeScale; -static constexpr uint32_t TL_Common = T1L/TimeScale; -static constexpr uint32_t TL_Add = (T0L-T1L)/TimeScale; - -static constexpr uint32_t T3 = 12;// - -// labels -struct bitloop {}; -struct do_one {}; -struct do_zero {}; - - -/* -.wrap_target -bitloop: - out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls - jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse -do_one: - jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse -do_zero: - nop side 0 [T2 - 1] ; Or drive low, for a short pulse -.wrap -*/ -// PIO program -static constexpr auto pio_prog = PIOProgram::begin() - .sideset<1> - .wrapTarget<> - .label - .instr(pio::Out.x<1> .side<0>.delay) - .instr(pio::Jmp.not_x.to .side<1>.delay) - .label - .instr(pio::Jmp.to .side<1>.delay) - .label - .instr(pio::Nop .side<0>.delay) - .wrap<> - .end(); - struct HW { @@ -86,21 +33,9 @@ main() HW::DataGpio::setOutput(Gpio::OutputType::PushPull, Gpio::SlewRate::Fast); HW::DataGpio::setDriveStrength(Gpio::DriveStrength::mA_12); - auto pio_prog_offset = HW::PIO::addProgram(pio_prog); - - HW::PIO::connect(); - - HW::PIO_SM::addOutput(); - - HW::PIO_SM::config() - .setup(pio_prog_offset,pio_prog) - .setSidesetPins() - .setFifoJoinTx() - .setOutShift() - .setFrequency() - .init(pio_prog_offset+pio_prog.getOffset()); + auto pio_program_offset = HW::PIO::addProgram(ws2812::program); - HW::PIO_SM::setEnabled(true); + ws2812::init(pio_program_offset); constexpr auto delay_val = 5ms; diff --git a/examples/rp_pico/pio_ws2812/ws2812.pio.hpp b/examples/rp_pico/pio_ws2812/ws2812.pio.hpp new file mode 100644 index 0000000000..fb58096c3e --- /dev/null +++ b/examples/rp_pico/pio_ws2812/ws2812.pio.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include + +/* from https://github.com/raspberrypi/pico-examples/blob/master/pio/ws2812/ws2812.pio */ + +/* .program ws2812 */ +namespace ws2812 +{ + using namespace modm::platform::pio; + + // constants WS2812 + // static constexpr uint32_t T0H = 350; // ns + // static constexpr uint32_t T0L = 800; + // static constexpr uint32_t T1H = 700; + // static constexpr uint32_t T1L = 600; + + // constants WS2812B + static constexpr uint32_t T0H = 400; // ns + static constexpr uint32_t T0L = 850; + static constexpr uint32_t T1H = 850; + static constexpr uint32_t T1L = 400; + + static constexpr uint32_t TimeScale = 50; + + static constexpr uint32_t TH_Common = T0H/TimeScale; + static constexpr uint32_t TH_Add = (T1H-T0H)/TimeScale; + static constexpr uint32_t TL_Common = T1L/TimeScale; + static constexpr uint32_t TL_Add = (T0L-T1L)/TimeScale; + + // labels + struct bitloop {}; + struct do_one {}; + struct do_zero {}; + + /* + .side_set 1 + .wrap_target + bitloop: + out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls + jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse + do_one: + jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse + do_zero: + nop side 0 [T2 - 1] ; Or drive low, for a short pulse + .wrap + */ + + // PIO program + static constexpr auto program = PIOProgram::begin() + .sideset<1> + .wrapTarget<> + .label + .instr(pio::Out.x<1> .side<0>.delay) + .instr(pio::Jmp.not_x.to .side<1>.delay) + .label + .instr(pio::Jmp.to .side<1>.delay) + .label + .instr(pio::Nop .side<0>.delay) + .wrap<> + .end(); + + static_assert(program.code[0]==0x6721,"invalid program code[0]"); + static_assert(program.code[1]==0x1723,"invalid program code[1]"); + /* + pio_gpio_init(pio, pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + + pio_sm_config c = ws2812_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, pin); + sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + + int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3; + float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit); + sm_config_set_clkdiv(&c, div); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); + */ + // initialization code + template + static constexpr void init(uint16_t offset) { + PIO::template connect(); + SM::template addOutput(); + + SM::config(offset,program) + .template setSidesetPins() + .template setOutShift() + .setFifoJoinTx() + .template setFrequency() + .init(offset+program.getOffset()); + SM::setEnabled(true); + } + +} diff --git a/src/modm/platform/pio/rp/pio_asm.hpp b/src/modm/platform/pio/rp/pio_asm.hpp index 983f55e0e3..5ba0e1d138 100644 --- a/src/modm/platform/pio/rp/pio_asm.hpp +++ b/src/modm/platform/pio/rp/pio_asm.hpp @@ -150,12 +150,12 @@ namespace modm::platform::pio using Base = InstructionEncoding>; template - struct JmpImpl : InstructionEncoding>{ + struct JmpImpl : InstructionEncoding>{ static constexpr const Opcode opcode = Opcode::JMP; static constexpr const JmpCondition condition_value = condition; static constexpr const uint16_t addr_value = addr; using LabelName = LabelImpl; - using Base = InstructionEncoding>; + using Base = InstructionEncoding>; constexpr JmpImpl() {} template static constexpr Instruction encode(const Encoder& coder) { @@ -605,12 +605,13 @@ namespace modm::platform::pio }; - template + template struct ProgramCode { + using settings = ProgramSettings; static constexpr const size_t length = Length; - const uint16_t wrap_target; - const uint16_t wrap; - constexpr ProgramCode( std::array&& code,uint16_t wrap_target,uint16_t wrap) : wrap_target(wrap_target),wrap(wrap),code(std::move(code)) { + static constexpr const uint16_t wrap_target = wrap_target_t; + static constexpr const uint16_t wrap = wrap_t; + explicit constexpr ProgramCode( std::array&& code) : code(std::move(code)) { } const std::array code; @@ -621,12 +622,14 @@ namespace modm::platform::pio }; - template + template struct ProgramSettings { - static constexpr uint32_t sideset_count = sideset_count_t; + static constexpr uint32_t count = count_t; + static constexpr uint32_t sideset_count = sideset_is_opt_t ? (count_t+1) : count_t; static constexpr bool sideset_is_opt = sideset_is_opt_t; static constexpr uint16_t delay_max = delay_max_t; static constexpr uint16_t sideset_max = sideset_max_t; + static constexpr bool sideset_pindirs = false; }; template struct ProgramSettingsSideset { @@ -636,7 +639,7 @@ namespace modm::platform::pio template struct ProgramSettingsOptSideset { static_assert(count <= 4,"maximum number of side set bits is 4"); - using result = ProgramSettings; + using result = ProgramSettings; }; template @@ -696,11 +699,12 @@ namespace modm::platform::pio using AddedInstructions = typename instructions::add; return ProgramBuilder(); } - static constexpr ProgramCode end() { + static constexpr auto end() { ProgramBuilder pb; - return ProgramCode(instructions::build(pb), + return ProgramCode(instructions::build(pb)); } }; diff --git a/src/modm/platform/pio/rp/pio_sm.hpp b/src/modm/platform/pio/rp/pio_sm.hpp index 031a0916d0..9e617f58e3 100644 --- a/src/modm/platform/pio/rp/pio_sm.hpp +++ b/src/modm/platform/pio/rp/pio_sm.hpp @@ -59,12 +59,15 @@ namespace modm::platform::pio::implementation (addPin(),...); sm().pinctrl = pinctrlSaved; } + template struct Config { + using settings = Setting; uint32_t clkdiv{0}; - uint32_t execctrl{0}; - uint32_t shiftctrl{0}; - uint32_t pinctrl{0}; - template < uint16_t div_int, uint8_t div_frac > + uint32_t execctrl{0}; + uint32_t shiftctrl{0}; + uint32_t pinctrl{0}; + + template < uint16_t div_int, uint8_t div_frac > constexpr Config& setClkDiv() { clkdiv = (uint32_t(div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) | (uint32_t(div_int) << PIO_SM0_CLKDIV_INT_LSB); @@ -98,16 +101,26 @@ namespace modm::platform::pio::implementation ((pullThreshold & 0x1fu) << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB); return *this; } - template < class StartPin , size_t count, bool optional, bool pindirs> - constexpr Config& setSidesetPins() { - static_assert((count+(optional?1:0)) <= 5,"too many sideset pins"); - pinctrl = (pinctrl & ~(PIO_SM0_PINCTRL_SIDESET_COUNT_BITS | PIO_SM0_PINCTRL_SIDESET_BASE_BITS)) | - ((count+(optional?1:0)) << PIO_SM0_PINCTRL_SIDESET_COUNT_LSB) | - (uint32_t(StartPin::pin) << PIO_SM0_PINCTRL_SIDESET_BASE_LSB); - execctrl = (execctrl & ~(PIO_SM0_EXECCTRL_SIDE_EN_BITS | PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) | + constexpr Config& setSideset() { + constexpr auto bit_count = settings::sideset_count; + constexpr auto optional = settings::sideset_is_opt; + constexpr auto pindirs = settings::sideset_pindirs; + static_assert(bit_count <= 5,"too many sideset pins"); + static_assert(!optional || bit_count >= 1,"invalid config"); + + pinctrl = (pinctrl & ~PIO_SM0_PINCTRL_SIDESET_COUNT_BITS) | + (bit_count << PIO_SM0_PINCTRL_SIDESET_COUNT_LSB); + execctrl = (execctrl & ~(PIO_SM0_EXECCTRL_SIDE_EN_BITS | PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) | ((optional?1:0) << PIO_SM0_EXECCTRL_SIDE_EN_LSB) | ((pindirs?1:0) << PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB); - return *this; + return *this; + } + template < class StartPin> + constexpr Config& setSidesetPins() { + + pinctrl = (pinctrl & ~(PIO_SM0_PINCTRL_SIDESET_BASE_BITS)) | + (uint32_t(StartPin::pin) << PIO_SM0_PINCTRL_SIDESET_BASE_LSB); + return *this; } template < class StartPin , size_t count> constexpr Config& setOutPins() { @@ -143,11 +156,7 @@ namespace modm::platform::pio::implementation shiftctrl = (shiftctrl & ~(PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS)); return *this; } - template - constexpr Config& setup(size_t offset,const Program& prg) { - setWrap(prg.wrap_target+offset,prg.wrap+offset); - return *this; - } + void init(uint16_t startPC) { StateMachine::setEnabled(false); @@ -192,10 +201,12 @@ namespace modm::platform::pio::implementation return *this; } }; - static constexpr Config config() { - return Config() + template + static constexpr auto config(size_t offset,const Program& ) { + return Config() + .setSideset() .template setClkDiv<1,0>() - .setWrap(0,31) + .setWrap(Program::wrap_target+offset,Program::wrap+offset) .template setInShift() .template setOutShift(); }