江科大学习笔记 _15.硬件SPI

W25Q64:地址宽度24位,3字节 8M->块->扇区->页
8 * 1024 *1024 范围:00 00 00H--7F FF FFH (8MB)
8M分为128个块,每个块(64K) 块0-块127,
(8*1024 *1024 /64*1024) = 128 范围:xx 00 00 H--xx FF FFH(64KB)
64K分为16个扇区,每个扇区(4k),扇区0--扇区15
(64*1024/4*1024) = 16 范围:xx x0 00h -- xx xF FFh (4KB)
4K分为16个页,每个页(256字节),页0--页15
(4*1024/256) = 16 范围:xx xx 00h -- xx xx FFh (256)

STM32单片机为主机,W25Q64为从机
CS:片选
DO:从机输出
CLK:时钟
DI:从机输入

SPI和IIC都是高位先行
串口是低位先行
每次交换8或16位数据
SPI时钟 = fPCLK/分频系数(2,4,8,16,32,64,128,256),
SPI1和SPI2挂载总线不同SPI1->APB2(72M),SPI2>APB1(36M)

TDR/RDR/TXE/RXNE
TXE:TDR数据全部移入移位寄存器,置1
RXNE:移位寄存器数据全部移入RDR,置1

CPOL = 1;CPHA = 1,SPI模式3 SCK默认高电平
检测到TXE = 1,TDR为空 -> 软件写入0XF1至SPI_DR -> TDR的值变为F1,TXE变为0
RXNE置1后,读出接收到的第一个数据, 再写入下一个字节数据
交换字节时序
1. 等待TXE为1
2. 写入发送的数据至TDR
3. 等待RXNE为1
4. 读取RDR接收的数据,重复这4步
硬件SPI配置步骤
1. 开始时钟SPI、GPIO
2. 初始化GPIO口,SCK/MOSI推挽输出,MISO为上拉输入,SS通用推挽输出
3. 配置SPI外设
4. SPI_Cmd
void MySPI_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = SS;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_Port, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin = SCK|MOSI;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_Port, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = MISO;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SPI_Port, &GPIO_InitStruct);
SPI_InitTypeDef SPI_InitStruct;
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;//主机or从机
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;//交换数据8位or16位
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //高位开始or低位开始
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//预分频
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//第一个边沿采样or第二个边沿采样
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//默认时钟极性低or高
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI1,&SPI_InitStruct);
SPI_Cmd(SPI1, ENABLE);
MySPI_W_SS(1);//默认不选中从机
}
交换字节时序
1.等待TXE为1
2.写入发送的数据至TDR
3.等待RXNE为1
4.读取RDR接收的数据,重复这4步
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
//等待TXE为1
SPI_I2S_SendData(SPI1, ByteSend);
//写发送的数据至TDR
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET);
//等待RXNE为1(发送完成即接收完成)
return SPI_I2S_ReceiveData(SPI1);
//读取RDR接收数据
}
需要考虑标志位是否会自动清除,如果不自动清除,则要手动清除