SPI DEV使用参考
1. 概述¶
本文主要介绍Linux用户环境下SPI driver的使用。
2. SPI控制¶
2.1. SPI Pads¶
SPI pad modes 可设定的mode 和脚位对应如下。
表 2‑1:Pudding平台
Spi Group | Mode | SPI0_CZ | SPI0_CK | SPI0_DI(MOSI) | SPI0_DO(MISO) | DEV |
---|---|---|---|---|---|---|
SPI 0 | 1 | PAD_I2S0_BCK | PAD_I2S0_WCK | PAD_I2S0_DI | PAD_I2S0_DO | /dev/spidev0.0 |
2 | PAD_FUART_RX | PAD_FUART_TX | PAD_FUART_CTS | PAD_FUART_RTS | ||
SPI 1 | 1 | PAD_FUART_RX | PAD_FUART_TX | PAD_FUART_CTS | PAD_FUART_RTS | /dev/spidev1.0 |
2 | PAD_GPIO12 | PAD_GPIO12 | PAD_GPIO12 | PAD_GPIO12 | ||
5 | PAD_PM_SPI_CZ | PAD_PM_SPI_CK | PAD_PM_SPI_DI | PAD_PM_SPI_DO |
表 2‑2:Ispahan平台
Spi Group | Mode | SPI0_CZ | SPI0_CK | SPI0_DI(MOSI) | SPI0_DO(MISO) | DEV |
---|---|---|---|---|---|---|
SPI 0 | 1 | PAD_SPI0_CZ | PAD_SPI0_CK | PAD_SPI0_DI | PAD_SPI0_DO | /dev/spidev0.0 |
2 | PAD_GPIO4 | PAD_GPIO5 | PAD_GPIO6 | PAD_GPIO7 | ||
3 | PAD_FUART_RX | PAD_FUART_TX | PAD_FUART_CTS | PAD_FUART_RTS | ||
4 | PAD_SD1_IO0 | PAD_SD1_IO2 | PAD_SD1_IO3 | PAD_SD1_IO4 | ||
SPI 1 | 3 | PAD_SD_D0 | PAD_ SD_D1 | PAD_ SD_D2 | PAD_ SD_D3 | /dev/spidev1.0 |
4 | PAD_GPIO0 | PAD_ GPIO2 | PAD_ GPIO3 | PAD_ GPIO |
2.2. SPI0的 dts 配置¶
以 Pudding mode4为例。
如下use-dma表示是否使用DMA,修改 infinity6e.dtsi:
添加 SPI0 padmux 复用
修改 infinity6e-padmux-qfn.dtsi
SPI0 选择 Mode4(PAD_GPIO0/PAD_GPIO1/PAD_GPIO2/PAD_GPIO3)进行输出,没有在其他组输出的话,需要将其他组注释掉。
2.3. SPI1的 dts 配置¶
以 Ispphand mode4为例。Ispahan无padmux,只需在对应的节点添加pad-ctrl属性,其值为对应mode的CZ pad。
如下 use-dma表示是否使用DMA,修改 infinity6b0.dtsi:
3. KERNEL配置¶
3.1. 打开 kernel 对 SPI 的配置¶
3.2. 打开 SStar SPI 驱动配置¶
4. 用户DEMO¶
4.1. SPI device¶
" /dev/spidev1.0” //根据使用哪一组spi确认节点
4.2. Sample code¶
static const char *device = "/dev/spidev1.0"; //根据使用哪一组spi确认节点 static uint8_t mode = 0; /* SPI通信使用全双工,设置CPOL=0,CPHA=0。 */ static uint8_t bits = 8; /* 8bits读写,MSB first。*/ static uint32_t speed = 60*1000*1000;/* 设置传输速度 */ static uint16_t delay = 0; static int g_SPI_Fd = 0; static void pabort(const char *s) { perror(s); abort(); } /** * 功 能:同步数据传输 * 入口参数 : * TxBuf -> 发送数据首地址 * len -> 交换数据的长度 * 出口参数: * RxBuf -> 接收数据缓冲区 * 返回值:0 成功 * 开发人员:Lzy 2013-5-22 */ 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, .delay_usecs = delay, }; ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) perror("can't send spi message\n"); else { #if SPI_DEBUG int i; printf("nsend spi message Succeed\n"); printf("nSPI Send [Len:%d]: \n", len); for (i = 0; i < len; i++) { if (i % 8 == 0) printf("nt\n"); printf("0x%02X \n", TxBuf[i]); } printf("n"); printf("SPI Receive [len:%d]:\n", len); for (i = 0; i < len; i++) { if (i % 8 == 0) printf("nt\n"); printf("0x%02X \n", RxBuf[i]); } printf("\n"); #endif } return ret; } /** * 功 能:发送数据 * 入口参数 : * TxBuf -> 发送数据首地址 *len -> 发送与长度 *返回值:0 成功 * 开发人员:Lzy 2013-5-22 */ int SPI_Write(uint8_t *TxBuf, int len) { int ret; int fd = g_SPI_Fd; ret = write(fd, TxBuf, len); if (ret < 0) perror("SPI Write error\n"); else { #if SPI_DEBUG int i; printf("SPI Write [Len:%d]: \n", len); for (i = 0; i < len; i++) { if (i % 8 == 0) printf("\n\t"); printf("0x%02X \n", TxBuf[i]); } printf("\n"); #endif } return ret; } /** * 功 能:接收数据 * 出口参数: * RxBuf -> 接收数据缓冲区 * rtn -> 接收到的长度 * 返回值:>=0 成功 * 开发人员:Lzy 2013-5-22 */ int SPI_Read(uint8_t *RxBuf, int len) { int ret; int fd = g_SPI_Fd; ret = read(fd, RxBuf, len); if (ret < 0) printf("SPI Read error\n"); else { #if SPI_DEBUG int i; printf("SPI Read [len:%d]:\n", len); for (i = 0; i < len; i++) { if (i % 8 == 0) printf("\n\t"); printf("0x%02X \n", RxBuf[i]); } printf("\n"); #endif } return ret; } /** * 功 能:打开设备 并初始化设备 * 入口参数 : * 出口参数: * 返回值:0 表示已打开 0XF1 表示SPI已打开 其它出错 * 开发人员:Lzy 2013-5-22 */ int SPI_Open(void) { 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\n"); else printf("SPI - Open Succeed. Start Init SPI...\n"); g_SPI_Fd = fd; /* * spi mode */ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); if (ret == -1) pabort("can't set spi mode\n"); ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); if (ret == -1) pabort("can't get spi mode\n"); /* * bits per word */ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't set bits per word\n"); ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); if (ret == -1) pabort("can't get bits per word\n"); /* * max speed hz */ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't set max speed hz\n"); ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); if (ret == -1) pabort("can't get max speed hz\n"); printf("spi mode: %d\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d KHz (%d MHz)\n", speed / 1000, speed / 1000 / 1000); return ret; } /** * 功 能:关闭SPI模块 */ int SPI_Close(void) { int fd = g_SPI_Fd; if (fd == 0) /* SPI是否已经打开*/ return 0; close(fd); g_SPI_Fd = 0; return 0; } /** * 功 能:自发自收测试程序 * 接收到的数据与发送的数据如果不一样 ,则失败 * 说明: * 在硬件上需要把输入与输出引脚短跑 * 开发人员:Lzy 2013-5-22 */ 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; printf("nSPI - LookBack Mode Test...\n"); ret = SPI_Transfer(tx, rx, BufSize); if (ret > 1) { ret = memcmp(tx, rx, BufSize); if (ret != 0) { printf("tx:\n"); for (i = 0; i < BufSize; i++) { printf("%d ", tx[i]); } printf("\n"); printf("rx:\n"); for (i = 0; i < BufSize; i++) { printf("%d ", rx[i]); } printf("\n"); perror("LookBack Mode Test error\n"); } else printf("SPI - LookBack Mode OK\n"); } return ret;