wofei3344 发表于 2013-11-4 15:00:36

W25X80读不到数据,使用MSP430F247单片机

如题,程序如下:
#include "define.h"
#include "w25x80add.h"
/*
W25x80,8M-bit
共16个扇区,每扇区64Kbyte
每扇区有256页,每页256byte

*/

//#include <stdio.h>
//#include <string.h>

#define W25X_CS         P2OUT_bit.P7   
#define W25X_CLK      P3OUT_bit.P3
//#define W25X_SI         P3OUT_bit.P1
//#define W25X_SO         P3IN_bit.P1
#define W25X_SO         P3IN_bit.P2
#define W25X_SI         P3OUT_bit.P1
#define W25X_WP         P3OUT_bit.P0


#define WREN 0x06
#define WRDIS 0x04
#define RDSR 0x05
#define WRSR 0x01
#define READ 0x03
#define FARD 0x0b
#define PGPM 0x02
#define STES4K 0x20
#define BKES32K 0x52
#define BKES64K 0xd8
#define CPES 0xc7
#define W25X_DeviceID                0xAB
#define W25X_ManufactDeviceID       0x90
#define W25X_JedecDeviceID                0x9F
/*--------------------------------------------------
w25x80延时n*300us
IN:i,延时系数
OUT:NONE
____________________________________________________*/
void w25_wait(u16 i)
{
    for(;i>0;i--)
      delay_us(300);
}

/*------------------------------------------------*/
//w25X80初始化
void w25_init(void)
{
    //IO初始化
    P2SEL_bit.P7=0;//CS
    P2DIR_bit.P7=1;
   
    P3SEL_bit.P0=0;//WP
    P3SEL_bit.P1=0;//SI,输出
    P3SEL_bit.P2=0;//SO,输入
    P3SEL_bit.P3=0;//SCLK
    P3DIR_bit.P0=1;//wp
    P3DIR_bit.P1=1;//si
    P3DIR_bit.P3=1;//sclk
    P3DIR_bit.P2=0;//so
    W25X_WP=1;//低电平有效
    W25X_CLK=0;//软件模拟MODE0,CLK平时低电平
    W25X_CS=1;       

}

void w25_wrbyte(unsigned char sbyte)
{
    unsigned char i;       
    //W25X_CLK=0;
    //W25X_CS=1;
    W25X_CLK=0;
    W25X_CS=0;
    //P3DIR_bit.P2=1;
    for(i=0;i<8;i++)
    {
         W25X_CLK=0;
         if((sbyte&0x80)==0x80)
         
            W25X_SI=1;//din=1;
         else
            W25X_SI=0;//din=0;
         
         sbyte<<=1;
         //delay_us(2);
         W25X_CLK=1;
         
    }
    W25X_CS=1;
    W25X_CLK=0;
}
/*-----------------------------------------------

_________________________________________________________*/
unsigned char w25_rdbyte(void)
{
    unsigned char i=0,temp=0;
   W25X_CLK=0;
    W25X_CS=0;
    //P3DIR_bit.P2=0;
    for(i=0;i<8;i++)
    {
      temp<<=1;
      W25X_CLK=0;
      if(W25X_SO!=0)//if(dio!=0)
          temp|=0x01;
      //else
          //temp&=~0x01;
      W25X_CLK=1;
            
    }
    W25X_CS=1;
    W25X_CLK=0;
    return temp;       
}
/*----------------------------------------------------
//描述:写允许函数
//功能:在写入状态或者擦除或者数据时必须进行写允许操作
//形参:无
//返回:无
__________________________________________________________*/
void w25_enable(void)
{
    W25X_CLK=0;
    W25X_CS=0;
    w25_wrbyte(WREN);
    W25X_CS=1;       
    W25X_CLK=0;
}
/*----------------------------------------------------
//描述:写禁止函数
//功能:禁止写操作
//形参:无
//返回:无
__________________________________________________________*/
void w25_disable(void)
{
    W25X_CLK=0;
    W25X_CS=0;
    w25_wrbyte(WRDIS);
    W25X_CS=1;       
    W25X_CLK=0;
}
/*----------------------------------------------------
//描述:读ID1函数
//功能:读取ID1值
//形参:无
//返回:byte (字节数据)
__________________________________________________________*/
u8 w25_rdid1(void)
{
    u8 byte;
    W25X_CS=0;
    w25_wrbyte(W25X_DeviceID);
    w25_wrbyte(0);
    w25_wrbyte(0);
    w25_wrbyte(0);
    byte=w25_rdbyte();
    W25X_CS=1;       
    delay_us(2);
    return byte;
}
/*----------------------------------------------------
//描述:读ID2函数
//功能:读取ID2值
//形参:ID_Addr (字节数据)
//返回:IData16(16位)
__________________________________________________________*/
u16 w25_rdid2(u8 ID_Addr)
{
    u16 dd;
    W25X_CS=0;
    w25_wrbyte(W25X_ManufactDeviceID);
    w25_wrbyte(0);
    w25_wrbyte(0);
    w25_wrbyte(ID_Addr);
    dd=w25_rdbyte();
    dd |= w25_rdbyte();
    W25X_CS=1;       
    return dd;
}
/*----------------------------------------------------
//描述:读ID3函数
//功能:读取ID3值
//形参:无
//返回:IData16(16位)
__________________________________________________________*/
u16 w25_rdid3(void)
{
    u16 dd;
    W25X_CS=0;
    w25_wrbyte(W25X_JedecDeviceID);
    dd=w25_rdbyte();
    dd |= w25_rdbyte();
    w25_rdbyte();       
    W25X_CS=1;       
    return dd;
}
/*----------------------------------------------------------
读取寄存器的值
IN:NONE
OUT:u8 byte
_______________________________________________________________*/
unsigned char w25_rdsr(void)
{
    unsigned char pbyte;
    W25X_CLK=1;
    W25X_CS=0;
   
    w25_wrbyte(RDSR);
    pbyte=w25_rdbyte();
    W25X_CS=1;
    W25X_CLK=1;
    return pbyte;
}
/*----------------------------------------------------------
//描述:写状态寄存器函数(可设置写保护状态)
//功能:写状态到flash状态寄存器里 ( 需要时间15ms)
//形参:byte (字节数据)
//返回:无
_______________________________________________________________*/
void w25_wrsr(u8 byte)
{
    W25X_CLK=1;
    W25X_CS=0;
   
    w25_wrbyte(WRSR);
    w25_wrbyte(byte);
    W25X_CS=1;
    W25X_CLK=1;
}

