Skip to content

Instantly share code, notes, and snippets.

@patryk4815
Created March 13, 2025 12:05
Show Gist options
  • Save patryk4815/fd30d518aa8f79c11d07bc4381823250 to your computer and use it in GitHub Desktop.
Save patryk4815/fd30d518aa8f79c11d07bc4381823250 to your computer and use it in GitHub Desktop.
const std = @import("std");
const microzig = @import("microzig");
const rp2xxx = microzig.hal;
const gpio = rp2xxx.gpio;
const time = rp2xxx.time;
const Pio = rp2xxx.pio.Pio;
const StateMachine = rp2xxx.pio.StateMachine;
const manchester_tx = blk: {
@setEvalBranchQuota(8000);
break :blk rp2xxx.pio.assemble(
\\.program manchester_tx
\\.side_set 1 opt
\\
\\; Transmit one bit every 12 cycles. a '0' is encoded as a high-low sequence
\\; (each part lasting half a bit period, or 6 cycles) and a '1' is encoded as a
\\; low-high sequence.
\\;
\\; Side-set bit 0 must be mapped to the GPIO used for TX.
\\; Autopull must be enabled -- this program does not care about the threshold.
\\; The program starts at the public label 'start'.
\\
\\.wrap_target
\\do_1:
\\ nop side 1 [5] ; Low for 6 cycles (5 delay, +1 for nop)
\\ jmp get_bit side 0 [3] ; High for 4 cycles. 'get_bit' takes another 2 cycles
\\do_0:
\\ nop side 0 [5] ; Output high for 6 cycles
\\ nop side 1 [3] ; Output low for 4 cycles
\\public start:
\\get_bit:
\\ out x, 1 ; Always shift out one bit from OSR to X, so we can
\\ jmp !x do_0 ; branch on it. Autopull refills the OSR when empty.
\\.wrap
, .{}).get_program_by_name("manchester_tx");
};
// Pick one PIO instance arbitrarily. We're also arbitrarily picking state
// machine 0 on this PIO instance (the state machines are numbered 0 to 3
// inclusive).
const pio: Pio = rp2xxx.pio.num(0);
const sm: StateMachine = .sm0;
const DOUT_NEW = gpio.num(5);
pub fn manchester_tx_program_init() void {
pio.gpio_init(DOUT_NEW);
// This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
// * Note: This method only works for pins < 32. To use with pins >= 32 call pio_sm_set_pins_with_mask64
// uint32_t pin_values, uint32_t pin_mask
// pio_sm_set_pins_with_mask(pio, sm, 0, 1u << pin);
pio.sm_set_pin(sm, 5, 1, 1);
// uint pins_base, uint pin_count, bool is_out
// pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio.sm_set_pindir(sm, 5, 1, .out);
// T0...Carrier period time (1/125 kHz = 8 µs nominal).
// calc from_float: (150_000_000 / 125_000) * (32 / 12)
// rfid_bit_length = 32; // 256us = 1bit
// program_tx = 12 cycles = 1bit
pio.sm_load_and_start_program(sm, manchester_tx, .{
.clkdiv = rp2xxx.pio.ClkDivOptions.from_float(3200),
// sm_config_set_out_shift(&c, (shift_right)true, (autopull)true, (pull_threshold)32);
// sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
.shift = .{
.out_shiftdir = .right,
.autopull = true,
.pull_threshold = 0, // 0 means full 32-bits
.join_tx = true,
},
// sm_config_set_sideset_pins(&c, pin);
.pin_mappings = .{
.side_set = .{
.base = 5,
.count = 2,
}
},
}) catch unreachable;
pio.sm_set_enabled(sm, true);
const em4100_part1: u32 = 0b111111111_1110_1_0100_0_0000_0_0001_1_110;
const em4100_part2: u32 = 0b1_0_1010_1_1000_1_0100_1_1101_0_1101_1_0000_0;
while (true) {
pio.sm_blocking_write(sm, @bitReverse(em4100_part1));
pio.sm_blocking_write(sm, @bitReverse(em4100_part2));
time.sleep_ms(50);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment