STM32f746gdiscovery 开发板使用的是16MB的SDRAM,由于少了一根地址线,只有8MB可用。( [; ?3 Y" s5 p$ _9 @0 m
( t7 c' q+ R5 _6 K8 R2 q4 P) @
" c- O- x8 V# v7 u; Y6 O; c3 x1 w( f* H: C4 ^6 t+ o
& _2 `, P- e) t& T" }$ z" r6 x- /*************************************************************************************************************
( h$ m) Z: B! b2 \3 x( A. d - * 文件名 : stm32f7_sdram.c
3 N8 l) ^0 `- F, i( n - * 功能 : STM32F7 外部SDRAM驱动8 Q, o3 n3 p3 g$ b8 L" G2 q
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 a4 U$ V/ F8 ?+ @/ ~+ s
- * 创建时间 : 2019-09-08
# x% `+ D1 D7 Y* _" S - * 最后修改时间 : 2019-09-08+ y" d2 s' X Z9 |* W
- * 详细 : 2019-10-31 设置突发长度:4(可以是1/2/4/8)-测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点! e. Z1 R0 }; {* Z
- *************************************************************************************************************/
; I! |, r6 r R4 }9 C, z; E - #include "stm32f7_sdram.h" O6 |" d& T/ y9 \4 [4 h
- #include "SYSTEM.H"
0 [& l/ g' H2 A( I" O - 9 }% i J+ ^4 M# ]2 B( o+ T* ]
4 Z" {( m6 f5 W3 B' H/ P. r- 5 }! L/ Q8 o1 M! {
- //BANK选择
" E( \7 F& m7 e A - typedef enum
r0 C. e6 }) f) v+ P, K, p8 b - {# ?6 k X) |0 i+ R8 O4 u3 q' H
- SDRAM_CMD_BANK1 = 2, //命令模板存储区域1
7 u% a8 |: v b+ h5 h - SDRAM_CMD_BANK2 = 1, //命令模板存储区域2
3 O8 L2 Z' z2 W6 v) L# i3 W+ k5 R - SDRAM_CMD_BANK1_2 = 3, //命令模板存储区域1与2
O. K2 n9 S+ Q - }SDRAM_CMD_BANK_SELECT;7 @. B8 d" D2 b) n: c; Q3 a) Q
3 L- x/ q a7 M3 H4 i: D- ' k4 @ g1 M- \- ^3 f7 K
- //命令* ?. P3 a1 v8 |9 x8 Q1 F
- typedef enum
! b* V- }7 s0 j- G6 g$ t6 D& z - {
: L$ q+ D7 e, w; c1 @" i. Q' O - SDRAM_CMD_NORMAL = 0, //正常模式
, ?! U% E8 U- z* |; r3 M - SDRAM_CMD_CLOCK_CONFIG = 1, //时钟配置使能
& P% S' G; J8 T$ J% a; K - SDRAM_CMD_PALL = 2, //预充电所有存储区域
* C3 T" l1 @8 d' Y: V2 _ - SDRAM_CMD_AR = 3, //自刷新命令
, A% @* }8 Z' e4 R/ m1 B8 S/ f - SDRAM_CMD_LOAD_MODE = 4, //加载模式寄存器
* H3 o: [! v( b - //SDRAM_CMD_AR = 5, //自刷新命令
, i" O! e A# n' Q - SDRAM_CMD_POWER_DOWN = 6, //掉电命令; b4 J7 U" T1 A& o: Z
- }SDRAM_CMD_TYPE;
# Z* q' R: t, P# T
+ U3 |5 ]6 ~+ E! f2 d2 @, v- % p1 N% r: v ]& _8 W; b
- bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mode, u8 AutoRefresh, SDRAM_CMD_TYPE cmd);//SDRAM 命令模式设置
9 S4 d8 A7 B4 M5 n& l
; p3 s9 N( i# Z$ ~3 ?
& c& T( Z1 w, x1 Z- y- /*************************************************************************************************************************( {# ]% A' z6 P- P" K
- * 函数 : void SDRAM_Init(void)
$ N/ t: \- R- e* V! Z+ _- |( W p5 e - * 功能 : SDRAM 接口初始化
& N: q& t% ~3 j I8 r% v" G% n - * 参数 : 无
2 X. j+ Y5 y1 K1 H& l - * 返回 : 无
7 h6 v+ t1 K" r' e7 @ - * 依赖 : 底层宏定义# E' F: J2 k1 Z
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>! s: B" A( B, b, A1 X* y6 \- d! f$ c
- * 时间 : 2019-09-08( G4 j! W* ^; p8 J5 I0 K
- * 最后修改时间 : 2019-09-08
) |2 j3 }( j+ j: h' z - * 说明 : 用于初始化STM32F7 SDRAM 接口
9 u) W- f1 J' e! V8 k$ S8 H" w - *************************************************************************************************************************/ " {. ^# V! k+ }5 B& L
- void SDRAM_Init(void)+ X( U* B% _4 H- y6 Z) W( g7 T1 U
- {
! s- E% b/ @5 @( Q" t - u32 temp;
0 M( s7 q4 H9 p; X -
$ X& K2 Y E" e& r& Q% ? - SYS_DeviceClockEnable(DEV_FSMC, TRUE); //FSMC时钟使能
( i2 |) F' a0 v7 k6 L5 s. d- Z0 J - SYS_DeviceClockEnable(DEV_GPIOC, TRUE); //使能GPIOC时钟0 b& v" x" `5 q, \- W( T, y
- SYS_DeviceClockEnable(DEV_GPIOD, TRUE); //使能GPIOD时钟
# f. E. d& \" H/ K6 j - SYS_DeviceClockEnable(DEV_GPIOE, TRUE); //使能GPIOE时钟
" a; n- v5 C) n$ U8 {! y - SYS_DeviceClockEnable(DEV_GPIOF, TRUE); //使能GPIOF时钟
; Y8 V$ H) c6 z" c% d* a/ X - SYS_DeviceClockEnable(DEV_GPIOG, TRUE); //使能GPIOG时钟
- U. ^4 l; c' D - SYS_DeviceClockEnable(DEV_GPIOH, TRUE); //使能GPIOH时钟
0 i/ k% ~( [; o - ' P4 k! I2 [ w2 `/ H7 M+ g
- //初始化IO O' u! u/ b% O9 _8 J
- SYS_GPIOx_Init(GPIOC, BIT3, AF_PP_OPU, SPEED_100M); //PC3 ( ~0 J2 e; W J* ?; x
- SYS_GPIOx_Init(GPIOD, BIT0|BIT1|BIT8|BIT9|BIT10|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PD0/1/8/9/10/14/15 8 Q( P1 {' H4 k' ^: l( i) d! I% a9 _
- SYS_GPIOx_Init(GPIOE, BIT0|BIT1|(0X1FF<<7), AF_PP_OPU, SPEED_100M); //PE0/1/7~15
" P& N4 \$ e5 \4 y8 | - SYS_GPIOx_Init(GPIOF, BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT11|BIT12|BIT13|BIT14|BIT15, AF_PP_OPU, SPEED_100M); //PF0~5/11~15
# ^4 T7 z& l8 w: Q8 `7 M6 L - SYS_GPIOx_Init(GPIOG, BIT0|BIT1|BIT4|BIT5|BIT8|BIT15, AF_PP_OPU, SPEED_100M); //PG0/1/4/5/8/15
2 {. a3 h3 D& x0 g - SYS_GPIOx_Init(GPIOH, BIT3|BIT5, AF_PP_OPU, SPEED_100M);- S. ]* a! \4 C5 {
-
2 @2 y" \* k H8 T9 X8 C - SYS_GPIOx_SetAF(GPIOC, 3, AF12_FSMC); //PC3,AF12. P6 n& ~$ Y2 s
- , E+ l& y9 d+ b% j
- SYS_GPIOx_SetAF(GPIOD, 0, AF12_FSMC); //PD0,AF12
! U, c9 G7 Q" W5 c! B - SYS_GPIOx_SetAF(GPIOD, 1, AF12_FSMC); //PD1,AF12
' P3 |# x: n5 Z4 I - SYS_GPIOx_SetAF(GPIOD, 8, AF12_FSMC); //PD8,AF12
3 H- W, [! Y- A$ [5 p - SYS_GPIOx_SetAF(GPIOD, 9, AF12_FSMC); //PD9,AF12
& U" c0 B4 T- W& J - SYS_GPIOx_SetAF(GPIOD, 10, AF12_FSMC); //PD10,AF12
: h1 \3 n, g, ?- D8 I) D1 s' U - SYS_GPIOx_SetAF(GPIOD, 14, AF12_FSMC); //PD14,AF12
8 P6 z% D2 O7 K& y5 x2 `- p - SYS_GPIOx_SetAF(GPIOD, 15, AF12_FSMC); //PD15,AF12
- l' h. Q5 @ a8 N! c* p1 f - % C. Z, l8 _' S: V; R
- SYS_GPIOx_SetAF(GPIOE, 0, AF12_FSMC); //PE0,AF12 ' H; X6 R& Q' T7 ?* J. O
- SYS_GPIOx_SetAF(GPIOE, 1, AF12_FSMC); //PE1,AF12
! C! P. ^1 V3 q5 z - SYS_GPIOx_SetAF(GPIOE, 7, AF12_FSMC); //PE7,AF12
7 e/ x$ j+ J" e3 I; M- V6 n; Y - SYS_GPIOx_SetAF(GPIOE, 8, AF12_FSMC); //PE8,AF12
0 x# ?' z% w, ^5 |) c0 Q - SYS_GPIOx_SetAF(GPIOE, 9, AF12_FSMC); //PE9,AF12
8 i! y# q# J* K, S+ @$ y1 U& R - SYS_GPIOx_SetAF(GPIOE, 10, AF12_FSMC); //PE10,AF12
9 n! L$ }; n8 g0 r - SYS_GPIOx_SetAF(GPIOE, 11, AF12_FSMC); //PE11,AF128 V+ N7 k, `5 j( q! t
- SYS_GPIOx_SetAF(GPIOE, 12, AF12_FSMC); //PE12,AF12% p T' E4 G4 Z# I1 ^
- SYS_GPIOx_SetAF(GPIOE, 13, AF12_FSMC); //PE13,AF12' E' g2 H, d* z4 C- _1 c, Z
- SYS_GPIOx_SetAF(GPIOE, 14, AF12_FSMC); //PE14,AF12% a/ ?4 D) k/ |; A% w
- SYS_GPIOx_SetAF(GPIOE, 15, AF12_FSMC); //PE15,AF12
# `. K. {; C8 S6 G1 K9 S$ {
3 F5 x. J; X4 I" t# J& u- SYS_GPIOx_SetAF(GPIOF, 0, AF12_FSMC); //PF0,AF12
+ O& Z T7 D# ]$ \# I5 e - SYS_GPIOx_SetAF(GPIOF, 1, AF12_FSMC); //PF1,AF12
3 F; m( t- b1 a0 j! n% o - SYS_GPIOx_SetAF(GPIOF, 2, AF12_FSMC); //PF2,AF12& X# q9 \, h5 \3 }1 V/ R% r! w; t
- SYS_GPIOx_SetAF(GPIOF, 3, AF12_FSMC); //PF3,AF127 X- V7 d% U( I% X6 F+ H, W
- SYS_GPIOx_SetAF(GPIOF, 4, AF12_FSMC); //PF4,AF12; m7 m( d- Z" O3 k
- SYS_GPIOx_SetAF(GPIOF, 5, AF12_FSMC); //PF5,AF12
' J8 ^! \1 U1 x - SYS_GPIOx_SetAF(GPIOF, 11, AF12_FSMC); //PF11,AF12
: ^) l, c9 G' N5 K - SYS_GPIOx_SetAF(GPIOF, 12, AF12_FSMC); //PF12,AF12
r1 Z- C5 E2 N' h, V, ~/ V% K; m# P - SYS_GPIOx_SetAF(GPIOF, 13, AF12_FSMC); //PF13,AF12) a% u) S' f0 @$ `3 V4 o y% b
- SYS_GPIOx_SetAF(GPIOF, 14, AF12_FSMC); //PF14,AF12
3 o. Z' z, E. o4 g( I1 | - SYS_GPIOx_SetAF(GPIOF, 15, AF12_FSMC); //PF15,AF125 n, V& b5 M* o5 ^$ s
-
9 S! n' k' O! t: K# o - SYS_GPIOx_SetAF(GPIOG, 0, AF12_FSMC); //PG0,AF12
) k! i! } M6 s, W. d: \: W) G; ] - SYS_GPIOx_SetAF(GPIOG, 1, AF12_FSMC); //PG1,AF12
2 F, c1 D0 j6 |. \. }% r5 x6 x1 r - SYS_GPIOx_SetAF(GPIOG, 4, AF12_FSMC); //PG4,AF12, k/ f4 D* A7 ^" r
- SYS_GPIOx_SetAF(GPIOG, 5, AF12_FSMC); //PG5,AF12
9 H6 t# n* U; \$ f2 D - SYS_GPIOx_SetAF(GPIOG, 8, AF12_FSMC); //PG8,AF123 }% E0 Y- _/ K+ C4 {
- SYS_GPIOx_SetAF(GPIOG, 15, AF12_FSMC); //PG15,AF12
3 l0 \* y" j4 o# L3 [) H U - : e/ S1 `8 P, c, K, g! j3 b( |
- SYS_GPIOx_SetAF(GPIOH, 3, AF12_FSMC); //PH3,AF12
s+ s0 W. l, w2 I( d5 V3 f1 N' ] - SYS_GPIOx_SetAF(GPIOH, 5, AF12_FSMC); //PH5,AF12
8 f4 K3 r, R( f -
w( Q a0 E5 }' Z$ {6 X9 I& N - ( F" I1 h% F* _# f
- temp = 0;; Y2 t+ W+ N3 P0 G3 P' q$ |& |
- temp |= 0<<0; //8位列地址
! S% l$ G/ ]! t - temp |= 1<<2; //12位行地址3 u( H3 ^2 A9 U4 h+ S
- temp |= 1<<4; //16位数据位宽
5 o7 Y- t( J4 A: c. ?+ U+ n$ L' _ - temp |= 1<<6; //4个内部存区(4 BANKS)3 `- y( J# }8 m2 E8 @
- temp |= 2<<7; //2个CAS延迟
# M& _( P9 v q7 b3 t - temp |= 0<<9; //允许写访问
8 V6 q" |" m) j. t/ C - temp |= 2<<10; //SDRAM时钟=HCLK/2
1 E- [& t6 ^0 f( u( L8 M0 \6 N - temp |= 1<<12; //使能突发访问
: c7 V5 b- Y5 T9 @9 [0 p - temp |= 0<<13; //读通道延迟0个HCLK4 `9 l7 l& r6 i5 E
- FMC_Bank5_6->SDCR[0] = temp; //设置FMC BANK5 SDRAM控制寄存器(BANK5和6用于管理SDRAM).! t9 k/ W: R2 e$ H: r. b- p
- 6 H l' W" A* { f* W( t A$ d
- temp = 0;
+ v0 p0 z4 K( C a# S - temp|=1<<0; //加载模式寄存器到激活时间的延迟为2个时钟周期) U7 e1 c# k" R' d
- temp|=5<<4; //退出自刷新延迟为6个时钟周期8 g6 t$ X3 o& v
- temp|=3<<8; //自刷新时间为4个时钟周期
4 [ _/ i. v- I) m. r, u - temp|=5<<12; //行循环延迟为6个时钟周期3 y+ v( e) G+ P0 w6 D8 P/ |8 X
- temp|=1<<16; //恢复延迟为2个时钟周期
) E/ D: z0 v+ X6 D6 P" E- A - temp|=1<<20; //行预充电延迟为2个时钟周期" B: p2 ]- l J2 U! Y
- temp|=1<<24; //行到列延迟为2个时钟周期4 _1 ~! x5 q6 o7 ^
- FMC_Bank5_6->SDTR[0] = temp; //设置FMC BANK5 SDRAM时序寄存器 % b1 A! |1 _. Z& e
- 2 c; |; l Z% R1 G0 w
- SDRAM_SendCmd(SDRAM_CMD_BANK1, 0, 1, SDRAM_CMD_CLOCK_CONFIG); //时钟配置使能 6 X6 n3 n) j: w8 ~
- Delay_US(300); //至少延迟200us.
3 A! \! i) b/ | X' P - SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 1, SDRAM_CMD_PALL); //对所有存储区预充电% h+ R- ]. _0 I' E) p2 X& J
- SDRAM_SendCmd(SDRAM_CMD_BANK1,0, 8, SDRAM_CMD_AR); //设置自刷新次数 5 g: s# G3 n; m
-
% G) x2 V4 ^/ ~5 e3 a: O! R - temp = 0;
5 Y# \/ X% [* B5 a2 @! e - temp |= 2<<0; //设置突发长度:4(可以是1/2/4/8) -测试过1/2/4发现都正常,唯独8的时候,屏幕会出现随机噪点
: F3 \, e% T, ]6 t5 C: T9 S - temp |= 0<<3; //设置突发类型:连续(可以是连续/交错)
7 ^! f( f# e; ` ^3 H - temp |= 2<<4; //设置CAS值:2
* d3 @) M0 ~9 T: v* ?& L6 u" M% m: z - temp |= 0<<7; //设置操作模式:0,标准模式+ U8 t, `9 c+ i) L
- temp |= 1<<9; //设置突发写模式:1,单点访问
$ }* _: o) q( Q3 } - SDRAM_SendCmd(SDRAM_CMD_BANK1,temp, 1, SDRAM_CMD_LOAD_MODE); //设置SDRAM模式# p- G3 X N+ H# K1 {6 u& N
-
+ {" ]: p# R3 c1 ^% A - //COUNT=SDRAM刷新周期/行数-205 d d {% x3 Z. D
- //SDRAM刷新周期为64ms,SDCLK=AHB/2=100Mhz,行数为4096.% P9 Q4 [4 i6 m0 G3 a3 w
- //计算方法为64*1000*AHB/2/4096-20
?( d4 {5 G: r4 w+ R+ J - temp = 64*1000*(SYS_GetAHBClockSpeed()/1000000/2)/4096-20;
Z2 s f0 C* i; z% F- I1 n - FMC_Bank5_6->SDRTR = temp<<1; //设置刷新频率计数器
5 e0 w) D+ q3 U+ R, g3 j - }
( P3 _; f/ m" P" g ]+ Y+ ? - 3 [4 k& Y* G8 y" q# k
S& G& u* B' _2 O- /*************************************************************************************************************************
4 U# i! ~; V" H2 r, u - * 函数 : bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)4 c/ f6 I/ I! k+ F% E2 ^* d" N( t4 ^
- * 功能 : SDRAM 命令模式设置
1 ?+ J- B2 U1 K3 a" h$ o* V9 P4 K - * 参数 : BankSelect:bank选择;mdr:模式;AutoRefresh:自刷新设置;mode:模式命令0 N' r# J' G5 f8 k. |7 i
- * 返回 : TRUE:成功;FALSE:失败3 ^9 b+ U$ P2 f3 ]( B1 U
- * 依赖 : 底层宏定义
! Y7 G7 V. s% q9 O - * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
: q, P% d' N3 c4 m - * 时间 : 2019-09-08& b& a. L* ?- o& P4 e$ Z+ j3 E
- * 最后修改时间 : 2019-09-081 D, Q/ p; d+ u# q
- * 说明 : - N% c" q' C& m+ A( K7 ^
- *************************************************************************************************************************/ " u4 ?3 g4 T( E4 L. i
- bool SDRAM_SendCmd(SDRAM_CMD_BANK_SELECT BankSelect, u16 mdr, u8 AutoRefresh, SDRAM_CMD_TYPE mode)
' f, Z8 T* z7 U c - {4 H. v. i4 h- ^- `
- u32 retry=0;6 K$ H9 O% X* x/ M0 _8 K9 O: T' c. q
- u32 temp = 0;
6 L K6 h3 ?8 ^/ K# W, v" y# D - $ r6 H* L# Z0 m @
- temp |= mode<<0; //设置指令6 ]& [/ h3 [" j+ c8 I7 W* w
- temp |= BankSelect<<3; //设置发送指令到bank5还是6
6 D2 T/ A8 i. E K O% R - temp |= (AutoRefresh&0xf)<<5; //设置自刷新次数+ ~" Z2 o$ X; M
- temp |= mdr<<9; //设置模式寄存器的值& e/ p1 l8 I/ i; [: T8 x
- FMC_Bank5_6->SDCMR = temp; //配置寄存器
" h; p" ?$ @9 r r8 i2 k) N - 3 j7 |6 w6 [- } N
- //temp = FMC_Bank5_6->SDCMR;
2 N& n% u2 e0 Y# x5 } - //uart_printf("FMC_Bank5_6->SDCMR=%X\r\n", temp);* a7 f% }1 g, U. ~+ i
- while((FMC_Bank5_6->SDSR&(1<<5))) //等待指令发送完成 4 |* @! ~& B/ N4 c% l% o4 ?
- {0 h- [0 n: U+ p1 l4 c
- retry++;$ B! R7 b3 p. }" n; I, f" v
- Delay_US(1);+ D; Y+ C4 }; M, D$ c: b, l
- if(retry > 50000)return FALSE;
. k0 b! }1 q+ L9 P" F - }
% ~5 A8 h0 t) I9 i/ F5 V) J -
( R% ` c9 A/ y" _8 u( @ - ( |2 j; ]. K( R$ I* P6 F5 d/ x
- return TRUE;
, F* h- ~: l/ x9 F! B) Y - }
复制代码
9 v& E9 `8 a* V& T7 \; L s! T4 `( ^; F* i4 o- B" }5 z
- F- b8 I9 z' k" {1 k: k9 N4 x
- /*************************************************************************************************************
% k/ X% Y0 h) Y - * 文件名 : stm32f7_sdram.h1 v' o/ ^) S0 ~5 \
- * 功能 : STM32F7 外部SDRAM驱动- [+ [1 q: P5 f; n. v0 ~% R" x7 i+ u
- * 作者 : <a href="mailto:cp1300@139.com">cp1300@139.com</a>
* a! e9 j" c( B) d; H - * 创建时间 : 2019-09-08
. K h4 u/ i2 E - * 最后修改时间 : 2019-09-085 f0 w- m/ ?8 d
- * 详细: 1 x2 @/ r& W' f" y! k
- *************************************************************************************************************/ # a! v4 O- s& a! z
- #ifndef __STM32F7_SDRAM_H_( d( L6 R3 a$ _
- #define __STM32F7_SDRAM_H_ + v( r, x) W7 `, A; u
- #include "system.h"
$ ?1 X- j: f' U: D+ z8 s/ \7 c - + ?) L3 X, }; x( t( c/ Q* x
- 6 x5 J. O( E5 X- D% f, m7 ?
- //========================================================================
; L+ \, Z1 u( z4 g- U3 k' I - // SRAM硬件相关配置2 v7 [/ m9 d# t2 X
- //------------------------------------------------------------------------2 O) M3 M# V( U4 }
- #define Bank5_SDRAM_ADDR ((u32)0XC0000000)
/ S e, z$ m: n$ e/ s' w! ^8 r -
5 R, x1 Q, e# m. T0 q - void SDRAM_Init(void); //SDRAM初始化! J5 y, b9 j. y; m7 O; U. B
+ d: D& O+ Q# @" `9 F- & Z3 }5 ], s( j8 B {
- #endif //__STM32F7_SDRAM_H_
; O1 T( u) b5 q: [/ O4 i
复制代码
0 ]5 r0 b& D; |8 O# O" X! t; ?0 l+ S; [* Q, ^
|