野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 575|回复: 3

指南者 SPI Flash 扇区擦除异常,读出来全部是0x2

[复制链接]
发表于 2025-3-3 23:43:25 | 显示全部楼层 |阅读模式
本帖最后由 Rddavid 于 2025-3-4 20:40 编辑

各位老师好,麻烦帮忙审核一下我的代码,谢谢!

1. 代码目的:擦除Flash 地址为0的扇区的数据,然后读取出来确认是否已经完全擦除。
2. 遇到的问题:读取到的数不是0xFF,而是0x2
以下为我的代码截图和代码附件。
----------------------------------------Main函数----------------------------------------

uint32_t buff[4096];

int main(void)
{
        uint32_t i=0;
        uint32_t id;

        LED_GPIO_Config();        
        USART_Config();
        I2C_EE_Init();
        SPI_Flash_Init();
        LED_G(OFF);        
               
        id=SPI_FLASH_Read_ID();
        printf("SPI发送后接收到的数据为:0x%x\n",id);
        
  SPI_FLASH_SectorErase(0);
  SPI_FLASH_WaitForWriteEnd();
        
        SPI_FLASH_Read(0,buff,4096);
        for (i=0;i<4096;i++)
        {
                printf("0x%x ",buff);
                if (i%10==0)
                printf("\n");
        }


----------------------------------------SPI_Flash.c----------------------------------------
#include "./spi/bsp_spi_flash.h"

static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;   
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t ErrorCode);

static void SPI_GPIO_Config(void)        
{
        GPIO_InitTypeDef GPIO_InitStructure;
        
        // 打开SPI外设的时钟
        FLASH_SPI_APBxClock_FUN (FLASH_SPI_CLK,ENABLE);
        
        // 打开SPI GPIO的时钟
        FLASH_SPI_GPIO_APBxClock_FUN (FLASH_SPI_SCL_GPIO_CLK,ENABLE);
        
        // 将SPI SCK配置为复用推挽输出模式
        GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(FLASH_SPI_SCK_PORT,&GPIO_InitStructure);
        
        // 将SPI MOSI配置为复用推挽输出模式
        GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(FLASH_SPI_MOSI_PORT,&GPIO_InitStructure);
        
        // 将SPI MISO配置为浮空模式
        GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(FLASH_SPI_MISO_PORT,&GPIO_InitStructure);
        
        // 将SPI CS配置为推挽输出模式,使用软件控制
        GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(FLASH_SPI_CS_PORT,&GPIO_InitStructure);
}

static void SPI_MODE_Config(void)        
{
        SPI_InitTypeDef  SPI_InitStructure;        
        /* I2C 配置 */
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //分频因子
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //时钟相位,模式3
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟极性,模式3
        SPI_InitStructure.SPI_CRCPolynomial = 0;//不使用CRC校验功能,数值随便写,这个数是无效的。
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;//
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;//
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//        
        
        /* SPI 初始化 */
        SPI_Init(FLASH_SPIx, &SPI_InitStructure);
        /* I2C 使能 */
        SPI_Cmd(FLASH_SPIx, ENABLE);
}

void SPI_Flash_Init(void)
{
  SPI_GPIO_Config();
        SPI_MODE_Config();
} //封装起来

uint8_t SPI_FLASH_Send_Byte(uint8_t data)
{
        SPITimeout = SPIT_FLAG_TIMEOUT;
        //发送缓冲区非空就一直等待,直到超时
        while(SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_TXE)==RESET)
        {
                if(SPITimeout--==0)
                return SPI_TIMEOUT_UserCallback(0);
        }
        //发送缓冲区空后,可以往缓冲区写入数据了
        SPI_I2S_SendData(FLASH_SPIx, data);
        //发送与接收是同步的(注意:时间上其实还是有先后的),接收非空,说明主机的数据已经发送出去了
        
        SPITimeout = SPIT_FLAG_TIMEOUT;
        //接收缓冲区为空就一直等待,直到超时
        while(SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_RXNE)==RESET)
        {
                if(SPITimeout--==0)
                return SPI_TIMEOUT_UserCallback(1);
        }
        //作为此函数的返回值发送出去
        return SPI_I2S_ReceiveData(FLASH_SPIx);
}

