你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeMX 外部SRAM经验分享

[复制链接]
攻城狮Melo 发布时间:2023-6-28 15:32
1.外部SRAM简介
本例程使用的STM32F103ZET6本身有64K字节的SRAM,一般应用已经足够;不过在一些对内存要求高的场合,比如跑算法或者GUI等,就需要外扩SRAM来满足大内存使用的需求。这里我们使用了一颗256K字节容量的SRAM芯片:IS62WV12816,利用STM32F1的FSMC控制该SRAM芯片,实现对该SRAM芯片的访问控制
IS62WV12816是ISSI公司生产的16位宽128K(128*2,即256K字节)容量的CMOS静态内存芯片,它有高速访问、低功耗、兼容TTL电平接口、全静态操作(不需要刷新和时钟电路)、三态输出和字节控制(支持高/低字节控制)等特点。IS62WV12816的引脚以及对应的引脚功能如下图示:

$ N6 E2 B- \! |- V( ?( ?* |
微信图片_20230628153158.png
% @* L. Y  _$ N1 @; a6 c( n
A0 ~ A16为地址线,总共17根地址线(可访问2^17 = 128K字节空间);I/O0 ~ I/O15为数据线,总共16根数据线;CS1(低电平有效)和CS2(高电平有效)都是片选信号;WE为输入使能信号(写信号);OE为输出使能信号(读信号);UB和LB分别是高字节和低字节控制信号
% Y% i& z0 n3 g2 m. ~

6 }# @  e' G5 Y
2.硬件设计
D1指示灯用来提示系统运行状态,按键用来控制IS62WV12816数据读写,TFTLCD和串口1用来显示读写的内容

      v4 ^! i0 r/ {- w% E
  • D1指示灯
  • K_UP/K_DOWN按键  p( k9 M' ^$ C" D8 _
  • USART1串口
  • TFTLCD
    . ]8 a, l" O* X
  • IS62WV12816
    - ]9 @4 y+ i0 i3 h! @# B, A4 {& S
    ( M6 z6 t. M. u) V: V% H
从电路图中可以看到IS62WV12816和STM32F1的连接线路:) P6 c) e7 s6 D  y
A0 ~ A16连接在FSMC_A0 ~ FSMC_A16上(连接顺序可以打乱,因为地址是固定的)
# u% x7 v7 R! `0 MI/O0 ~ I/O15连接在FSMC_D0 ~ FSMC_D15上(连接顺序不能打乱,否则读写数据将出错)8 y/ r: G" y  N( Q2 |5 N4 c* ^
UB和LB连接在FSMC_NBL1 和 FSMC_NBL0上
4 p5 r1 \* A6 v/ b, COE和WE分别连接在FSMC_NOE 和 FSMC_NWE上' |8 A' n  Y$ ~
CE连接在FSMC_NE3上

) H. ^) o. J5 d  y
微信图片_20230628153150.png

2 z  u$ F, A. z

由于TFTLCD核SRAM共用FSMC总线,因此他们通过不同片选分时复用,互不影响


7 _8 t# x; P  o# S# {

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,生成工程代码

; i4 p0 L5 P  ~) N- @- M0 P+ [

由于TFTLCD使用的Bank1_sector4和SRAM使用的Bank1_sector3无法同时在CubeMX里设置分时复用,因此需要单独创建SRAM的FSMC初始化函数(可自行创建,也可另外创建一个CubeMX工程,按下图设置后将生成的相关FSMC初始化代码拷贝到当前工程源码中并稍作修改)


. @$ @4 ^# i) e7 b

微信图片_20230628153141.png

8 E2 e, t+ Z- f4 g) b' Q' c3 g
3.2 MDK-ARM软件编程
➡️ 创建按键驱动文件key.c和key.h,参考按键输入例程
➡️ 创建LCD驱动文件tftlcd.c 和tftlcd.h,参考TFTLCD显示例程
➡️ 创建IS62WV12816芯片驱动文件sram.c和sram.h

