野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 24468|回复: 1

新手请教SPI读取FLASH Read JEDEC ID 返回0x0

[复制链接]
发表于 2020-10-28 15:07:19 | 显示全部楼层 |阅读模式
本帖最后由 brave_hui 于 2020-10-28 15:11 编辑

我跟着教程写单片机读取的FLASHW25Q128值都是0x0,找了两天也没找出问题,用原教程的代码下载到单片机后也是0x0
麻烦大家给看看。硬件使用SPI3端口,CS软件模拟,读取FLASH的ID结果是0x0,擦除0扇区后去读的结果也是0x0,怎么都没找到是哪里出了问题
头文件:
#ifndef _W25Q128_H
#define _W25Q128_H

#include "stm32f10x.h"
#include <stdio.h>

/*SPI 参数定义****************************/


#define FLASH_SPIx                    SPI3                      //使用SPI3端口
#define FLASH_SPI_APBxClock_FUN       RCC_APB1PeriphClockCmd    //开启SPI时钟函数封装成宏-使能SPI1时钟 配置SPI时钟
#define FLASH_SPI_CLK                 RCC_APB1Periph_SPI3       //SPI时钟开启函数的输入参数  ↑  

#define FLASH_SPI_GPIO_APBxClock_FUN  RCC_APB2PeriphClockCmd    //开启GPIO时钟函数封装成宏-使能GPIO时钟 配置GPIO时钟
#define FLASH_SPI_GPIO_CLK            (RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOB)      //开启GPIO时钟函数的输入参数  ↑  

#define FLASH_SPI_CS_PORT             GPIOD
#define FLASH_SPI_CS_PIN              GPIO_Pin_2

//SCK 引脚
#define FLASH_SPI_SCK_PORT            GPIOB
#define FLASH_SPI_SCK_PIN             GPIO_Pin_3

//MISO 引脚
#define FLASH_SPI_MISO_PORT           GPIOB
#define FLASH_SPI_MISO_PIN            GPIO_Pin_4

//MOSI 引脚
#define FLASH_SPI_MOSI_PORT           GPIOB
#define FLASH_SPI_MOSI_PIN            GPIO_Pin_5

#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 DUMMY                           0x00
#define Dummy                                                                                                                0x00
#define READ_JEDEC_ID                   0x9f
#define ERASE_SECTOR                    0x20
#define READ_STATUS                     0x05
#define READ_DATA                       0x03

/*信息输出*/
#define FLASH_DEBUG_ON         1

#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)

void SPI_FLASH_Init(void);
uint8_t SPI_FLASH_Read_Byte(void);
uint32_t SPI_Read_ID(void);       
void SPI_Write_Enable(void);               
void SPI_waitForwriteEnd(void);
void SPI_Read_Data(uint32_t addr,uint8_t *readbuff,uint32_t numByteToRead);
void SPI_Erase_Sector(uint32_t addr);

#endif
                                                                                                                                                                       
c文件
#include "./w25q128/w25q128.h"


//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q128
//容量为16M字节,共有256个Block,4096个Sector

//GPIO 初始化

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

void SPI_FLASH_Init(void)
       

{
       
        GPIO_InitTypeDef  GPIO_InitStruct;
        SPI_InitTypeDef   SPI_InitStruct;

        RCC_APB1PeriphClockCmd (RCC_APB1Periph_SPI3,ENABLE);     //打开SPI功能时钟       
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD , ENABLE);  //打开GPIO引脚时钟
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);
       
/*-------1.初始化SPI GPIO引脚-------*/
       
//CS,普通GPIO,软件配置
        GPIO_InitStruct.GPIO_Pin = FLASH_SPI_CS_PIN;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //CS 使用软件配置,配置成普通推挽输出
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(FLASH_SPI_CS_PORT , &GPIO_InitStruct);
       
//SCK
        GPIO_InitStruct.GPIO_Pin = FLASH_SPI_SCK_PIN;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;       
  GPIO_Init(GPIOB, &GPIO_InitStruct);       

//MISO
        GPIO_InitStruct.GPIO_Pin = FLASH_SPI_MISO_PIN ;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //浮空输入
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;       
  GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStruct);       
       
//MOSI
        GPIO_InitStruct.GPIO_Pin = FLASH_SPI_MOSI_PIN ;
        GPIO_InitStruct.GPIO_Mode =GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;       
  GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStruct);       
       
//FLASH停止信号:CS为高电平时停止
  FLASH_SPI_CS_HIGH;

        /*-------2.配置SPI功能模式-------*/
       
         // FLASH芯片 支持SPI模式0及模式3,配置SPI0模式为模式3:CPOL 1 CPHA 1
         
        SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
        SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;
        SPI_InitStruct.SPI_CPOL = SPI_CPOL_High;
        SPI_InitStruct.SPI_CRCPolynomial = 7 ;                       //不实用CRC功能,数值随便写
        SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
        SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//配置SPI为双线全双工
        SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;              
        SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
        SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;                         //NSS软件配置
       
        SPI_Init (SPI3,&SPI_InitStruct);    //写入配置到寄存器
  SPI_Cmd(SPI3 , ENABLE);             //使能SPI

}

/*--------------------向存储器发送一个字节数据-------------------*/


/*1.检测并等待TXE为1(发送缓冲区为空)
  2.发送一个字节
  3.检测检测并等待RXNE为1(接收缓冲区为空),
    因为SPI是同步通信,只有发送数据的时候才产生SCK时钟,当接收缓冲区为空,发送缓冲区也为空(参考通讯时序图)
*/