uint8_t SPI_FLASH_Read_Byte(void)
{
   return SPI_FLASH_Send_Byte(Dummy);
}

uint32_t SPI_FLASH_Read_ID(void)
{
        uint32_t Flash_ID;
        
        FLASH_SPI_CS_LOW;
        SPI_FLASH_Send_Byte(Read_JEDEC_ID);
        Flash_ID=SPI_FLASH_Send_Byte(Dummy);
        Flash_ID <<= 8; //左移8位,并且给自己赋值
        Flash_ID |=SPI_FLASH_Send_Byte(Dummy);
        Flash_ID <<= 8; //左移8位,并且给自己赋值
        Flash_ID |=SPI_FLASH_Send_Byte(Dummy);
        FLASH_SPI_CS_HIGH;
        return Flash_ID;
}

void SPI_FLASH_WriteEnable(void)
{
        FLASH_SPI_CS_LOW;
        SPI_FLASH_Send_Byte(Write_Enable);
        FLASH_SPI_CS_HIGH;
}

//擦除FLASH指定扇区
void SPI_FLASH_SectorErase(uint32_t addr)
{
        SPI_FLASH_WriteEnable();
        SPI_FLASH_WaitForWriteEnd();
        FLASH_SPI_CS_LOW;
        SPI_FLASH_Send_Byte(Erase_Sector);
        SPI_FLASH_Send_Byte((addr>>16)&0xFF); //先发送高位,右移16位,然后与运算取一个字节。
        SPI_FLASH_Send_Byte((addr>>8)&0xFF); //取中间的字节
        SPI_FLASH_Send_Byte(addr&0xFF);        //取最后一个字节
        FLASH_SPI_CS_HIGH;
  SPI_FLASH_WaitForWriteEnd();        
}

//等待Flash内部操作完成
void SPI_FLASH_WaitForWriteEnd()
{
        uint8_t Status_Reg = 0;
        FLASH_SPI_CS_LOW;
        SPI_FLASH_Send_Byte(Read_Status);
        do
        {
                Status_Reg = SPI_FLASH_Send_Byte(Dummy);
        } while ((Status_Reg &0x01) == 1); //取Status_Reg的最低位,如果等于1,说明Flash一直在忙,需要继续循环。
}

//读取FLASH的内容
void SPI_FLASH_Read(uint32_t addr,uint32_t *buffer,uint32_t numByteToRead)
{
        FLASH_SPI_CS_LOW;
        SPI_FLASH_Send_Byte(Read_Data);
        SPI_FLASH_Send_Byte((addr>>16)&0xFF);
        SPI_FLASH_Send_Byte((addr>>8)&0xFF);
        SPI_FLASH_Send_Byte(addr&0xFF); //分三次发送要读取的地址
        while(numByteToRead--)
        {
          *buffer = SPI_FLASH_Send_Byte(Dummy); //类似读flash的id号,发送dummy数据即可。
                buffer++;
        }
        FLASH_SPI_CS_HIGH;
}


static uint32_t SPI_TIMEOUT_UserCallback(uint8_t ErrorCode)
{
        FLASH_ERROR("SPI 等待超时!ErrorCode = %d ", ErrorCode);
        return 0;
}

----------------------------------------SPI_Flash.h----------------------------------------


#ifndef __BSP_SPI_FLASH_H
#define        __BSP_SPI_FLASH_H

#include "stm32f10x.h"
#include "stdio.h"   

//SPI引脚定义
#define   FLASH_SPIx                        SPI1
#define   FLASH_SPI_APBxClock_FUN           RCC_APB2PeriphClockCmd
#define   FLASH_SPI_CLK                     RCC_APB2Periph_SPI1

//SPI GPIO引脚宏定义
#define   FLASH_SPI_GPIO_APBxClock_FUN      RCC_APB2PeriphClockCmd

