文章列表
嵌入式各协议标准按照OSI模型的思路进行逐个梳理,文章列表如下:
- 串行通信&UART协议梳理附STM32平台采用DMA以UART方式收发不定长信息
- I²C总线协议梳理附STM32平台I2C总线SSD1306OLED屏幕软件模拟方式驱动
- SDIO协议梳理附SD卡读写以及FATFS移植实例
- SPI协议梳理附SSD1306OLED屏幕驱动
SPI(Serial Peripheral Interface)也采用串行通信的思想;是一种简单的双向四线制的全双工总线协议,SPI协议标准涉及OSI模型的物理层,数据链路层。
物理层
协议项 | 协议内容 |
---|---|
通信模式 | 全双工 |
连接线电气特性 | 四根线:MOSI(主发从收线),MISO(主收从发线),SCLK(时钟线),CS(片选线,如果单设备可以不使用,即三线制) |
电平值 | 8v,5v,3.3v |
速度 | 不规定最大速率,取决于主机与设备的SPI接口速度 |
主从模式 | 一主一从(三线制),一主多从(四线制) |
一个主设备可以通过提供时钟信号和片选控制多个从设备,SPI规定从设备的时钟由主设备提供,没有时钟信号从设备不能正常工作。
- 独立从机型SPI(典型连线方式):
- 菊花链型SPI连线方式:
数据链路层
SPI协议需要片选线选择需要通信的从机,然而原始的SPI协议因为没有信号应答机制(如I²C应答位),所以SPI主机实际并不知道从机是否正确收到信息,甚至不知道从机是否真的存在。
极性和相位
极性
无数据传输的空闲状态时,SCLK为低电平,即CPOL=0:
无数据传输的空闲状态时,SCLK为高电平,即CPOL=1:
相位
所谓采样,也就是SDA进行下一步的输出电平信号的转换时间。
CPHA=0:SCLK第一个跳变沿开始采样:
CPHA=1:SCLK第二个跳变沿开始采样:
传输模式
模式 | 极性 | 相位 |
---|---|---|
模式1 | 低电平空闲,高电平传输 | 前沿采样,后沿输出 |
模式2 | 低电平空闲,高电平传输 | 后沿采样,前沿输出 |
模式3 | 高电平空闲,低电平传输 | 前沿采样,后沿输出 |
模式4 | 高电平空闲,低电平传输 | 后沿采样,前沿输出 |
模式1,CP0,CH0:
模式2,CP0,CH1:
模式3,CP1,CH0:
模式4,CP1,CH1:
SSD1306的SPI通信实例
SSD1306链接有七根线,除了VCC和VSS外有:SCLK(时钟),SDA(MOSI,主出从入),CS(片选),D/C(数据/命令),RES(复位)
接下来引述手册说明:
端口 使用方式 CS This pin is the chip select input. (active LOW). D/C This is Data/Command control pin. When it is pulled HIGH (i.e. connect to VDD), the data at D[7:0] is treated as data. When it is pulled LOW, the data at D[7:0] will be transferred to the command register. RES This pin is reset signal input. When the pin is pulled LOW, initialization of the chip is executed. Keep this pin HIGH (i.e. connect to VDD) during normal operation.
如上表上图所示:
- CS传输时需要置于低电平
- DC端口选择传输的时命令字符还是数据字符,高电平传输数据,低电平传输命令
- SCLK上升沿输出数据,下降沿采样。
function | RD | R/W | CS | DC | D0 |
---|---|---|---|---|---|
write command | tie low | tie low | low | low | ↑ |
write data | tie low | tie low | low | high | ↑ |
SDIN is shifted into an 8-bit shift register on every rising edge of SCLK in the order of D7, D6, … D0. D/C# is sampled on every eighth clock and the data byte in the shift register is written to the Graphic Display Data RAM (GDDRAM) or command register in the same clock.
核心代码
uint8_t OLED_InitCmd[26]={
0xAE,0x20,0x10,0xB0,0xC8,0x40,
0x81,0x7F,0xA1,0xA6,0xA8,0x3F,
0xA4,0xD3,0x00,0xD5,0xF0,0xD9,
0x22,0xDA,0x12,0xDB,0x20,0x8D,
0x14,0xAF,
};
void ssd1306_spi_init(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_4,GPIO_PIN_RESET);
uint8_t count_send;
for(count_send=0;count_send<26;count_send++){
HAL_SPI_Transmit(&hspi1,&OLED_InitCmd[count_send],1,HAL_MAX_DELAY);
}
}
void ssd1306_spi_send_data_arr(uint32_t data_num){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_4,GPIO_PIN_SET);
uint32_t count_send;
uint8_t data=0xFF;
for(count_send=0;count_send<data_num;count_send++){
HAL_SPI_Transmit(&hspi1,&data,1,HAL_MAX_DELAY);
}
}