搜索
bottom↓
回复: 17

25LC256写进去,读出来是0X00,为何?

[复制链接]

出0入0汤圆

发表于 2010-8-28 11:42:12 | 显示全部楼层 |阅读模式
25LC256写进去,读出来是0X00,为何?请教大家一下。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-8-28 12:14:29 | 显示全部楼层
不知道你的读写程序是否正确,而且要注意写完一页要延时,

出0入0汤圆

发表于 2010-8-28 14:29:49 | 显示全部楼层
最近我就在写25LC160的读写程序,
发现一些问题:
1.  读状态寄存器时,一定要先写WREN指令,再发送读状态寄存器指令,25LC160才会输出当前状态。这个在microchip的例程里是错的。
2.  执行写操作,发完WREN和WRITE写指令后都要等待一定时间,25LC160才会正常响应后面操作
3.  读数据时, 发完READ指令,及2字节地址后,这2个步骤后各需要等待一定时间,否则25LC160也不会响应,MISO口读到的数据自然就全是0

    另外我发现在读状态寄存器指令后,25LC160输出状态数据的第一个bit经常会有异常的毛刺尖峰信号出现,占据接近1个多bit位的宽度。3.3V供电,这个尖峰大约2V多的样子。读状态寄存器,出现这种情况的几率有90%以上,尖峰信号的幅值有时小有时大。至今不知道什么原因。官方的应用指南里的图片没看到这种现象

出0入0汤圆

 楼主| 发表于 2010-8-29 20:35:24 | 显示全部楼层
我已经读出来了。数据是对的。过段时间公布。

出0入0汤圆

发表于 2010-9-1 19:07:57 | 显示全部楼层
这两天我也在做25lc256的读写程序,和楼主的现象一样,
按照手册,

写命令字节0x02,地址字节0x0001,数据字节0x55依次给入
读命令字节0x03,地址字节0x0001,依次给入,读出来的却是0x00,示波器探了下,25lc256的SO引脚没看见过高电平

请问楼主,读25lc256的0x0001地址的字节,是不是一点要先把STATUS先配置一下?

出0入0汤圆

发表于 2010-9-1 19:40:01 | 显示全部楼层
void SPI_init(void)
{
        SPI_CS = 1;
        delayNOP();
        SPI_SCK = 1;
        WREN();
        delayms(10);
        WRSR(0x02);
        delayms(10);
}



/**********************************************************
  读字节数据子函数
  MCU从SPI读出数据
**********************************************************/
uchar SPI_Read()
{
        uchar i,read_data;
        read_data=0x00;
       
        for(i = 0; i < 8; i++)
        {     
                SPI_SCK = 0;
                delayNOP();
                read_data <<= 1;
                read_data |= SPI_SO;
                SPI_SCK = 1;
        }
        return(read_data);
}

/**********************************************************
  写字节数据子函数
  MCU写数据到SPI,
**********************************************************/
void SPI_Write(uchar write_data)
{
   uchar i;                                 //CS is Low
   for(i = 0; i < 8; i++)    //循环移入8个位
   {
         SPI_SCK = 0;
         if((write_data<<i) & 0x80)
                 SPI_SI = 1;
         else
                 SPI_SI = 0;
         SPI_SCK = 1;
         delayNOP();
   }
}


/**********************************************************
  写字节数据子函数
  将数据写入指定地址
**********************************************************/
void Write_byte(uint write_add,uchar write_data)           //将数据从16bit地址写入
{
        uchar add_L,add_H;
        SPI_CS = 0;
        add_H = write_add >> 8;
        add_L = write_add && 0x00ff;
        SPI_Write(0x02);
        SPI_Write(add_H);
        SPI_Write(add_L);
        SPI_Write(write_data);
        SPI_CS = 1;
}

uchar Read_byte(uint write_add)                         //将数据从16bit地址读出
{
        uchar add_L,add_H,velau;
        SPI_CS = 0;
        delayNOP();
        add_H = write_add >> 8;
        add_L = write_add && 0x00ff;
        SPI_Write(0x03);
        SPI_Write(add_H);
        SPI_Write(add_L);
        velau = SPI_Read();
        SPI_CS = 1;
        return velau;
}