void w25_busy(void)
{
    while (w25_rdsr() == 0x03)
      w25_rdsr();        //        waste time until not busy WEL & Busy bit all be 1 (0x03)
}
/*-----------------------------------------------------------
//描述:读flash中某个地址的数据字节
//功能:读取指定地址上的数据
//形参:waddr(24位的地址)
//返回:byte(字节数据)
________________________________________________________________*/
u8 w25_RD(unsigned long waddr)
{
    unsigned char byte;
    W25X_CS=0;
    w25_wrbyte(READ);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    byte=w25_rdbyte();
    W25X_CS=1;
    return byte;
}
/*-----------------------------------------------------------
//描述:读flash多字节数据的函数
//功能:读取指定地址上的数据 (读取的数据以字节的形式放在缓存数组tx_buff中)
//形参:waddr   (24位的地址),nBytes_128   (字节个数)
//返回:无
________________________________________________________________*/
void w25_RDS(unsigned long waddr,u8 * w25buf,u16 len)
{
    unsigned long i;
    W25X_CS=0;
    w25_wrbyte(READ);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    for(i=0;i<len;i++)
      *(w25buf+i)=w25_rdbyte();
    W25X_CS=1;
}
/*-----------------------------------------------------------
//描述:快速读flash数据的函数
//功能:快速读取指定地址上的数据
//形参:Dst_Addr   (24位的地址)
//返回:byte
________________________________________________________________*/
u8 w25_FRD(unsigned long waddr)
{
    u8 byte;
    W25X_CLK=1;
    W25X_CS=0;
    w25_wrbyte(FARD);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    w25_wrbyte(0xFF);
    byte=w25_rdbyte();
    W25X_CS=1;
    return byte;
}
/*-----------------------------------------------------------
//描述:快速读flash多字节数据的函数
//功能:快速读取指定地址上的数据 (读取的数据以字节的形式放在缓存数组tx_buff中)
//形参:Dst_Addr   (24位的地址),nBytes_128   (字节个数)
//返回:无
________________________________________________________________*/
void w25_FRDS(unsigned long waddr,u8 * w25buf,u16 len)
{
    unsigned long i;
    W25X_CS=0;
    w25_wrbyte(FARD);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    w25_wrbyte(0xFF);
    for(i=0;i<len;i++)
      *(w25buf+i)=w25_rdbyte();
    W25X_CS=1;
}
/*-----------------------------------------------------------
//描述:写flash数据的函数 (以一个字节的形式)
//功能:写入数据到指定地址上
//形参:Dst_Addr   (24位的地址),byte (数据)
//返回:无   
________________________________________________________________*/
void w25_WR(unsigned long waddr,u8 byte)
{
    w25_enable();
    w25_busy();
    W25X_CS=0;
    w25_wrbyte(PGPM);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    w25_wrbyte(byte);
    W25X_CS=1;
}
/*-----------------------------------------------------------
//描述:写多个字节flash数据的函数 (以多字节的形式)(这之前要先把数据存到upper_128缓存数组中 )
//功能:写入多个字节数据到指定地址上
//形参:Dst_Addr   (24位的地址),nBytes_128 (字节个数)
//返回:无   
________________________________________________________________*/
void w25_WRS(unsigned long waddr,u8 *w25buf,u16 len)
{
    u8 i;
    W25X_CS=0;
    w25_enable();
    W25X_CS=0;
    w25_wrbyte(PGPM);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)(waddr & 0xFF));
    for(i=0;i<len;i++)
      w25_wrbyte(*(w25buf+i));
    W25X_CS=1;
}
/*----------------------------------------------------------
//描述:flash扇区擦除函数(w25x32扇区擦除需要150ms~300ms)
//功能:擦除页,每页4k (如果该页被保护,擦除无效)
//形参:Dst_Addr   (24位的地址)(此地址可为此页中的任何地址)
//返回:无   
_________________________________________________________________*/
void w25_erase4k(unsigned long waddr)
{       
    W25X_CS=0;
    w25_enable();
    W25X_CS=0;
    w25_wrbyte(STES4K);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)waddr & 0xFF);
    W25X_CS=1;
    W25X_CLK=1;
    w25_busy();
}
/*----------------------------------------------------------
//描述:flash块区擦除函数(w25x32块区擦除需要0.8s~2s)
//功能:擦除块区,每块64k (如果该块被保护,擦除无效)
//形参:Dst_Addr   (24位的地址)
//返回:无   
_________________________________________________________________*/
void w25_erase64k(unsigned long waddr)
{
    W25X_CLK=1;
    W25X_CS=0;
    w25_enable();
    W25X_CS=0;
    w25_wrbyte(BKES64K);
    w25_wrbyte((u8)((waddr & 0xFFFFFF) >> 16));
    w25_wrbyte((u8)((waddr & 0xFFFF) >> 8));
    w25_wrbyte((u8)waddr & 0xFF);
    W25X_CS=1;
    W25X_CLK=1;
    w25_busy();
}
/*------------------------------------------------
//描述:flash芯片擦除函数(w25x32擦除整个芯片需要40s~80s)
//功能:擦除整个芯片 (如果写保护状态,擦除无效)
//形参:无
//返回:无   
_________________________________________________________________*/
void w25_erase(void)
{
    W25X_CLK=1;
    W25X_CS=0;
    w25_enable();
    W25X_CS=0;
    w25_busy();
    W25X_CS=0;
    w25_wrbyte(CPES);
    W25X_CS=1;
    W25X_CLK=1;
    w25_busy();
}
电路见附图
,求指点....

