这两天调试STM32F103外扩SRAM,将调试过程中遇到的问题记录下,SRAM的规格是256K*16的异步SRAM,地址总线为18,数据线宽度为16. 在调试过程中遇到一些小问题,希望读者能少走些弯路。 先看一下FSMC内存映射图: 由图可知,stm32的FSMC模块分为四个bank,每个bank的大小事64M。 , `' U" E, @8 o9 e
3 b- [. q( b0 I& M0 v2 ]+ y& g) I
下面这张图是FSMC各个块的信号分配图。
# r1 H. O1 J9 ?0 p* F/ F7 u+ E$ P5 b' \6 x" N8 d
由上图可知,bank1 NOR/PSRAM可以分为4个子块,由FSMC_NE[4:1]来选择使能哪个子块。 例如:每小块NOR/PSRAM的64M地址范围如下: 第一块:6000 0000h--63ff ffffh 第二块:6400 0000h--67ff ffffh 第二块:6800 0000h--6bff ffffh 第三块:6c00 0000h--6fff ffffh ) @! f6 M8 K0 o# J- t
我们可以通过选择HADDR[27:26]来确定当前使用的是哪个64M的分地址块,如下图所示: 9 w4 R8 n3 V. n# `4 B$ a9 f) V. t
9 e% Q" ~- ? H. M% [5 D( g
这里我使用的是100脚的stm32,只有NE1引脚可用,也就是说只能用Bank1的存储块1,即FSMC_Bank1_NORSRAM1。 我用的STM32是100脚的,地址和数据总线是复用的,那么需要用到锁存器来区分地址和数据,而锁存信号是NADV输出的,注意看图173和图174的NADV信号在输出地址时是低电平,输出数据时是高电平,所以锁存器要选择一个高电平锁存或者加个反向器。 在配置STM32的FSMC的寄存器时要注意下面两句话: - //使能复用模式
+ S! H$ s2 z; s3 c; T# q3 y - FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Enable;
/ O5 J4 g, ?$ I: _( r# i) w - //注意这里不是FSMC_MemoryType_SRAM而是FSMC_MemoryType_NOR,手册上说要想输出NADV信号只能设置成FSMC_MemoryType_NOR。
" g1 s( V2 ?6 b) t - FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR
复制代码
0 G9 m+ `7 s1 K; p+ x* R
+ G; k u3 V4 t9 L& H: Z! |
, [( D T5 T2 C" T! h5 Z
% L8 e; l" R2 y, ?2 p! |SRAM参考原理图如下图:
T, N$ a+ T' W7 w5 i( ^/ A0 G+ ?stm32的FSMC功能用到的复用IO口比较多,配置时需要细点心: - /*
f/ E5 h& v+ O) h2 W" x+ I1 U - *PD14(DA0) PD15(DA1) PD0(DA2) PD1(DA3) PE7~PE15(DA4~DA12) PD8~PD10(DA13~DA15) PD11(A16) PD12(A17): F" E0 P* L% a8 y1 s+ U
- *PD5(WE) PD7(NE1) PD4(OE)0 u1 _4 n: b, A
- *PE0(BL0) PE1(BL1) NADV(PB7)2 z r2 z! q+ X2 R3 R
- */* ~- n M. H$ a3 j2 V6 K
- void sram_gpio_configration(void)% a0 L2 \ X* c- I
- {
+ H' I5 P, e+ }4 h - GPIO_InitTypeDef GPIO_InitStructure;
9 D% Y. p0 \. R! F9 h+ N( J4 _" s
" V& f h4 l9 n4 h( [: `! u* M- ?- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |4 P5 ? E0 y' U0 ~/ N, O% Y
- GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | 6 a; e; H' g d5 r% b8 t: @* G( `
- GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15;
7 S+ o- [1 H0 }- q5 N - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;% i5 X+ F' l7 t/ C1 q) i
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
% \: I9 ?# M5 m" G! ]8 J - GPIO_Init(GPIOD, &GPIO_InitStructure);
" _" q' N3 ]; P T+ K9 I% e ?
1 }: R$ c. S% a$ s4 B5 k- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_7 | GPIO_Pin_8 |/ l0 y7 w& m# t& U- V6 C w
- GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 |
1 D! d$ r3 l8 K5 {/ M - GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
& y- {4 m. J# x7 j# [* O3 } - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- |- A% E5 e. b! H; H( g - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;3 B/ \* g( q% Y! y" ]9 W1 p: u8 N
- GPIO_Init(GPIOE, &GPIO_InitStructure);; P( e# z8 e0 e8 w! N
- 6 j8 k7 _& q) E! M$ m T3 g
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
' _ x" T' P2 S: r8 |( M. o9 A" k - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; % K( l* z* a9 c+ Q; Z. m! ~
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/ \( @4 ~( y* O% w
- GPIO_Init(GPIOB, &GPIO_InitStructure);! k6 t a5 q- Q" I7 C: x5 ~" I/ s
- }
复制代码 # I; B! c+ C* N# k
外部SRAM的访问: 在访问SRAM时纠结了许久,最后终于弄明白了。网上看了很多资料,有说在访问时要先将地址偏移,有说直接访问就行。最后经过测试发现访问片外SRAM时跟访问内部RAM一样,直接访问就可以了,FSMC都帮我们做好了。 当访问字节数据时:*((u8*)(BANK1_SRAM_BASE+offset))。1.读取SRAM数据时,将offset设为0x00,用示波器测试SRAM的A0地址信号是低,当offset为0x01时,用示波器测试SRAM的A0地址信号也是低,当offset为0x02和0x03时SRAM的A0地址信号是高,这说明当字节访问时地址确实是偏移了1位,原因是SRAM是16位器件(SRAM的1个地址存储16位数据),一次可以访问2个字节的数据,这个时候FSMC将根据offset值判断,访问的是高8位还是低8位,即如果offset的最低位是0则访问的是16位数据的低8位,如果offset的最低位是1则访问的是16位数据的高8位。2. 向SRAM写数据时,道理也是一样的,只是写的时候通过BL[1:0]两个管脚控制写高字节还是低字节。 当访问半字数据时:*((u16*)(BANK1_SRAM_BASE+offset))。1.读取SRAM数据时,这个时候要注意了,FSMC在访问的时候要看offset的值是不是半字对齐的。如果offset是0x00,则直接访问的是SRAM的0x00地址处的16位数据,当offset是0x01时,FSMC是分两次访问的,第一次是访问SRAM的0x00地址的高字节,第二次是访问SRAM的0x01地址处的低字节(SRAM的1个地址存储16位数据),通过用示波器测量SRAM的A0地址信号得到,信号是先低在高的一个脉冲,验证了前面的说法。2. 向SRAM写数据时,道理也是一样的,只是写的时候通过BL[1:0]两个管脚控制写高字节还是低字节。 当访问字数据时:访问字时,FSMC分为2个半字访问。 总结:外部SRAM就跟片内SRAM一样用就行了。
" L: ]( e6 f: T4 [. p |