void WREN()                     //写允许
{
        SPI_CS = 0;
        delayNOP();
        SPI_Write(0x06);
        SPI_CS = 1;
}

void WRDI()                         //写禁止
{
        SPI_CS = 0;
        delayNOP();
        SPI_Write(0x04);
        SPI_CS = 1;
}

uchar RDSR(void)                 //读状态寄存器
{
        uchar velau;
        SPI_CS = 0;
        delayNOP();
        SPI_Write(0x05);
        velau = SPI_Read();
        SPI_CS = 1;
        return velau;
}

void WRSR(uchar Sta)          //写状态寄存器
{
        SPI_CS = 0;
        delayNOP();
        SPI_Write(0x01);
        SPI_Write(Sta);
        SPI_CS = 1;
}

出0入0汤圆

发表于 2010-9-3 11:03:19 | 显示全部楼层
我已经被dsPIC33的spi硬设打败了,就是不能读25lc256,提供的AN1069文档,cn527722的例程试过了,没有效果呀!反正我没得到文档中SO的时序

同事们都劝我,不要太专注技术细节,条条大路通罗马,反正用sunnyhook的方法就可以了,

但是,个人觉得如鲠在喉,居然玩不转这几个时序

出0入0汤圆

 楼主| 发表于 2010-9-3 19:24:15 | 显示全部楼层
的确DSPIC33的SPI很难。我也试过了,NG。于是干脆用模拟方式,OK,解决问题了。呵呵。

出0入0汤圆

发表于 2010-9-7 10:06:09 | 显示全部楼层
#include <p33fxxxx.h>
#define READ    0x03  // READ       instruction code
#define WRITE   0x02  // WRITE      instruction code
#define WRDI    0x04  // WR DISBALE instruction code
#define WREN    0x06  // WR ENABLE  instruction code
#define RDSR    0x05  // RD STATUS  instruction code
#define WRSR    0x01  // WR STATUS  instruction code
#define NOPROT  0x00  // NO WRITE PROTECTION
#define ENPROT  0b0001100

#define Eprom_CS LATGbits.LATG3  //


typedef union
{
   unsigned char Byte[16];
   unsigned int  Word[8];

}B16W8;

unsigned char EpromWriteStep = 255; //          status of write
                                    // 255:     no write
                                    // 220:     start check status
                                    // 221:     check status step2
                                    // 222:     check status step3
                                    // 223:     check status step4
                                    // 224:     check status reasult
                                    // 200:     send WREN
                                    // 199:     send WREN complete
                                    // 197:     send WRITE
                                    // 196:     send Address high
                                    // 195:     send Address low
                                    // 100:     write complete
                                    // default: send byte


unsigned char EpromReadStep = 255;  //          status of read
                                    // 255:     no read
                                    // 220:     start check status
                                    // 221:     check status step2
                                    // 222:     check status step3
                                    // 223:     check status step4
                                    // 224:     check status reasult
                                    // 200:     send READ
                                    // 198:     send Address high
                                    // 197:     send Address low
                                    // 196:     send first read clock cycle
                                    // 254:     Read complete
                                    // default: send byte

unsigned char PageWrite;  // Eprom page you want to write
unsigned char PageRead;   // Eprom page you want to read

B16W8 Eprom_WriteBuf;                 // Eprom write buffer
B16W8 Eprom_ReadBuf;                  // Eprom Read buffer



const unsigned char Eprom_AddressTable[32][3]=
{
/*
addressH,
addressL,
length, max 16
*/
    { 0,  0, 16},  // 0
    { 0, 16, 16},  // 1
    { 0, 32, 16},  // 2
    { 0, 48, 16},  // 3
    { 0, 64, 16},  // 4
    { 0, 80, 16},  // 5
    { 0, 96, 16},  // 6
    { 0,112, 16},  // 7
    { 0,128, 16},  // 8
    { 0,144, 16},  // 9
    { 0,160, 16},  // 10
    { 0,176, 16},  // 11
    { 0,192, 16},  // 12
    { 0,208, 16},  // 13
    { 0,224, 16},  // 14
    { 0,240, 16},  // 15

    { 1,  0, 16},  // 16
    { 1, 16, 16},  // 17
    { 1, 32, 16},  // 18
    { 1, 48, 16},  // 19
    { 1, 64, 16},  // 20
    { 1, 80, 16},  // 21
    { 1, 96, 16},  // 22
    { 1,112, 16},  // 23
    { 1,128, 16},  // 24
    { 1,144, 16},  // 25
    { 1,160, 16},  // 26
    { 1,176, 16},  // 27
    { 1,192, 16},  // 28
    { 1,208, 16},  // 29
    { 1,224, 16},  // 30
    { 1,240, 16}   // 31

};

