SPI
SPI,全称Serial Peripheral Interface,即串行外设接口,是一种同步串行接口技术。它最初由Motorola公司推出,并在其MC68HCXX系列处理器上首次定义。SPI接口主要应用在EEPROM、FLASH、实时时钟、AD转换器,以及数字信号处理器和数字信号解码器之间。这种接口的主要特点如下:
- 通信方式:SPI是一种高速的、全双工、同步的通信总线。它采用主从模式进行通信,通常有一个主设备和一个或多个从设备。主设备启动一个数据交换,从设备则在被选择时响应。这种通信方式使得SPI能够在同一时刻进行数据的发送和接收,提高了数据传输的效率。
- 优点:SPI接口的主要优点包括支持全双工通信,使得数据传输速度更快;协议简单,使得硬件和软件实现都相对容易;并且由于SPI在芯片的管脚上只占用四根线,因此能节约芯片的管脚,同时为PCB的布局节省空间。
- 缺点:尽管SPI有许多优点,但也存在一些缺点。例如,SPI没有指定的流控制,也没有应答机制来确认是否接收到数据,因此在数据传输的可靠性方面存在一定的缺陷。此外,SPI还需要占用主机较多的口线,每个从机都需要一根片选线,这在一定程度上限制了其应用范围。
在应用场景方面,SPI协议被广泛应用于工业自动化、通信、航空航天等领域。在嵌入式系统中,SPI主要用于连接各种外设,如存储器、传感器、显示器等。例如,SD卡、TFT液晶屏、NFC模块、加速度计等常见的外设都可以通过SPI接口来实现数据通信。SPI协议还常常被用于多机通信,例如在车载系统中,多个设备可以通过SPI接口进行数据传输,从而实现各个设备之间的协同工作。
以上是来自文心一言的介绍。
ESP32中的SPI
ESP32中一共是有四个SPI。
四个SPI的不同点在下面。
除了上面一大堆不同点外,最显著的,对我们感知起来比较明显的点就是前两个SPI的引脚是固定的,而后两个的引脚是可以通过交换矩阵而自定义的。
因此我们常用的还是后两个SPI。
其实我们并不需要特别关心它的硬件设计,我们只要能用就行。
使用SPI
和I2C相比,编程指南中的SPI有些乱,我看着迷迷糊糊的,因此我以立创开发板的文档为主,以编程指南为辅介绍如何使用SPI。
关于SPI的时序,可以参考我之前的文章,那边介绍的相对详细一些。
初始化总线
首先先初始化SPI的总线。
参数一指定SPI资源。但是在选择的时候发现只有三个SPI,不过没有影响,因为编程指南里说了,不支持SPI0和1,因此我们直接选择2和3即可。
参数二的结构体的成员变量很多,不过我们大多用不到,因此配置的时候选择性的配置即可。
参数三指定DMA,SPI_DMA_DISABLED不使用DMA,SPI_DMA_CH_AUTO自动分配DMA。
使用DMA则最大传输量为4096Byte,不使用则为64Byte。
cpp
spi_bus_config_t spi_initer={
.miso_io_num=12,
.mosi_io_num=13,
.sclk_io_num=14,
.max_transfer_sz=64
};
if(spi_bus_initialize(SPI2_HOST,&spi_initer,SPI_DMA_DISABLED)!=ESP_OK) printf("bus init success\r\n");
在总线上挂载设备
参数二的结构体的成员变量也很多,我们一样是挑着用上的配置。
参数三是传出参数,我们拿一个SPI设备句柄去接收。
cpp
spi_device_handle_t dev_handle;
spi_device_interface_config_t device_initer={
.command_bits=0,
.address_bits=0,
.mode=0,
.spics_io_num=15,
.clock_speed_hz=1000*1000
};
if(spi_bus_add_device(SPI2_HOST,&dev_handle,&dev_handle)!=ESP_OK) printf("add device success\r\n");
发送/接收数据
参数二的结构体成员变量也不少,但是我们配置好要发送的数据和长度,以及接收数据的地方和长度即可。
硬件SPI差不多就是这样,本来想驱动一下ST7735S的,结果发现还是使用软件SPI会更方便,因为ST7735S除了SPI之外还有另外的控制线,这里就偷个懒不写了。下次有机会我再写个ESP32软件SPI驱动ST7735S屏幕的文章。
关于硬件SPI的示例代码,可以参考一下立创开发板的SPI驱动W25Q64,代码写的很详细,基本上复制粘贴修修改改就能用。
Docshttps://lceda001.feishu.cn/wiki/GOIlwwfbIi1SC3k8594cDeFVn8g