wofei3344 发表于 2013-11-5 09:25:06

自己顶贴吧,每一个人关注查看....~~~~(>_<)~~~~

dalarang 发表于 2013-11-6 10:55:07

哥们,你这样一上来扔一堆代码是很难问到答案的,因为一般人没那么好的耐心一行行代码核对过去,难度也太大。
自己找找问题吧,良好的排查问题的思路能事半功倍。
先试试w25_rdid1,看能不能读回ID,如果读回是0x00或是0xFF,那就是IO口配置或SPI读写函数有问题。

另外P3SEL_bit.P0=0这类语句是用宏实现的?怎么觉得不太对劲呢。

activeleo 发表于 2013-11-6 11:06:45

最起码的ID要验证读取成功在谈下一步阿!

peecehood 发表于 2013-11-6 14:19:42

本帖最后由 peecehood 于 2013-11-6 14:34 编辑

为什么有硬件SPI不用?
void w25_busy(void)
{
    while (w25_rdsr() == 0x03)
      w25_rdsr();      //      waste time until not busy WEL & Busy bit all be 1 (0x03)
}
这个0x03放入写入后面有过吗?不是写完一个指令WEL会自动清零。

wofei3344 发表于 2013-11-6 18:20:46

dalarang 发表于 2013-11-6 10:55 static/image/common/back.gif
哥们,你这样一上来扔一堆代码是很难问到答案的,因为一般人没那么好的耐心一行行代码核对过去,难度也太大 ...

谢谢你的建议 ,P3OUT_bit.P0等类似的宏是IAR5.5以后的版本中自带的<MSP430Fx24X.h>中定义的,表示要操作的位是P3.0,如果事先设置好P3SEL,那么可以直接P3OUT_bit.P0=0或者P3OUT_bit.P0=1以控制单片机输出高低电平;

我的问题最后解决了,是CS的问题,每次操作的函数只需要开头片选和结束时取消片选;除了片选问题和读忙状态有问题,其它目前测试没有问题;

wofei3344 发表于 2013-11-6 18:23:14

peecehood 发表于 2013-11-6 14:19 static/image/common/back.gif
为什么有硬件SPI不用?
void w25_busy(void)
{


谢谢你的关注,问题已经解决,片选除了问题,参见我上一条回复信息;

另外,读忙的这个函数是写错了;

用硬件SPI,示波器测试无CLK、无DI输出...不知道什么原因,IAR5.5后的头文件看起来有些乱,没找到一个好的用户指南,官方的和IAR中的寄存器也对不上,最终放弃了,改为IO模拟.....
页: [1]
查看完整版本: W25X80读不到数据,使用MSP430F247单片机