25LC256写进去,读出来是0X00,为何?
25LC256写进去,读出来是0X00,为何?请教大家一下。 不知道你的读写程序是否正确,而且要注意写完一页要延时, 最近我就在写25LC160的读写程序,发现一些问题:
1.读状态寄存器时,一定要先写WREN指令,再发送读状态寄存器指令,25LC160才会输出当前状态。这个在microchip的例程里是错的。
2.执行写操作,发完WREN和WRITE写指令后都要等待一定时间,25LC160才会正常响应后面操作
3.读数据时, 发完READ指令,及2字节地址后,这2个步骤后各需要等待一定时间,否则25LC160也不会响应,MISO口读到的数据自然就全是0
另外我发现在读状态寄存器指令后,25LC160输出状态数据的第一个bit经常会有异常的毛刺尖峰信号出现,占据接近1个多bit位的宽度。3.3V供电,这个尖峰大约2V多的样子。读状态寄存器,出现这种情况的几率有90%以上,尖峰信号的幅值有时小有时大。至今不知道什么原因。官方的应用指南里的图片没看到这种现象 我已经读出来了。数据是对的。过段时间公布。 这两天我也在做25lc256的读写程序,和楼主的现象一样,
按照手册,
写命令字节0x02,地址字节0x0001,数据字节0x55依次给入
读命令字节0x03,地址字节0x0001,依次给入,读出来的却是0x00,示波器探了下,25lc256的SO引脚没看见过高电平
请问楼主,读25lc256的0x0001地址的字节,是不是一点要先把STATUS先配置一下? 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;
} 我已经被dsPIC33的spi硬设打败了,就是不能读25lc256,提供的AN1069文档,cn527722的例程试过了,没有效果呀!反正我没得到文档中SO的时序
同事们都劝我,不要太专注技术细节,条条大路通罗马,反正用sunnyhook的方法就可以了,
但是,个人觉得如鲠在喉,居然玩不转这几个时序 的确DSPIC33的SPI很难。我也试过了,NG。于是干脆用模拟方式,OK,解决问题了。呵呵。 #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天才搞定. AN1069的例子,如果你把每次读写里德“ReadStatus(); ”去掉,不要读状态寄存器,那么AN1069就可以读写了(前提是你能保证读或写是在内部写周期完成以后)。
我在2楼里第一条说过了“1.读状态寄存器时,一定要先写WREN指令,再发送读状态寄存器指令,25LC160才会输出当前状态。这个在microchip的例程里是错的。” 看了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;”这样发动“读”?
总之,还没搞通,还没有读懂楼上的程序 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需要的延时分散到处理其它程序中去,因系统响应时间的需要,不能一直等在那里延时。 哪家的?25系列 有很多傢出的好像程序都不同
w25x XX
{:sweat:} hd12 发表于 2010-9-9 10:14 5 temp = SPI1BUF; // before first cycle need clear the SPIBUF : 这个用来清除SPI1BUF内 ...
请教大侠,3V25系列的FRAM写入和读出速度能达到多高,500K字节/秒能到吗? HZKJ 发表于 2013-1-11 13:12 static/image/common/back.gif
请教大侠,3V25系列的FRAM写入和读出速度能达到多高,500K字节/秒能到吗?
数据手册里肯定有这个参数的,我没用过
页:
[1]