" b+ l' k; l; ]( S
  1. #define Bank1_SRAM3_ADDR    ((uint32_t)(0x68000000))//Bank1区域3的起始地址        ; e) J7 N7 K6 O
  2. SRAM_HandleTypeDef SRAM_Handler;//定义SRAM句柄) n% d! t+ a0 }8 i* G
  3. //SRAM的FSMC初始化函数2 p. d4 Q8 V; K# V) W) _
  4. void FSMC_SRAM_Init(void){        7 V" X/ A' i& A  I0 l3 T, R5 T
  5.   GPIO_InitTypeDef GPIO_InitStruct;
    0 g1 v% ^* `+ N2 P5 u  M4 w
  6.   FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
    / R& Q6 q; R, O
  7.   __HAL_RCC_FSMC_CLK_ENABLE();           5 m2 t: P% S& b. u7 P3 Y- ^3 T7 n* j  [
  8.   __HAL_RCC_GPIOD_CLK_ENABLE();              / z7 t6 y! H5 I& G8 H; ~
  9.   __HAL_RCC_GPIOE_CLK_ENABLE();               $ i4 z. p5 C7 `# z
  10.   __HAL_RCC_GPIOF_CLK_ENABLE();              1 w# n6 q( J: D" y
  11.   __HAL_RCC_GPIOG_CLK_ENABLE();               
    $ K$ c/ y1 W) g5 L) v) \
  12.   GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
    6 ?  M( M. ]. Q0 `3 P1 Y% m
  13.                      |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13
    : v; {2 D( U& p: k1 M; ^3 S
  14.                      |GPIO_PIN_14|GPIO_PIN_15;! W5 f- N- }0 E; a
  15.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;- H' u# }8 Z5 B" h. z
  16.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    - v% c7 L1 e+ h
  17.   HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
    * u1 q# E" T$ j2 u. X+ A$ s
  18.   GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 9 x7 w- }$ ^2 u$ O
  19.                      |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_10;
    0 ^- v: r' o4 Q
  20.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;+ v$ [' i+ q* I5 w4 W) ~
  21.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    + R; A$ F( ]' s: H' t8 B/ \  C
  22.   HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);( ^& t9 S5 V; C
  23.   GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
    : W# }7 Z. X  w+ @& W
  24.                      |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 - ]; V1 D: N- d4 r( j2 Y
  25.                      |GPIO_PIN_15;+ _: g& ~) Y' E( O
  26.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;+ F# A# P. }& ~, ?5 Q1 L
  27.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    % A  F0 J8 s- T* h& G
  28.   HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    0 c) p  f8 S$ b' F7 I3 ~/ o
  29.   GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    8 L5 e0 R- f1 m% ]
  30.                      |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1 6 T. t6 R- w* p
  31.                      |GPIO_PIN_4|GPIO_PIN_5;7 Q% w! F2 m+ e+ d5 p
  32.   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    ; ]5 D) w* C0 G$ M, S
  33.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;- A: T! V1 C9 z0 a
  34.   HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);  + t: B. Q0 r) ~7 t9 K
  35.        
    . R; B& Y( n2 P* U
  36.   SRAM_Handler.Instance=FSMC_NORSRAM_DEVICE;                - i) d' v* a$ c6 A2 E) X
  37.   SRAM_Handler.Extended=FSMC_NORSRAM_EXTENDED_DEVICE;     
    * I7 R% ?) _( F1 d7 t7 F9 f% X6 t
  38.   SRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK3;        //使用NE3
    % d, Q9 G+ f$ |, @( N
  39.   SRAM_Handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;//地址/数据线不复用9 E5 P3 E4 v% n9 s2 M
  40.   SRAM_Handler.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM;            //SRAM' k1 l3 J) ^( R
  41.   SRAM_Handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;//16位数据宽度: d) J5 n, z8 r" z* h
  42.   SRAM_Handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;//不使能突发访问
    : v1 X- T0 ?: C* U
  43.   SRAM_Handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性(突发模式)
    : J% }* I4 {, [7 I" q! @$ M8 \
  44.   SRAM_Handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS;           1 j, j5 V3 F1 {: n: s: B
  45.   SRAM_Handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE;    //写使能
    ! R  s  K8 _$ c) a8 }; l0 ^
  46.   SRAM_Handler.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE;         
    0 P9 S6 f# `. Q* O6 h
  47.   SRAM_Handler.Init.ExtendedMode=FSMC_EXTENDED_MODE_DISABLE;       //读写使用相同的时序* z0 x1 p; _& z
  48.   SRAM_Handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;9 R5 f6 I+ s, y% N# f
  49.   SRAM_Handler.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE;           //禁止突发写8 n7 v% Y0 j" B) g( h9 Z" Z
  50.   //FSMC读时序控制器1 v8 h; @! t4 M8 l; s, T
  51.   FSMC_ReadWriteTim.AddressSetupTime=0x00;      //地址建立时间(ADDSET)为1个HCLK
    % T8 a, T! u! A2 P" q
  52.   FSMC_ReadWriteTim.AddressHoldTime=0x00;        //地址保持时间(ADDHLD)模式A未用到
    5 g# `, z0 {2 G. Y0 ?* O
  53.   FSMC_ReadWriteTim.DataSetupTime=0x08;                //数据保持时间(DATAST)为9个HCLK) Y& B( u9 k- y/ ]
  54.   FSMC_ReadWriteTim.BusTurnAroundDuration=0X00;
    : f; t$ o, \8 W& ~& o# I$ }& r3 C) y
  55.   FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A" [. f8 C" u2 u9 o+ W1 b& \
  56.   HAL_SRAM_Init(&SRAM_Handler,&FSMC_ReadWriteTim,&FSMC_ReadWriteTim);        2 f) |  x4 }$ i2 d9 |7 ]+ U
  57. }( O8 d% E+ m" S2 C* A! ]. n" H, a) Z
  58. //n向指定地址写数据' m3 R# f& i$ G
  59. void FSMC_SRAM_WriteBuffer(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t n){
    # m5 U4 ?) h9 T1 c) @2 Y  {  o1 @
  60.   for(;n!=0;n--){        // n表示要连续写入的字节个数
    3 s8 p0 w# w) K4 u/ o7 q
  61.     *(vu8*)(Bank1_SRAM3_ADDR + WriteAddr) = *pBuffer;- A( P# a7 c, |* A: m% f3 l( T# Y
  62.     WriteAddr++;        //要写入的地址
    ' a$ |7 x6 r% c; q* ?' }
  63.     pBuffer++;                //要写入的数据的指针
    " D6 {- E& M. ^( {4 o3 F! b
  64.   }: q  R8 `5 c  z1 [$ C* d
  65. }, Y9 z, R! w: `3 }
  66. //从指定地址读数据
    8 G! S- k# y) e0 s
  67. void FSMC_SRAM_ReadBuffer(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t n){
    6 L8 u% @, v  _% Y' G1 K
  68.   for(;n!=0;n--){        // n表示要连续读出的字节个数- s% R" O( {7 b% b7 E
  69.     *pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);//存放读出的数据
    / m: j0 z4 b4 z) N, Y
  70.     ReadAddr++;                //要读出的起始地址
    6 L! `" E# v0 Y, b8 e4 E9 H' O7 c
  71.   }" j# J5 k/ a! C3 {9 d
  72. }6 G  K+ s; \" J4 s  Z4 C* Q
  73. //            & w6 |* H2 k: S2 c8 T5 _
  74. void ExSRAM_Cap_Test(uint16_t x,uint16_t y){* }  m$ d" N; I+ b$ j
  75.   uint8_t writeData = 0xf0, readData;
    ! y$ c: y' g; q* a: l& E. r( g4 y
  76.   uint16_t cap=0;' L: U; `/ ~- A: J
  77.   uint32_t addr;       
    / s3 k* z1 Z/ W( T; j
  78.   addr = 1024;         //从1KB位置开始计算        4 F$ S$ t$ z* U9 A( V1 q) q: ?
  79.   LCD_ShowString(x,y,239,y+16,16,"ExSRAM Cap:   0KB");
    8 b, W8 b' @. J& M3 P
  80.        
    . Y0 M' j5 S( d. B" |: L8 w% ~* f
  81.   while(1){1 r1 M* @# e3 a) V. c6 U8 \
  82.     FSMC_SRAM_WriteBuffer(&writeData, addr, 1);( o! f. |0 `4 u( t& q* \
  83.     FSMC_SRAM_ReadBuffer(&readData,addr,1);
    - m  J/ t& J. S+ ^6 x3 u7 r
  84.        
    , ]2 `' \- E2 x" o8 |
  85.     if(readData == writeData){//检查读出的数据是否与写入的数据一样* o# @9 a: T+ \* n7 x
  86.       cap++;                //如果相同表示写入/读出成功,容量加1(单位KB)
      k: Y' M+ X' H+ k# g! B5 A: l( O
  87.       addr += 1024;        //地址加1024
    . o/ k6 e4 ?) E- @" L. {5 D
  88.       readData = 0;
    6 C& A' J) u( b6 `& R! @( f3 [
  89.       if(addr > 256 * 1024)//IS62WV12816的容量为256KB
    2 W  e4 Y4 v/ X6 F
  90.         break;   9 Z/ Z/ U2 `1 U$ l7 _( }$ g2 c
  91.     }
    1 y7 A( S" O) D  p
  92.     else. e: l% m; W9 _. h$ ?6 h- k
  93.       break;  
    ' z3 E# E2 e) R; n2 W
  94.   }
    & n8 Z* m6 y. `0 P3 @7 x' F
  95.   LCD_ShowxNum(x+11*8,y,cap,4,16,0);//LCD上显示内存容量7 T# ]$ z# i0 ?  h
  96.   printf("SRAM Menmory Size:%dKB\r\n",cap);
    + o3 t2 x% v5 q9 ]
  97. }
复制代码

/ H+ a7 t4 m  N" u
➡️ 在main.c文件下编写SRAM测试代码

. p+ z% Z% B- A# A. S% v5 j* Z
  1. int main(void){% D* V6 L& T# ?& B, @3 g3 a! I6 ?% e- C/ W
  2.   /* USER CODE BEGIN 1 */# R8 _4 q2 P' e' d' Z4 g$ ], h' }
  3.   uint8_t key;1 Z# i2 J7 ?  u- k7 m
  4.   uint8_t text_buf[] = "This is SRAM testing...";- J7 C+ F& |, i0 o  ~
  5.   uint8_t textlen = sizeof(text_buf);4 B& p$ A2 D; u  Q
  6.   uint8_t read_buf[textlen];7 Z: H8 u* o3 ^
  7.   /* USER CODE END 1 */- M4 [' ~; x8 V, G4 n. _4 w# H. R+ a
  8.   HAL_Init();
    2 c: Y) X, v& \3 y$ {
  9.   SystemClock_Config();( w8 D1 w8 ?, y5 z7 I2 E( Y
  10.   MX_GPIO_Init();
    ) Q6 a/ `2 F' d& t7 ]8 e
  11.   MX_FSMC_Init();4 C! E7 [2 ?; Y" H! K3 t3 D" f
  12.   MX_USART1_UART_Init();9 m" X2 T8 S1 g; ]) o8 b
  13.   /* USER CODE BEGIN 2 */  n; ^9 C& G+ q6 G' j1 F% Y
  14.   TFTLCD_Init();7 b3 F. b) {" y5 V. y! Q! |6 O
  15.   FSMC_SRAM_Init();1 G$ ?* f2 e+ q, N  J8 {5 D1 ?
  16.   FRONT_COLOR=BROWN;2 r& w  K! p+ ?0 U( B
  17.   LCD_DrawRectangle(5,5,235,95);
    * L6 B& X, R# B
  18.   FRONT_COLOR=BLACK;( C0 w5 y! @  R' _3 m
  19.   LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"ANDYXI STM32F1");/ j& ]) T2 V+ Q" `; _) `. Y
  20.   LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"STM32CubeMx SRAM");, @3 v; E8 J2 p4 {! Y+ G; L
  21.   LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,"ExSRAM Test");9 |4 w3 [, |. X
  22.   LCD_ShowString(10,70,tftlcd_data.width,tftlcd_data.height,16,"K_UP:Write   K_DOWN:Read");       
    0 k& \/ I4 J* o9 d: R) L
  23.   FRONT_COLOR=RED;; A5 C( c, @, r& Q$ O$ J
  24.   ExSRAM_Cap_Test(10,110); / [0 q& n7 Z4 \. j
  25.   FRONT_COLOR=MAGENTA;1 D; V3 k6 U% l4 M# B# B4 v& h: H
  26.   LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,16,"Write:");' d; ]! c* f7 h7 p' _
  27.   LCD_ShowString(10,150,tftlcd_data.width,tftlcd_data.height,16,"Read :");, T" p7 f# F- B6 Q
  28.   /* USER CODE END 2 */. w! f# I- E4 p! g/ o2 U5 R8 l
  29.   /* Infinite loop */
    6 y2 H5 y  g2 g2 Q" b
  30.   /* USER CODE BEGIN WHILE */
    & f3 [: x% C: m1 @
  31.   while(1){
    ' t  x, k9 [/ {) [
  32.     key = KEY_Scan(0);
    ) z; O6 Z" ?7 s- I2 e2 G% |3 w/ Y# l* Y
  33.     if(key == KEY_UP_PRES){        //KEY_UP按下写数据到SRAM$ ~/ L3 h+ Q* z- V* k
  34.       FSMC_SRAM_WriteBuffer(text_buf,0,textlen);- a& l4 H/ B4 o) D! _  B
  35.       printf("SRAM_Write:%s\r\n",text_buf);. u2 N1 K& a9 Z6 I! G
  36.       LCD_ShowString(10+6*8,130,tftlcd_data.width,tftlcd_data.height,16,(uint8_t *)text_buf);
    ( i; t# z% N( U
  37.     }
    3 `+ [0 L. o6 Z& u2 a  J% ?+ i
  38.     if(key == KEY_DOWN_PRES){        //KEY_DOWN按下从SRAM读出数据/ I. P. T; J6 ?  J6 P1 Y) C
  39.       FSMC_SRAM_ReadBuffer(read_buf,0,textlen);$ ]* h- V' n% t0 E& {
  40.       printf("SRAM_Read:%s\r\n",read_buf);/ k: n& v" v8 D( e' m
  41.       LCD_ShowString(10+6*8,150,tftlcd_data.width,tftlcd_data.height,16,read_buf);
    ) z4 b3 ?- D5 D* Z" }
  42.     }                ; v  `5 ^* c3 w
  43.     HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);+ D3 O" h+ ]& k" ~: k+ K
  44.     HAL_Delay(200);
    & J3 t" F. J: s- k  Y) C$ i
  45.   }$ K/ ?' X+ }5 n0 g0 d: u' e
  46. }
复制代码

" ^  D9 w9 `4 d' e3 _
4.下载验证

0 }, T/ E/ r: D% q3 g( A
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,KEY_UP按下写数据到SRAM,KEY_DOWN按下从SRAM读出数据,并将写入和读出的数据显示在LCD屏上,并通过串口1打印出来
微信图片_20230628153134.png
/ w0 c# k* G* Y0 K! [, {7 M9 F8 R
转载自: 嵌入式攻城狮
如有侵权请联系删除
6 t# P0 f5 S( m. G! _5 z
: j2 n" O; a8 s- P5 F* H0 A
赞 收藏 评论0 发布时间:2023-6-28 15:32

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版