#define   Use_ZhiNanZhe_PCB                 1
#if      (Use_ZhiNanZhe_PCB ==1)
   #define   FLASH_SPI_SCL_GPIO_CLK         (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC)
         #define   FLASH_SPI_CS_PORT              GPIOC
   #define   FLASH_SPI_CS_PIN               GPIO_Pin_0
#else
   #define   FLASH_SPI_SCL_GPIO_CLK         RCC_APB2Periph_GPIOA
         #define   FLASH_SPI_CS_PORT              GPIOA
   #define   FLASH_SPI_CS_PIN               GPIO_Pin_4
#endif

#define   FLASH_SPI_SCK_PORT                GPIOA   
#define   FLASH_SPI_SCK_PIN                 GPIO_Pin_5
#define   FLASH_SPI_MOSI_PORT               GPIOA
#define   FLASH_SPI_MOSI_PIN                GPIO_Pin_7
#define   FLASH_SPI_MISO_PORT               GPIOA
#define   FLASH_SPI_MISO_PIN                GPIO_Pin_6

#define   FLASH_SPI_CS_PORT                 GPIOC
#define   FLASH_SPI_CS_PIN                  GPIO_Pin_0

#define   FLASH_SPI_CS_LOW                  GPIO_ResetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN);
#define   FLASH_SPI_CS_HIGH                 GPIO_SetBits(FLASH_SPI_CS_PORT, FLASH_SPI_CS_PIN);

//等待超时时间
#define   SPIT_FLAG_TIMEOUT                 ((uint32_t)0x1000)
#define   SPIT_LONG_TIMEOUT                 ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))

#define   FLASH_INFO(fmt,arg...)            printf("<<-FLASH-INFO->> "fmt"\n",##arg)
#define   FLASH_ERROR(fmt,arg...)           printf("<<-FLASH-ERROR->> "fmt"\n",##arg)
#define   FLASH_DEBUG(fmt,arg...)           do{\
                                            if(FLASH_DEBUG_ON)\
                                            printf("<<-FLASH-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
                                            }while(0)
#define   Dummy                             0x00
#define   Read_JEDEC_ID                     0x9F
#define   Erase_Sector                      0x20
#define   Read_Status                       0x05
#define   Read_Data                         0x03
#define   Write_Enable                      0x06
                                                                                                                                                                                
                                                                                                                                                                                

void SPI_Flash_Init(void);
uint8_t SPI_FLASH_Send_Byte(uint8_t data);
uint8_t SPI_FLASH_Read_Byte(void);
uint32_t SPI_FLASH_Read_ID(void);
void SPI_FLASH_Read(uint32_t addr,uint32_t *buffer,uint32_t numByteToRead);
void SPI_FLASH_SectorErase(uint32_t addr);        
void SPI_FLASH_WriteEnable(void);                                                                                                                                                                                
void SPI_FLASH_WaitForWriteEnd();                                                                                                                                                        

#endif   /*__BSP_SPI_FLASH_H*/


野火论坛202503042034494729..png
野火论坛202503042040505105..png
野火论坛202503042040349733..png
野火论坛202503042040172600..png
野火论坛202503042040004634..png
野火论坛202503042039384070..png
野火论坛202503042039188428..png
回复

使用道具 举报

 楼主| 发表于 2025-3-5 21:21:45 | 显示全部楼层
附上源码,有老师帮忙看看吗?

25-SPI读写串行Flash(扇区擦除异常).rar

4.87 MB, 下载次数: 5

回复 支持 反对

举报

发表于 2025-3-8 10:12:56 | 显示全部楼层
没有拉高,这不对吧
野火论坛202503081012481275..png
回复 支持 反对

举报

 楼主| 发表于 2025-3-8 22:34:21 | 显示全部楼层
感谢老师帮忙审查并回复,搞定了!
确实是CS引脚没有拉高引起,查了几天都没查出来。以后要改改这粗心的毛病才行。
回复 支持 反对

举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2025-4-2 18:11 , Processed in 0.229467 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表