The Pico has a set of PIO co-processors. They are real-time controllers that can execute logic with deterministic timing. Ideal to run strict-timed sequences and state machines. And to implement extra peripherals (like a quadrature decoder here). |
The purpose of this blog isn't to write a PIO developer tutorial. I'm trying to backtrack how the developer implemented a standard protocol using the PIO instructions. I'm using C, CMake, VSCode and the Pico C SDK. Expected skill level: you can build and run the official pico-examples.
This post does not look into the code. It's just a test bed so that I can see if I can set up a CAN conversation.
Get the pio decode library
Clone or download the sources from Kevin's github.
git clone https://github.com/jamon/pi-pico-pio-quadrature-encoder.git
Set an environment variable that points to this location. This will take care that we can create a make script that's not dependent on where you keep 3rd party code. I'm using VSCode, and will define the environment variable there. You can also do it in your OS settings, shell script, ...
Project Folder
I created a directory with a CMake file, and a source folder to contain the very simple test file, taken from here. I only made a change so that it only logs a value when it changes, instead of every second. And used GIO 7 and 6 as the rotary pins A and B - to match the schematics of the development board.
source/main.c
// SPDX-FileCopyrightText: 2022 Jamon Terrell "jc: mail address removed, available on github" // SPDX-License-Identifier: MIT // https://github.com/jamon/pi-pico-pio-quadrature-encoder/blob/main/src/quadrature.pio #include <stdio.h> #include "pico/stdlib.h" #include "hardware/pio.h" #include "quadrature.pio.h" #define QUADRATURE_A_PIN 7 #define QUADRATURE_B_PIN 6 int main() { stdio_init_all(); PIO pio = pio0; uint offset = pio_add_program(pio, &quadrature_program); uint sm = pio_claim_unused_sm(pio, true); quadrature_program_init(pio, sm, offset, QUADRATURE_A_PIN, QUADRATURE_B_PIN); uint x = 0; while (true) { sleep_ms(1000); pio_sm_exec_wait_blocking(pio, sm, pio_encode_in(pio_x, 32)); uint y = pio_sm_get_blocking(pio, sm); if (y != x) { x = y; printf("%d\n", x); } } }
./CMakeList.txt
cmake_minimum_required(VERSION 3.13)
# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)
project(pio_rotary_project0 C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
#I've set this to allow breakpoints on any source line
set(PICO_DEOPTIMIZED_DEBUG=1)
pico_sdk_init()
add_executable(pio_rotary_project0
source/main.c
# $ENV{PIO_QUADRATURE_DECODER_PATH}/src/quadrature.pio
)
target_include_directories(pio_rotary_project0 PRIVATE
${CMAKE_CURRENT_LIST_DIR}/source
$ENV{PIO_QUADRATURE_DECODER_PATH}/src
)
target_link_libraries(pio_rotary_project0 pico_stdlib hardware_pio)
pico_add_extra_outputs(pio_rotary_project0)
Testing
To test this, you just need to connect a terminal program to the debugger*.
I'm attaching a ZIP of my VSCode project. Don't forget to download the pi-pico-quadrature-encoder source and set the environment variable.