linux系统SPI通讯测试
源码
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include "Debug.h"
#define SPI_DEBUG 0
static uint8_t mode = 0;
static uint8_t bits = 8;
static uint32_t speed = 12 * 1000 * 1000;
static uint16_t delay = 0;
static int g_SPI_Fd = 0;
unsigned char r_buf[256];
unsigned char w_buf[256];
static void pabort(const char *s)
{
perror(s);
abort();
}
int SPI_Transfer(const uint8_t *TxBuf, uint8_t *RxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long) TxBuf,
.rx_buf = (unsigned long) RxBuf,
.len = len,
.speed_hz = 0,
.delay_usecs = delay,
.bits_per_word = 2
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pr_err("can't send spi message");
else
{
#if SPI_DEBUG
int i;
pr_debug("\nsend spi message Succeed");
pr_debug("\nSPI Send [Len:%d]: ", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("\n\t");
printf("0x%02X ", TxBuf[i]);
}
printf("\n");
pr_debug("SPI Receive [len:%d]:", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("\n\t");
printf("0x%02X ", RxBuf[i]);
}
printf("\n");
#endif
}
return ret;
}
int SPI_Write(uint8_t *TxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;
ret = write(fd, TxBuf, len);
if (ret < 0)
pr_err("SPI Write error\n");
else
{
#if SPI_DEBUG
int i;
pr_debug("\nSPI Write [Len:%d]: ", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("\n\t");
printf("0x%02X ", TxBuf[i]);
}
printf("\n");
#endif
}
return ret;
}
int SPI_Read(uint8_t *RxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;
ret = read(fd, RxBuf, len);
if (ret < 0)
pr_err("SPI Read error\n");
else
{
#if SPI_DEBUG
int i;
pr_debug("SPI Read [len:%d]:", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("\n\t");
printf("0x%02X ", RxBuf[i]);
}
printf("\n");
#endif
}
return ret;
}
int SPI_Open_(const char* device)
{
int fd;
int ret = 0;
if (g_SPI_Fd != 0)
return 0xF1;
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
else
pr_debug("SPI - Open Succeed. Start Init SPI...\n");
g_SPI_Fd = fd;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
pr_debug("spi mode: %d\n", mode);
pr_debug("bits per word: %d\n", bits);
pr_debug("max speed: %d KHz (%d MHz)\n", speed / 1000, speed / 1000 / 1000);
return ret;
}
int SPI_Close(void)
{
int fd = g_SPI_Fd;
if (fd == 0)
return 0;
close(fd);
g_SPI_Fd = 0;
return 0;
}
int SPI_LookBackTest(void)
{
int ret, i;
const int BufSize = 16;
uint8_t tx[BufSize], rx[BufSize];
bzero(rx, sizeof(rx));
for (i = 0; i < BufSize; i++)
tx[i] = i;
pr_debug("\nSPI - LookBack Mode Test...\n");
ret = SPI_Transfer(tx, rx, BufSize);
if (ret > 1)
{
ret = memcmp(tx, rx, BufSize);
if (ret != 0)
{
pr_err("LookBack Mode Test error\n");
}
else
pr_debug("SPI - LookBack Mode OK\n");
}
return ret;
}
note
- 使用
write/read
测试SPI通讯只能半双工工作 - 使用
ioctl
就可以全双工工作,并且可以按照需求修改SPI配置
- 可以参考内核源:
kernel/linux-5.15/tools/spi/spidev_test.c