搜索
bottom↓
回复: 6

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

[复制链接]

出0入0汤圆

发表于 2013-11-4 15:00:36 | 显示全部楼层 |阅读模式
如题,程序如下:
#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[i]中)
//形  参: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[i]中)
//形  参: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[i]缓存数组中 )
//功  能:写入多个字节数据到指定地址上
//形  参: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();
}
电路见附图
,求指点....

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-11-5 09:25:06 | 显示全部楼层
自己顶贴吧,每一个人关注查看....~~~~(>_<)~~~~

出0入0汤圆

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

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

出0入0汤圆

发表于 2013-11-6 11:06:45 | 显示全部楼层
最起码的ID要验证读取成功在谈下一步阿!

出0入0汤圆

发表于 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会自动清零。

出0入0汤圆

 楼主| 发表于 2013-11-6 18:20:46 | 显示全部楼层
dalarang 发表于 2013-11-6 10:55
哥们,你这样一上来扔一堆代码是很难问到答案的,因为一般人没那么好的耐心一行行代码核对过去,难度也太大 ...

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

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

出0入0汤圆

 楼主| 发表于 2013-11-6 18:23:14 | 显示全部楼层
peecehood 发表于 2013-11-6 14:19
为什么有硬件SPI不用?
void w25_busy(void)
{

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

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

用硬件SPI,示波器测试无CLK、无DI输出...不知道什么原因,IAR5.5后的头文件看起来有些乱,没找到一个好的用户指南,官方的和IAR中的寄存器也对不上,最终放弃了,改为IO模拟.....
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-10 09:30

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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