打印

关于DSP外扩存储器的几个问题

[复制链接]
6839|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cruby|  楼主 | 2007-7-8 22:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我用的芯片是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 | 只看该作者

提一下思路

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 | 只看该作者

如果外接的数据存储器呢?

谢谢楼上提醒,但是如果我接的是数据存储器呢?比如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 | 只看该作者

看样子你是想把外部flash的0地址对应DSP的0x8000吧?

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的代价节省接口逻辑。

使用特权

评论回复
5
cruby|  楼主 | 2007-7-9 19:14 | 只看该作者

啊,这可怎么办?

如果不用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的空间吗?

使用特权

评论回复
6
wowow| | 2007-7-9 19:35 | 只看该作者

可以把Flash的A15也用IO来控制

只把A0-A14跟DSP总线相联,这样一次可中32k

使用特权

评论回复
7
cruby|  楼主 | 2007-7-9 22:09 | 只看该作者

我的硬件已经成型了,怎么办呢

非常感谢wowow指点,现在我的硬件已经成型了,地址线A0-A15已经跟Flash的A0-A15连接了,应该怎么办呢?

我往Flash上写东西时,要先往0x555、0x2aa等地址上写一些数据,按照现有的硬件条件怎么才能访问到这些地址呢?

使用特权

评论回复
8
wowow| | 2007-7-10 01:59 | 只看该作者

要么浪费,要么飞线

有的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.

使用特权

评论回复
9
tjsheep| | 2007-7-10 11:14 | 只看该作者

简单解答,呵呵

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的编译器,不能自动编译出这样的代码

使用特权

评论回复
10
cruby|  楼主 | 2007-7-10 11:27 | 只看该作者

看来是大大地浪费了

今天早上考虑了一下,把DS#接个反相器直接与存储器连了,这样我就只用了4M闪存的32k(心痛啊,好浪费!),暂时不管别的了,先把芯片调通了再说;

另外,我用的Flash是AMD(Spansion?)的Am29DL640D,数据手册好大,有六十多页,回去找找看看高位引脚跟命令字节有没有关系?

PS:wowow人品很不错~

使用特权

评论回复
11
iversonma| | 2007-7-10 15:28 | 只看该作者

理论上应该可以

command命令寄存器是不会占用存储空间的,你给具体的地址写数据系统不会识别是写命令或者写数据。不过提供了两个方法防止这种错误
首先一般写数据都要求先写一个命令字,下一个周期写入的数据才能写入,注意memory的集中mode
normal mode似乎写数据之前是需要命令字的,还有一种autoselect mode似乎不用,具体可以详细看看memory的datasheet。
再者一般的命令字都是连续好几个的,闲着没事估计没有人写地址数据刚好和命令字相同。

这个问题倒是问得不错,支持你按你的想法试一下,别忘了在这里说一下结果

使用特权

评论回复
12
cruby|  楼主 | 2007-7-12 22:08 | 只看该作者

To iversonma:

今天试了一下,向Flash编程时可以用0x8555代替0x555,我可以往Flash上写一个字,不过也就一个字;紧接着往第二个字写的时候发现没有用,可能是我的写时序有点问题,明天再看看~

不知道有谁写过读写Flash存储器Am29DL640D类似的程序,如果有的话我想参考一下。我的邮箱为:veshid@gmail.com

使用特权

评论回复
13
iversonma| | 2007-7-12 22:23 | 只看该作者

re

没有看明白什么意思?
命令可以替代,写数据什么意思?
am29dl是异步的吧,如果是的话找别的异步器件参考就行
别人的程序不会那么轻易就送出去的

使用特权

评论回复
14
随风飘2008| | 2007-7-12 23:07 | 只看该作者

re

我也没看明白

使用特权

评论回复
15
cruby|  楼主 | 2007-7-12 23:43 | 只看该作者

不明白吗

说得不够明白是吧
简单地说就是写命令字节进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#才能变低,所以......)

使用特权

评论回复
16
iversonma| | 2007-7-13 09:24 | 只看该作者

这不就是datasheet上面的原话吗

看来是你自己没有说清楚
另外你说的那个第二次写不进去的问题,应该是flash不支持页模式,或者你只设置为async模式,这样情况下写一次命令字只允许写一个数据位(如果falsh为16位就是16位)。和时序没有关系

使用特权

评论回复
17
cruby|  楼主 | 2007-7-13 11:27 | 只看该作者

继续

估计我不止没说清楚,也没有弄清楚,所以稀里糊涂的~
继续说几句吧,看看有没有人搞过类似的芯片,想交流一下:

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的值就不正确呢?
是不是每次读或者写后都必须得验证一下呢?
回去还得好好看看手册~

使用特权

评论回复
18
iversonma| | 2007-7-13 20:32 | 只看该作者

胡乱解释一下




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都有详细介绍。

使用特权

评论回复
19
cruby|  楼主 | 2007-7-13 22:35 | 只看该作者

看了一下午手册

看了一下午手册,有点弄明白了,不过晚上上机一试发现还是调不出来,郁闷,明天得加班继续了~

使用特权

评论回复
20
zhangmangui| | 2013-12-9 12:20 | 只看该作者
好贴  帮忙顶

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

64

帖子

0

粉丝