STM32f746gdiscovery 开发板使用的是16MB的SDRAM,由于少了一根地址线,只有8MB可用。9 w# C& u% n, p, k7 J
) n7 F9 r3 l" Y; q
$ o5 N& s. ]. r0 x i6 K# ]/ S7 U% d- T. [* J
9 _9 u' K) H! L& e- /*************************************************************************************************************
( k6 y# ?+ ~$ V - * 文件名 : stm32f7_sdram.c5 G" L$ G- _. i, M
- * 功能 : STM32F7 外部SDRAM驱动 A+ v. M9 B2 M7 n
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>2 E( k" ]. t7 T* C% ?
- * 创建时间 : 2019-09-08+ b E8 C. _9 x8 A9 V9 E& ]* g
- * 最后修改时间 : 2019-09-08# I3 ]4 w2 L0 L1 c; D0 r
- * 详细 : 2019-10-31 设置突发长度:4(可以是1/2/4/8)-测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点
2 P( N2 T! r5 C - *************************************************************************************************************/
: o5 U) N, l4 i0 z1 J7 A! ^* z - #include "stm32f7_sdram.h"3 S0 k1 V. m! s5 Q0 p A
- #include "SYSTEM.H" # n; t8 Q3 y$ o6 Z, R
- / x5 j% A0 D# R0 a
0 q, K: |$ p- V& h6 ?* h) Z4 Z- 0 ~# K J* d7 M2 U' k5 ? ]
- //BANK选择+ |7 _' y9 K* Q7 v1 ^8 ]0 U- z4 i* Q
- typedef enum% a7 }) V9 b3 S( k
- {. ^7 [9 M& L; j' n3 K# x
- SDRAM_CMD_BANK1 = 2, //命令模板存储区域1- B2 k' t9 q+ [; s/ z
- SDRAM_CMD_BANK2 = 1, //命令模板存储区域2
; v, z" K& @8 ~; H3 R6 ~ - SDRAM_CMD_BANK1_2 = 3, //命令模板存储区域1与2
+ ~6 B8 ?! ~6 M6 W6 r - }SDRAM_CMD_BANK_SELECT;! k$ _/ J2 W8 v) X1 [2 N
9 } r5 {( ]3 ]! ]2 p! e
( k8 b/ l, m, |0 z- //命令* ]& l7 Z% M. x9 x3 Z/ z
- typedef enum # }* S5 |6 w7 w" S5 z) i
- {) l# _; z9 e8 A3 R
- SDRAM_CMD_NORMAL = 0, //正常模式
& B8 _( L; @% ^9 U+ Z2 b4 c% q; D - SDRAM_CMD_CLOCK_CONFIG = 1, //时钟配置使能! F. k$ A* G; i1 M
- SDRAM_CMD_PALL = 2, //预充电所有存储区域
4 @6 _6 n+ U4 I( V - SDRAM_CMD_AR = 3, //自刷新命令
1 Z7 m0 _- R3 z$ {; N: @# ~ - SDRAM_CMD_LOAD_MODE = 4, //加载模式寄存器& q2 n6 J3 t- K+ G; {3 y, l
- //SDRAM_CMD_AR = 5, //自刷新命令) W5 Q0 X) o2 W$ F
- SDRAM_CMD_POWER_DOWN = 6, //掉电命令
% K1 s W) V" F: ]. ^1 | - }SDRAM_CMD_TYPE;
; B' V. o# ~' Q; _
2 t7 R- u/ n9 Q- i. m- ! }) R+ N7 Z4 j0 @- r4 C7 c
- bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mode, u8 AutoRefresh, SDRAM_CMD_TYPE cmd);//SDRAM 命令模式设置4 ]6 _8 ^7 j% h, {. `2 T( ?
) f! x0 a: ^8 m$ _! G( Y- x
# a# j. U5 m6 s+ C# ?3 J- /*************************************************************************************************************************
% V/ |* v. {- T2 A: b2 s9 i - * 函数 : void SDRAM_Init(void)
7 g! l" w7 b! ~, U6 ^" [) V, C6 s( H - * 功能 : SDRAM 接口初始化
/ b5 r5 V2 H2 n7 M" H - * 参数 : 无
6 Q! ^ w s; K7 L H! M0 a - * 返回 : 无/ z1 H+ Y4 w3 P. }; g& L* p5 |! f1 o
- * 依赖 : 底层宏定义: G" I7 {3 T( f$ m8 m2 X; Y
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
) t0 o; X5 O# [. H - * 时间 : 2019-09-088 A+ z( r* G0 d! H) m" V0 j
- * 最后修改时间 : 2019-09-08& l3 H3 y# P9 {4 G
- * 说明 : 用于初始化STM32F7 SDRAM 接口- y5 f/ Z4 ^. ]2 r( T- q/ a
- *************************************************************************************************************************/ . F* y2 ~) A5 }* J5 f6 d$ S }
- void SDRAM_Init(void)
& {4 r4 c% L+ v- o4 S - {
( ^- g' T0 d6 j; _ V - u32 temp;
5 F/ H5 A+ b% [ e; \* m* c' I) z% d -
" y' o- u& o6 j' n5 q6 ^7 Z# q - SYS_DeviceClockEnable(DEV_FSMC, TRUE); //FSMC时钟使能- d M: ?" r! H' ^
- SYS_DeviceClockEnable(DEV_GPIOC, TRUE); //使能GPIOC时钟
' p; x# r: k* u# _# Z1 x& a - SYS_DeviceClockEnable(DEV_GPIOD, TRUE); //使能GPIOD时钟
+ e1 n1 ]/ v6 x8 g4 I% S$ f- J$ Y3 ~ - SYS_DeviceClockEnable(DEV_GPIOE, TRUE); //使能GPIOE时钟
" E" Q# I9 ~' a0 h - SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //使能GPIOF时钟9 y8 s6 ]( N( {& S
- SYS_DeviceClockEnable(DEV_GPIOG, TRUE); //使能GPIOG时钟; b% U; l) ~& Z. D5 [5 Y' D& b+ R
- SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟 c2 c/ \# G- F+ @) c- P
-
7 O' a% B V% {- u- @ - //初始化IO9 z* v8 Y+ U1 w1 [0 Q
- SYS_GPIOx_Init(GPIOC, BIT3, AF_PP_OPU, SPEED_100M); //PC3
3 _# f; w( A; h; R" O1 x# H - SYS_GPIOx_Init(GPIOD, BIT0|BIT1|BIT8|BIT9|BIT10|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PD0/1/8/9/10/14/15
+ j& p( e+ z0 B/ \& w4 d - SYS_GPIOx_Init(GPIOE, BIT0|BIT1|(0X1FF<<7), AF_PP_OPU, SPEED_100M); //PE0/1/7~15
% h6 Q3 V4 k% n7 L9 F& a( T* K - SYS_GPIOx_Init(GPIOF, BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT11|BIT12|BIT13|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PF0~5/11~15
7 [' b' e. O3 A' W - SYS_GPIOx_Init(GPIOG, BIT0|BIT1|BIT4|BIT5|BIT8|BIT15, AF_PP_OPU, SPEED_100M); //PG0/1/4/5/8/15; Y' J# ~) J* X8 p2 C
- SYS_GPIOx_Init(GPIOH, BIT3|BIT5, AF_PP_OPU, SPEED_100M);
1 O% \- r( E+ ?7 f2 Q - , W: y `/ D/ k( J; l8 m
- SYS_GPIOx_SetAF(GPIOC, 3, AF12_FSMC); //PC3,AF129 c' \- Q& E- H0 q8 |
-
' q/ B) E8 O9 h2 P( } - SYS_GPIOx_SetAF(GPIOD, 0, AF12_FSMC); //PD0,AF12
/ d) [3 ]- H5 D7 z4 } - SYS_GPIOx_SetAF(GPIOD, 1, AF12_FSMC); //PD1,AF12 * D/ O) _# R) q1 Z5 @5 j
- SYS_GPIOx_SetAF(GPIOD, 8, AF12_FSMC); //PD8,AF12
- v7 C7 T7 P) F1 d) W% } - SYS_GPIOx_SetAF(GPIOD, 9, AF12_FSMC); //PD9,AF12
$ D; M, ?! P% d& I1 a/ C: P# _4 L9 { - SYS_GPIOx_SetAF(GPIOD, 10, AF12_FSMC); //PD10,AF12
* G/ c) N8 O; n! u3 ?% C, ^: m - SYS_GPIOx_SetAF(GPIOD, 14, AF12_FSMC); //PD14,AF12
, N8 U- E- \. P: p - SYS_GPIOx_SetAF(GPIOD, 15, AF12_FSMC); //PD15,AF12
; C q4 Y$ O7 \/ {( M* u7 D -
' u" M: _3 N& T5 M: `; d, ]! s - SYS_GPIOx_SetAF(GPIOE, 0, AF12_FSMC); //PE0,AF12
3 Q4 b6 a/ I* j6 ]1 s - SYS_GPIOx_SetAF(GPIOE, 1, AF12_FSMC); //PE1,AF12 # I3 X( f" K( O: `8 x
- SYS_GPIOx_SetAF(GPIOE, 7, AF12_FSMC); //PE7,AF12$ h* g% w$ d/ p0 m7 P7 l0 z
- SYS_GPIOx_SetAF(GPIOE, 8, AF12_FSMC); //PE8,AF12
8 F! L$ o4 s r! ~ - SYS_GPIOx_SetAF(GPIOE, 9, AF12_FSMC); //PE9,AF122 \: X" S: S/ K% h" H2 ?( Z' T; G
- SYS_GPIOx_SetAF(GPIOE, 10, AF12_FSMC); //PE10,AF12
$ o2 C( E. B- P: |" d - SYS_GPIOx_SetAF(GPIOE, 11, AF12_FSMC); //PE11,AF12
5 t# _! ]4 B, b* J; W5 f( d* s z/ l - SYS_GPIOx_SetAF(GPIOE, 12, AF12_FSMC); //PE12,AF12
) V( u* i0 Y& t7 H; {4 |& A - SYS_GPIOx_SetAF(GPIOE, 13, AF12_FSMC); //PE13,AF124 l% _; S" Z3 q) W6 ^' c D
- SYS_GPIOx_SetAF(GPIOE, 14, AF12_FSMC); //PE14,AF12& L: S" I8 q! P7 C* Y* n- [- L
- SYS_GPIOx_SetAF(GPIOE, 15, AF12_FSMC); //PE15,AF12. c( J- P# w2 _% v. G4 f5 m2 o/ ^
# P# O( m5 y' S+ \* k- SYS_GPIOx_SetAF(GPIOF, 0, AF12_FSMC); //PF0,AF12 3 ~: m9 b4 A6 U( ? @+ n3 c
- SYS_GPIOx_SetAF(GPIOF, 1, AF12_FSMC); //PF1,AF12
& K5 u1 c( F: j* l - SYS_GPIOx_SetAF(GPIOF, 2, AF12_FSMC); //PF2,AF12
6 A$ A6 Q% F0 c$ t - SYS_GPIOx_SetAF(GPIOF, 3, AF12_FSMC); //PF3,AF12* o' W# G; {' o1 c8 u& A& ^3 f
- SYS_GPIOx_SetAF(GPIOF, 4, AF12_FSMC); //PF4,AF12; J, P. H( G0 V0 d6 F
- SYS_GPIOx_SetAF(GPIOF, 5, AF12_FSMC); //PF5,AF125 @9 b* W! v* H. K0 k: \
- SYS_GPIOx_SetAF(GPIOF, 11, AF12_FSMC); //PF11,AF12
1 }; ~7 U% w F; g0 i( [ ]# K - SYS_GPIOx_SetAF(GPIOF, 12, AF12_FSMC); //PF12,AF12! b& a6 J( G/ A0 A3 x9 v
- SYS_GPIOx_SetAF(GPIOF, 13, AF12_FSMC); //PF13,AF12& R1 O) P3 z% r% O
- SYS_GPIOx_SetAF(GPIOF, 14, AF12_FSMC); //PF14,AF12; W- [+ j( Y( S5 n5 \
- SYS_GPIOx_SetAF(GPIOF, 15, AF12_FSMC); //PF15,AF12; K, N$ X1 d }$ L$ R- S5 X! }4 b
-
# q$ J4 N7 d7 N1 r! a* q6 p - SYS_GPIOx_SetAF(GPIOG, 0, AF12_FSMC); //PG0,AF12 ( L' E5 m: W: L1 |% t! G8 k
- SYS_GPIOx_SetAF(GPIOG, 1, AF12_FSMC); //PG1,AF12 ' u: n7 L) z: w9 D- J1 M4 w# g
- SYS_GPIOx_SetAF(GPIOG, 4, AF12_FSMC); //PG4,AF12
8 e% l/ W) A+ f3 n - SYS_GPIOx_SetAF(GPIOG, 5, AF12_FSMC); //PG5,AF12
7 [ M) @% ^6 J: C- A, T' t, H - SYS_GPIOx_SetAF(GPIOG, 8, AF12_FSMC); //PG8,AF12# r6 W, K# u" v2 H) a$ C
- SYS_GPIOx_SetAF(GPIOG, 15, AF12_FSMC); //PG15,AF12
' X8 T! B. ?+ W: [3 v - # |7 u3 }8 ?% h" r; O4 @* T
- SYS_GPIOx_SetAF(GPIOH, 3, AF12_FSMC); //PH3,AF12* z7 E* O% {: g! S- o
- SYS_GPIOx_SetAF(GPIOH, 5, AF12_FSMC); //PH5,AF12 4 a3 T% x! k/ r
-
- R1 n3 b9 B4 b1 ]& n
9 [% u) U# [9 @! `. S! K% v- temp = 0;
% F5 |5 h- c, p7 d - temp |= 0<<0; //8位列地址% K5 g/ R( b7 Z) G! Q. m- F M0 j
- temp |= 1<<2; //12位行地址
/ s" K2 @+ M8 z( W; ]$ F - temp |= 1<<4; //16位数据位宽* n) V2 a% Y0 o9 B
- temp |= 1<<6; //4个内部存区(4 BANKS)8 z# L3 f( l' ?9 d& @$ a
- temp |= 2<<7; //2个CAS延迟: v. G4 [6 D% u" T$ m( Q8 H
- temp |= 0<<9; //允许写访问6 Q8 D/ y+ U- Y% C
- temp |= 2<<10; //SDRAM时钟=HCLK/23 {: K9 P" |! ?' `1 V# E& b
- temp |= 1<<12; //使能突发访问
; J7 y" h( {* P9 {8 W) a# B/ @ - temp |= 0<<13; //读通道延迟0个HCLK9 g5 R7 _) u4 `! q# T- B
- FMC_Bank5_6->SDCR[0] = temp; //设置FMC BANK5 SDRAM控制寄存器(BANK5和6用于管理SDRAM).
/ i/ h6 f& B7 v) P6 N) l# d: S - 4 B6 G+ ^. `9 f. H* b
- temp = 0;- y5 ]4 E/ {5 g. H2 I$ @
- temp|=1<<0; //加载模式寄存器到激活时间的延迟为2个时钟周期
/ [' A2 e g. x8 ?5 ` - temp|=5<<4; //退出自刷新延迟为6个时钟周期
. x4 \/ o1 Z, N( p, g - temp|=3<<8; //自刷新时间为4个时钟周期
( |3 W# x$ m1 u( C9 f" F; b) D - temp|=5<<12; //行循环延迟为6个时钟周期
6 `% V2 j% W1 o7 \! b( t - temp|=1<<16; //恢复延迟为2个时钟周期+ Z l1 w M0 k2 S8 r5 [
- temp|=1<<20; //行预充电延迟为2个时钟周期
0 v: u# ?0 ?' B, W - temp|=1<<24; //行到列延迟为2个时钟周期
# r2 O2 ^! R# l7 z. { L+ A - FMC_Bank5_6->SDTR[0] = temp; //设置FMC BANK5 SDRAM时序寄存器
2 {' k% v1 k2 H0 n - ; }1 s( [, m; X4 F$ ?5 i
- SDRAM_SendCmd(SDRAM_CMD_BANK1, 0, 1, SDRAM_CMD_CLOCK_CONFIG); //时钟配置使能 7 s( V# I" m+ b2 H# U
- Delay_US(300); //至少延迟200us.. f* p. c3 k4 Q0 X" w; F9 P8 B
- SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 1, SDRAM_CMD_PALL); //对所有存储区预充电
3 W2 } ~9 \5 O - SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 8, SDRAM_CMD_AR); //设置自刷新次数
' Q. H0 K+ Z# U! f4 ^; T - ; X; o+ f" m5 B( B6 q' W6 C
- temp = 0;) x. R9 k7 ~/ B* H, M
- temp |= 2<<0; //设置突发长度:4(可以是1/2/4/8) -测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点6 j; X- h! \5 t# q9 C
- temp |= 0<<3; //设置突发类型:连续(可以是连续/交错)
: k& s/ M3 X7 p - temp |= 2<<4; //设置CAS值:2
. d6 z) D" z: M! G - temp |= 0<<7; //设置操作模式:0,标准模式
& t6 I2 S) O. V! o. Q4 }4 p - temp |= 1<<9; //设置突发写模式:1,单点访问
+ e) O9 ?: U: e1 y - SDRAM_SendCmd(SDRAM_CMD_BANK1,temp, 1, SDRAM_CMD_LOAD_MODE); //设置SDRAM模式4 q+ x; g& \& T2 y) W! C3 t
-
! o7 R6 j' m3 W+ J - //COUNT=SDRAM刷新周期/行数-20
2 h, C5 J9 z) l+ {$ ], n - //SDRAM刷新周期为64ms,SDCLK=AHB/2=100Mhz,行数为4096.
8 |# `6 p: q% @- x- e' e - //计算方法为64*1000*AHB/2/4096-20
0 Y/ n( L7 @. m) o1 J5 P6 ] - temp = 64*1000*(SYS_GetAHBClockSpeed()/1000000/2)/4096-20;
( h0 a. k4 x8 M, G - FMC_Bank5_6->SDRTR = temp<<1; //设置刷新频率计数器 2 N, I' Y# ~0 L" X2 q
- }
e8 k- k* `) W - ' U& [4 C |- F) g) B3 D+ X/ ?, \. Z
- # j9 P1 s) }( w8 i# t
- /*************************************************************************************************************************
) F* U( C$ a- K& {! y) M - * 函数 : bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)* ~/ B( V4 U0 |" P
- * 功能 : SDRAM 命令模式设置
: J: @4 ?8 e: S0 L' V - * 参数 : BankSelect:bank选择;mdr:模式;AutoRefresh:自刷新设置;mode:模式命令: x6 J2 d2 c# d7 |4 a( p8 g
- * 返回 : TRUE:成功;FALSE:失败
+ L' c* T( D3 i - * 依赖 : 底层宏定义
; ]) q& T, T, N# P! h* S - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
5 Q0 l( M/ B0 Q2 o7 r - * 时间 : 2019-09-08* [! r1 B7 m; m. U P
- * 最后修改时间 : 2019-09-08: Z7 _1 `3 c% R( T/ \3 c% [/ A8 c/ p9 ~
- * 说明 :
% L0 {. `/ k8 ?- v3 p - *************************************************************************************************************************/ # x/ u6 y( W/ v: U. O$ i
- bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)
0 S5 m9 T9 q! |. e. w2 D" M - {
E7 Z2 V0 S6 D9 B - u32 retry=0;4 Z( E; d$ h. k6 ]* B/ q
- u32 temp = 0; 6 H( U% Y: C7 C H
-
; v! P. J! C3 y4 a4 y2 c* S0 R5 Q - temp |= mode<<0; //设置指令
2 U+ o7 K- {% Q. \( m - temp |= BankSelect<<3; //设置发送指令到bank5还是6
# @0 C g3 T0 s - temp |= (AutoRefresh&0xf)<<5; //设置自刷新次数5 a+ K) m2 X$ ~6 D1 |3 w8 h' H
- temp |= mdr<<9; //设置模式寄存器的值" r K( M* F l( X3 F( g, s
- FMC_Bank5_6->SDCMR = temp; //配置寄存器
! f0 |5 n) }: |& U -
2 R1 a6 g" U, Z1 Z! ^9 g h - //temp = FMC_Bank5_6->SDCMR;" T$ S, r$ M4 m* w" v* E
- //uart_printf("FMC_Bank5_6->SDCMR=%X\r\n", temp);
# w2 c1 N. U$ P5 f E* ? - while((FMC_Bank5_6->SDSR&(1<<5))) //等待指令发送完成 1 g* o- [5 ?+ d; p; P: n
- {
+ i9 }$ V% ^( `6 }3 r, s - retry++;
3 u' ]/ q$ M: {, o - Delay_US(1);
& Z u* d6 A1 D) G - if(retry > 50000)return FALSE;
5 h4 a0 L* [1 a' @3 ^+ z6 a - }
! M+ Q' R: F* Q, Q2 _% u( ~ - ; Q3 W' O9 K/ [3 w/ x
- 0 D& P7 q9 E! V# ]1 c
- return TRUE;
% ~% I2 `' Q1 \$ m z - }
复制代码
! ?/ k( W% u7 k q( m8 e0 E6 w% P+ t6 j+ q
( S) O' k0 m; y7 A- D0 D- /*************************************************************************************************************
/ n& \6 w' G# c1 M/ D& S% a; l - * 文件名 : stm32f7_sdram.h4 ^3 e s) O7 o' U2 v" U4 j
- * 功能 : STM32F7 外部SDRAM驱动3 P9 I, u) e) r( @" x" G0 |3 |
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>% P% P m$ Q4 I0 u8 {3 ^
- * 创建时间 : 2019-09-08
W! Q( Z2 X2 j, z5 P! w- w1 j4 j- } - * 最后修改时间 : 2019-09-08
; M1 n3 J: W! O9 S - * 详细: . `! E+ m+ F1 z7 x, h7 H
- *************************************************************************************************************/ : q1 K& h' e4 o4 C
- #ifndef __STM32F7_SDRAM_H_9 k. s* a7 {, @; x; h2 |
- #define __STM32F7_SDRAM_H_
" K; C8 p* \. k. \, d) j c - #include "system.h"
7 L: E% U/ W( c! Z1 E
: X' C" Q g3 f: P0 I, X$ h/ k- 1 @! `. c+ ~: W
- //========================================================================" B5 i' U9 u' l1 c" N D# X
- // SRAM硬件相关配置8 i. ^4 h; B3 X! J- _
- //------------------------------------------------------------------------
X0 v) @3 O n, o - #define Bank5_SDRAM_ADDR ((u32)0XC0000000)
0 @0 q3 v3 [4 @' C1 B - ; y& q: `, b8 r5 u
- void SDRAM_Init(void); //SDRAM初始化% H. y+ @8 l/ X$ b2 @9 i
- 1 w2 Q' x! R( ?* W0 Z% g
S# b& I) l( i' P. x1 q- #endif //__STM32F7_SDRAM_H_
$ [7 C0 J7 o+ \
复制代码 0 ?4 d0 R( H& {, M+ q; O
+ u. P* b1 i( i% b# y8 U
|