Skip to content

Commit

Permalink
piolib: Add apitest
Browse files Browse the repository at this point in the history
apitest tests many of the API calls, demonstrating error handling.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
  • Loading branch information
pelwell committed Nov 21, 2024
1 parent 775224a commit 4223460
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 2 deletions.
5 changes: 5 additions & 0 deletions piolib/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
225 changes: 225 additions & 0 deletions piolib/examples/apitest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <stdio.h>
#include <stdlib.h>

#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;
}
39 changes: 39 additions & 0 deletions piolib/examples/echo.pio.h
Original file line number Diff line number Diff line change
@@ -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
5 changes: 3 additions & 2 deletions piolib/include/piolib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -298,15 +299,15 @@ 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;
}

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");
}

Expand Down

0 comments on commit 4223460

Please sign in to comment.