SPI timeout if transferring > 32 bytes

Hello,

As far as I can tell, it is not possible to perform SPI transfers larger than 32 bytes, an unfortunately small size, and I believe this is a bug(or something) in the rockchip spi driver. For reference, the following basic spi code performs correctly with tx/rx size of 32, but returns an spi timeout error if the buffer size is > 32:

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/spi/spidev.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>

// SZ <= 32 OK (PIO transfers), >32 timeout
#define SZ 33

int main()
{
int fd = open("/dev/spidev32766.0", O_RDWR);

uint8_t mode = SPI_MODE_0;
ioctl(fd, SPI_IOC_WR_MODE, &mode);
ioctl(fd, SPI_IOC_RD_MODE, &mode);

struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));

uint8_t tx_buf[SZ];
memset(tx_buf, 0, sizeof(tx_buf));

uint8_t rx_buf[SZ];
memset(rx_buf, 0, sizeof(rx_buf));

xfer.tx_buf = (unsigned long)&tx_buf;
xfer.rx_buf = (unsigned long)&rx_buf;
xfer.len = sizeof(rx_buf);
xfer.speed_hz = 1000000;
xfer.bits_per_word = 8;

int status = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer);

printf(“status %d\n”, status);
int i;
for(i=0; i<sizeof(rx_buf); i++) printf("%02x “, rx_buf[i]);
printf(”\n");

close(fd);

return 0;
}

I’ve found this reference from a few years ago - https://github.com/rockchip-linux/kernel/issues/19 that I think confirms my suspicion that it is an issue in the driver. Somebody claims it has been fixed though, although maybe instead of randomly failing, it now times out. Or maybe the fix is in a future version of the kernel that we dont have at the moment.

I know this a long shot, but does anybody have any ideas here? I can sort of get around it by chaining together spi calls, but I’m still making a ton of driver calls, which has a very real overhead.

1 Like

I’ve figured this out. This is actually due to an error in the devspi1 & devspi2 overlayt dtbo files, this is rockpi4 specific. The dma channels are wrong. For spi1 the channels should be 0xc & 0xd, spi2 the channels should be 0xe & 0xf, as specified here - http://opensource.rock-chips.com/images/e/ee/Rockchip_RK3399TRM_V1.4_Part1-20170408.pdf

You can fix this yourself by decompiling the overlays & changing the values, but Radxa should probably fix this on their end.

3 Likes

Thanks, really appreciate the update and solution!

Thanks for sharing. We will fix it on our side.

1 Like