STM32f746gdiscovery 开发板使用的是16MB的SDRAM,由于少了一根地址线,只有8MB可用。
. p$ z7 K l* i2 g+ K; d
* ?' }9 `" Z' s' t
, i5 e+ Q. ] Z4 d
9 w" V7 M5 w, y4 K: m6 s2 k0 y3 ^* t1 v! U" u+ Y; n
- /*************************************************************************************************************
! k; W; y1 X4 A8 k& E A- B - * 文件名 : stm32f7_sdram.c2 ~# Z- Z# Y* E1 ?8 W
- * 功能 : STM32F7 外部SDRAM驱动
3 \+ w2 B+ X+ i7 u: W! ^9 L& g - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
4 M) X, ] W3 A% c, n S8 M$ x- z4 Z2 C - * 创建时间 : 2019-09-08
+ j) f/ L+ U% L2 {3 C" I' n2 T - * 最后修改时间 : 2019-09-08, z. j3 d% o7 c( ^& w) @1 D, J
- * 详细 : 2019-10-31 设置突发长度:4(可以是1/2/4/8)-测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点( O; D6 g" i6 R3 V
- *************************************************************************************************************/ 3 O. n0 J9 c Z% ]6 R# A
- #include "stm32f7_sdram.h"4 s9 L& [( A% Y( _8 l2 z
- #include "SYSTEM.H" ( z" h8 `4 H8 ]2 u& }, u
, `+ f2 i% [: f, \
& `7 Z* o( Z$ t! z- g* T
7 ] t/ `5 l* f% b- //BANK选择2 q3 n w+ P$ k9 t1 a L
- typedef enum
, x% T8 G8 a# `- B: j5 e6 T - {, _! D5 |7 o8 [, q/ B [
- SDRAM_CMD_BANK1 = 2, //命令模板存储区域13 ]3 ~( ~2 M0 h7 l# r; {, e
- SDRAM_CMD_BANK2 = 1, //命令模板存储区域2; q6 U/ j$ @7 @" ?- F
- SDRAM_CMD_BANK1_2 = 3, //命令模板存储区域1与2
% k y" l! V! h l4 { - }SDRAM_CMD_BANK_SELECT;+ h8 ]' d' \( v6 N
0 i- ^/ A# B$ J, ]1 }5 t- 6 p5 F6 n3 A8 G# j
- //命令
1 {$ s* N" D. n2 h - typedef enum : f1 ~$ X" N! h1 ?3 G- {+ y
- {% v7 o& a4 f( l+ N
- SDRAM_CMD_NORMAL = 0, //正常模式% N0 h' i8 u: Y$ S; O _6 a
- SDRAM_CMD_CLOCK_CONFIG = 1, //时钟配置使能4 |5 `! ]7 W8 o4 e+ l. L9 V; R
- SDRAM_CMD_PALL = 2, //预充电所有存储区域
/ _0 y8 I k6 U/ o - SDRAM_CMD_AR = 3, //自刷新命令" i! h9 [* L' d
- SDRAM_CMD_LOAD_MODE = 4, //加载模式寄存器% V. s0 |! ]5 }# b* F+ `) L( T4 C$ H6 C
- //SDRAM_CMD_AR = 5, //自刷新命令
; Y3 e4 _1 w, p) q/ W - SDRAM_CMD_POWER_DOWN = 6, //掉电命令/ n. Q' @4 C7 s* z" Z# b' X3 z
- }SDRAM_CMD_TYPE;3 f |" P7 _, F% l; I# V
- - U% ?$ p4 R W- l
- 1 C# H7 ]: i0 c% v
- bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mode, u8 AutoRefresh, SDRAM_CMD_TYPE cmd);//SDRAM 命令模式设置
% r# M) X( P- E- S/ d+ v
+ T* s& J. E% n- 8 Z8 }% H8 m2 b7 E
- /*************************************************************************************************************************
9 z1 Y/ Q! z. i - * 函数 : void SDRAM_Init(void)& m6 d }5 K. q) e* N1 E
- * 功能 : SDRAM 接口初始化- o; @2 U+ n; B. K
- * 参数 : 无! L X( n6 w/ z+ G Z
- * 返回 : 无
0 `! t$ x/ b& @5 u# P1 M6 r - * 依赖 : 底层宏定义: g6 w* ?6 \. P6 y9 J% D2 \8 K% |7 ?6 v
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
5 q- l* H' m: z - * 时间 : 2019-09-08
; [! P, k5 s. V9 A# B7 t6 p' M - * 最后修改时间 : 2019-09-08
. U( m) t* m3 L% y+ f, Z) R, \$ \ - * 说明 : 用于初始化STM32F7 SDRAM 接口3 j! L3 X( w8 j8 J
- *************************************************************************************************************************/ / z' Y" u! k5 @5 M* S/ { e5 h' Y. U
- void SDRAM_Init(void) K: K8 g. q2 n1 S
- {
3 |1 A, D) u2 I3 J2 U$ D - u32 temp;
0 v) r3 A5 j( f. G' ^, C - 4 y; N; j( l; l8 v( P
- SYS_DeviceClockEnable(DEV_FSMC, TRUE); //FSMC时钟使能
9 S# L a( Z* w" T& v - SYS_DeviceClockEnable(DEV_GPIOC, TRUE); //使能GPIOC时钟
8 l/ X% @+ ?. i! l; w/ K& B* K - SYS_DeviceClockEnable(DEV_GPIOD, TRUE); //使能GPIOD时钟4 ~9 E' t/ W/ [. N" U# B8 Y
- SYS_DeviceClockEnable(DEV_GPIOE, TRUE); //使能GPIOE时钟! V! M1 Y2 a9 X$ E- z
- SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //使能GPIOF时钟
; H$ _4 G# }1 e5 b, ]. p! c$ { - SYS_DeviceClockEnable(DEV_GPIOG, TRUE); //使能GPIOG时钟- B* X4 U6 K( H6 d# C3 @" R
- SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟) y7 ^4 K+ |; B9 h2 ?5 C5 ]3 Z
- % V; d# X: I4 w7 M+ W0 Z) o
- //初始化IO
7 b# N- E! s2 ^ - SYS_GPIOx_Init(GPIOC, BIT3, AF_PP_OPU, SPEED_100M); //PC3
( v. p3 E) I* ]% I4 L& I - SYS_GPIOx_Init(GPIOD, BIT0|BIT1|BIT8|BIT9|BIT10|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PD0/1/8/9/10/14/15
: g( E9 g/ A9 [" J: k# h0 e - SYS_GPIOx_Init(GPIOE, BIT0|BIT1|(0X1FF<<7), AF_PP_OPU, SPEED_100M); //PE0/1/7~15
5 _* R, h9 n( l+ F* h' w, O) V - SYS_GPIOx_Init(GPIOF, BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT11|BIT12|BIT13|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PF0~5/11~15
( {/ r( E D% y/ F - SYS_GPIOx_Init(GPIOG, BIT0|BIT1|BIT4|BIT5|BIT8|BIT15, AF_PP_OPU, SPEED_100M); //PG0/1/4/5/8/15* S1 h6 G& S! R8 W4 y
- SYS_GPIOx_Init(GPIOH, BIT3|BIT5, AF_PP_OPU, SPEED_100M);
, g% g) k! S. g# a* I( Y - 9 e* `' Z1 F% S* g8 O! h5 z
- SYS_GPIOx_SetAF(GPIOC, 3, AF12_FSMC); //PC3,AF126 r& X# I" |$ @. J+ ]! g
- $ g! L& G8 s# j+ N* l7 L
- SYS_GPIOx_SetAF(GPIOD, 0, AF12_FSMC); //PD0,AF12 5 c) @" v3 X# Z+ q
- SYS_GPIOx_SetAF(GPIOD, 1, AF12_FSMC); //PD1,AF12 . ~+ p" X* K6 J
- SYS_GPIOx_SetAF(GPIOD, 8, AF12_FSMC); //PD8,AF12 O9 G3 n0 s% g+ Z; s
- SYS_GPIOx_SetAF(GPIOD, 9, AF12_FSMC); //PD9,AF12
6 N" d/ y* x9 M4 F - SYS_GPIOx_SetAF(GPIOD, 10, AF12_FSMC); //PD10,AF12
$ E$ Q& [, ]7 A4 V6 w" z - SYS_GPIOx_SetAF(GPIOD, 14, AF12_FSMC); //PD14,AF12
9 Q6 R! |. j" U* v5 K: A1 t - SYS_GPIOx_SetAF(GPIOD, 15, AF12_FSMC); //PD15,AF128 o% L7 t! u$ l" D4 Z" o
- 6 E# q+ E2 y! R# q; H2 U/ M/ N
- SYS_GPIOx_SetAF(GPIOE, 0, AF12_FSMC); //PE0,AF12 6 w* k: G ^. o( s8 R
- SYS_GPIOx_SetAF(GPIOE, 1, AF12_FSMC); //PE1,AF12 - _. J) f4 ]$ E& D! v" \, M
- SYS_GPIOx_SetAF(GPIOE, 7, AF12_FSMC); //PE7,AF12
- h' p! j" R0 E1 C - SYS_GPIOx_SetAF(GPIOE, 8, AF12_FSMC); //PE8,AF12
& f. ~/ R; S$ j9 F - SYS_GPIOx_SetAF(GPIOE, 9, AF12_FSMC); //PE9,AF12
! g7 p7 [! e5 `4 p. [1 a/ K - SYS_GPIOx_SetAF(GPIOE, 10, AF12_FSMC); //PE10,AF12( l* Y. B1 {6 y, V$ @1 J! M
- SYS_GPIOx_SetAF(GPIOE, 11, AF12_FSMC); //PE11,AF12
7 a @. x# M! V7 m; W. r6 C - SYS_GPIOx_SetAF(GPIOE, 12, AF12_FSMC); //PE12,AF12
' G& E" E) L2 N% v# c4 J - SYS_GPIOx_SetAF(GPIOE, 13, AF12_FSMC); //PE13,AF12
, N3 M7 U3 {6 b$ B: O+ r" | - SYS_GPIOx_SetAF(GPIOE, 14, AF12_FSMC); //PE14,AF12$ V9 _+ F0 i1 R% N0 \/ ~) q
- SYS_GPIOx_SetAF(GPIOE, 15, AF12_FSMC); //PE15,AF12
4 g7 x3 e& K0 d - % ]6 z/ `$ i4 C# V, }7 N2 }
- SYS_GPIOx_SetAF(GPIOF, 0, AF12_FSMC); //PF0,AF12
g, \5 p8 F c4 v) l W - SYS_GPIOx_SetAF(GPIOF, 1, AF12_FSMC); //PF1,AF12
) y: H" `! f) x+ O0 y - SYS_GPIOx_SetAF(GPIOF, 2, AF12_FSMC); //PF2,AF128 ?7 ?& Y+ W1 L# C, x. g" }7 F
- SYS_GPIOx_SetAF(GPIOF, 3, AF12_FSMC); //PF3,AF12; K+ v( J& s! D( g* f- t
- SYS_GPIOx_SetAF(GPIOF, 4, AF12_FSMC); //PF4,AF12
" n7 j% Q$ O: i; o - SYS_GPIOx_SetAF(GPIOF, 5, AF12_FSMC); //PF5,AF12
( {# y) ?1 g$ z" S' `5 s9 Q" K - SYS_GPIOx_SetAF(GPIOF, 11, AF12_FSMC); //PF11,AF12 Z _, t( W" v( }" N7 {
- SYS_GPIOx_SetAF(GPIOF, 12, AF12_FSMC); //PF12,AF12
3 f& F) m9 R9 a5 f, e9 t - SYS_GPIOx_SetAF(GPIOF, 13, AF12_FSMC); //PF13,AF12+ U0 P+ v4 w1 p2 J- x8 w9 e+ F
- SYS_GPIOx_SetAF(GPIOF, 14, AF12_FSMC); //PF14,AF12, w z) l# `: w- [0 {! }) m) R
- SYS_GPIOx_SetAF(GPIOF, 15, AF12_FSMC); //PF15,AF12
8 Z! u- U3 e! W - 9 O+ A f. C6 O1 P. J" k" G
- SYS_GPIOx_SetAF(GPIOG, 0, AF12_FSMC); //PG0,AF12 1 {% W% c: d* z
- SYS_GPIOx_SetAF(GPIOG, 1, AF12_FSMC); //PG1,AF12
8 }% V' r' H# x1 g! N& S( m - SYS_GPIOx_SetAF(GPIOG, 4, AF12_FSMC); //PG4,AF12
. z3 h- k+ \/ j1 q. e' S$ H - SYS_GPIOx_SetAF(GPIOG, 5, AF12_FSMC); //PG5,AF12
" }1 ?& p9 b/ h( [7 U - SYS_GPIOx_SetAF(GPIOG, 8, AF12_FSMC); //PG8,AF12! J, D# _1 P6 J
- SYS_GPIOx_SetAF(GPIOG, 15, AF12_FSMC); //PG15,AF12
3 V, v- b2 M1 o( v+ y. S1 a7 i( I -
?% D* t- r7 P( }, F - SYS_GPIOx_SetAF(GPIOH, 3, AF12_FSMC); //PH3,AF12/ }* T- h6 |, L. s0 m. e
- SYS_GPIOx_SetAF(GPIOH, 5, AF12_FSMC); //PH5,AF12
! L0 h& [: a0 {0 Q - * }# F, \3 F+ L M; s8 T' X; k7 [% c
9 Z$ D) M E2 [, o+ e4 {- temp = 0; T! l% e, ] B7 m) k# _
- temp |= 0<<0; //8位列地址, ?+ `! s& ^0 |+ C. u
- temp |= 1<<2; //12位行地址( T! {. s9 H6 b5 q
- temp |= 1<<4; //16位数据位宽' P: I4 M w; c* V
- temp |= 1<<6; //4个内部存区(4 BANKS)
; g4 q4 V8 Y3 ]3 x! n0 m& n - temp |= 2<<7; //2个CAS延迟
% d) z* r m5 z - temp |= 0<<9; //允许写访问, F+ K6 }4 w1 @' f, J# N
- temp |= 2<<10; //SDRAM时钟=HCLK/2
: Y5 y8 ]# U( A6 F! R - temp |= 1<<12; //使能突发访问
4 b5 I4 C2 V3 J* W - temp |= 0<<13; //读通道延迟0个HCLK
! B% L+ y5 Y4 t. R, }1 S0 Q C* O - FMC_Bank5_6->SDCR[0] = temp; //设置FMC BANK5 SDRAM控制寄存器(BANK5和6用于管理SDRAM).7 U! Q1 L9 |! }. P# c& d, J* B# ^
- & o9 S* t- r0 C7 t/ t
- temp = 0;. i1 `1 [; z& |$ i. c
- temp|=1<<0; //加载模式寄存器到激活时间的延迟为2个时钟周期- u- k {$ o% W3 }( s. h, N) M
- temp|=5<<4; //退出自刷新延迟为6个时钟周期
' k( l6 q* B% n) ?& ` - temp|=3<<8; //自刷新时间为4个时钟周期4 O4 o5 j8 k( H- w6 ?5 v
- temp|=5<<12; //行循环延迟为6个时钟周期
7 S7 q4 r: e, {5 J - temp|=1<<16; //恢复延迟为2个时钟周期9 e$ r! ?- X9 F4 ^5 x
- temp|=1<<20; //行预充电延迟为2个时钟周期9 @ Z' f/ x6 I
- temp|=1<<24; //行到列延迟为2个时钟周期
& B' `% K1 y- g, \$ r" x - FMC_Bank5_6->SDTR[0] = temp; //设置FMC BANK5 SDRAM时序寄存器
& w& N% i; l, `7 J, @& b - 3 |5 Z& S# z/ S: Y
- SDRAM_SendCmd(SDRAM_CMD_BANK1, 0, 1, SDRAM_CMD_CLOCK_CONFIG); //时钟配置使能 % t6 l0 }8 d5 M p) }6 O$ D
- Delay_US(300); //至少延迟200us.
( w0 Z$ M; |4 B: R! F0 ? - SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 1, SDRAM_CMD_PALL); //对所有存储区预充电
% m! w/ p" q8 c0 y - SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 8, SDRAM_CMD_AR); //设置自刷新次数 & T7 [8 g- h; ]$ T7 d
- ' |0 x5 a! m; n
- temp = 0;& v. G) p+ u2 F+ k7 c! @9 q
- temp |= 2<<0; //设置突发长度:4(可以是1/2/4/8) -测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点& ?6 T1 h4 \ P0 ~* t# M$ X
- temp |= 0<<3; //设置突发类型:连续(可以是连续/交错)# y* f" @, J& ~
- temp |= 2<<4; //设置CAS值:2% b/ _, \# L& I0 d) k6 a9 d
- temp |= 0<<7; //设置操作模式:0,标准模式
) [) f. ^+ X. e' d4 t) s - temp |= 1<<9; //设置突发写模式:1,单点访问' V& o- @5 e& p' j0 e5 g; }
- SDRAM_SendCmd(SDRAM_CMD_BANK1,temp, 1, SDRAM_CMD_LOAD_MODE); //设置SDRAM模式/ c. h, x* L; H7 ?
-
, A+ S* j' C- ` - //COUNT=SDRAM刷新周期/行数-20+ k$ ^; G+ H9 O/ b! I
- //SDRAM刷新周期为64ms,SDCLK=AHB/2=100Mhz,行数为4096.5 a' V: ?, k9 K' b
- //计算方法为64*1000*AHB/2/4096-20, r: h& L" c& v/ N% N, J. U* L
- temp = 64*1000*(SYS_GetAHBClockSpeed()/1000000/2)/4096-20;
; x% l8 G" E! @8 \ - FMC_Bank5_6->SDRTR = temp<<1; //设置刷新频率计数器 4 U3 d; C2 l8 a2 c1 ]
- }2 z( T9 c* [) F& t* N
- - q, D4 V, x, Y( O5 J. ?
- 0 {" Z8 G" n1 }9 r. b6 u
- /*************************************************************************************************************************
9 V; Q2 j' q- ~7 X, t; F/ O8 ^& n - * 函数 : bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)
6 _7 p! O; a, r( d0 V9 U - * 功能 : SDRAM 命令模式设置
: q3 p$ [ b6 o! ~: p - * 参数 : BankSelect:bank选择;mdr:模式;AutoRefresh:自刷新设置;mode:模式命令
. o4 s' V( n9 U6 J! Q - * 返回 : TRUE:成功;FALSE:失败
2 Z4 \" n( Y$ H - * 依赖 : 底层宏定义, a2 w; c ?/ y" F) |
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>6 e/ L0 e* s0 W1 S
- * 时间 : 2019-09-08
2 h. U' M# o" K+ o) ` - * 最后修改时间 : 2019-09-08
; U- Y& T5 \9 [- p$ y* A - * 说明 :
- }$ Q( ~! E+ [2 ^( A! g1 T - *************************************************************************************************************************/
4 r" i% E' y6 A z! U - bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)/ E% T& |. ]1 E f# B% v5 U$ f
- {0 E+ M( N; x( e# v) N- f0 c
- u32 retry=0;
" m. u4 }7 a! H, u8 d. Y+ B - u32 temp = 0;
. ~1 c8 Y2 Y% F. Z - % W0 c. J! e4 T! T- E9 O
- temp |= mode<<0; //设置指令5 }4 p. l/ p$ p7 @" x5 @
- temp |= BankSelect<<3; //设置发送指令到bank5还是6
( P! M q( A$ X; R - temp |= (AutoRefresh&0xf)<<5; //设置自刷新次数
4 U4 R; ?! K5 \( F - temp |= mdr<<9; //设置模式寄存器的值4 o" N H2 d$ n3 k) T* Q7 M
- FMC_Bank5_6->SDCMR = temp; //配置寄存器8 Q) W" [+ ~8 \* d7 \3 ?
-
( @# q- @( f+ E. h9 ]( q: B$ I3 l - //temp = FMC_Bank5_6->SDCMR;& f+ {4 L# G% ^9 D' V
- //uart_printf("FMC_Bank5_6->SDCMR=%X\r\n", temp);) t3 }1 @8 _6 ` i: w4 ^
- while((FMC_Bank5_6->SDSR&(1<<5))) //等待指令发送完成 & Y, A+ A( r$ Y" _! j* x3 ~6 p
- {
1 J& R+ J$ H" {' M7 L1 L - retry++;
9 J: t/ W% O. l - Delay_US(1);; Z# K* s1 E$ h- u1 j" j, W& x
- if(retry > 50000)return FALSE; " \6 ]. q2 S, l3 d' J
- }
! ~+ X: p; P* x9 z* o - / W0 X/ e; e! w3 p, R) T9 [
-
0 U Q1 D5 `& T/ | E3 A* K& e& x- K - return TRUE;
5 S' U$ n# d% M5 D - }
复制代码
; C' E1 R; T4 o& _% q5 }: `9 e2 X2 J: J! S4 f; Q: b1 {
- f8 _8 `3 b. g- /*************************************************************************************************************
* P. V6 g8 q6 ~; R$ H* i; W0 o# ~ - * 文件名 : stm32f7_sdram.h
. F' h1 e5 d( G% }. ]. @ - * 功能 : STM32F7 外部SDRAM驱动* W7 S* R* d5 C3 s+ e
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>8 E5 J8 a% s' ?
- * 创建时间 : 2019-09-08* g5 z4 `: z3 T) Z6 I! O* G/ e0 ^
- * 最后修改时间 : 2019-09-08
0 e: n5 J. `8 W# W6 W& f - * 详细: $ {1 Y# o+ W c) f4 J: _
- *************************************************************************************************************/
; t6 b& d' F: z' S! x' m% {0 Q - #ifndef __STM32F7_SDRAM_H_# z( G' l" a3 D6 i8 s( p* ?( l
- #define __STM32F7_SDRAM_H_ ! Q Y0 h% J# v2 `+ I: h3 A3 r
- #include "system.h"1 q4 i) l7 {) ?: A
- ' D6 [+ w E7 ?1 [+ ?6 G
$ F5 R8 j4 y% s9 M1 C/ W: L. {- //========================================================================) z5 W+ u' R. u, j
- // SRAM硬件相关配置( T: I# L; O# M
- //------------------------------------------------------------------------. G2 k( }) i$ x% P* z
- #define Bank5_SDRAM_ADDR ((u32)0XC0000000)1 g' t# C' k/ p8 j8 B9 Z- e
-
8 B0 L0 f2 @" j& j1 F9 _' K1 W - void SDRAM_Init(void); //SDRAM初始化7 K% X9 V$ U! V& U4 I. D
- 5 U5 y$ e: K( k/ G8 D O
/ Z7 p" Y' k0 H0 [ j O4 ]- #endif //__STM32F7_SDRAM_H_
& j" M/ x ?& [4 O* _- y& a
复制代码 - O% K% ~; z$ M" z7 d5 _
8 h R8 L- W# ~: l+ d0 F1 L9 y! d, h
|