SPI使用参考

Version 0.3


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.ctools/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);
}

用户态测试步骤

  1. make menuconfig

    将 Device Drivers –> SPI Support -> User mode SPI device driver support 选为y

  2. make –j32

  3. cp arch/arm/boot/uImage.xz ../project/image/output/images/kernel

  4. reboot board into uboot and excute “estar”

  5. cd tools/

  6. make spi

  7. cp tools/spi/spidev_test to board /customer/

  8. excute cmd on board shell:cd customer;./spidev_test –D /dev/spidev0.0

  9. 使用示波器查看MSPI0输出,应输出spidev_test预设数据:

关于spidev_test的更多用法请参考:tools/spi/spidev_test.c文件。