ESP32C3 SPI 的使用
0.ESP32C3 SPI 接口介绍
ESP32-C3 内部集成了 3 个 SPI 外设,SPI0
、SPI1
、SPI2
。其中SPI0
和SPI1
两个控制器共享相同的 SPI 总线信号,由一个仲裁器来确定SPI0
和SPI1
哪个可以访问总线,SPI0
和SPI1
只可以配置成SPI 存储器模式。SPI2
是一个通用 SPI 控制器。具有独立的同名信号总线。该总线有 6 条 CS 线来驱动多达 6 个 SPI 从机。
1.ESP32C3 SPI2 设置
ESP32C3有三个SPI外设,其中只有SPI2
是通用的SPI控制器(SPI0
和SPI1
只能做存储器且共享总线,这里就就不介绍了)。
ESP32C3的SPI配置大体上可以分为两个部分:1.SPI2外设的设置(包括SPI总线速度、SPI模式等)。2.SPI2总线的设置(其实就是设置SPI2控制器和哪些GPIO相连)
ESP32C3 内部存在着IO MUX
和GPIO交换矩阵
用来灵活的配置外设的GPIO,可以将其内部结构简单理解为下图。
我们可以通过GPIO交换矩阵
将任意GPIO和SPI2控制器相连。当信号频率较高时,可以设置IO MUX
绕过GPIO交换矩阵
获得更好的高频数字特性。由于绕过了GPIO交换矩阵
SPI2控制器便只能和规定GPIO连接。下图为官方手册中给出的SPI2控制器
对应的IO MUX管脚
。
由上图不难看出,SPI2控制器工作在FSPIQ
模式的IO MUX管脚对应的是GPIO2
,FSPIHD
对应的是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交换矩阵
)
2.ESP32C3 SPI2 设置代码介绍
2.1SPI总线初始化
以下代码配置SPI2工作在master模式作为说明,首先定义了buscfg
结构体,在buscfg
结构体中,描述了SPI2外设和外部GPIO口的映射关系,不需要使用的信号使用-1
标记。最后使用spi_bus_initialize()
对SPI2总线初始化,其实总初始化的过程可以理解为对IO MUX
和GPIO交换矩阵
的设置过程。
最后需要注意的两点:
- SPI的
CS
不在此处设置,我们将在下文中设置。 buscfg
结构体中存在着uint32_t flags
成员变量,我们可以使用flags
进行一些特殊的配置,比如设置GPIO
和SPI外设
之间强制使用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);
就先写这么多吧!!
以上
小尾巴,SPI
的 slave
模式的配置和master
模式大体相同,只是使用的是spi_slave_initialize()
初始化总线和SPI外设,嗯大家自己研究下吧。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
非常感谢博主的精彩讲解,正好在找ESP32-C3的SPI引脚复用的相关资料