From 422346057b7041468eb5c894ba0829bdbc6f4280 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Tue, 19 Nov 2024 22:51:41 +0000 Subject: [PATCH] piolib: Add apitest apitest tests many of the API calls, demonstrating error handling. Signed-off-by: Phil Elwell --- piolib/examples/CMakeLists.txt | 5 + piolib/examples/apitest.c | 225 +++++++++++++++++++++++++++++++++ piolib/examples/echo.pio.h | 39 ++++++ piolib/include/piolib.h | 5 +- 4 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 piolib/examples/apitest.c create mode 100644 piolib/examples/echo.pio.h diff --git a/piolib/examples/CMakeLists.txt b/piolib/examples/CMakeLists.txt index b08793b..f24e883 100644 --- a/piolib/examples/CMakeLists.txt +++ b/piolib/examples/CMakeLists.txt @@ -11,6 +11,11 @@ if (CMAKE_COMPILER_IS_GNUCC) add_definitions (-ffunction-sections) endif () +add_executable(apitest apitest.c) +target_include_directories(apitest PRIVATE ../include) +target_link_libraries(apitest pio) +install(TARGETS apitest RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + add_executable(piotest piotest.c) target_include_directories(piotest PRIVATE ../include) target_link_libraries(piotest pio) diff --git a/piolib/examples/apitest.c b/piolib/examples/apitest.c new file mode 100644 index 0000000..2f6597d --- /dev/null +++ b/piolib/examples/apitest.c @@ -0,0 +1,225 @@ +/** + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "piolib.h" + +#include "pico/stdlib.h" +#include "hardware/pio.h" +#include "echo.pio.h" +#include "genseq.pio.h" + +#define DATA_WORDS 16 + +int main(int argc, const char **argv) { + uint32_t databuf[DATA_WORDS]; + bool use_dma = true; + int ret = 0; + int i, j; + uint16_t dummy_program_instructions[1]; + struct pio_program dummy_program = { + .instructions = dummy_program_instructions, + .length = 1, + .origin = -1, + }; + pio_sm_config c; + PIO pio = pio0; + uint sm; + uint offset; + uint gpio = 4; + if (argc == 2) + gpio = (uint)strtoul(argv[1], NULL, 0); + + pio_enable_fatal_errors(pio, false); + + for (sm = 0; sm < pio_get_sm_count(pio); sm++) { + if (pio_sm_is_claimed(pio, sm)) + pio_panic("SM claimed (1)"); + + pio_sm_claim(pio, sm); + if (pio_get_error(pio)) + pio_panic("SM claim failed"); + + if (!pio_sm_is_claimed(pio, sm)) + pio_panic("SM not claimed (1)"); + + pio_sm_claim(pio, sm); + if (!pio_get_error(pio)) + pio_panic("SM not claimed (2)"); + pio_clear_error(pio); + } + + for (sm = 0; sm < pio_get_sm_count(pio); sm++) { + pio_sm_unclaim(pio, sm); + if (pio_sm_is_claimed(pio, sm)) + pio_panic("SM still claimed"); + } + + pio_claim_sm_mask(pio, (1 << (pio_get_sm_count(pio) - 1)) - 1); + if (pio_get_error(pio)) + pio_panic("masked claim failed"); + if ((uint)pio_claim_unused_sm(pio, false) != pio_get_sm_count(pio) - 1) + pio_panic("wrong SM (expected the last)"); + + for (sm = 0; sm < pio_get_sm_count(pio); sm++) { + pio_sm_unclaim(pio, sm); + if (pio_sm_is_claimed(pio, sm)) + pio_panic("SM still claimed"); + } + + sm = pio_claim_unused_sm(pio, true); + + for (offset = 0; offset < pio_get_instruction_count(pio); offset++) { + dummy_program_instructions[0] = offset + 1; + if (!pio_can_add_program(pio, &dummy_program)) + pio_panic("can't add program"); + if (pio_add_program(pio, &dummy_program) == PIO_ORIGIN_ANY) + pio_panic("failed to add program (1)"); + } + + dummy_program_instructions[0] = offset + 1; + + if (pio_can_add_program(pio, &dummy_program)) + pio_panic("can add program"); + if (pio_add_program(pio, &dummy_program) != PIO_ORIGIN_INVALID) + pio_panic("added program again"); + pio_clear_error(pio); + + for (offset = 0; offset < pio_get_instruction_count(pio); offset++) { + pio_remove_program(pio, &dummy_program, offset); + if (pio_get_error(pio)) + pio_panic("remove program failed"); + pio_remove_program(pio, &dummy_program, offset); + if (!pio_get_error(pio)) + pio_panic("removed program again"); + pio_clear_error(pio); + } + + for (offset = 0; offset < pio_get_instruction_count(pio); offset++) { + dummy_program_instructions[0] = offset + 1; + if (!pio_can_add_program_at_offset(pio, &dummy_program, offset)) + pio_panic("can't add program at offset"); + pio_add_program_at_offset(pio, &dummy_program, offset); + } + + for (offset = 0; offset < pio_get_instruction_count(pio); offset++) { + pio_remove_program(pio, &dummy_program, offset); + } + + offset = pio_add_program(pio, &echo_program); + c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + echo_wrap_target, offset + echo_wrap); + + pio_sm_init(pio, sm, offset, &c); + + pio_sm_put(pio, sm, 0); + + if (pio_sm_is_tx_fifo_empty(pio, sm)) + pio_panic("TX FIFO is empty (1)"); + + pio_sm_clear_fifos(pio, sm); + + if (!pio_sm_is_tx_fifo_empty(pio, sm)) + pio_panic("TX FIFO is not empty (1)"); + if (pio_sm_get_tx_fifo_level(pio, sm) != 0) + pio_panic("TX FIFO level is not zero"); + for (i = 1; i <= (int)pio_get_fifo_depth(pio); i++) + { + if (pio_sm_is_tx_fifo_full(pio, sm)) + pio_panic("TX FIFO is full (1)"); + pio_sm_put(pio, sm, i); + if (pio_sm_is_tx_fifo_empty(pio, sm)) + pio_panic("TX FIFO is empty (2)"); + if ((int)pio_sm_get_tx_fifo_level(pio, sm) != i) + pio_panic("Wrong TX FIFO level"); + } + + if (!pio_sm_is_tx_fifo_full(pio, sm)) + pio_panic("TX FIFO is not full (1)"); + + pio_sm_drain_tx_fifo(pio, sm); + + if (!pio_sm_is_tx_fifo_empty(pio, sm)) + pio_panic("TX FIFO is not empty (2)"); + + for (i = 1; i <= (int)pio_get_fifo_depth(pio); i++) + pio_sm_put(pio, sm, i); + + if (!pio_sm_is_tx_fifo_full(pio, sm)) + pio_panic("TX FIFO is not full (2)"); + + if (!pio_sm_is_rx_fifo_empty(pio, sm)) + pio_panic("RX FIFO not empty"); + + if ((int)pio_sm_get_rx_fifo_level(pio, sm) != 0) + pio_panic("RX FIFO level not 0"); + + pio_sm_set_enabled(pio, sm, true); + + if (!pio_sm_is_tx_fifo_empty(pio, sm)) + pio_panic("TX FIFO is not empty (3)"); + + if (!pio_sm_is_rx_fifo_full(pio, sm)) + pio_panic("RX FIFO is not full"); + + if (pio_sm_get_rx_fifo_level(pio, sm) != pio_get_fifo_depth(pio)) + pio_panic("RX FIFO level not the maximum"); + + for (i = pio_get_fifo_depth(pio) - 1; i >= 0; i--) + { + if (pio_sm_is_rx_fifo_empty(pio, sm)) + pio_panic("RX FIFO is empty"); + if (pio_sm_get(pio, sm) != (uint)(pio_get_fifo_depth(pio) - i)) + pio_panic("wrong RX data"); + if ((int)pio_sm_get_rx_fifo_level(pio, sm) != i) + pio_panic("wrong RX FIFO level"); + } + + if (!pio_sm_is_rx_fifo_empty(pio, sm)) + pio_panic("RX FIFO is not empty"); + + offset = pio_add_program(pio, &genseq_program); + pio_sm_config_xfer(pio, sm, PIO_DIR_FROM_SM, 256, 1); + + pio_gpio_init(pio, gpio); + pio_sm_set_consecutive_pindirs(pio, sm, gpio, 1, true); + c = genseq_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, gpio); + pio_sm_init(pio, sm, offset, &c); + + pio_sm_set_enabled(pio, sm, true); + + for (i = 0; i < DATA_WORDS; i++) { + printf("Iter %d:\n", i); + pio_sm_put_blocking(pio, sm, i); + if (use_dma) { + ret = pio_sm_xfer_data(pio, sm, PIO_DIR_FROM_SM, (i + 1) * sizeof(databuf[0]), databuf); + if (ret) + break; + + for (j = i; j >= 0; j--) + { + int v = databuf[i - j]; + if (v != j) + printf(" %d: %d\n", j, v); + } + } else { + for (j = i; j >= 0; j--) + { + int v = pio_sm_get_blocking(pio, sm); + if (v != j) + printf(" %d: %d\n", j, v); + } + } + sleep_ms(10); + } + + if (ret) + printf("* error %d\n", ret); + return ret; +} diff --git a/piolib/examples/echo.pio.h b/piolib/examples/echo.pio.h new file mode 100644 index 0000000..a447d8c --- /dev/null +++ b/piolib/examples/echo.pio.h @@ -0,0 +1,39 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// ---- // +// echo // +// ---- // + +#define echo_wrap_target 0 +#define echo_wrap 2 +#define echo_pio_version 0 + +static const uint16_t echo_program_instructions[] = { + // .wrap_target + 0x80a0, // 0: pull block + 0xa0c7, // 1: mov isr, osr + 0x8020, // 2: push block + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program echo_program = { + .instructions = echo_program_instructions, + .length = 3, + .origin = -1, +}; + +static inline pio_sm_config echo_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + echo_wrap_target, offset + echo_wrap); + return c; +} +#endif diff --git a/piolib/include/piolib.h b/piolib/include/piolib.h index 80502f9..c274a53 100644 --- a/piolib/include/piolib.h +++ b/piolib/include/piolib.h @@ -24,6 +24,7 @@ extern "C" { #define PIO_ERR_VAL(x)((int)(uintptr_t)(x)) #define PIO_ORIGIN_ANY ((uint)(~0)) +#define PIO_ORIGIN_INVALID PIO_ORIGIN_ANY #define pio0 pio_open_helper(0) @@ -298,7 +299,7 @@ static inline uint pio_add_program(PIO pio, const pio_program_t *program) uint offset; check_pio_param(pio); offset = pio->chip->pio_add_program_at_offset(pio, program, PIO_ORIGIN_ANY); - if (offset == PIO_ORIGIN_ANY) + if (offset == PIO_ORIGIN_INVALID) pio_error(pio, "No program space"); return offset; } @@ -306,7 +307,7 @@ static inline uint pio_add_program(PIO pio, const pio_program_t *program) static inline void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) { check_pio_param(pio); - if (pio->chip->pio_add_program_at_offset(pio, program, offset) == PIO_ORIGIN_ANY) + if (pio->chip->pio_add_program_at_offset(pio, program, offset) == PIO_ORIGIN_INVALID) pio_error(pio, "No program space"); }