Closed
Description
For #107, the ability to transfer more than 65532 bytes at a time was added.
On my system with kernel 6.6.74+rpt-rpi-v8 this works. On my colleague's system with 6.12.18-v8-16k+, large transfers result in "pio_sm_xfer_data: Operation not permitted".
This can easily be seen for example by using a modified version of the "pull noblock" test from #116 (comment)
On an affected system, running it with no args will give an error
$ uname -a
Linux raspberrypi 6.12.18-v8-16k+ #1862 SMP PREEMPT Wed Mar 12 12:33:09 GMT 2025 aarch64 GNU/Linux
$ ./bench1
Loaded program at 29, using sm 0
Actual frequency 10.000000MHz
Bounce buffer size 65532
Transfer size 262144
pio_sm_xfer_data: Operation not permitted
Aborted
while specifying a transfer size of 65532 will succeed:
$ ./bench1 10e6 65532
Loaded program at 29, using sm 0
Actual frequency 10.000000MHz
Bounce buffer size 65532
Transfer size 65532
32241744 bytes in 3000.3ms (10.2MiB/s)
{"frequency": 1e+07, "rate": 1.07463e+07}
pull noblock test with block size control
#include <errno.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "piolib.h"
#include "ws2812.pio.h"
#define bench_wrap_target 1
#define bench_wrap 2
static const uint16_t bench_program_instructions[] = {
0xe020, // set x,0
// .wrap_target
0x8080, // pull noblock
0x6000, // out pins, 32
// .wrap
};
static const struct pio_program bench_program = {
.instructions = bench_program_instructions,
.length = 3,
.origin = -1,
};
static inline pio_sm_config bench_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + bench_wrap_target, offset + bench_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline float bench_program_init(PIO pio, int sm, int offset, float freq, int gpio_base) {
pio_sm_config c = bench_program_get_default_config(offset);
sm_config_set_out_shift(&c, false, false /* auto pull */, 32);
sm_config_set_out_pins(&c, 0, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
float div = clock_get_hz(clk_sys) / freq;
if(div < 1) div = 1;
if(div > 65535) div = 65535;
int div_int = (int)div;
int div_frac = (int)((div - div_int) * 256);
sm_config_set_clkdiv_int_frac(&c, div_int, div_frac);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
pio_gpio_init(pio, gpio_base);
pio_gpio_init(pio, gpio_base+1);
pio_sm_set_consecutive_pindirs(pio, sm, gpio_base, 2, true);
return clock_get_hz(clk_sys) / (div_int + div_frac / 256.);
}
double monotonic() {
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return tv.tv_sec + tv.tv_nsec * 1e-9;
}
long databuf[32768];
int main(int argc, const char **argv)
{
float frequency = argc > 1 ? atof(argv[1]) : 10e6;
size_t xfer_size = argc > 2 ? (size_t)atoi(argv[2]) : sizeof(databuf);
size_t bounce_buffer_size = 65532;
PIO pio;
int sm;
uint offset;
if (xfer_size > sizeof(databuf)) xfer_size = sizeof(databuf);
pio = pio0;
sm = pio_claim_unused_sm(pio, true);
pio_sm_config_xfer(pio, sm, PIO_DIR_TO_SM, bounce_buffer_size, 3);
offset = pio_add_program(pio, &bench_program);
fprintf(stderr, "Loaded program at %d, using sm %d\n", offset, sm);
float actual_frequency = bench_program_init(pio, sm, offset, frequency, /* base pin */ 5);
fprintf(stderr, "Actual frequency %fMHz\n", actual_frequency/1e6);
fprintf(stderr, "Bounce buffer size %zu\n", bounce_buffer_size);
fprintf(stderr, "Transfer size %zu\n", xfer_size);
pio_sm_clear_fifos(pio, sm);
for(size_t i=0; i<sizeof(databuf)/sizeof(databuf[0]); i++ )
databuf[i] = i % 2 ? 0x55555555 : 0xaaaaaaaa;
double t0 = monotonic();
size_t xfer = 0;
do {
int r = pio_sm_xfer_data(pio, sm, PIO_DIR_TO_SM, xfer_size, databuf);
if (r < 0) { errno = -r; perror("pio_sm_xfer_data"); abort(); }
xfer += xfer_size;
} while(monotonic() - t0 < 3);
double t1 = monotonic();
double dt = t1 - t0;
double rate = xfer / dt; // bytes per second
fprintf(stderr, "%zu bytes in %.1fms (%.1fMiB/s)\n",
xfer, dt*1e3, rate / 1048576);
printf("{\"frequency\": %g, \"rate\": %g}\n",
actual_frequency, rate);
return 0;
}
Metadata
Metadata
Assignees
Labels
No labels