如下图2所示为USART的数据帧类型示意图,当USART用作同步通信时,可通过配置同步时钟引脚即USART_SCK引脚的时钟极性和时钟相位实现SPI功能的通信。此时没有起始位,校验位以及停止位功能,仅支持8位。通过配置时钟极性CPOL和时钟相位CPHA可以实现基于USART的SPI通信的工作模式0-3。
根据以上配置步骤USART1同步模式实现SPI通信的配置步骤,使用MM32SPIN0230的库函数配置USART1为同步模式主机功能实现SPI通信读写W25Q32 Flash存储器,分别配置GPIO PA11复用为USART1_TX功能,PA12复用为USART1_RX功能,PB2复用为USART1_SCLK功能(注:USART1用作同步模式主机功能PA11 USART1_TX当做SPI_MOSI引脚使用,PA12 USART1_RX当做SPI_MISO引脚使用,PB2 USART1_SCLK当做SPI_SCL使用)并配置GPIO PB4为推挽输出模式当做SPI_CSS引脚使用。
- #define SPI_FLASH_CS_H() GPIO_WriteBit(GPIOB, GPIO_Pin_4, Bit_SET)
- #define SPI_FLASH_CS_L() GPIO_WriteBit(GPIOB, GPIO_Pin_4, Bit_RESET)
- uint16_t DeviceID = 0; /* W25Q64 Device ID */
- uint32_t JEDEC_ID = 0; /* W25Q64 JEDEC ID */
- void USART_Configure(uint32_t Baudrate)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART1, ENABLE);
- USART_SyncMasterConfig(USART1, USART_Clock_Idle_Low, USART_Clock_Phase_1Edge, Baudrate); /* USART Init configure SPI Mode0 */
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_5); /* PA11 AF USART_TX for SPI_MOSI function */
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_5); /* PA12 AF USART_RX for SPI_MISO function */
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource2, GPIO_AF_6); /* PB2 AF USART_SCLK for SPI_SCLK function */
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; /* PB4 for SPI_CSS function */
- GPIO_Init(GPIOB, &GPIO_InitStruct);
- SPI_FLASH_CS_H(); /* Set PB4 for SPI_CSS High leve */
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;
- GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_StructInit(&GPIO_InitStruct);
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOB, &GPIO_InitStruct);
- NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStruct.NVIC_IRQChannelPriority = 0x01;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStruct);
- USART_Cmd(USART1, ENABLE);
- }
USART1同步通信模式中断接收数据,代码如下所示。
- void USART_Synchronous_RxData_Interrupt(uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- for (i = 0; i < Length; i++)
- {
- USART_RxStruct.Buffer[i] = 0;
- USART_TxStruct.Buffer[i] = 0;
- }
- USART_RxStruct.Length = Length;
- USART_RxStruct.CurrentCount = 0;
- USART_RxStruct.CompleteFlag = 0;
- USART_TxStruct.Length = Length;
- USART_TxStruct.CurrentCount = 0;
- USART_TxStruct.CompleteFlag = 0;
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
- while (0 == USART_TxStruct.CompleteFlag)
- {
- }
- while (0 == USART_RxStruct.CompleteFlag)
- {
- }
- for (i = 0; i < Length; i++)
- {
- Buffer[i] = USART_RxStruct.Buffer[i];
- }
- }
USART1同步通信模式中断发送数据,代码如下所示。
- void USART_Synchronous_TxData_Interrupt(uint8_t *Buffer, uint8_t Length)
- {
- uint8_t i = 0;
- for (i = 0; i < Length; i++)
- {
- USART_RxStruct.Buffer[i] = 0;
- USART_TxStruct.Buffer[i] = Buffer[i];
- }
- USART_RxStruct.Length = Length;
- USART_RxStruct.CurrentCount = 0;
- USART_RxStruct.CompleteFlag = 0;
- USART_TxStruct.Length = Length;
- USART_TxStruct.CurrentCount = 0;
- USART_TxStruct.CompleteFlag = 0;
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
- USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
- while (0 == USART_TxStruct.CompleteFlag)
- {
- }
- while (0 == USART_RxStruct.CompleteFlag)
- {
- }
- }
USART1同步通信模式读SPI Flash,代码如下所示
- void SPI_FLASH_RxBuffer(uint8_t *Buffer, uint8_t Length)
- {
- if (Length)
- {
- USART_Synchronous_RxData_Interrupt(Buffer, Length);
- }
- }
USART1同步通信模式写SPI Flash,代码如下所示
- void SPI_FLASH_TxBuffer(uint8_t *Buffer, uint8_t Length)
- {
- if (Length)
- {
- USART_Synchronous_TxData_Interrupt(Buffer, Length);
- }
- }
USART1同步通信模式处理中断接收和发送命令和读写数据,即读写SPI Flash,代码如下所示
- void USART1_IRQHandler(void)
- {
- uint8_t RxData = 0;
- if (RESET != USART_GetITStatus(USART1, USART_IT_RXNE))
- {
- RxData = USART_ReceiveData(USART1);
- if (0 == USART_RxStruct.CompleteFlag)
- {
- USART_RxStruct.Buffer[USART_RxStruct.CurrentCount++] = RxData;
- if (USART_RxStruct.CurrentCount == USART_RxStruct.Length)
- {
- USART_RxStruct.CompleteFlag = 1;
- USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
- USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
- }
- }
- }
- if (RESET != USART_GetITStatus(USART1, USART_IT_TXE))
- {
- if (0 == USART_TxStruct.CompleteFlag)
- {
- USART_SendData(USART1, USART_TxStruct.Buffer[USART_TxStruct.CurrentCount++]);
- if (USART_TxStruct.CurrentCount == USART_TxStruct.Length)
- {
- USART_TxStruct.CompleteFlag = 1;
- }
- }
- }
- }
USART1同步通信模式SPI Flash写使能,代码如下所示
- void SPI_FLASH_WriteEnable(void)
- {
- uint8_t Command = 0x06;
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(&Command, 0x01);
- SPI_FLASH_CS_H();
- }
USART1同步通信模式判断SPI Flash是否处于总线忙转态,代码如下所示
- void SPI_FLASH_WaitBusy(void)
- {
- uint8_t Status = 0;
- uint8_t Command[2] =
- {
- 0x05, 0xFF
- };
- uint32_t Timeout = 0;
- do
- {
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(Command, 0x02);
- SPI_FLASH_RxBuffer(&Status, 0x01);
- SPI_FLASH_CS_H();
- if (Timeout++ > 0xFFFF)
- {
- break;
- }
- }
- while (Status & 0x01);
- }
USART1同步通信模式读SPI Flash DeviceID,代码如下所示
- void SPI_FLASH_ReadDeviceID(void)
- {
- uint8_t Command[4] =
- {
- 0x90, 0xFF, 0xFF, 0x00
- };
- uint8_t Buffer[2];
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(Command, 0x04);
- SPI_FLASH_RxBuffer(Buffer, 0x02);
- SPI_FLASH_CS_H();
- DeviceID = Buffer[0];
- DeviceID <<= 8;
- DeviceID |= Buffer[1];
- }
USART1同步通信模式读SPI Flash JEDEC ID,代码如下所示
- void SPI_FLASH_ReadJEDEC_ID(void)
- {
- uint8_t Command = 0x9F;
- uint8_t Buffer[3];
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(&Command, 0x01);
- SPI_FLASH_RxBuffer(Buffer, 0x03);
- SPI_FLASH_CS_H();
- JEDEC_ID = Buffer[0];
- JEDEC_ID <<= 8;
- JEDEC_ID |= Buffer[1];
- JEDEC_ID <<= 8;
- JEDEC_ID |= Buffer[2];
- }
USART1同步通信模式SPI Flash 扇区擦除,代码如下所示
- void SPI_FLASH_SectorErase(uint16_t Index)
- {
- uint8_t Command[4] =
- {
- 0x20, 0x00, 0x00, 0x00
- };
- uint32_t Address = Index * 4 * 1024;
- Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
- Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
- Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
- SPI_FLASH_WriteEnable();
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(Command, 4);
- SPI_FLASH_CS_H();
- SPI_FLASH_WaitBusy();
- }
USART1同步通信模式快速读SPI Flash,代码如下所示
- void SPI_FLASH_FastRead(uint32_t Address, uint8_t *Buffer, uint32_t Length)
- {
- uint8_t Command[5] =
- {
- 0x0B, 0x00, 0x00, 0x00, 0xFF
- };
- Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
- Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
- Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(Command, 0x05);
- SPI_FLASH_RxBuffer(Buffer, Length);
- SPI_FLASH_CS_H();
- }
USART1同步通信模式页编程SPI Flash,代码如下所示
- void SPI_FLASH_PageProgram(uint32_t Address, uint8_t *Buffer, uint32_t Length)
- {
- uint8_t Command[4] =
- {
- 0x02, 0x00, 0x00, 0x00
- };
- Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
- Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
- Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);
- SPI_FLASH_WriteEnable();
- SPI_FLASH_CS_L();
- SPI_FLASH_TxBuffer(Command, 0x04);
- SPI_FLASH_TxBuffer(Buffer, Length);
- SPI_FLASH_CS_H();
- SPI_FLASH_WaitBusy();
- }
验证USART1同步通信模式读写W25Q32 SPI Flash,本实例在MDK Keil环境下编译验演示,在main函数中调用读写W25Q32 SPI Flash的函数,代码如下所示:
- int main(void)
- {
- uint8_t i = 0;
- uint8_t EraseBuffer[100], WriteBuffer[100], ReadBuffer[100];
- USART_RxStruct.CompleteFlag = 0;
- USART_TxStruct.CompleteFlag = 1;
- USART_Configure(8000000); /* Configure USART Read/write SPI Flash baud rate 8M */
- SPI_FLASH_ReadDeviceID();
- SPI_FLASH_ReadJEDEC_ID();
- SPI_FLASH_SectorErase(0); /* USART erases the SPI Flash sector */
- SPI_FLASH_FastRead(0, EraseBuffer, 100);
- for (i = 0; i < 100; i++)
- {
- WriteBuffer[i] = i;
- }
- SPI_FLASH_PageProgram(0, WriteBuffer, 100); /* USART page programming SPI Flash writes 100 bytes of data */
- SPI_FLASH_FastRead(0, ReadBuffer, 100); /* The USART reads 100 bytes of data written to the SPI Flash */
- PLATFORM_DeInitUSART1();
- PLATFORM_InitConsole(115200);
- printf("\r\n\r\n");
- printf("\r\nSPI Flash DeviceID : 0x%04x", DeviceID);
- printf("\r\nSPI Flash JEDEC ID : 0x%06x", JEDEC_ID);
- printf("\r\nSPI FLASH Sector Erase...");
- printf("\r\nSPI FLASH Read...");
- for (i = 0; i < 100; i++)
- {
- if (0 == (i % 10))
- {
- printf("\r\n");
- }
- printf("0x%02x ", EraseBuffer[i]);
- }
- printf("\r\nSPI FLASH Page Program...");
- printf("\r\nSPI FLASH Read...");
- for (i = 0; i < 100; i++)
- {
- if (0 == (i % 10))
- {
- printf("\r\n");
- }
- printf("0x%02x ", ReadBuffer[i]);
- }
- while (1)
- {
- }
- }
使用MM32-LINK Mini调试下载工具连接MM32SPIN0230 MiniBoard,板子USB口连接USB串口工具连接到电脑端,打开串口调试助手,并配置串口波特率为115200,按快捷键F7编译工程,编译成功后按快捷键F8下载程序到MM32SPIN0230 MiniBoard,如下图3所示,串口调试助手分别打印输出了W25Q32 SPI Flash的DeviceID和JEDEC ID,USART1同步通信模式扇区擦除W25Q32 SPI Flash数据后读出的100字节0xFF数据(说明擦除成功),以及USART1同步通信模式写入到W25Q32 SPI Flash中的0-99共100字节数据(每行10字节,共10行),读出了写入的0-99共100字节数据,写入和读出的数据一致即0-99对应十六进制为0x00-0x63。
图3 测试结果