本帖最后由 聪聪哥哥 于 2024-12-30 19:34 编辑
1.1 SPI 介绍:
SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)。
SPI通信具有以下特点:
同步,全双工;
支持总线挂载多设备(SPI仅支持一主多从);
在不同情况下,通信线的名称可能有所变化:
SCK:SCLK、CLK、CK;
MOSI:DI(对从机而言);
MISO:DO(对从机而言);
SS:CS(Chip Select)、NSS(Not Slave Select);
SPI通信的SS线可以有多条,即对每一个从机而言都有单独的从机选择线,一般为低电平有效。
1.2 硬件连接
所有SPI设备的SCK、MOSI、MISO分别连在一起
主机另外引出多条SS控制线,分别接到各从机的SS引脚,同一时间,主机只能选择一条SS线为低电平
输出引脚配置为推挽输出(推挽输出能使SPI的通信速度轻松达到MHz的级别),输入引脚配置为浮空或上拉输入。当从机未被SS线选中时,从机的输出引脚MISO必须呈现高阻态,以防止数据冲突
2:硬件连接方式:
由于CW32FL010开发板没有将SPI通讯线连接起来,仅仅是将芯片的引脚引出,这样做有一个好处是我们可以任意的切换SPI的引脚,或者是选择其他的引脚,只是外部在调试的时候需用杜邦线连接起来就可以,只是杜邦线有时候会出现松动的情况,不利于我们查找软件问题或者是硬件问题。
这是我们使用的是 SPI1,W25Q64的引脚如下;
SPI_NCS ←----→ PA02
SPI_MISO ←----→ PA3
SPI_MOSI ←----→ PA4
SPI_CLK ←----→ PA05
我们利用串口1,将测试数据打印到串口接收工具,接线如下:
同样我们需要利用杜邦线接线连接到一起,由于我使用的是串口供电,不知道为什么J5接线端子,并没有电压,导致在我调试的过程中CH340芯片并没有工作,我还以为是代码的问题,找了半天才去测试电压,原来供电都不正常,将3.3V接入,就正常了。
我们这边使用OLED屏幕对调试的结果信息进行一个显示,显示SPI的通讯状态是否可以正常通过;
软件代码编写:定义一下发送的数据
uint8_t TxBuffer[] = "CW32L010 SPI FLASH Test by cong cong ge ge ";
uint8_t RxBuffer[BufferSize];
OLED屏幕显示固定的信息如下所示:
OLED_Init(); //OLED初始化
OLED_ShowString(1,2,"21IC lun tan ");
OLED_ShowString(2,2,"CW32 SPI TEST");
OLED_ShowString(3,2,"congcong gegge");
// OLED_ShowString(4,2,"FLASH SUCCESS");
SPI有关初始化部分:
void SPI_FLASH_Init(void)
{
SPI_InitTypeDef SPI_InitStructure = {0};
GPIO_InitTypeDef GPIO_InitStructure = {0};
/************************GPIO Configuration***********************/
SYSCTRL_AHBPeriphClk_Enable(FLASH_SPI_SCK_GPIO_CLK | FLASH_SPI_MISO_GPIO_CLK | FLASH_SPI_MOSI_GPIO_CLK | FLASH_SPI_CS_GPIO_CLK, ENABLE);
FLASH_SPI_APBClkENx(FLASH_SPI_CLK, ENABLE);
//CS
GPIO_InitStructure.Pins = FLASH_SPI_CS_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);
//SCK
GPIO_InitStructure.Pins = FLASH_SPI_SCK_GPIO_PIN;
GPIO_Init(FLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
//MOSI
GPIO_InitStructure.Pins = FLASH_SPI_MOSI_GPIO_PIN;
GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
//MISO
GPIO_InitStructure.Pins = FLASH_SPI_MISO_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_Init(FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
//SPI SCK MOSI MISO 复用
FLASH_SPI_AF_SCK;
FLASH_SPI_AF_MISO;
FLASH_SPI_AF_MOSI;
//拉高CS
FLASH_SPI_CS_HIGH();
/************************SPI Configuration***********************/
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 双线全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主机模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 帧数据长度为8bit
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // 时钟空闲电平为高
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 第二个边沿采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 片选信号由SSI寄存器控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 波特率为PCLK的8分频
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // 最高有效位 MSB 收发在前
SPI_InitStructure.SPI_Speed = SPI_Speed_Low; // 低速SPI
SPI_Init(FLASH_SPIx, &SPI_InitStructure);
SPI_Cmd(FLASH_SPIx, ENABLE);
}
这里我们使用两线制的SPI通讯,根据存储芯片的特点,在第二哥个边沿进行采样,配置信息如上所示:
主程序测试代码如下:
SPI_FLASH_BufferRead(RxBuffer, FLASH_ReadAddress, BufferSize);
printf("Read data:%s\r\n", RxBuffer);
//检查写入的数据与读出的数据是否一致
TransferStatus = Buffercmp(TxBuffer, RxBuffer, BufferSize);
//擦除扇区 4KB
SPI_FLASH_SectorErase(FLASH_SectorToEraseAddress);
//读数据
SPI_FLASH_BufferRead(RxBuffer, FLASH_ReadAddress, BufferSize);
if(TransferStatus == PASSED)
{
PB02_SETHIGH();
printf("\r\nFLASH Success\r\n");
OLED_ShowString(4,2,"FLASH SUCCESS");
}
else
{
printf("\r\nFLASH Error 1\r\n");
OLED_ShowString(4,2,"FLASH ERROR");
}
for(uint8_t j = 0; j < BufferSize; j++)
{
if(RxBuffer[j] != 0xFF)
{
printf("\r\nFLASH Error 2\r\n");
}
}
如上所示:先将发送buffer写到外部存储芯片后,并输出调试串口,随后对存储地址的内的数据,写入到读取buffer里面。为了检测SPI读写是否正常,需要将TXBUFFER 和RXBUFFER 里面的数据进行比较,当保持一致时,在OLED上面,显示“flash SUCCESS”的字样,如下图所示:
这里由于之前的代码中OLED显示所用的IO口,与SPI接口冲突,所以对IO口进行更换,不过在修改底层驱动的时候,只需要更改宏定义就可以,很方面。
串口工具接收到的数据如下所示:
|