//-----------------------------------Eprom_Init
void Eprom_Init(void)
{
/*Port set as output*/
    TRISGbits.TRISG3  = 0;

/*No open Dran*/
    ODCGbits.ODCG3 = 0;
}

oid WritePage(void)
{
    static unsigned char temp;
    switch (EpromWriteStep)
    {
        case 255:
        {
            break;
        };
        case 220:  // start check status
        {
            LCD_Hold();  // stop Lcd
            Eprom_CS = 0;
            SPI1BUF = WREN;  // send WREN
            EpromWriteStep = 221;
            break;
        };
        case 221:  // check status step2
        {
            Eprom_CS = 1;
            EpromWriteStep = 222;
            break;
        };
        case 222:  // check status step3
        {
            Eprom_CS = 0;
            SPI1BUF = RDSR;  // send RDSR-------------------------
            EpromWriteStep = 223;
            break;
        };
        case 223:  // check status step4
        {
            temp = SPI1BUF; // before first cycle need clear the SPIBUF
            SPI1STATbits.SPIROV = 0;
            SPI1BUF = 0x00;        // initiate bus cycle
            EpromWriteStep = 224;
            break;
        };
        case 224:  // check status result
        {
            temp = SPI1BUF;
            Eprom_CS = 1;
            if((temp & 0x01) == 1)    // internal write
            {
                EpromWriteStep = 220;
            }
            else     // no busy
            {
                EpromWriteStep = 200;
            };
            break;
        };
        case 200:  // send WREN
        {
            Eprom_CS = 0;
            SPI1BUF = WREN;
            EpromWriteStep = 199;
            break;
        };
        case 199:  // send WREN complete
        {
            Eprom_CS = 1;
            EpromWriteStep = 197;
            break;
        };
        case 197:  // 199: send WRITE
        {
            Eprom_CS = 0;
            SPI1BUF = WRITE;
            EpromWriteStep = 196;
            break;
        };
        case 196:  // 198: send Address high
        {
            SPI1BUF = Eprom_AddressTable[PageWrite][0];
            EpromWriteStep = 195;
            break;
        };
        case 195:  // 197: send Address low
        {
            SPI1BUF = Eprom_AddressTable[PageWrite][1];
            EpromWriteStep = 0;
            break;
        };
        case 100:  // write complete
        {
            EpromWriteStep = 255;
            Eprom_CS = 1;
            break;
        };
        default:  // default: send byte
        {
            SPI1BUF = Eprom_WriteBuf.Byte[EpromWriteStep];  // write data
            EpromWriteStep++;
            if( EpromWriteStep == (Eprom_AddressTable[PageWrite][2]) )
            {
                EpromWriteStep = 100;
            };
            break;
        };
    };
}

