SPI使用参考
1. 概述¶
表1-1
MSPI Group | DMA | Buff | Full-duplex |
---|---|---|---|
HW MSPI group0 | Support | Support | Support |
HW MSPI group1 | Support | Support | Support |
HW MSPI group2 | Not support | Support | Support |
提供3组HW MSPI,MSPI0和MSPI1支持DMA模式,MSPI2不支持DMA模式。
可以参考上图修改是否使用DMA模式。
注意:MSPI2不支持DMA模式,开启MSPI2的DMA模式可能会影响到其他组MSPI DMA模式的工作。用户可在板子上执行ls sys/class/spi_master/
查看已注册的spi master。
端口复用关系(Padmux)请修改相应padmux.dtsi
文件。例如:
图中的宏定义均以预定义好,如发现有遗漏,请联系相关工程师添加。
图中第一列GPIO Index(与GPIO Name相同),可在driver/sstar/include/mercury6/gpio.h
中找到;
第二列为复用的设定,可在driver/sstar/include/mercury6/padmux.h
中找到;
第三列为该组设定的索引,需要获取该组设定的时候,可以使用mdrv_padmux_getpad获取设定。如图中代表的含义为“将PAD_GPIO2、PAD_GPIO3、PAD_GPIO4和PAD_GPIO5分别设置为MSPI0的CS脚、Clock脚、MOSI脚和MISO脚”。
2. 使用MSPI¶
2.1. 用户态读写MSPI¶
内核有自带一套用于测试MSPI Master的Device Driver以及用户程序:drivers/spi/spidev.c
和tools/spi/spidev_test.c
。要使用内核自带测试程序,需要修改配置文件打开CONFIG_SPI_SPIDEV 选项。CONFIG_SPI_SPIDEV选项在menuconfig中:Device Drivers –> SPI Support -> User mode SPI device driver support
。
开启CONFIG_SPI_SPIDEV选项后,内核会在/dev文件夹下生成spidev0.0、spidev1.0以及spidev2.0文件。用户程序可以通过操作这几个文件操作对应的spi master。对这几个文件的操作可以参考tools/spi/spidev_test.c
。
spidev_test的生成可以通过在tools/目录下执行make spi获取,生成的文件在:tools/spi/spidev_test,将spidev_test拷贝到开发板上运行,就可以通过命令行操作MSPI Master了。spidev_test核心发送/接收函数示例如下:
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) { int ret; int out_fd; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = len, .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; if (mode & SPI_TX_QUAD) tr.tx_nbits = 4; else if (mode & SPI_TX_DUAL) tr.tx_nbits = 2; if (mode & SPI_RX_QUAD) tr.rx_nbits = 4; else if (mode & SPI_RX_DUAL) tr.rx_nbits = 2; if (!(mode & SPI_LOOP)) { if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) tr.rx_buf = 0; else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) tr.tx_buf = 0; } ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); if (verbose) hex_dump(tx, len, 32, "TX"); if (output_file) { out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (out_fd < 0) pabort("could not open output file"); ret = write(out_fd, rx, len); if (ret != len) pabort("not all bytes written to output file"); close(out_fd); } if (verbose || !output_file) hex_dump(rx, len, 32, "RX"); }
当struct spi_ioc_transfer tr中.rx_buff不为null,.tx_buff为null时,MSPI Master执行的为半双工读操作;当.rx_buff为null,.tx_buff不为null时,执行的为半双工写操作;当.rx_buff和.tx_buff都不为null时,执行的为全双工读写操作。对应的波形示意图如下:
图中MOSI对应的为.tx_buff中的数据,MISO对应的为.rx_buff中的数据。
内核态读写MSPI¶
内核态读写MSPI可以参考/drivers/spi/spidev.c
的实现:
spidev_sync_read(struct spidev_data *spidev, size_t len) { struct spi_transfer t = { .rx_buf = spidev->rx_buffer, .len = len, .speed_hz = spidev->speed_hz, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); return spidev_sync(spidev, &m); } spidev_sync_write(struct spidev_data *spidev, size_t len) { struct spi_transfer t = { .tx_buf = spidev->tx_buffer, .len = len, .speed_hz = spidev->speed_hz, }; struct spi_message m; spi_message_init(&m); spi_message_add_tail(&t, &m); return spidev_sync(spidev, &m); }
用户态测试步骤¶
-
make menuconfig
将 Device Drivers –> SPI Support -> User mode SPI device driver support 选为y
-
make –j32
-
cp arch/arm/boot/uImage.xz ../project/image/output/images/kernel
-
reboot board into uboot and excute “estar”
-
cd tools/
-
make spi
-
cp tools/spi/spidev_test to board /customer/
-
excute cmd on board shell:cd customer;./spidev_test –D /dev/spidev0.0
-
使用示波器查看MSPI0输出,应输出spidev_test预设数据:
关于spidev_test的更多用法请参考:tools/spi/spidev_test.c
文件。