将数组的子集传递给linux spi驱动程序

时间:2016-10-31 00:43:35

标签: c linux spi

我有一个问题,我很难解决。 我有一个联合,其中包含一个缓冲区,其结构映射缓冲区的位。有些东西(当然是pragma):

union
uint32 buf[512]
struct
uint8_t pad[256];
uint32_t data[256];

buf[]部分旨在作为接收缓冲区传递给Linux spi驱动程序。我遇到的问题是,根据我的传输,我收到的填充的大小是可变的,因此,它不能直接使用联合进行访问。

我需要做的是能够将特定索引的buf[]传递给spi驱动程序,I.E Rx缓冲区从buf[128]而不是buf[0]开始。这并不总是相等的,所以我有一个等式,告诉我我需要的起点是&(buf[0]+padmax-padsize]),它应该导致buf[0]buf[256]之间的值。然而,问题是spi驱动程序期望传输缓冲区的参数包含指向缓冲区的指针,并且传递它的直接地址并不能给我我想要的东西。

我也尝试过指定上述等式的地址并将其传递给rxbuffer结构的spi部分,它再次没有给我我想要的东西。

是否可以创建一个数组,该数组是另一个数组的子集,从外部数组的指定地址开始?我认为这可以解决我的问题,但我也害怕那个

的记忆含义

1 个答案:

答案 0 :(得分:0)

原因很可能是您以32位为单位(以buf元素为单位)计算地址,而不是根据算法计算出的字节数。

让我们简化一下情况,并说结构只是

#define MAX_PAD  256
#define MAX_DATA 256

struct spi_data {
    uint8_t  pad[MAX_PAD];
    uint32_t data[MAX_DATA];
};

并且您想要实现类似于

的功能
size_t spi_recv(int fd, struct spi_data *ref, size_t pad, size_t data)

,其中

  • fd是来自<{p>

  • read()的文件描述符
  • ref是指向要使用的struct spi_data的指针

  • padref->pad[]数组末尾填充的填充条目数

  • data是在ref->data[]数组开头填写的条目数

  • 返回值是收到的data条目数(已完全填写)

请考虑以下事项(为了简单起见,省略fd == -1ref == NULLpad > MAX_PADdata > MAX_DATA的参数检查:

size_t spi_recv(int fd, struct spi_data *ref, size_t pad, size_t data)
{
    ssize_t  n;

    n = read(fd, &ref->pad[sizeof ref->pad / sizeof ref->pad[0] - pad],
                 pad * sizeof ref->pad[0] + data * sizeof ref->data[0]);

    if (n == -1) {
        /* Error; errno already set */
        return 0;
    } else
    if (n < 0) {
        /* Should never occur, but let's be paranoid */
        errno = EIO;
        return 0;
    } else
    if (n < pad * sizeof ref->pad[0]) {
        /* Only partial padding received */
        errno = 0;
        return 0;
    } else {
        /* Zero or more data words received */
        errno = 0;
        return (n - pad * sizeof ref->pad[0]) / sizeof ref->data[0];
    }
}

指向填充的最后pad个元素的指针是

    &ref->pad[sizeof ref->pad / sizeof ref->pad[0] - pad])

基本上等同于&(ref->pad[MAX_PAD - pad]),除了MAX_PAD宏,我们使用(sizeof ref->pad)/(sizeof ref->pad[0])来评估为ref->pad[]数组声明的成员数。 (这仅在ref->pad是数组时有效;如果它是指针则不起作用。)

像往常一样,read()将字节数 - 而不是ref->padref->data的元素 - 作为参数,因此我们需要将元素计数乘以它们各自的元素大小字节数;因此,填充的pad元素和数据data元素的字节数为pad * sizeof ref->pad[0] + data * sizeof ref->data[0]

由于函数返回接收到的完整数据字的数量,必须从返回值中减去填充字节数,然后除以数据元素类型(整数除法向下舍入),以获得完整数据字的数量

然而,我并不认为上述界面是最佳的。我特别不喜欢SPI传输以部分字结尾的可能性;上述界面不会让调用者可靠地检测到这种情况。

如果你使用spidev,ioctl()接口会更好用。例如,您可以使用SPI_IOC_MESSAGE(2)将填充和数据读取到单独的缓冲区中,甚至可以SPI_IOC_MESSAGE(3)来写入命令,然后读取填充缓冲区,将另一个读取到数据缓冲区。 Linux-Sunxi Wiki页面有一个非常简单的用法here的例子,除了它使用单个读取而不是读取填充到单独的缓冲区。但是,扩展这些示例应该非常简单。