// a multi pin uart that send 8 bits at a time by treating the buffer as // transposed (i.e. byte0 provides LSB0 of all pins, byte1 -> LSB1 etc.) // buffer is 32 bits, so for 8 x 8-bit pushes, we need two full buffers // to fill a single UART byte (start-b7-b6-b5-b4-b3-b2-b1-b0-stop) // only tested at https://wokwi.com/tools/pioasm so far, not on a real // device see also https://wokwi.com/projects/344410676217774675 .program uart_tx pull mov pins, null [1] ; start bit (0) out pins, 8 [1] out pins, 8 [1] out pins, 8 [1] out pins, 8 pull out pins, 8 [1] out pins, 8 [1] out pins, 8 [1] out pins, 8 [1] mov pins, !null ; stop bit (1) % c-sdk { static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) { const int PIN_COUNT = 8; const int PIN_MASK = 0xFF; // the number of PIO cycles that it takes to output a single bit const uint cycles_per_bit = 2; // the clock divider (number of CPU cycles that each PIO cycle takes) float div = (float)clock_get_hz(clk_sys) / (baud * cycles_per_bit); // initialize the pins to high indicating the stop bit pio_sm_set_set_pins(pio, sm, pin, PIN_COUNT); pio_sm_set_pindirs_with_mask(pio, sm, 0xFFFFFFFF, PIN_MASK << pin); pio_sm_set_pins_with_mask(pio, sm, 0xFFFFFFFF, PIN_MASK << pin); for (int i = 0; i < PIN_COUNT; i++) { pio_gpio_init(pio, pin + i); } pio_sm_config c = uart_tx_program_get_default_config(offset); sm_config_set_out_shift(&c, true, false, 32); // shift to right, no autopull sm_config_set_out_pins(&c, pin, PIN_COUNT); // Set 8 pins starting at `pin` sm_config_set_set_pins(&c, pin, PIN_COUNT); // Set 8 pins starting at `pin` sm_config_set_clkdiv(&c, div); pio_sm_init(pio, sm, offset, &c); // Load config pio_sm_set_enabled(pio, sm, true); // Start state machine } static inline void uart_tx_program_putc(PIO pio, uint sm, uint32_t b1, uint32_t b2) { pio_sm_put_blocking(pio, sm, b1); pio_sm_put_blocking(pio, sm, b2); } %}