From e630805086dafb85c7da8313f26c078a4aa8c21c Mon Sep 17 00:00:00 2001 From: Arne Zachlod Date: Fri, 16 Jan 2026 16:59:52 +0100 Subject: [PATCH] example PIO code from RPI for differential manchester encoding --- CMakeLists.txt | 18 +++++++ differential_manchester.c | 43 +++++++++++++++ differential_manchester.pio | 105 ++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 differential_manchester.c create mode 100644 differential_manchester.pio diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7d52ea5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.12) + +# Pull in SDK (must be before project) +include(pico_sdk_import.cmake) + +project(base10-t1s) + +# Initialize the SDK +pico_sdk_init() + +add_executable(pio_differential_manchester) + +pico_generate_pio_header(pio_differential_manchester ${CMAKE_CURRENT_LIST_DIR}/differential_manchester.pio) + +target_sources(pio_differential_manchester PRIVATE differential_manchester.c) + +target_link_libraries(pio_differential_manchester PRIVATE pico_stdlib hardware_pio) +pico_add_extra_outputs(pio_differential_manchester) diff --git a/differential_manchester.c b/differential_manchester.c new file mode 100644 index 0000000..c8b5612 --- /dev/null +++ b/differential_manchester.c @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "differential_manchester.pio.h" + +// Differential serial transmit/receive example +// Need to connect a wire from GPIO2 -> GPIO3 + +const uint pin_tx = 2; +const uint pin_rx = 3; + +int main() { + stdio_init_all(); + + PIO pio = pio0; + uint sm_tx = 0; + uint sm_rx = 1; + + uint offset_tx = pio_add_program(pio, &differential_manchester_tx_program); + uint offset_rx = pio_add_program(pio, &differential_manchester_rx_program); + printf("Transmit program loaded at %d\n", offset_tx); + printf("Receive program loaded at %d\n", offset_rx); + + // Configure state machines, set bit rate at 5 Mbps + differential_manchester_tx_program_init(pio, sm_tx, offset_tx, pin_tx, 125.f / (16 * 5)); + differential_manchester_rx_program_init(pio, sm_rx, offset_rx, pin_rx, 125.f / (16 * 5)); + + pio_sm_set_enabled(pio, sm_tx, false); + pio_sm_put_blocking(pio, sm_tx, 0); + pio_sm_put_blocking(pio, sm_tx, 0x0ff0a55a); + pio_sm_put_blocking(pio, sm_tx, 0x12345678); + pio_sm_set_enabled(pio, sm_tx, true); + + for (int i = 0; i < 3; ++i) + printf("%08x\n", pio_sm_get_blocking(pio, sm_rx)); +} diff --git a/differential_manchester.pio b/differential_manchester.pio new file mode 100644 index 0000000..c061ef3 --- /dev/null +++ b/differential_manchester.pio @@ -0,0 +1,105 @@ +; +; Copyright (c) 2020 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; +.pio_version 0 // only requires PIO version 0 + +.program differential_manchester_tx +.side_set 1 opt + +; Transmit one bit every 16 cycles. In each bit period: +; - A '0' is encoded as a transition at the start of the bit period +; - A '1' is encoded as a transition at the start *and* in the middle +; +; Side-set bit 0 must be mapped to the data output pin. +; Autopull must be enabled. + +public start: +initial_high: + out x, 1 ; Start of bit period: always assert transition + jmp !x high_0 side 1 [6] ; Test the data bit we just shifted out of OSR +high_1: + nop + jmp initial_high side 0 [6] ; For `1` bits, also transition in the middle +high_0: + jmp initial_low [7] ; Otherwise, the line is stable in the middle + +initial_low: + out x, 1 ; Always shift 1 bit from OSR to X so we can + jmp !x low_0 side 0 [6] ; branch on it. Autopull refills OSR for us. +low_1: + nop + jmp initial_low side 1 [6] ; If there are two transitions, return to +low_0: + jmp initial_high [7] ; the initial line state is flipped! + +% c-sdk { +static inline void differential_manchester_tx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) { + pio_sm_set_pins_with_mask(pio, sm, 0, 1u << pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + pio_gpio_init(pio, pin); + + pio_sm_config c = differential_manchester_tx_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, pin); + sm_config_set_out_shift(&c, true, true, 32); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset + differential_manchester_tx_offset_start, &c); + + // Execute a blocking pull so that we maintain the initial line state until data is available + pio_sm_exec(pio, sm, pio_encode_pull(false, true)); + pio_sm_set_enabled(pio, sm, true); +} +%} +.program differential_manchester_rx + +; Assumes line is idle low +; One bit is 16 cycles. In each bit period: +; - A '0' is encoded as a transition at time 0 +; - A '1' is encoded as a transition at time 0 and a transition at time T/2 +; +; The IN mapping and the JMP pin select must both be mapped to the GPIO used for +; RX data. Autopush must be enabled. + +public start: +initial_high: ; Find rising edge at start of bit period + wait 1 pin, 0 [11] ; Delay to eye of second half-period (i.e 3/4 of way + jmp pin high_0 ; through bit) and branch on RX pin high/low. +high_1: + in x, 1 ; Second transition detected (a `1` data symbol) + jmp initial_high +high_0: + in y, 1 [1] ; Line still high, no centre transition (data is `0`) + ; Fall-through + +.wrap_target +initial_low: ; Find falling edge at start of bit period + wait 0 pin, 0 [11] ; Delay to eye of second half-period + jmp pin low_1 +low_0: + in y, 1 ; Line still low, no centre transition (data is `0`) + jmp initial_high +low_1: ; Second transition detected (data is `1`) + in x, 1 [1] +.wrap + +% c-sdk { +static inline void differential_manchester_rx_program_init(PIO pio, uint sm, uint offset, uint pin, float div) { + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); + pio_gpio_init(pio, pin); + + pio_sm_config c = differential_manchester_rx_program_get_default_config(offset); + sm_config_set_in_pins(&c, pin); // for WAIT + sm_config_set_jmp_pin(&c, pin); // for JMP + sm_config_set_in_shift(&c, true, true, 32); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); + + // X and Y are set to 0 and 1, to conveniently emit these to ISR/FIFO. + pio_sm_exec(pio, sm, pio_encode_set(pio_x, 1)); + pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0)); + pio_sm_set_enabled(pio, sm, true); +} +%}