void ReadPage(void)
{
    static unsigned char temp;
    switch (EpromReadStep)
    {
        case 255:  // no read
        {
            break;
        };
        case 220:  // start check status
        {
            LCD_Hold();  // stop Lcd
            Eprom_CS = 0;
            SPI1BUF = WREN;  // send WREN
            EpromReadStep = 221;
            break;
        };
        case 221:  // check status step2
        {
            Eprom_CS = 1;
            EpromReadStep = 222;
            break;
        };
        case 222:  // check status step3
        {
            Eprom_CS = 0;
            SPI1BUF = RDSR;  // send RDSR--------------
            EpromReadStep = 223;
            break;
        };
        case 223:  // check status step4
        {
            temp = SPI1BUF; // before first cycle need clear the SPIBUF
            SPI1STATbits.SPIROV = 0;
            SPI1BUF = 0x00;        // initiate bus cycle
            EpromReadStep = 224;
            break;
        };
        case 224:  // check status result
        {
            temp = SPI1BUF;
            Eprom_CS = 1;
            if((temp & 0x01) == 1)    // internal write
            {
                EpromReadStep = 220;
            }
            else     // no busy
            {
                EpromReadStep = 200;
            };
            break;
        };
        case 200:  // send Read
        {
            Eprom_CS = 0;
            SPI1BUF = READ;
            EpromReadStep = 198;
            break;
        };
        case 198:  // send Address high
        {
            SPI1BUF = Eprom_AddressTable[PageRead][0];
            EpromReadStep = 197;
            break;
        };
        case 197:  //  send Address low
        {
            SPI1BUF = Eprom_AddressTable[PageRead][1];
            EpromReadStep = 196;
            break;
        };
        case 196:  //  first read cycle
        {
            temp = SPI1BUF; // before first cycle need clear the SPIBUF
            SPI1STATbits.SPIROV = 0;
            SPI1BUF = 0x00;        // initiate bus cycle
            EpromReadStep = 0;
            break;
        };
        default:  // default: read byte
        {
            Eprom_ReadBuf.Byte[EpromReadStep] = SPI1BUF;
            EpromReadStep++;
            if( EpromReadStep == (Eprom_AddressTable[PageRead][2]))
            {
                Eprom_CS = 1;
                EpromReadStep = 254;  // data are ready
            }
            else
            {
                SPI1BUF = 0x00;  // start another read clock cycle
            }
            break;
        };
    };
}


//----------------------------------SPI1硬件设置------------------------------------------
/*
BIT         15 14 13    12     11      10    9    8     7    6    5      4-2    1-0
NAME        X  X  X   DISSCK DISSDO  MODE16 SMP  CKE  SSEN  CKP MSTEN    SPRE   PPRE                     
SPI1CON1    1  1  1      0     0       0     0    1     0    0    1      101     10
*/
// Fcy = 40Mhz ,SPI Baud Rate = 3.3Mbps
SPI1CON1 = 0B1110000100110110;
SPI1CON2 = 0;

//---------------------------------------------------------------------------------------

使用例子:

假如你在function4()中需要读25LC160的第0页(因为我用的是25LC160,如果是25LC256你应该知道要改哪些的)
void function4(void)
{
    ...
    PageRead = 0;  //设置需要操作的页为0,见Eprom_AddressTable【】,这里面存贮了我保存数据的页地址,及数据长度,根据自己需要定义的
    EpromReadStep = 220; // 改变25LC160读操作步骤数值,主程序中的“ReadPage();”将有机会执行。数据会保存在Eprom_ReadBuf【16】中,通过查询EpromReadStep是否为254,确定数据是否读完

}

main()
{
    function1();
    function2();
    function3();
    .......
    ReadPage();
    WritePage();
    function4();



}


注意25LC系列的数据手册,因为25LC256系列的速度在4.5V~5.5V供电时最高10MHz时钟频率,2.5~4.5V时最高5MHz,所以SPI口的预分频你得注意设置,不要过快,否则也不会操作成功。
并且要保证
    function1();
    function2();
    function3();
这些程序运行所占用的时间要大于SPI口发送一个字节的数据,因为我用这些子程序作为延时用。如果你只是测试,需要在主程序中插入延时程序,以保证每次进入ReadPage();或WritePage();时SPI口的数据操作已经完成。
或者你可以将上面我的程序改成一次性读、写完成的程序,只是在每个步骤间需要插入足够的延时。我弄了5天才搞定.

出0入0汤圆

发表于 2010-9-7 10:20:58 | 显示全部楼层
AN1069的例子,如果你把每次读写里德“ReadStatus(); ”去掉,不要读状态寄存器,那么AN1069就可以读写了(前提是你能保证读或写是在内部写周期完成以后)。
我在2楼里第一条说过了“1.  读状态寄存器时,一定要先写WREN指令,再发送读状态寄存器指令,25LC160才会输出当前状态。这个在microchip的例程里是错的。”

出0入0汤圆

