|
| 出处:21ic 时间: 2007-07-13 |
|
cruby 发布于 2007-7-8 22:07:00 我用的芯片是2407,在外扩存储器时有几个问题搞不清楚,请各位帮我看看:
1. 假设我要外扩程序存储器,现在我将PS#跟存储器Flash的CE#连接(这里用#表示“反/非”的意思),要使Flash使能就必须使CE#为0,也就是要使PS#为0,那么怎么才能使PS#为0呢?
2. 如果我令MP/MC# = 0(从内部读取复位向量),那么能访问外部的存储器吗?如果能,那么假设我要读外部存储器0x0010地址处的值时,我应该用什么指令呢? 是 unsigned int getValue = 0; //定义一个内部变量 getValue = *(unsigned int*)0x0010; 还是 unsigned int getValue = 0; getValue = *(unsigned int*)(0x0010 + 0x8000);呢?
3. 如果我令MP/MC# = 1(从外部读取复位向量),那么怎么才能访问外部的存储器呢? 是 unsigned int getValue = 0; getValue = *(unsigned int*)0x0010; 还是 unsigned int getValue = 0; getValue = *(unsigned int*)(0x0010 + 0x8000);呢?
4. 接着第3个问题,此时还能访问内部的存储器吗?如果能的话怎么访问内部的存储器呢?如果不能的话,那么内部32K的Flash不是没用了吗;外扩的时候内部32K的Flash是不是始终都有用还是说外扩后就没用了?
wowow 发布于 2007-7-9 13:03:00 C2000的我不熟,提一下在其它5000系列中的思路供参考: 接到PS#说明是程序空间,如果是汇编就用相关的指令,如果是C,*(unsigned int*)0x0010这种方法肯定不行,这是数据指针,是访问数据空间用的。函数指针才会指向程序空间,但用函数指针来访问数据肯定也不恰当.
能想到的办法中有通过变量,确保它分配到程序空间 1.对于const变量,定义: const int x; 然后将.const段(前面的.不要漏了)分配到程序空间的Section里面。(C2000里也应该有Page0/Page1吧?前面争了半天的,呵呵) 这个方法只能用于全局变量,因为局部变量是在stack里,不会分配到.const段。还有前面不能加volatile,因为volatile变量处理方法不一样。
2.自定义一个section,比如取名叫mysect,将其也分配到程序空间的Section里。然后在定义变量的前面加上#pragma DATA_SECTION编译指示: #pragma DATA_SECTION (y, "mysect") int y;
但这种方法访问数据估计会比较慢,因为程序空间的寻址方式很少,你可以看一一反汇编的代友,一般要先把数据先复制到寄存器或数据空间里再参与运算。不划算吧?所以除常量以外的数据最好都放在数据空间。
Cruby 发布于 2007-7-9 14:19:00 谢谢楼上提醒,但是如果我接的是数据存储器呢?比如DS#接外部数据存储器的片选信号CE#,那么怎么才能使DS#变为0呢?
另外,我访问外部数据存储器地址的0x0010时,我用 unsigned int getValue = 0; //定义一个内部变量 getValue = *(unsigned int*)0x0010; 还是 unsigned int getValue = 0; getValue = *(unsigned int*)(0x0010 + 0x8000);呢?
wowow 发布于 2007-7-9 16:25:00 1.要想DS#变低,就要访问外部地址空间, 比如将0x8000地址以上映射到extern memory, 访问*(unsigned int*)(0x0010 + 0x8000)就可以使DS#变低
如果你想外部flash的0地址对应DSP的0x8000,就要将高位地址线A15取反,再跟DS#脚相或,再接到Flash的CE#,低地址A14-A0线一一对应接。这样你访问0x8010时,A15为低,跟DS#相或后仍然是低,选中Flash。但实际操作的是Flash的0x0010地址。
其实也不复杂,只要想好:DSP的引脚输出什么电平,外部芯片需要输入什么电平才能选中,中间加个组合逻辑匹配一下就行了。
如果你用的是32k*16的Flash,只能这样接了。如果是64k或更大的,反正只能用到32k,总是有浪费的。可以直接DS#接Flash的CE#,并将低32k的数据空间由于是映射到内部空间,高32k数据空间映射到外部空间,那么flash的低32k是访问不到的了,高32k与程序中的地址是一一对应的。这样以浪费flash的代价节省接口逻辑。
cruby 发布于 2007-7-9 19:14:00 如果不用A15取反的话,就永远不能访问前32k了是吗?
因为如果我直接将DS#与Flash的CE#连起来的话,用*(unsigned int*)(0x0010 + 0x8000)访问的就是存储器的0x8010的地址;而用*(unsigned int*)(0x0010)的话就是访问数据存储器内部的0x0100地址而不是Flash的0x0010地址,是这样吗?
我现在碰到的情况是用DS#接外部一个4M的Flash(共22根地址线)的CE#,地址线A0-A15连Flash的A0-A15,剩下的地址线不够用就用IO口PE0-PE5代替;另外,DSP的RD#接Flash的OE#,WE#接WE#;如果这样的话,是不是说这4M的Flash的前32K也是不能用了?另外,这IO口能代替数据线访问Flash的空间吗?
wowow 发布于 2007-7-9 19:35:00 只把A0-A14跟DSP总线相联,这样一次可中32k
cruby 发布于 2007-7-9 22:09:00 非常感谢wowow指点,现在我的硬件已经成型了,地址线A0-A15已经跟Flash的A0-A15连接了,应该怎么办呢?
我往Flash上写东西时,要先往0x555、0x2aa等地址上写一些数据,按照现有的硬件条件怎么才能访问到这些地址呢?
wowow 发布于 2007-7-10 1:59:00 有的flash的0x555、0x2aa写命令不在意A15是高还是低,这个要看datasheet。
Address format A14-A0 (Hex): Address A15 is “Don’t Care” for the Command sequence for SST39LF/VF512. Address A15 and A16 are “Don’t Care” for the Command sequence for SST39LF/VF010. Address A15, A16 and A17 are “Don’t Care” for the Command sequence for SST39LF/VF020. Address A15, A16, A17 and A18 are “Don’t Care” for the Command sequence for SST39LF/VF040.
SST39LF/VF200A SST39LF/VF400A SST39LF/VF800A: Address format A14-A0 (Hex), Addresses AMS-A15 can be VIL or VIH, but no other value, for the Command sequence.
tjsheep 发布于 2007-7-10 11:14:00 1. 假设我要外扩程序存储器,现在我将PS#跟存储器Flash的CE#连接(这里用#表示“反/非”的意思),要使Flash使能就必须使CE#为0,也就是要使PS#为0,那么怎么才能使PS#为0呢?
----mp/mc设为mp模式,访问程序时候ps有效,就是外部空间
2. 如果我令MP/MC# = 0(从内部读取复位向量),那么能访问外部的存储器吗?如果能,那么假设我要读外部存储器0x0010地址处的值时,我应该用什么指令呢? 是 unsigned int getValue = 0; //定义一个内部变量 getValue = *(unsigned int*)0x0010; 还是 unsigned int getValue = 0; getValue = *(unsigned int*)(0x0010 + 0x8000);呢?
--------访问外部什么空间?数据还是程序?
3. 如果我令MP/MC# = 1(从外部读取复位向量),那么怎么才能访问外部的存储器呢? 是 unsigned int getValue = 0; getValue = *(unsigned int*)0x0010; 还是 unsigned int getValue = 0; getValue = *(unsigned int*)(0x0010 + 0x8000);呢?
------8000以后的数据空间自动访问外部的,c语言里的变量分配用cmd文件指定,一般不用绝对地址
4. 接着第3个问题,此时还能访问内部的存储器吗?如果能的话怎么访问内部的存储器呢?如果不能的话,那么内部32K的Flash不是没用了吗;外扩的时候内部32K的Flash是不是始终都有用还是说外扩后就没用了?
------内部外部程序空间是重叠的,一般来说是不能同时用的,但是用手动的办法来访问也是可以的,但是不符合c的编译器,不能自动编译出这样的代码
cruby 发布于 2007-7-10 11:27:00 今天早上考虑了一下,把DS#接个反相器直接与存储器连了,这样我就只用了4M闪存的32k(心痛啊,好浪费!),暂时不管别的了,先把芯片调通了再说;
另外,我用的Flash是AMD(Spansion?)的Am29DL640D,数据手册好大,有六十多页,回去找找看看高位引脚跟命令字节有没有关系?
PS:wowow人品很不错~
cruby 发布于 2007-7-10 12:44:00 手册上有下面这些话: /********************************************************* Unless otherwise noted, address bits A21-A11 (x16-only devices) or address bits A22-A11 (x8-only devices) are don't cares for unlock and command cycles, unless SA or PA is required. **********************************************************/ 它说写命令字节的时候,A21-A11是没有关系的,但如果我用*(unsigned int*)(0x8555),芯片是怎么知道我是在写命令字节还是在往0x8555的地址上写一个值呢?
换句话说,是不是我用: //555,2AA,555地址构成一个命令序列 *(unsigned int*)(0x0A555) = 0xAA; *(unsigned int*)(0x0B2AA) = 0x55; *(unsigned int*)(0x0D555) = 0xA0; 就等价与 *(unsigned int*)(0x0555) = 0xAA; *(unsigned int*)(0x02AA) = 0x55; *(unsigned int*)(0x0555) = 0xA0;
而 //455,244,333地址不能构成一个命令序列 *(unsigned int*)(0x0A455) = 0xAA; *(unsigned int*)(0x0B244) = 0x55; *(unsigned int*)(0x0D333) = 0xA0; 就不等价与 *(unsigned int*)(0x0455) = 0xAA; *(unsigned int*)(0x0244) = 0x55; *(unsigned int*)(0x0333) = 0xA0; 呢?
iversonma 发布于 2007-7-10 15:28:00 command命令寄存器是不会占用存储空间的,你给具体的地址写数据系统不会识别是写命令或者写数据。不过提供了两个方法防止这种错误 首先一般写数据都要求先写一个命令字,下一个周期写入的数据才能写入,注意memory的集中mode normal mode似乎写数据之前是需要命令字的,还有一种autoselect mode似乎不用,具体可以详细看看memory的datasheet。 再者一般的命令字都是连续好几个的,闲着没事估计没有人写地址数据刚好和命令字相同。
这个问题倒是问得不错,支持你按你的想法试一下,别忘了在这里说一下结果
cruby 发布于 2007-7-12 22:08:00 今天试了一下,向Flash编程时可以用0x8555代替0x555,我可以往Flash上写一个字,不过也就一个字;紧接着往第二个字写的时候发现没有用,可能是我的写时序有点问题,明天再看看~
不知道有谁写过读写Flash存储器Am29DL640D类似的程序,如果有的话我想参考一下。我的邮箱为:fisherdia@gmail.com
iversonma 发布于 2007-7-12 22:23:00 没有看明白什么意思? 命令可以替代,写数据什么意思? am29dl是异步的吧,如果是的话找别的异步器件参考就行 别人的程序不会那么轻易就送出去的
随风飘2008 发布于 2007-7-12 23:07:00 我也没看明白
cruby 发布于 2007-7-12 23:43:00 说得不够明白是吧 简单地说就是写命令字节进A22-A11的状态是无所谓的,这样 *(unsigned int*)(0x0A555) = 0xAA; *(unsigned int*)(0x0B2AA) = 0x55; *(unsigned int*)(0x0C555) = 0xA0; 就等价与 *(unsigned int*)(0x0555) = 0xAA; *(unsigned int*)(0x02AA) = 0x55; *(unsigned int*)(0x0555) = 0xA0;了,
因为我现在板子的硬件设置访问不了外部Flash 0x8000前的空间,而要往Flash里写数据的话必须写几个命令字节(在555,2aa,555等地址,注意:这些地址都在0x8000前);所以一开始我以为访问不了Flash的8000前地址,也就不能往这些地址写上东西,但是后来看到A22-A21无关后,就试了一下,发现在555,2aa之类的地址加上8000也无所谓(为什么我要加8000呢? 因为访问8000以上地址,WE#才能变低,所以......)
iversonma 发布于 2007-7-13 9:24:00 看来是你自己没有说清楚 另外你说的那个第二次写不进去的问题,应该是flash不支持页模式,或者你只设置为async模式,这样情况下写一次命令字只允许写一个数据位(如果falsh为16位就是16位)。和时序没有关系
cruby 发布于 2007-7-13 11:27:00 估计我不止没说清楚,也没有弄清楚,所以稀里糊涂的~ 继续说几句吧,看看有没有人搞过类似的芯片,想交流一下:
1. 芯片名字叫Am29DL640D,现在好像已经停产了,官方推荐用S29JL064H代替~ 2. 读芯片没什么特殊的,直接读地址就可以了 3. “写”芯片(program flash)就麻烦了:首先要先命令字节,另外还有两种写的模式,一个是常规的,需四个周期,还有一种叫bypass模式,只需2个周期; 4. 有两种擦除模式,一个是Chip Erase,另一个是Sector Erase,是不是在写之前都要擦除一下呢? 5. 另外还有个引脚叫WP#/ACC,好像可以加速读写速度的,具体不清楚,都是英文,看得头都大了,相关中文资料找了好久也没找到什么有价值的,痛苦啊~
我只是奇怪,为什么我用 ProgramFlash(0x8888, 0x1111); //往8888地址写1111 ProgramFlash(0x9999, 0x2222); getValue1 = ReadFlash(0x8888);//读取8888地址的值 getValue2 = ReadFlash(0x9999); 后,getValue1的值正确,而getValue2的值就不正确呢? 是不是每次读或者写后都必须得验证一下呢? 回去还得好好看看手册~
iversonma 发布于 2007-7-13 20:32:00
1. 芯片名字叫Am29DL640D,现在好像已经停产了,官方推荐用S29JL064H代替~ 这个没有问题,基本软件是全部兼容的,而且速度肯定要上去一些,因为采用了更高级的制造工艺,这样spansion的成本也降下来了。 2. 读芯片没什么特殊的,直接读地址就可以了 因为不会破坏内部数据,所以不用写命令。 3. “写”芯片(program flash)就麻烦了:首先要先命令字节,另外还有两种写的模式,一个是常规的,需四个周期,还有一种叫bypass模式,只需2个周期; 模式不止这两种, 4. 有两种擦除模式,一个是Chip Erase,另一个是Sector Erase,是不是在写之前都要擦除一下呢? 在nor flash里面,是由好多sector(块)组成的,擦除的时候可以选择Chip Erase(整片擦除)和sector erase(块擦除)写之前不一定必须擦除,如果你不确定memory里面是否有数据,写之前擦除一下也是很必要的。取决于你自己
5. 另外还有个引脚叫WP#/ACC,好像可以加速读写速度的,具体不清楚,都是英文,看得头都大了,相关中文资料找了好久也没找到什么有价值的,痛苦啊~
wp#/acc管脚也有可能是两个分开,wp#是硬件写保护信号(write protect)有效时软件写操作被屏蔽,可以起到保护的作用。acc是加速的意思,一般烧写器或者工厂大批量烧写的时候用到,比普通的软件在线编程速度快一倍多(不同的器件可能有差异,大致是这个意思)。
其实对于做软件驱动而言,只要关心操作数和时序就可以了,好多种的保护模式实际很少用刀,除非作烧写器或者要大批量生产。
关于资料,memory的资料一般都是英文的,没有办法,技术更新的太快,目前中文有一本译文的,名字好像是《半导体存储器-结构 》不确定,不过你网上搜,也只有一本,讲的比较基础,目前市面上常用的memory都有详细介绍。
cruby 发布于 2007-7-13 22:35:00 看了一下午手册,有点弄明白了,不过晚上上机一试发现还是调不出来,郁闷,明天得加班继续了~
|
| 【关闭】 【打印】 |
|
|
|
|