程序刚下载时,spi读取id是正常的,重启之后spi会多读一个0xff
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/08/08
* Description : Main program body.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
/*
*@Note
SPI接口操作FLASH外设例程:
Master:SPI1_SCK(PA5)、SPI1_MISO(PA6)、SPI1_MOSI(PA7)。
本例程演示 SPI 操作 Winbond W25Qxx SPIFLASH。
注:
pins:
CS —— PA2
DO —— PA6(SPI1_MISO)
WP —— 3.3V
DI —— PA7(SPI1_MOSI)
CLK —— PA5(SPI1_SCK)
HOLD —— 3.3V
*/
#include "debug.h"
#include "string.h"
u8 SPI_FLASH_BUF[1024];
const u8 TEXT_Buf[] = {"CH32F203 SPI FLASH W25Qxx"};
#define SIZE sizeof(TEXT_Buf)
/* Winbond SPIFalsh ID */
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q1280XEF17
/* Winbond SPIFalsh Instruction List */
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg0x05
#define W25X_WriteStatusReg0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID0x90
#define W25X_JedecDeviceID0x9F
/* Global define */
/* Global Variable */
/*********************************************************************
* @fn SPI1_ReadWriteByte
*
* @brief SPI1 read or write one byte.
*
* @param TxData - write one byte data.
*
* @return Read one byte data.
*/
u8 SPI1_ReadWriteByte( u8 TxData )
{
u8 i = 0;
while( SPI_I2S_GetFlagStatus( SPI3, SPI_I2S_FLAG_TXE ) == RESET )
{
i++;
if( i > 200 )
{
return 0;
}
}
SPI_I2S_SendData( SPI3, TxData );
i = 0;
while( SPI_I2S_GetFlagStatus( SPI3, SPI_I2S_FLAG_RXNE ) == RESET )
{
i++;
if( i > 200 )
{
return 0;
}
}
return SPI_I2S_ReceiveData( SPI3 );
}
/*********************************************************************
* @fn SPI_Flash_Init
*
* @brief Configuring the SPI for operation flash.
*
* @return none
*/
void SPI_Flash_Init( void )
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
SPI_InitTypeDef SPI_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE );
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI3, ENABLE );
GPIO_PinRemapConfig(GPIO_Remap_SPI3,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
GPIO_SetBits( GPIOA, GPIO_Pin_15 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOC, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOC, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOC, &GPIO_InitStructure );
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init( SPI3, &SPI_InitStructure );
SPI_Cmd( SPI3, ENABLE );
}
/*********************************************************************
* @fn SPI_Flash_ReadSR
*
* @brief Read W25Qxx status register.
* -BIT7 6 5 4 3 2 1 0
* -SPR RV TB BP2 BP1 BP0 WEL BUSY
*
* @return byte - status register value.
*/
u8 SPI_Flash_ReadSR( void )
{
u8 byte = 0;
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_ReadStatusReg );
byte = SPI1_ReadWriteByte( 0Xff );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
return byte;
}
/*********************************************************************
* @fn SPI_FLASH_Write_SR
*
* @brief Write W25Qxx status register.
*
* @param sr - status register value.
*
* @return none
*/
void SPI_FLASH_Write_SR( u8 sr )
{
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_WriteStatusReg );
SPI1_ReadWriteByte( sr );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
}
/*********************************************************************
* @fn SPI_Flash_Wait_Busy
*
* @brief Wait flash free.
*
* @return none
*/
void SPI_Flash_Wait_Busy( void )
{
while( ( SPI_Flash_ReadSR() & 0x01 ) == 0x01 );
}
/*********************************************************************
* @fn SPI_FLASH_Write_Enable
*
* @brief Enable flash write.
*
* @return none
*/
void SPI_FLASH_Write_Enable( void )
{
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_WriteEnable );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
}
/*********************************************************************
* @fn SPI_FLASH_Write_Disable
*
* @brief Disable flash write.
*
* @return none
*/
void SPI_FLASH_Write_Disable( void )
{
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_WriteDisable );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
}
/*********************************************************************
* @fn SPI_Flash_ReadID
*
* @brief Read flash ID.
*
* @return Temp - FLASH ID.
*/
u16 SPI_Flash_ReadID( void )
{
u16 Temp = 0;
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_ManufactDeviceID );
SPI1_ReadWriteByte( 0x00 );
SPI1_ReadWriteByte( 0x00 );
SPI1_ReadWriteByte( 0x00 );
Temp |= SPI1_ReadWriteByte( 0xFF )<<8;
Temp |= SPI1_ReadWriteByte( 0xFF );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
return Temp;
}
/*********************************************************************
* @fn SPI_Flash_Erase_Sector
*
* @brief Erase one sector(4Kbyte).
*
* @param Dst_Addr - 0 - 2047
*
* @return none
*/
void SPI_Flash_Erase_Sector( u32 Dst_Addr )
{
Dst_Addr *= 4096;
SPI_FLASH_Write_Enable();
SPI_Flash_Wait_Busy();
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_SectorErase );
SPI1_ReadWriteByte( ( u8 )( ( Dst_Addr ) >> 16 ) );
SPI1_ReadWriteByte( ( u8 )( ( Dst_Addr ) >> 8 ) );
SPI1_ReadWriteByte( ( u8 )Dst_Addr );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
SPI_Flash_Wait_Busy();
}
/*********************************************************************
* @fn SPI_Flash_Read
*
* @brief Read data from flash.
*
* @param pBuffer -
* ReadAddr -Initial address(24bit).
* size - Data length.
*
* @return none
*/
void SPI_Flash_Read( u32 ReadAddr,u8 *pBuffer, u16 size )
{
u16 i;
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_ReadData );
SPI1_ReadWriteByte( ( u8 )( ( ReadAddr ) >> 16 ) );
SPI1_ReadWriteByte( ( u8 )( ( ReadAddr ) >> 8 ) );
SPI1_ReadWriteByte( ( u8 )ReadAddr );
for( i = 0; i < size; i++ )
{
pBuffer[i] = SPI1_ReadWriteByte( 0XFF );
}
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
}
/*********************************************************************
* @fn SPI_Flash_Write_Page
*
* @brief Write data by one page.
*
* @param pBuffer -
* WriteAddr - Initial address(24bit).
* size - Data length.
*
* @return none
*/
void SPI_Flash_Write_Page( u32 WriteAddr,u8 *pBuffer, u16 size )
{
u16 i;
SPI_FLASH_Write_Enable();
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_PageProgram );
SPI1_ReadWriteByte( ( u8 )( ( WriteAddr ) >> 16 ) );
SPI1_ReadWriteByte( ( u8 )( ( WriteAddr ) >> 8 ) );
SPI1_ReadWriteByte( ( u8 )WriteAddr );
for( i = 0; i < size; i++ ){
SPI1_ReadWriteByte( pBuffer[i] );
}
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
SPI_Flash_Wait_Busy();
}
/*********************************************************************
* @fn SPI_Flash_Write_NoCheck
*
* @brief Write data to flash.(need Erase)
* All data in address rang is 0xFF.
*
* @param pBuffer -
* WriteAddr - Initial address(24bit).
* size - Data length.
*
* @return none
*/
void SPI_Flash_Write_NoCheck( u32 WriteAddr,u8 *pBuffer, u16 size )
{
u16 pageremain;
pageremain = 256 - WriteAddr % 256;
if( size <= pageremain )
{
pageremain = size;
}
while( 1 )
{
SPI_Flash_Write_Page( WriteAddr,pBuffer, pageremain );
if( size == pageremain )
{
break;
}
else
{
pBuffer += pageremain;
WriteAddr += pageremain;
size -= pageremain;
if( size > 256 )
{
pageremain = 256;
}
else
{
pageremain = size;
}
}
}
}
/*********************************************************************
* @fn SPI_Flash_Write
*
* @brief Write data to flash.(no need Erase)
*
* @param pBuffer -
* WriteAddr - Initial address(24bit).
* size - Data length.
*
* @return none
*/
void SPI_Flash_Write( u32 WriteAddr,u8 *pBuffer, u16 size )
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
secpos = WriteAddr / 4096;
secoff = WriteAddr % 4096;
secremain = 4096 - secoff;
if( size <= secremain )
{
secremain = size;
}
while( 1 )
{
SPI_Flash_Read( secpos * 4096,SPI_FLASH_BUF, 4096 );
for( i = 0; i < secremain; i++ )
{
if( SPI_FLASH_BUF[secoff + i] != 0XFF )
{
break;
}
}
if( i < secremain )
{
SPI_Flash_Erase_Sector( secpos );
for( i = 0; i < secremain; i++ )
{
SPI_FLASH_BUF[i + secoff] = pBuffer[i];
}
SPI_Flash_Write_NoCheck( secpos * 4096, SPI_FLASH_BUF, 4096 );
}
else
{
SPI_Flash_Write_NoCheck( WriteAddr,pBuffer, secremain );
}
if( size == secremain )
{
break;
}
else
{
secpos++;
secoff = 0;
pBuffer += secremain;
WriteAddr += secremain;
size -= secremain;
if( size > 4096 )
{
secremain = 4096;
}
else
{
secremain = size;
}
}
}
}
/*********************************************************************
* @fn SPI_Flash_Erase_Chip
*
* @brief Erase all FLASH pages.
*
* @return none
*/
void SPI_Flash_Erase_Chip( void )
{
SPI_FLASH_Write_Enable();
SPI_Flash_Wait_Busy();
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_ChipErase );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
SPI_Flash_Wait_Busy();
}
/*********************************************************************
* @fn SPI_Flash_PowerDown
*
* @brief Enter power down mode.
*
* @return none
*/
void SPI_Flash_PowerDown( void )
{
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_PowerDown );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
Delay_Us( 3 );
}
/*********************************************************************
* @fn SPI_Flash_WAKEUP
*
* @brief Power down wake up.
*
* @return none
*/
void SPI_Flash_WAKEUP( void )
{
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 0 );
SPI1_ReadWriteByte( W25X_ReleasePowerDown );
GPIO_WriteBit( GPIOA, GPIO_Pin_15, 1 );
Delay_Us( 3 );
}
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
u8 buf[1024];
u8 buf2[1024];
int main( void )
{
u8 datap[SIZE];
u16 Flash_Model;
u32 i=0;
u32 j=0;
Delay_Init();
USART_Printf_Init( 115200 );
printf( "SystemClk:%d\r\n", SystemCoreClock );
SPI_Flash_Init();
Flash_Model = SPI_Flash_ReadID();
switch( Flash_Model )
{
case W25Q80:
printf( "W25Q80 OK!\r\n" );
break;
case W25Q16:
printf( "W25Q16 OK!\r\n" );
break;
case W25Q32:
printf( "W25Q32 OK!\r\n" );
break;
case W25Q64:
printf( "W25Q64 OK!\r\n" );
break;
case W25Q128:
printf( "W25Q128 OK!\r\n" );
break;
default:
printf( "Fail!\r\n" );
break;
}
// for(j = 0; j < sizeof(buf); j++)
// {
// buf[j] = j%100;
// }
//// SPI_Flash_Erase_Sector(0);
////SPI_Flash_Erase_Chip();
//// FLASH_SPI_Read(0,buf1,sizeof(buf1));
//// for(i = 0; i < sizeof(buf1); i++) {
//// printf("%d ",buf1[i]);
//// }
// printf("\r\n");
// SPI_Flash_Write_NoCheck(0,buf,sizeof(buf));
// SPI_Flash_Read(0,buf2,sizeof(buf2));
// for(i = 0; i < sizeof(buf2); i++) {
//// if (buf[i] != buf2[i]) {
//// printf("%d ",i);
//// printf("write is error\n");
//// }
// printf("%d ",buf2[i]);
// }
while( 1 ){
Flash_Model = SPI_Flash_ReadID();
printf("Flash_Model=%x \n",Flash_Model);
Delay_Ms(200);
}
}