uint8_t  SPI_FLASH_SendByte(uint8_t data)
{
         
        SPITimeout = SPIT_FLAG_TIMEOUT;
       

  while (SPI_I2S_GetFlagStatus( SPI3, SPI_I2S_FLAG_TXE)==RESET)  //当TXE=0,TX缓冲区非空,执行if减减
                                                                                                                                                                                                                                                                                         //  TXE=1,TX缓冲区空
   {if((SPITimeout--)==0) return SPI_TIMEOUT_UserCallback(1);}

        SPI_I2S_SendData(SPI3, data);                                  //1-程序执行到这里,说明TX缓冲区为空.2-写入数据寄存器,把要写入的数据写入发送缓冲区向,


  while (SPI_I2S_GetFlagStatus( SPI3, SPI_I2S_FLAG_RXNE)==RESET) //当RXNE=0,RX缓冲区空,当RXNE为1说明说句发送完成
                                                                                                                                                                                                                                                                                         //RXNE=1,RX缓冲区非空
         {if((SPITimeout--)==0) return SPI_TIMEOUT_UserCallback(0);}
         
         return SPI_I2S_ReceiveData(SPI3);                              //当RXNE=1,非空时,程序执行到这里,说明数据发送完成,并且接到一个字节
         
}




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

/*---------------------------读取FLASH的ID--------------------------*/

uint32_t SPI_Read_ID(void)
{
        uint32_t flash_id;
       
        //片选使能
        FLASH_SPI_CS_LOW;

        SPI_FLASH_SendByte(READ_JEDEC_ID);
       
        flash_id = SPI_FLASH_SendByte(DUMMY);

        flash_id <<= 8;
       
        flash_id |= SPI_FLASH_SendByte(DUMMY);
       
        flash_id <<= 8;
       
        flash_id |= SPI_FLASH_SendByte(DUMMY);
       
        FLASH_SPI_CS_HIGH;       
       
        return flash_id;
       
}
//FLASH写入使能
void SPI_Write_Enable(void)
{
                //片选使能
        FLASH_SPI_CS_LOW;
        SPI_FLASH_SendByte(0x06);         
        FLASH_SPI_CS_HIGH;       
}

/*---------------------------擦除FLASH指定的4K扇区,代码20H--------------------------*/
void SPI_Erase_Sector(uint32_t addr)
{
                //片选使能
        FLASH_SPI_CS_LOW;
        SPI_FLASH_SendByte(ERASE_SECTOR);
        SPI_FLASH_SendByte((addr>>16)&0xff);
        SPI_FLASH_SendByte((addr>>8)&0xff);
        SPI_FLASH_SendByte(addr&0xff);
        FLASH_SPI_CS_HIGH;
        SPI_waitForwriteEnd();

}

/*---------------------等待FLASH内部时序操作完成,检测BUSY位状态-------------------*/
void SPI_waitForwriteEnd(void)
{       
       
        uint8_t status_reg = 0;
        FLASH_SPI_CS_LOW;
        SPI_FLASH_SendByte(READ_STATUS);  //读取状态寄存器1的BUSY位,1为忙碌 0为操作完成,空闲
        do
  {
        status_reg = SPI_FLASH_SendByte(Dummy);
        }
        while ((status_reg&0x01)==1);
        FLASH_SPI_CS_HIGH;

}


/*---------------------------读取FLASH的内容--------------------------*/
//addr:读取flash地址 readbuff:读取的内容存储到buff中 numByteToRead ;读取的数量

void SPI_Read_Data(uint32_t addr,uint8_t *readbuff,uint32_t numByteToRead)
{
                //片选使能
        FLASH_SPI_CS_LOW;
        SPI_FLASH_SendByte(ERASE_SECTOR);
        SPI_FLASH_SendByte((addr>>16)&0xff);
        SPI_FLASH_SendByte((addr>>8)&0xff);
        SPI_FLASH_SendByte(addr&0xff);
        while(numByteToRead--)
        {
        *readbuff = SPI_FLASH_SendByte(Dummy);
        readbuff++;
       
        }
        FLASH_SPI_CS_HIGH;
        SPI_waitForwriteEnd();

}





/*---------------------------写入FLASH指定的扇区--------------------------*/

//static  uint16_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
//{
//  /* 等待超时后的处理,输出错误信息 */
//  FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
//  return 0;
//}

//static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;     


//static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);



static  uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
  /* 等待超时后的处理,输出错误信息 */
  FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
  return 0;
}

main.c
#include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
#include "rccclkconfig.h"
#include "bsp_led.h"
#include "key.h"
#include "exti.h"
#include "systick.h"
#include "usart.h"
//#include "dma_mtom.h"
//#include "dma_mtop.h"
#include "i2c.h"
#include "./w25q128/w25q128.h"
#include <string.h>


void Delay( uint32_t count )
{
        for(; count!=0; count--);
}
        uint8_t buff[4096];

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

          HSI_SetSysClk( RCC_PLLMul_16); //配置系统时钟为HSI:8/2*16=64M
    LED_GPIO_Config();
                LED_G(ON);
                Delay(1000);
                USART_Config();
                SPI_FLASH_Init();
                 printf("\r\n this is a SPI3 \r\n");
       
    SPI_Write_Enable();
               
                id = SPI_Read_ID();
               
                printf("\r\n id is 0x%x \r\n",id);        


        while(1)
               
        {
          LEDR_TOGGLE;
    Delay(0xFFFFF);       
               
        }
}




野火论坛202010281511026443..png
回复

使用道具 举报

 楼主| 发表于 2020-10-29 12:32:18 | 显示全部楼层
问题已经解决,最终的解决方法是:SPI3跟JTAG引脚重复了,需要开启AFIO时钟,禁止JTAG
回复 支持 1 反对 0

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-23 11:01 , Processed in 0.032698 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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