lions 发表于 2010-8-28 11:42:12

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

25LC256写进去,读出来是0X00,为何?请教大家一下。

Forever 发表于 2010-8-28 12:14:29

不知道你的读写程序是否正确,而且要注意写完一页要延时,

hd12 发表于 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%以上,尖峰信号的幅值有时小有时大。至今不知道什么原因。官方的应用指南里的图片没看到这种现象

lions 发表于 2010-8-29 20:35:24

我已经读出来了。数据是对的。过段时间公布。

hahahaluo 发表于 2010-9-1 19:07:57

这两天我也在做25lc256的读写程序,和楼主的现象一样,
按照手册,

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

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

sunnyhook 发表于 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;
}

hahahaluo 发表于 2010-9-3 11:03:19

我已经被dsPIC33的spi硬设打败了,就是不能读25lc256,提供的AN1069文档,cn527722的例程试过了,没有效果呀!反正我没得到文档中SO的时序

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

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

lions 发表于 2010-9-3 19:24:15

的确DSPIC33的SPI很难。我也试过了,NG。于是干脆用模拟方式,OK,解决问题了。呵呵。

hd12 发表于 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 ENABLEinstruction code
#define RDSR    0x05// RD STATUSinstruction code
#define WRSR    0x01// WR STATUSinstruction code
#define NOPROT0x00// NO WRITE PROTECTION
#define ENPROT0b0001100

#define Eprom_CS LATGbits.LATG3//


typedef union
{
   unsigned char Byte;
   unsigned intWord;

}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=
{
/*
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;
            EpromWriteStep = 195;
            break;
      };
      case 195:// 197: send Address low
      {
            SPI1BUF = Eprom_AddressTable;
            EpromWriteStep = 0;
            break;
      };
      case 100:// write complete
      {
            EpromWriteStep = 255;
            Eprom_CS = 1;
            break;
      };
      default:// default: send byte
      {
            SPI1BUF = Eprom_WriteBuf.Byte;// write data
            EpromWriteStep++;
            if( EpromWriteStep == (Eprom_AddressTable) )
            {
                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;
            EpromReadStep = 197;
            break;
      };
      case 197://send Address low
      {
            SPI1BUF = Eprom_AddressTable;
            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 = SPI1BUF;
            EpromReadStep++;
            if( EpromReadStep == (Eprom_AddressTable))
            {
                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      XXX   DISSCK DISSDOMODE16 SMPCKESSENCKP MSTEN    SPRE   PPRE                     
SPI1CON1    111      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天才搞定.

hd12 发表于 2010-9-7 10:20:58

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

hahahaluo 发表于 2010-9-8 22:01:00

看了hd12的帖子,着实振奋了一下,
用完sunnyhook的办法,也想试试hd12的,
只是有一点不明白,
1         Eprom_CS = 0;
2         SPI1BUF = READ;
3         SPI1BUF = Eprom_AddressTable; //high address
4         SPI1BUF = Eprom_AddressTable; //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 = SPI1BUF;
9         Eprom_CS = 1;

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

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

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

hd12 发表于 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; //high address
      delay(80);
4         SPI1BUF = Eprom_AddressTable; //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 = SPI1BUF;
9         Eprom_CS = 1;

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

5768340 发表于 2013-1-10 17:38:52

jetli 发表于 2013-1-10 17:49:59

哪家的?25系列 有很多傢出的好像程序都不同

w25x XX
{:sweat:}

HZKJ 发表于 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字节/秒能到吗?

hd12 发表于 2013-1-11 18:09:16

HZKJ 发表于 2013-1-11 13:12 static/image/common/back.gif
请教大侠,3V25系列的FRAM写入和读出速度能达到多高,500K字节/秒能到吗?

数据手册里肯定有这个参数的,我没用过

5768340 发表于 2013-1-11 21:27:40

5768340 发表于 2013-1-11 22:21:12

页: [1]
查看完整版本: 25LC256写进去,读出来是0X00,为何?