我有一个问题,我很难解决。 我有一个联合,其中包含一个缓冲区,其结构映射缓冲区的位。有些东西(当然是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
部分,它再次没有给我我想要的东西。
是否可以创建一个数组,该数组是另一个数组的子集,从外部数组的指定地址开始?我认为这可以解决我的问题,但我也害怕那个
的记忆含义答案 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
的指针
pad
是ref->pad[]
数组末尾填充的填充条目数
data
是在ref->data[]
数组开头填写的条目数
返回值是收到的data
条目数(已完全填写)
请考虑以下事项(为了简单起见,省略fd == -1
,ref == NULL
,pad > MAX_PAD
,data > 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->pad
或ref->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的例子,除了它使用单个读取而不是读取填充到单独的缓冲区。但是,扩展这些示例应该非常简单。