0.ESP32C3 SPI 接口介绍

ESP32-C3 内部集成了 3 个 SPI 外设,SPI0SPI1SPI2。其中SPI0SPI1两个控制器共享相同的 SPI 总线信号,由一个仲裁器来确定SPI0SPI1哪个可以访问总线,SPI0SPI1 只可以配置成SPI 存储器模式。SPI2 是一个通用 SPI 控制器。具有独立的同名信号总线。该总线有 6 条 CS 线来驱动多达 6 个 SPI 从机。

1.ESP32C3 SPI2 设置

ESP32C3有三个SPI外设,其中只有SPI2是通用的SPI控制器(SPI0SPI1只能做存储器且共享总线,这里就就不介绍了)。

ESP32C3的SPI配置大体上可以分为两个部分:1.SPI2外设的设置(包括SPI总线速度、SPI模式等)。2.SPI2总线的设置(其实就是设置SPI2控制器和哪些GPIO相连)

ESP32C3 内部存在着IO MUXGPIO交换矩阵用来灵活的配置外设的GPIO,可以将其内部结构简单理解为下图。

image-20220310103824648

我们可以通过GPIO交换矩阵将任意GPIO和SPI2控制器相连。当信号频率较高时,可以设置IO MUX 绕过GPIO交换矩阵获得更好的高频数字特性。由于绕过了GPIO交换矩阵SPI2控制器便只能和规定GPIO连接。下图为官方手册中给出的SPI2控制器对应的IO MUX管脚

image-20220310110650878

由上图不难看出,SPI2控制器工作在FSPIQ模式的IO MUX管脚对应的是GPIO2FSPIHD对应的是GPIO4 .......

但是SPI2工作在其他模式时SPI2控制器对应的IO MUX管脚是什么呢?我在手册上找到了下图。

结合两张图可以看出,当SPI2控制器工作在全双工SPI模式时MOSI对应GPIO7 MISO对应GPIO2 CS对应GPIO10 CLK对应GPIO6

需要注意的是,全双工SPI信号的CS可以对应FSPI信号的FSPICS0~FSPICS5中的任意一个,但是只有FSPICS0有对应的IO MUX管脚(说人话就是只有FSPICS0可以绕过GPIO交换矩阵)

image-20220310112500706

2.ESP32C3 SPI2 设置代码介绍

2.1SPI总线初始化

以下代码配置SPI2工作在master模式作为说明,首先定义了buscfg结构体,在buscfg结构体中,描述了SPI2外设和外部GPIO口的映射关系,不需要使用的信号使用-1标记。最后使用spi_bus_initialize()对SPI2总线初始化,其实总初始化的过程可以理解为对IO MUXGPIO交换矩阵的设置过程。

最后需要注意的两点:

  • SPI的CS不在此处设置,我们将在下文中设置。
  • buscfg结构体中存在着uint32_t flags成员变量,我们可以使用flags进行一些特殊的配置,比如设置GPIOSPI外设之间强制使用GPIO交换矩阵等等。希望大家在使用时留意一下,在下面的例子中并没有对flags做什么设置,默认情况下spi_bus_initialize()检查buscfg中描述的GPIO。如果为IO MUX功能引脚,会自动设置绕过GPIO交换矩阵
spi_bus_config_t buscfg={
        .miso_io_num=PIN_NUM_MISO,              //MISO
        .mosi_io_num=PIN_NUM_MOSI,              //MOSI
        .sclk_io_num=PIN_NUM_CLK,               //CLK
        .quadwp_io_num=-1,                      //不使用
        .quadhd_io_num=-1,                      //不使用
        .max_transfer_sz=320                    //最大传送数据长度
};

spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);    //初始化SPI总线

2.2 SPI2外设初始化

void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
    int dc=(int)t->user;
    gpio_set_level(PIN_NUM_DC, dc);
}

spi_device_interface_config_t devcfg={
        .clock_speed_hz=50*1000*1000,           //时钟速度
        .mode=3,                                //SPI 工作模式
        .spics_io_num=-1,                       //CS
        .queue_size=6,                          //传送队列深度
        .pre_cb=lcd_spi_pre_transfer_callback,  //SPI发送数据前执行的回调函数,一般用于SPI屏幕的D/C信号切换
};

static spi_device_handle_t spi;
spi_bus_add_device(SPI2_HOST, &devcfg, &spi);

2.3 SPI2发送数据

根据博主不负责任的研究,spi_device_queue_trans()在发送数据前会申请一块与trans.tx_buffer一样大的内存,将trans.tx_buffer中的数据拷贝到新申请的内存后,通过DMA发送数据,此处应在注意内存的消耗问题。

    static spi_transaction_t trans;
    
    trans.tx_buffer=(void *)(data);
    trans.length=len;
    trans.user=(void*)1;              //此处的user会被lcd_spi_pre_transfer_callback()回调函数的形参spi_transaction_t *t 携带

    spi_device_queue_trans(spi, &trans, portMAX_DELAY);

就先写这么多吧!!

以上

小尾巴,SPIslave模式的配置和master模式大体相同,只是使用的是spi_slave_initialize()初始化总线和SPI外设,嗯大家自己研究下吧。

文章目录