1.外部SRAM简介 本例程使用的STM32F103ZET6本身有64K字节的SRAM,一般应用已经足够;不过在一些对内存要求高的场合,比如跑算法或者GUI等,就需要外扩SRAM来满足大内存使用的需求。这里我们使用了一颗256K字节容量的SRAM芯片:IS62WV12816,利用STM32F1的FSMC控制该SRAM芯片,实现对该SRAM芯片的访问控制 IS62WV12816是ISSI公司生产的16位宽128K(128*2,即256K字节)容量的CMOS静态内存芯片,它有高速访问、低功耗、兼容TTL电平接口、全静态操作(不需要刷新和时钟电路)、三态输出和字节控制(支持高/低字节控制)等特点。IS62WV12816的引脚以及对应的引脚功能如下图示: ! v% Y& z0 L$ A$ o' t" T
! m" l1 Q) ?, bA0 ~ A16为地址线,总共17根地址线(可访问2^17 = 128K字节空间);I/O0 ~ I/O15为数据线,总共16根数据线;CS1(低电平有效)和CS2(高电平有效)都是片选信号;WE为输入使能信号(写信号);OE为输出使能信号(读信号);UB和LB分别是高字节和低字节控制信号
" ]4 l) h$ }* H! b
4 @2 l, Z8 U6 Y' w1 D$ a
2.硬件设计  D1指示灯用来提示系统运行状态,按键用来控制IS62WV12816数据读写,TFTLCD和串口1用来显示读写的内容 . ] z# h a$ F
D1指示灯 K_UP/K_DOWN按键
, y3 Y" p Q1 c7 F- I3 R USART1串口 TFTLCD , T9 m/ c/ Z* s6 ^, j [
IS62WV12816 2 S! J! B u$ S! R% V6 H! e
! _9 q' ^3 q' r' \/ e0 [- F" u6 g0 r
从电路图中可以看到IS62WV12816和STM32F1的连接线路:
0 y" M+ K' {1 I6 C, l2 ]A0 ~ A16连接在FSMC_A0 ~ FSMC_A16上(连接顺序可以打乱,因为地址是固定的)
! h; Q V8 T8 Y% J# r0 xI/O0 ~ I/O15连接在FSMC_D0 ~ FSMC_D15上(连接顺序不能打乱,否则读写数据将出错)2 t* t( v) P# U% y3 ^1 Z
UB和LB连接在FSMC_NBL1 和 FSMC_NBL0上, {& P5 ~4 `2 L( g2 _( ~1 s* M1 d
OE和WE分别连接在FSMC_NOE 和 FSMC_NWE上
! X! B0 J6 F2 sCE连接在FSMC_NE3上
/ I$ X( \+ w- ~- Z# e% F
2 C8 s$ P2 U& u4 @" s) C
由于TFTLCD核SRAM共用FSMC总线,因此他们通过不同片选分时复用,互不影响
+ P2 \- g' k; H/ ? u
3.软件设计  3.1 STM32CubeMX设置 ➡️ RCC设置外接HSE,时钟设置为72M ➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平 ➡️ PA0设置为GPIO输入模式、下拉模式;PE3设置为GPIO输入模式、上拉模式 ➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位 ➡️ 激活FSMC ➡️ 输入工程名,选择路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
" z7 T: t( R9 n' S5 e' ^1 f
由于TFTLCD使用的Bank1_sector4和SRAM使用的Bank1_sector3无法同时在CubeMX里设置分时复用,因此需要单独创建SRAM的FSMC初始化函数(可自行创建,也可另外创建一个CubeMX工程,按下图设置后将生成的相关FSMC初始化代码拷贝到当前工程源码中并稍作修改) 8 h5 M `; n) h/ i/ r& Z" a
( H! X0 P0 {* e! b7 t+ _( {
3.2 MDK-ARM软件编程 ➡️ 创建按键驱动文件key.c和key.h,参考按键输入例程 ➡️ 创建LCD驱动文件tftlcd.c 和tftlcd.h,参考TFTLCD显示例程 ➡️ 创建IS62WV12816芯片驱动文件sram.c和sram.h
, P4 i# O: o& Q1 F+ ^
- #define Bank1_SRAM3_ADDR ((uint32_t)(0x68000000))//Bank1区域3的起始地址 : _/ h5 q% {; d3 U
- SRAM_HandleTypeDef SRAM_Handler;//定义SRAM句柄, }& j* B" G" O8 ?/ N9 }
- //SRAM的FSMC初始化函数
5 u. E7 u* s* o" f - void FSMC_SRAM_Init(void){ - T" O8 I3 o9 ]5 P z5 V+ s4 a# e
- GPIO_InitTypeDef GPIO_InitStruct;
/ \1 f9 F7 }- D, K8 N1 Q d6 L' l - FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
( p) m( P8 w$ Y6 j# V - __HAL_RCC_FSMC_CLK_ENABLE(); 6 P8 U1 r0 j, I1 Y1 j
- __HAL_RCC_GPIOD_CLK_ENABLE();
S T9 }3 A, Z3 E- @4 q; C$ r - __HAL_RCC_GPIOE_CLK_ENABLE();
0 G6 a+ c3 D; R- ^ - __HAL_RCC_GPIOF_CLK_ENABLE(); ' A: H6 t) _3 x7 U+ n$ O% X( }
- __HAL_RCC_GPIOG_CLK_ENABLE(); 5 ^6 d: @# d" y3 T6 h c+ p& t8 c3 Y
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
' a, J! ]' w0 b5 B3 Q3 a: M - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13 * x& b% T7 K3 J2 J4 p) D3 G2 d, {
- |GPIO_PIN_14|GPIO_PIN_15;
4 j' ^2 F, }* P+ i @" \ - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;. e* \0 s# P/ S0 e
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;8 o# e5 x3 c, R
- HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
* G5 E2 ~* V9 M5 }! K4 A) _ - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 9 [. |/ S7 X* Y# s6 O2 s
- |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_10;
# P* ]5 d. B8 i5 [2 N- A - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;3 E' v' \3 B# O( u
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
0 z% a* s$ y. J3 S$ k - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); o# `2 e( g) f0 P
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 $ l$ u L9 U+ c/ g& K: c( |! d
- |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 " a* L9 |# M9 q8 G
- |GPIO_PIN_15;% b/ _+ b- I$ a7 K4 N3 Q& h! H1 |2 ~
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
5 e l+ g! r9 U - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;# J) Z( o$ E- [6 E3 V" u1 T
- HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);2 X8 W8 {* Z6 ]! z5 \
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 " K" a" J/ g5 \. y( n- W# `
- |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1 & h% F3 \4 e; j9 v8 l: {
- |GPIO_PIN_4|GPIO_PIN_5;. v8 `! j& [7 E( u. N
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;/ h0 j9 {! Y9 H9 i/ W
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;" v% M% S! W$ |3 D# K- c9 a% R
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); 6 [* g; p8 b- X8 H6 o
- 9 ]. s9 ]. ~+ m/ ~ U# O8 g5 S
- SRAM_Handler.Instance=FSMC_NORSRAM_DEVICE;
% g7 ]2 o5 t" U; j+ I - SRAM_Handler.Extended=FSMC_NORSRAM_EXTENDED_DEVICE; # P1 J/ f) G8 f+ ?- n* d) g
- SRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK3; //使用NE3
* r! d3 D% e7 C - SRAM_Handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;//地址/数据线不复用
3 p' E# r' u' [ - SRAM_Handler.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM; //SRAM
0 z+ R0 A5 p/ U - SRAM_Handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;//16位数据宽度
" c9 i/ _6 }) _ X8 m$ j( C - SRAM_Handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;//不使能突发访问" l( C6 I2 M! z3 B2 \* j% J2 t/ ^
- SRAM_Handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性(突发模式)* t6 F5 P0 J1 c( k6 e# G
- SRAM_Handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS; + |: \" d) \( G% U6 ]
- SRAM_Handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE; //写使能. A1 D% n9 c% n- d/ h: E
- SRAM_Handler.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE;
" c9 B* W9 U/ }, [ - SRAM_Handler.Init.ExtendedMode=FSMC_EXTENDED_MODE_DISABLE; //读写使用相同的时序
0 K/ ]' S* x- a, f% G+ R; b - SRAM_Handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;
. [; j" E- Z( c3 e - SRAM_Handler.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE; //禁止突发写9 f& D* Y, L) `1 a- @
- //FSMC读时序控制器! T) J0 R/ B; S3 g C5 h$ i
- FSMC_ReadWriteTim.AddressSetupTime=0x00; //地址建立时间(ADDSET)为1个HCLK& @8 y) H1 G0 T. ^# @" K* C
- FSMC_ReadWriteTim.AddressHoldTime=0x00; //地址保持时间(ADDHLD)模式A未用到
% w7 O# J, R; r3 W) T# j - FSMC_ReadWriteTim.DataSetupTime=0x08; //数据保持时间(DATAST)为9个HCLK
0 d# G; y. n: U( K! {1 H3 U) A - FSMC_ReadWriteTim.BusTurnAroundDuration=0X00;
/ q1 t+ u d" l$ y* P _9 `; |% x - FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A
& U B( b" p. A - HAL_SRAM_Init(&SRAM_Handler,&FSMC_ReadWriteTim,&FSMC_ReadWriteTim); & |* N# S: O9 J/ \+ p, p; U
- }
" A3 @8 {7 {( j$ R8 h" i - //n向指定地址写数据
2 V1 j+ j) _( a, a" m2 \& c - void FSMC_SRAM_WriteBuffer(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t n){
( Q) u: f0 m1 z5 A - for(;n!=0;n--){ // n表示要连续写入的字节个数
% t/ p1 i' W; q- o g - *(vu8*)(Bank1_SRAM3_ADDR + WriteAddr) = *pBuffer;) W/ g) q4 N) ^8 D6 g- W: K
- WriteAddr++; //要写入的地址
7 V; F1 Z5 H3 ^) X }/ _* U0 H7 d - pBuffer++; //要写入的数据的指针
# j' J1 A, K S - }
* Z9 E/ ]! k) Q I- r - }, X+ h5 X* w, `
- //从指定地址读数据
4 k; _+ W! ]# H. x9 w$ j+ ?! ? - void FSMC_SRAM_ReadBuffer(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t n){
8 B% e+ k# T% K9 q - for(;n!=0;n--){ // n表示要连续读出的字节个数
: r# S' Z4 _2 f) `+ I8 c: ]& q: Z# } - *pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);//存放读出的数据
2 r3 m7 V/ i+ G* A* W - ReadAddr++; //要读出的起始地址
' E }& s0 P# U' X$ K7 ?8 o - }* }9 f8 i# f1 N. D* Y5 g
- }
, f5 V, P6 Q0 I - // 6 [5 t" y7 [ L6 [4 b ~
- void ExSRAM_Cap_Test(uint16_t x,uint16_t y){& f, N% K' ?( x& J3 p7 p/ s4 U' `0 T, X
- uint8_t writeData = 0xf0, readData;
1 t% u+ }. j0 M2 h: l: {" _& Y& I q - uint16_t cap=0;' L' E+ f8 O1 M/ V: I4 R# J7 h
- uint32_t addr; . d. i$ i% V. b' ]* C1 d; N p/ P
- addr = 1024; //从1KB位置开始计算
% k/ Z. d/ Q7 @+ V - LCD_ShowString(x,y,239,y+16,16,"ExSRAM Cap: 0KB");
+ K8 \! r; ] C+ F; D& P" P Y - + v% @+ `: k9 Z
- while(1){& Y2 l! p* L8 C5 v2 I
- FSMC_SRAM_WriteBuffer(&writeData, addr, 1);
* p4 d) m, {; F& `9 ~9 F2 R - FSMC_SRAM_ReadBuffer(&readData,addr,1);3 Y* E% J; _- F2 T$ U: [
- 3 [! w! {; V- I
- if(readData == writeData){//检查读出的数据是否与写入的数据一样
5 o8 L1 S( y8 Z I2 |* `/ O& o& v" y - cap++; //如果相同表示写入/读出成功,容量加1(单位KB)3 a/ O" r: q8 H- n& y
- addr += 1024; //地址加1024
. s: D y7 I/ ?# ~+ ~+ A: S - readData = 0;; A; a8 w% g% A% T( Q# m
- if(addr > 256 * 1024)//IS62WV12816的容量为256KB
$ N7 t: ]3 s( i! k - break;
, p: Q& D/ i* e" [ - }
. s# D0 ?+ _' q0 q5 u/ Y - else* l$ v& }( I: Z R( \, b
- break; 7 D0 K z7 y$ N" _% w. R3 M" F. }) P
- }
9 s+ [( I" O9 ^ m$ U. f - LCD_ShowxNum(x+11*8,y,cap,4,16,0);//LCD上显示内存容量, V! r6 s3 S! ~ e9 @3 t L
- printf("SRAM Menmory Size:%dKB\r\n",cap);
- {5 g( y: {' G$ t' t - }
复制代码 ! v) {! U" H# R) q
➡️ 在main.c文件下编写SRAM测试代码 % C9 F# u, J0 P& C) \" S5 `
- int main(void){
8 H6 r* L; j$ I6 A# @ - /* USER CODE BEGIN 1 */
/ q+ |5 n! V4 k* w: V - uint8_t key;
. G' H4 w* ? T - uint8_t text_buf[] = "This is SRAM testing...";
" ?8 B5 x6 o, n" q6 x( V' M - uint8_t textlen = sizeof(text_buf);
- R% k; X' h/ D# P - uint8_t read_buf[textlen];6 p/ _% A5 ?. y; Q1 I
- /* USER CODE END 1 */
3 x% l* T! K# p8 v! C- |3 g4 R, U- I% | - HAL_Init();2 h4 V9 j, f8 L2 A% a% G
- SystemClock_Config();
! `- X+ l/ c! n* F! x5 O- e0 I" n - MX_GPIO_Init();& K c/ f+ j/ s w- V4 L
- MX_FSMC_Init();
$ Q9 l) s) ?" {- o( o - MX_USART1_UART_Init();
0 E/ X- R0 Z: I" e' s. s' ^ - /* USER CODE BEGIN 2 */# I5 p( K7 X1 n( S" ~; L
- TFTLCD_Init();' A8 _5 H6 j( ^+ O) J6 M' [
- FSMC_SRAM_Init();
, q7 h& ?8 J' j; v- C# W6 g$ o - FRONT_COLOR=BROWN;
* P$ u1 t6 I: Q% w8 Q6 I9 } - LCD_DrawRectangle(5,5,235,95);
: F" ~' @; k1 q0 {: {. u7 Q4 @ O - FRONT_COLOR=BLACK;
' J5 D1 u. L' Q' s, V - LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"ANDYXI STM32F1");
% B/ H% ]& f& d - LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"STM32CubeMx SRAM");
; ^1 v0 L: Q! C9 _+ a& l - LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,"ExSRAM Test");
0 X5 E9 R; U/ R; I* t9 ~9 H - LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,16,"K_UP:Write K_DOWN:Read"); ) d6 n4 H1 t* j
- FRONT_COLOR=RED;5 X2 n& }4 g' V Y. M5 X
- ExSRAM_Cap_Test(10,110);
|' Q# E9 A- B1 j* B( H - FRONT_COLOR=MAGENTA;
7 x" Y0 s" r' Y - LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,16,"Write:");% g5 o- K, ~' ]0 G
- LCD_ShowString(10,150,tftlcd_data.width,tftlcd_data.height,16,"Read :");: o" D0 a* [, m# k' p. J
- /* USER CODE END 2 */2 @1 T" p& {" z
- /* Infinite loop */
' d# X! h2 q5 I - /* USER CODE BEGIN WHILE */
" |- V7 Y& A5 R! J! l. t3 @ - while(1){
6 b& s" K* e1 b4 s* T. @0 ]( K - key = KEY_Scan(0);
1 u" d: X1 w) y7 t( G - if(key == KEY_UP_PRES){ //KEY_UP按下写数据到SRAM: p2 d. Q6 Y$ S% s W( X. q1 r
- FSMC_SRAM_WriteBuffer(text_buf,0,textlen);
9 V$ y8 n9 z/ R0 P: l - printf("SRAM_Write:%s\r\n",text_buf);# Q5 |3 o) a7 f4 Y
- LCD_ShowString(10+6*8,130,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)text_buf);
8 b* d% i* i# y0 k x E - }
+ }; A8 ?5 v* S# h$ ? - if(key == KEY_DOWN_PRES){ //KEY_DOWN按下从SRAM读出数据
1 M" n2 V: z! Z/ Q% q2 S6 r - FSMC_SRAM_ReadBuffer(read_buf,0,textlen);
" [! o4 o# r f) ?* W - printf("SRAM_Read:%s\r\n",read_buf);
* C6 t, }1 ^& z6 D) Q! j - LCD_ShowString(10+6*8,150,tftlcd_data.width,tftlcd_data.height,16,read_buf);$ K1 }6 o0 ]6 d! t. F
- } 6 U+ m0 Q& H9 f
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
# J, f; R1 I& _% A0 Q; Q; c - HAL_Delay(200);4 r& I, m2 L) v% }- ^, i, s
- }% b c2 S+ ^: p: x* a
- }
复制代码 ) F% w& e% M3 F, \: k4 t* L* w
4.下载验证 - M# }1 Z; H% N3 S% H: O& j
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,KEY_UP按下写数据到SRAM,KEY_DOWN按下从SRAM读出数据,并将写入和读出的数据显示在LCD屏上,并通过串口1打印出来 / _2 m# @6 v: I: c9 x
如有侵权请联系删除
% `* `8 A" {+ `" E# q8 n
( a, }2 N$ W4 G7 ^, S/ @ |