发表于 2010-9-8 22:01:00 | 显示全部楼层
看了hd12的帖子,着实振奋了一下,
用完sunnyhook的办法,也想试试hd12的,
只是有一点不明白,
1           Eprom_CS = 0;
2           SPI1BUF = READ;
3           SPI1BUF = Eprom_AddressTable[PageRead][0]; //high address
4           SPI1BUF = Eprom_AddressTable[PageRead][1]; //low address
5           temp = SPI1BUF;                            // before first cycle need clear the SPIBUF
6           SPI1STATbits.SPIROV = 0;
7           SPI1BUF = 0x00;                            // initiate bus cycle
8           Eprom_ReadBuf.Byte[EpromReadStep] = SPI1BUF;
9           Eprom_CS = 1;

5、6、7怎么也搞不懂,实际读出的还是0x00,示波器上SO引脚没看见过高电平,

我不明白的是SPI1BUF = xxxx;可以发动“写”,那么“读”是怎么发动?
是“temp = SPI1BUF; ”这样发动“读”?
还是“SPI1BUF = 0x00;”这样发动“读”?

总之,还没搞通,还没有读懂楼上的程序

出0入0汤圆

发表于 2010-9-9 10:14:20 | 显示全部楼层
5       temp = SPI1BUF;        // before first cycle need clear the SPIBUF  
: 这个用来清除SPI1BUF内容,不清理一次的话,有时候会出错,不清楚是不是跟dsPIC的SPI读和写BUF地址相同所致。

6           SPI1STATbits.SPIROV = 0;  
: 清除SPI1的“读”错误标志,如果不执行这一步,程序会跑飞,我没检查飞哪去了

7       SPI1BUF = 0x00;        // initiate bus cycle  
: dsPIC做为主控器件,需要给出读数据的时钟,25LC256才会依次把数据发出来,dsPIC没专门的命令让它的时钟口输出时钟,就用这个方法了。后面的数据不一定是0x00,可以是任意数。

你如果只把上面的1-9挑出来测试的话,需要加延时,假设你的dsPIC工作在40MHz,SPI口时钟按3.3MHz,

void delay(unsigned char times)
{
    while(times)
    {
        times--;
    };
}

1           Eprom_CS = 0;  
      delay(5);
2           SPI1BUF = READ;
      delay(80);
3           SPI1BUF = Eprom_AddressTable[PageRead][0]; //high address
      delay(80);
4           SPI1BUF = Eprom_AddressTable[PageRead][1]; //low address
      delay(120);
5           temp = SPI1BUF;                            // before first cycle need clear the SPIBUF
6           SPI1STATbits.SPIROV = 0;  
7           SPI1BUF = 0x00;                            // initiate bus cycle
      delay(50);
8           Eprom_ReadBuf.Byte[EpromReadStep] = SPI1BUF;
9           Eprom_CS = 1;

上面的延时加的很长,你可以观察示波器上的变化,适当的减小延时。我8楼的程序是将读写25LC160需要的延时分散到处理其它程序中去,因系统响应时间的需要,不能一直等在那里延时。
头像被屏蔽

出0入0汤圆

发表于 2013-1-10 17:38:52 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2013-1-10 17:49:59 | 显示全部楼层
哪家的?25系列 有很多傢出的好像程序都不同

w25x XX

出0入17汤圆

发表于 2013-1-11 13:12:34 来自手机 | 显示全部楼层
hd12 发表于 2010-9-9 10:14 5 temp = SPI1BUF; // before first cycle need clear the SPIBUF : 这个用来清除SPI1BUF内 ...

请教大侠,3V25系列的FRAM写入和读出速度能达到多高,500K字节/秒能到吗?

出0入0汤圆

发表于 2013-1-11 18:09:16 | 显示全部楼层
HZKJ 发表于 2013-1-11 13:12
请教大侠,3V25系列的FRAM写入和读出速度能达到多高,500K字节/秒能到吗?

数据手册里肯定有这个参数的,我没用过
头像被屏蔽

出0入0汤圆

发表于 2013-1-11 21:27:40 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
头像被屏蔽

出0入0汤圆

发表于 2013-1-11 22:21:12 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-24 05:21

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

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