|
1.外部SRAM简介 本例程使用的STM32F103ZET6本身有64K字节的SRAM,一般应用已经足够;不过在一些对内存要求高的场合,比如跑算法或者GUI等,就需要外扩SRAM来满足大内存使用的需求。这里我们使用了一颗256K字节容量的SRAM芯片:IS62WV12816,利用STM32F1的FSMC控制该SRAM芯片,实现对该SRAM芯片的访问控制 IS62WV12816是ISSI公司生产的16位宽128K(128*2,即256K字节)容量的CMOS静态内存芯片,它有高速访问、低功耗、兼容TTL电平接口、全静态操作(不需要刷新和时钟电路)、三态输出和字节控制(支持高/低字节控制)等特点。IS62WV12816的引脚以及对应的引脚功能如下图示:
7 p; V( P B- U& F' y9 |+ Q/ {+ {3 v. S
A0 ~ A16为地址线,总共17根地址线(可访问2^17 = 128K字节空间);I/O0 ~ I/O15为数据线,总共16根数据线;CS1(低电平有效)和CS2(高电平有效)都是片选信号;WE为输入使能信号(写信号);OE为输出使能信号(读信号);UB和LB分别是高字节和低字节控制信号
; F+ v# l4 ~! a( u% u
; E7 x& A8 d" k. z2 A/ O; K% d
2.硬件设计  D1指示灯用来提示系统运行状态,按键用来控制IS62WV12816数据读写,TFTLCD和串口1用来显示读写的内容 3 m5 t' Z7 v- W& j: U& j
D1指示灯 K_UP/K_DOWN按键6 s) f8 q i( e
USART1串口 TFTLCD
, X6 Y2 S0 y* v5 H# K0 C# I# hIS62WV12816 p; e& l& G' [, L) F" |- M. ^, W
+ S3 T5 O7 ^6 p8 f v' E+ O5 U 从电路图中可以看到IS62WV12816和STM32F1的连接线路:. ^, B |& b0 x* m
A0 ~ A16连接在FSMC_A0 ~ FSMC_A16上(连接顺序可以打乱,因为地址是固定的)
6 S! U G! \7 w& z: zI/O0 ~ I/O15连接在FSMC_D0 ~ FSMC_D15上(连接顺序不能打乱,否则读写数据将出错)
! S5 _8 u$ I5 b9 x. e& F5 WUB和LB连接在FSMC_NBL1 和 FSMC_NBL0上
2 w9 U! o7 {# D" r lOE和WE分别连接在FSMC_NOE 和 FSMC_NWE上9 z) u$ ~* X6 ` M% ]
CE连接在FSMC_NE3上 ' K9 x7 @; r1 P6 e. e& U6 f& ?
1 v/ l/ ^- _3 y8 p: U
由于TFTLCD核SRAM共用FSMC总线,因此他们通过不同片选分时复用,互不影响
" v; j4 V9 C9 O9 P7 \$ Y B
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,生成工程代码 ! z/ s0 M# A1 g8 F
由于TFTLCD使用的Bank1_sector4和SRAM使用的Bank1_sector3无法同时在CubeMX里设置分时复用,因此需要单独创建SRAM的FSMC初始化函数(可自行创建,也可另外创建一个CubeMX工程,按下图设置后将生成的相关FSMC初始化代码拷贝到当前工程源码中并稍作修改) 9 ~8 L0 w d4 l$ _4 X6 K2 r0 _! C
( A c8 q+ |; a" @; E, g: d% E
3.2 MDK-ARM软件编程 ➡️ 创建按键驱动文件key.c和key.h,参考按键输入例程 ➡️ 创建LCD驱动文件tftlcd.c 和tftlcd.h,参考TFTLCD显示例程 ➡️ 创建IS62WV12816芯片驱动文件sram.c和sram.h
" i+ u7 O8 k+ D4 U$ [
- #define Bank1_SRAM3_ADDR ((uint32_t)(0x68000000))//Bank1区域3的起始地址
. c" s K: M5 f- r - SRAM_HandleTypeDef SRAM_Handler;//定义SRAM句柄/ X; K( {9 g2 X) d
- //SRAM的FSMC初始化函数
( |- H& k( G# }0 C - void FSMC_SRAM_Init(void){ 1 w K$ Q+ m2 Y0 q
- GPIO_InitTypeDef GPIO_InitStruct;
/ }9 c/ p0 E8 Y1 J% c - FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
: J; u0 c' D/ D0 g' B# Z - __HAL_RCC_FSMC_CLK_ENABLE();
/ x: y, F0 ^' m! ~2 u' e/ D/ P - __HAL_RCC_GPIOD_CLK_ENABLE();
( j. \" R5 G, V/ u- d. t9 @8 N - __HAL_RCC_GPIOE_CLK_ENABLE();
! v/ Q# e0 |7 x - __HAL_RCC_GPIOF_CLK_ENABLE(); " S- Z/ R4 d" \1 ~0 G6 U
- __HAL_RCC_GPIOG_CLK_ENABLE();
$ ]7 F9 v+ g1 e- R2 A - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 8 q9 Z! l8 v6 W) h
- |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13 8 Y: ]% v0 Y5 S$ |4 D6 _
- |GPIO_PIN_14|GPIO_PIN_15;' I: m% z1 K6 O
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;' K5 \" |0 c2 F7 v+ `
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
* ]: j# L) {7 P( ` - HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
$ R6 R9 f# B U, S, M - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
8 Y( V0 o' S1 \$ n - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_10;" m% U) H: h- G6 x# T% U3 H
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;4 |6 m8 |* Y" i4 p
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
/ t0 N1 |8 B3 z' r5 z/ A: h6 w( z - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);6 O+ E/ s. q* O3 q+ B) O! o, R
- GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 / a6 E. X" F m
- |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
! _* _0 ?' `1 \6 m% h5 G - |GPIO_PIN_15;
: M2 E3 \: A% V6 b - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
9 D' Y# P7 Q2 Q: Q# U- E9 G - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;5 I6 I+ f5 @% C& ~# e6 |
- HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);+ `3 Z" n2 l3 b
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
. z- Z- j+ O4 ~1 R i. h - |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1
/ [' k) d) a$ a$ u - |GPIO_PIN_4|GPIO_PIN_5;
/ D' t0 f7 R; B% L& g7 P - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;, k: f# e# j" Q) X8 a
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
6 V2 Z. ]9 ]9 U7 w- `4 p - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
: F- g: B( j" Z1 ]$ g - 6 W: T9 C# Y& a0 i" @4 V
- SRAM_Handler.Instance=FSMC_NORSRAM_DEVICE; 8 y; n1 A5 ~: q4 q3 B4 _
- SRAM_Handler.Extended=FSMC_NORSRAM_EXTENDED_DEVICE; : H8 l$ x) Z4 ]& o1 e9 b, F; S
- SRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK3; //使用NE3
0 ]1 `3 P* M# w7 Q - SRAM_Handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;//地址/数据线不复用
b5 f! V1 w1 f C1 \7 E - SRAM_Handler.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM; //SRAM5 j& V% n+ g) u r3 B) T" b/ d
- SRAM_Handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;//16位数据宽度! \9 P9 C+ z9 E: M
- SRAM_Handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;//不使能突发访问
1 O$ p' S$ D3 p6 ~ k# T - SRAM_Handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性(突发模式); d8 B6 b3 w0 `
- SRAM_Handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS;
+ f" z$ \" p* \+ t9 P( g8 P0 G - SRAM_Handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE; //写使能
7 G7 Q M; d% J N, I9 j2 n, \ - SRAM_Handler.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE; ) N2 K" K \0 [% e/ p9 x
- SRAM_Handler.Init.ExtendedMode=FSMC_EXTENDED_MODE_DISABLE; //读写使用相同的时序) }' n' o6 }5 l+ i- @9 c' j
- SRAM_Handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;) x1 w! |1 l9 \
- SRAM_Handler.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE; //禁止突发写
& u+ i ?8 H# x9 i - //FSMC读时序控制器, w2 ]+ Z H: Q
- FSMC_ReadWriteTim.AddressSetupTime=0x00; //地址建立时间(ADDSET)为1个HCLK
% [: M. d7 H: [% U$ } - FSMC_ReadWriteTim.AddressHoldTime=0x00; //地址保持时间(ADDHLD)模式A未用到
. k t/ p1 g( f; P: D - FSMC_ReadWriteTim.DataSetupTime=0x08; //数据保持时间(DATAST)为9个HCLK
% ]5 ]$ o& h3 F) f1 U: X - FSMC_ReadWriteTim.BusTurnAroundDuration=0X00;
" v4 i9 ]2 l7 x( m. K6 e - FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A
! v& `9 @. H* Y9 S& h: f9 q& B - HAL_SRAM_Init(&SRAM_Handler,&FSMC_ReadWriteTim,&FSMC_ReadWriteTim);
, Y2 T! ~4 c4 Q - }
9 u: P; t/ u6 C5 H - //n向指定地址写数据
! O6 E; B, Z% s$ ^, z - void FSMC_SRAM_WriteBuffer(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t n){
7 _7 w3 [5 X# t6 R$ c, G - for(;n!=0;n--){ // n表示要连续写入的字节个数; w: U# g! m6 ]* Y/ Q) K. J
- *(vu8*)(Bank1_SRAM3_ADDR + WriteAddr) = *pBuffer;9 u' x& ?8 c' S9 B3 X6 C
- WriteAddr++; //要写入的地址$ r( F1 l% m- E. t. `. X5 T9 U3 v
- pBuffer++; //要写入的数据的指针
6 X4 E t6 F( }: H7 K$ ^, g+ b - }7 m) X) Q* q, F7 g
- }
# Y8 Q! @4 ^% a& C% r3 b - //从指定地址读数据
' [( ?, L& m/ g- G1 l% x - void FSMC_SRAM_ReadBuffer(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t n){7 Z0 z; Y( g a6 ^! n- B. j) z
- for(;n!=0;n--){ // n表示要连续读出的字节个数
% }2 |* P1 \- {& V+ `" e( S" c. F - *pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);//存放读出的数据% D5 }. i' b$ |8 O L4 z) N& \
- ReadAddr++; //要读出的起始地址
5 U% u1 U/ s* X4 k# C( @7 Q - }
- E y! _5 s. h - }
0 |. C2 N [' V" @+ m$ ]! R - // $ @& T- O! j7 }2 l& a0 Y( D4 Y7 N
- void ExSRAM_Cap_Test(uint16_t x,uint16_t y){ r# ?* k+ {# F
- uint8_t writeData = 0xf0, readData;; [6 e1 I# }* W/ T9 _
- uint16_t cap=0;/ m/ [2 ~; H3 A0 B& A, f" `" I
- uint32_t addr; % G7 ^% S8 T' J) w
- addr = 1024; //从1KB位置开始计算 # e; z; d/ x# a
- LCD_ShowString(x,y,239,y+16,16,"ExSRAM Cap: 0KB"); 0 j4 s+ S' V* X9 s
-
$ C( t2 o" ~3 H$ ~! S - while(1){
! C) q* [4 R$ t( ^1 h) f - FSMC_SRAM_WriteBuffer(&writeData, addr, 1);( V% S# O- Z7 A+ @0 m( [% v
- FSMC_SRAM_ReadBuffer(&readData,addr,1);
6 L% |9 Q5 Z1 n/ d4 ]. `1 I -
$ L4 y8 q5 a4 v$ d. w. S - if(readData == writeData){//检查读出的数据是否与写入的数据一样6 i, d% w. o. [ ?9 D- S$ R
- cap++; //如果相同表示写入/读出成功,容量加1(单位KB)
9 N9 n! N( h& c1 Z8 h - addr += 1024; //地址加1024
" g" J" g4 C9 L3 b2 Q) Y* X - readData = 0;
; G; c/ D' P# e - if(addr > 256 * 1024)//IS62WV12816的容量为256KB1 o+ `) `( {0 a* S B6 ?
- break;
1 N" P3 q; l5 i0 w$ Z) G. |9 l - }& s8 n( b0 @2 H4 Z8 t% s& T' ~
- else
$ u, W& @, Q& U: y. x* S( v - break; 9 w2 \ }5 {1 F# Q
- }- @ Q" }- b: M; L# ?2 D" X
- LCD_ShowxNum(x+11*8,y,cap,4,16,0);//LCD上显示内存容量
+ X& v6 t0 S% `- c' _3 ` - printf("SRAM Menmory Size:%dKB\r\n",cap);/ i; a5 E* {! b6 {2 |9 ^
- }
复制代码 ' P0 q+ L7 A1 n# [# T$ Y+ K
➡️ 在main.c文件下编写SRAM测试代码 ) \& m# h- I! h, o
- int main(void){% k: n( v+ y& ?2 ~4 G- t. I$ V
- /* USER CODE BEGIN 1 */. j8 [; J* _! K& @
- uint8_t key;
7 a5 T6 M- C, o. g" R* h$ Q2 e+ r - uint8_t text_buf[] = "This is SRAM testing...";5 Q( d4 Q0 @; _! T1 H4 i1 g- b- G
- uint8_t textlen = sizeof(text_buf);$ l5 r- t- }6 P# a0 h
- uint8_t read_buf[textlen]; }' `4 N8 T% k3 d5 k. L5 w$ ?
- /* USER CODE END 1 */- N0 m1 g& p5 g" l5 Q+ N
- HAL_Init();
. o( c( ]- E8 b R* k: | ]: H - SystemClock_Config();2 e6 \! p9 y, v- w+ r" B; i6 z |
- MX_GPIO_Init();
; E# I) [% o. e$ n, l - MX_FSMC_Init();
( f; z8 f8 N/ p3 a: F1 t' g! ? - MX_USART1_UART_Init();8 q* A) |( c1 _% s( D: I- V
- /* USER CODE BEGIN 2 */
$ h4 i4 C2 ]; a5 z, | - TFTLCD_Init();- I' n! _- M# w3 f" u
- FSMC_SRAM_Init();/ P J3 @" A" ^; \; M+ u$ l/ H! n9 j
- FRONT_COLOR=BROWN;
7 o* k* F1 e: d+ y D; m - LCD_DrawRectangle(5,5,235,95);
; j/ s6 u! b- q. k) N5 c9 R - FRONT_COLOR=BLACK;
" B; ^# f! j! ?: ]; | - LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"ANDYXI STM32F1");. U2 M% e/ {( A/ {: _" W( e
- LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"STM32CubeMx SRAM");$ t$ [5 j; T- u- X7 F
- LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,"ExSRAM Test");! \. W; ?1 c7 c5 L6 x
- LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,16,"K_UP:Write K_DOWN:Read");
3 \3 g! E5 X C8 O* g# a' E - FRONT_COLOR=RED;& ?- r4 Q- m3 C; |9 W
- ExSRAM_Cap_Test(10,110);
% P: z3 T/ R+ C: T4 M - FRONT_COLOR=MAGENTA;
3 ~/ A' _& f( {8 K2 |7 T - LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,16,"Write:");# R6 ~5 }7 a+ C4 N0 B/ C5 s: j( t
- LCD_ShowString(10,150,tftlcd_data.width,tftlcd_data.height,16,"Read :");
1 g6 l3 l/ ?. W5 B- o& P - /* USER CODE END 2 */
/ k' E% v- l: Q2 M& B" A( ^! V - /* Infinite loop */
( Y5 O. I! Q, O9 k' `. t0 Y; R! p4 _' Y0 x - /* USER CODE BEGIN WHILE */
. B4 c, v& {# k - while(1){
8 h8 H5 Z" e* P; ?# O3 A, E - key = KEY_Scan(0);7 g# O$ s/ q: S: q8 s
- if(key == KEY_UP_PRES){ //KEY_UP按下写数据到SRAM
2 x6 b% K8 T. ?3 C a+ e - FSMC_SRAM_WriteBuffer(text_buf,0,textlen);" x2 f* M" T: k6 ^
- printf("SRAM_Write:%s\r\n",text_buf);
- _* s& v5 V) R3 W( c- q% e - LCD_ShowString(10+6*8,130,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)text_buf);
! J1 f8 ?$ D' K( p+ `1 ]9 p/ K2 A7 c - }
! D. D& F% \5 Z* h7 D2 c - if(key == KEY_DOWN_PRES){ //KEY_DOWN按下从SRAM读出数据
5 P3 [) e8 n" L+ l. T+ o+ _# K - FSMC_SRAM_ReadBuffer(read_buf,0,textlen);
" u3 s+ J" b2 i8 n, R/ d; k - printf("SRAM_Read:%s\r\n",read_buf);& y) I; ?$ m$ y5 `
- LCD_ShowString(10+6*8,150,tftlcd_data.width,tftlcd_data.height,16,read_buf);1 b5 G! J8 Y2 c7 k: T! y7 U
- } : D* C1 q) |' R8 S( V7 q# s
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);# F' k2 F6 S3 E/ _
- HAL_Delay(200);( p0 a" b* F3 Y# R1 m
- }
/ B/ @6 ]1 X; {9 b4 A# U - }
复制代码 6 E/ Y: K, H: A
4.下载验证 * g% H* g+ O2 ~+ u+ ]
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,KEY_UP按下写数据到SRAM,KEY_DOWN按下从SRAM读出数据,并将写入和读出的数据显示在LCD屏上,并通过串口1打印出来
/ M' j+ q! N4 e/ `% u( n/ J6 X如有侵权请联系删除
4 x8 Z0 f$ M! k7 }. G4 d2 d
% ]( Z1 C1 P- y5 T5 m |