From e81e0a022a82286a8ae0f73f832e0d6864f9a726 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Fri, 5 Feb 2021 11:25:26 +0000 Subject: [PATCH] Add pio_clocked_input example --- pio/CMakeLists.txt | 1 + pio/clocked_input/CMakeLists.txt | 16 +++++++ pio/clocked_input/clocked_input.c | 71 +++++++++++++++++++++++++++++ pio/clocked_input/clocked_input.pio | 51 +++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 pio/clocked_input/CMakeLists.txt create mode 100644 pio/clocked_input/clocked_input.c create mode 100644 pio/clocked_input/clocked_input.pio diff --git a/pio/CMakeLists.txt b/pio/CMakeLists.txt index ff56da3..8855161 100644 --- a/pio/CMakeLists.txt +++ b/pio/CMakeLists.txt @@ -1,6 +1,7 @@ if (NOT PICO_NO_HARDWARE) add_subdirectory(addition) add_subdirectory(apa102) + add_subdirectory(clocked_input) add_subdirectory(differential_manchester) add_subdirectory(hello_pio) add_subdirectory(hub75) diff --git a/pio/clocked_input/CMakeLists.txt b/pio/clocked_input/CMakeLists.txt new file mode 100644 index 0000000..cd71408 --- /dev/null +++ b/pio/clocked_input/CMakeLists.txt @@ -0,0 +1,16 @@ +add_executable(pio_clocked_input) + +pico_generate_pio_header(pio_clocked_input ${CMAKE_CURRENT_LIST_DIR}/clocked_input.pio) + +target_sources(pio_clocked_input PRIVATE clocked_input.c) + +target_link_libraries(pio_clocked_input PRIVATE + pico_stdlib + hardware_pio + hardware_spi + ) + +pico_add_extra_outputs(pio_clocked_input) + +# add url via pico_set_program_url +example_auto_set_url(pio_clocked_input) diff --git a/pio/clocked_input/clocked_input.c b/pio/clocked_input/clocked_input.c new file mode 100644 index 0000000..5175b36 --- /dev/null +++ b/pio/clocked_input/clocked_input.c @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "hardware/clocks.h" +#include "hardware/pio.h" +#include "hardware/spi.h" +#include "clocked_input.pio.h" + +// Set up a PIO state machine to shift in serial data, sampling with an +// external clock, and push the data to the RX FIFO, 8 bits at a time. +// +// Use one of the hard SPI peripherals to drive data into the SM through a +// pair of external jumper wires, then read back and print out the data from +// the SM to confirm everything worked ok. +// +// On your Pico you need to connect jumper wires to these pins: +// - GPIO 2 -> GPIO 5 (clock output to clock input) +// - GPIO 3 -> GPIO 4 (data output to data input) + +#define SPI_SCK_PIN 2 +#define SPI_TX_PIN 3 +// GPIO 4 for PIO data input, GPIO 5 for clock input: +#define PIO_INPUT_PIN_BASE 4 + +#define BUF_SIZE 8 + +int main() { + stdio_init_all(); + + // Configure the SPI before PIO to avoid driving any glitches into the + // state machine. + spi_init(spi0, 1000 * 1000); + uint actual_freq_hz = spi_set_baudrate(spi0, clock_get_hz(clk_sys) / 6); + printf("SPI running at %u Hz\n", actual_freq_hz); + gpio_set_function(SPI_TX_PIN, GPIO_FUNC_SPI); + gpio_set_function(SPI_SCK_PIN, GPIO_FUNC_SPI); + + // Load the clocked_input program, and configure a free state machine + // to run the program. + PIO pio = pio0; + uint offset = pio_add_program(pio, &clocked_input_program); + uint sm = pio_claim_unused_sm(pio, true); + clocked_input_program_init(pio, sm, offset, PIO_INPUT_PIN_BASE); + + // Make up some random data to send. + static uint8_t txbuf[BUF_SIZE]; + puts("Data to transmit:"); + for (int i = 0; i < BUF_SIZE; ++i) { + txbuf[i] = rand() >> 16; + printf("%02x\n", txbuf[i]); + } + + // The "blocking" write function will send all the data in one go, and not + // return until the full transmission is finished. + spi_write_blocking(spi0, (const uint8_t*)txbuf, BUF_SIZE); + + // The data we just sent should now be present in the state machine's FIFO. + puts("Reading back from RX FIFO:"); + for (int i = 0; i < BUF_SIZE; ++i) { + uint8_t rxdata = pio_sm_get_blocking(pio, sm); + printf("%02x %s\n", rxdata, rxdata == txbuf[i] ? "OK" : "FAIL"); + } + puts("Done."); +} diff --git a/pio/clocked_input/clocked_input.pio b/pio/clocked_input/clocked_input.pio new file mode 100644 index 0000000..51fa54c --- /dev/null +++ b/pio/clocked_input/clocked_input.pio @@ -0,0 +1,51 @@ +; +; Copyright (c) 2021 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program clocked_input + +; Sample bits using an external clock, and push groups of bits into the RX FIFO. +; - IN pin 0 is the data pin +; - IN pin 1 is the clock pin +; - Autopush is enabled, threshold 8 +; +; This program samples data with each rising clock edge (like mode 0 or mode 3 +; SPI). The data is actually sampled one system clock cycle after the rising +; edge is observed, so a clock ratio of at least input_clk < clk_sys / 6 is +; recommended for good sampling alignment. + + wait 0 pin 1 + wait 1 pin 1 + in pins, 1 + +% c-sdk { +static inline void clocked_input_program_init(PIO pio, uint sm, uint offset, uint pin) { + pio_sm_config c = clocked_input_program_get_default_config(offset); + + // Set the IN base pin to the provided `pin` parameter. This is the data + // pin, and the next-numbered GPIO is used as the clock pin. + sm_config_set_in_pins(&c, pin); + // Set the pin directions to input at the PIO + pio_sm_set_consecutive_pindirs(pio, sm, pin, 2, false); + // Connect these GPIOs to this PIO block + pio_gpio_init(pio, pin); + pio_gpio_init(pio, pin + 1); + + // Shifting to left matches the customary MSB-first ordering of SPI. + sm_config_set_in_shift( + &c, + false, // Shift-to-right = false (i.e. shift to left) + true, // Autopush enabled + 8 // Autopush threshold = 8 + ); + + // We only receive, so disable the TX FIFO to make the RX FIFO deeper. + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + + // Load our configuration, and start the program from the beginning + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} +%}