简介
6 Z) U6 I7 }3 ?5 R1 z最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。( X# ` i3 K& |! Z( A
( P. b# q) U9 P4 m" Z2 V! x( TSTM32Cube配置) I$ N6 B. E8 ~# s
Pinout9 H: q- d& b3 `+ N# Y! D1 |
& @& N5 P4 |) N3 N; j
+ Z8 Z1 z/ z3 {: i7 d: }/ x- V( i
/ E/ c5 z, o9 l! P* z }1 s2 o5 w5 y% q2 e
只需要注意绿色部分的设定7 `9 t% ^0 F3 @" c& ~8 ?( r
+ |5 B$ r7 ?% C# J8 \3 }Clock配置
" ]. w6 W. Z8 J
( E0 G; E# @* u6 l+ W( w* T
, O4 y- @: m3 p这里使用了最大的Clock,SDMMC1的时钟是48MHz C7 V+ E. x) \' R, f
# E6 z& R9 ]" b* `FATFS配置9 ^2 O+ ]) l$ v& [+ S
2 r* e" i2 k- k: B( A; W3 p. O( \) {5 `5 ~- S5 z* n2 x* p
: f* g" |* d8 B* u& O
Freertos配置5 X" \! {- G( Q7 i, M
$ b! h( Q5 z+ z9 o; D
- ~: b. J% v8 ^) H3 h, C1 H' D1 v. N1 j. J6 ^) i1 P5 i$ F2 t
这里增大了Heap size,使用了heap_4的内存管理方式。5 ~1 }* ~' T( L7 r4 V
- M- b+ i% D* W+ u8 V& ]& ASD卡配置
2 s L. O3 v" T% c+ K# g& z0 @' d3 C
: ]5 T2 B3 x7 z0 K# X A( ^& Q4 | m; }% @3 L
) D9 y f0 T$ B- P* v3 g
. d9 n; u/ v+ \ w
) ^1 f8 }) q7 K& s: C$ C6 \在这里打开SD的全局中断,并使用DMA2的方式传输数据' ^$ e9 J6 n9 h6 I
4 a* P; \3 u1 r, Q4 n- @
NVIC配置
! K/ T( s P3 W) }% m5 [* f8 B6 Z" o* Y
' a" X. K+ m) _' w+ u
4 K( |$ Y7 k8 z: @ @1 u ?, L
SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。/ D# o) q$ X# ^7 [3 R9 N
5 W3 g4 O1 |$ P1 _
工程配置
, Y- O; _8 a: G; `% v1 Q9 |. w
6 [3 ]& m8 q# C! o% U% e2 [3 X+ K& S& Y) M( l
! j, Z! E0 R3 a0 @! t
- L. t9 |- n/ [$ X9 \+ W
" O% M% Y' a$ C以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。$ K8 W- u- l. r/ Z/ {; [& y
) z/ E4 w$ R5 M代码修改3 e/ n2 l- O0 d' N7 c' h4 m9 C. v; i
初始化SD卡
* b: o1 @( n1 `9 p! {0 I我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。/ g# B+ f T- F
- /* StartDefaultTask function */) h; |' `( r, K1 x
- void StartDefaultTask(void const * argument)3 q6 ]- D$ | G9 \8 e5 C. \. V
- {" q: _$ I2 S$ R3 Q% L' z
- BSP_SD_Init();
3 [/ U: `9 E" }& ]+ h+ x& a - /* init code for FATFS */$ o* i) b; _9 r$ r- q3 B
- MX_FATFS_Init();2 @2 Z. M$ u, r! Y# C3 l" u6 a
1 Y* u- c4 J0 H; h- /* USER CODE BEGIN StartDefaultTask */' u" K- M+ v8 t$ @8 T# \) [
- /* Infinite loop */
' E& P' n# V, S# Q } - for(;;)
+ s* ~ k1 a7 d1 }$ p, Q- Q - {& f7 U: X; c5 J8 t
- MX_FATFS_Run();0 U R. e* q7 o E: n
- vTaskDelay( 5000 );
5 @' s8 {( c, B0 u - }
$ n' @1 d- m. P9 B% ? - /* USER CODE END StartDefaultTask */" l6 d# u; m% n' O) {0 ^
- }
复制代码
1 F# V- C* M8 U" E' K- \添加DMA中断处理函数
9 i, I2 X; m. J1 ?stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:! A2 A- {; y6 K( ]3 e
- void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd), m- b; W: C) E! }' H
- {' f8 D( _" Y- z- E) U
- BSP_SD_WriteCpltCallback();
+ B4 Z" @: r& r4 u7 U- {; ? - }
+ {% x5 [5 J9 ~- N! M - 2 M7 D' G! Y7 e
- void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)7 U" w+ E% k3 ^4 J' ?
- {1 A; R. S& V' f, E, W" a( P
- BSP_SD_ReadCpltCallback();7 K: |! k2 ]1 c) ~- t0 z9 z9 s/ n n9 }
- }
复制代码
2 p* H- a$ W' @+ K创建Queue
2 k- |* K) k, Z在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。' g# c: P- y: E* |8 L
- DSTATUS SD_initialize(BYTE lun)2 w* G2 N+ |: | [, ?
- {
8 t% [7 v3 b1 @% E9 F - osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);5 F5 h/ t6 U5 }
- SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
7 M6 e# n4 F3 q' q - return SD_CheckStatus(lun);. g( ~, j$ Y1 D7 W' S: |
- }
复制代码 " z$ K) z( p- T5 B/ K
将Pin的配置改为上拉' g% v8 y% O' R- {. l2 G: V# ~! e: C1 h
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:
- v4 Z2 i$ q5 V5 g4 e4 u! z- /*卡在这个循环中出不去*/" n+ N8 h! j8 n& @! R
- while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
, ?9 P: g+ j3 n w2 d% H - {. E% l& F1 \' X7 P* h$ Y2 O
- if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
3 D6 t' n F" O; y - {) ]) ~. y, r0 U; x- I+ K( L T+ A. d# W
- *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
+ A" p' H2 R* P& z6 H [ - index++;
) O8 ?3 ~$ |( M5 R W$ ? - }9 M+ Y: {6 R" x; {. t4 b
- " A* j$ N* Z: }9 l# r& n; Y; t
- if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT). ]) Q$ t! _4 |* [/ s/ [' `
- {$ k/ {! X. r1 q, L
- return HAL_SD_ERROR_TIMEOUT;
& s! n5 x) b1 m, l+ y4 E - }
4 I: Z" s) K! C4 p Y, x - }
复制代码 0 \# l8 O1 z3 s: f
后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
7 b* b" b$ D: ?' @' }& d' ]$ o
% [# {% L) {( j* @) _/ g' `- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
6 B) A! h# C0 b+ I - |GPIO_PIN_12;
+ \( U- `& C. L; M* k. O, U7 V# R, T - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;9 {6 j$ ], C/ \0 U/ a1 A' s
- GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;& y% N' {. K2 z2 P
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;: n6 w& k. ? b3 b" {* w
- GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
' {; s' s K8 L% _8 I - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);. }6 @$ E, m$ ^
- p4 Z. q5 i" f4 C4 d5 I- GPIO_InitStruct.Pin = GPIO_PIN_2;
- q: W0 m" S4 c& z! o - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
/ X8 ?( A# \: t: x: p* j( j( r - GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;8 F, h9 i. t" X V. p4 o: l- Y
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
8 @4 C6 ]: a+ P2 W) g. o3 ` - GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
N: {) ~% P" l& m! F6 Q - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码 7 u6 o2 Y* _# O; C3 B# \# ?* L
简单Fatfs应用
0 C y# I- }* g" T- void StartDefaultTask(void const * argument)
" g9 @- G: {$ K( H - {( q7 y1 d9 X6 B1 v, c
- BSP_SD_Init();
# N9 x5 p. c4 o5 m" T - /* init code for FATFS */
) v$ t: v4 _& p4 ]. f - MX_FATFS_Init();! t8 p: E A- y4 r
# L& D6 M3 _% H S1 A2 t- /* USER CODE BEGIN StartDefaultTask */; [' s& h/ E$ n- d! ~' b4 I' J _
- /* Infinite loop */
5 }( X7 V% }- G) O* }7 n - 8 ]6 c6 z4 U5 i9 O
- for(;;)
4 s- ~( |! t7 x6 \6 f* X7 c7 y4 ]; L - {
# v: |" l+ s2 h# h' J! x0 z$ Y. g9 y - /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/
$ Z) R# n& g) |3 G! R+ \) L+ a - MX_FATFS_Run();
0 v- q w8 X$ E8 m& r$ X4 Y - vTaskDelay( 5000 );5 u5 Z/ q5 ^' Q; p- p0 T% p
- }# _' K: n z8 e) E+ v
- /* USER CODE END StartDefaultTask */: r2 S" r6 O/ N7 j8 V
- }
$ [' D3 p+ w! \* s$ }' e* e! c - 3 _9 k5 Z+ {7 K8 \
- void MX_FATFS_Init(void) ^6 ^3 \( o. i4 |
- {% ]2 L( N: M4 E; o3 Y! p* p G
- /*## FatFS: Link the SD driver ###########################*/
5 `& k5 R% r j/ W& F - retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
: j" u$ W r/ c! S7 p - . \# X* R( r" B7 F5 O
- /* USER CODE BEGIN Init */
* ~1 q" P8 ~/ ^) K - /* 在Init的时候挂载文件系统 */ 9 q3 U9 ?! B1 p0 j1 B
- if(f_mount(&SDFatFS, SDPath,0) != FR_OK) 6 E% O ~: b3 t P7 w
- {
7 i3 \6 F% K4 q8 D \ - while(1);' C- W) m7 f' h. z! X
- } ) r! u$ D: e/ l# g! w6 M" M# g6 x6 E
- /* USER CODE END Init */3 O0 G2 j4 D% D* H5 Q
- }
5 I C. t0 G0 H, E2 `* F
$ M; C6 v4 l! g! e3 h3 D- void MX_FATFS_Run(void)$ G$ D) ~$ @' S9 w7 l5 V% P' ^
- {
+ y- o( l- L5 c m/ y9 L0 l" t5 `7 `& { - UINT writeBytes;% H1 L2 N9 E' m4 v% c" N8 v
- /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/
. O* c" @ }8 \( s# Z - if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)% X) U' U4 H# }5 I, `
- {
6 [3 P- s5 g2 I# d* @7 ` - while(1);
0 X) y( ^9 X( ^) u3 M y9 T+ m - }; D& j" c6 @. ]5 w4 Z
- if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
( E# Y) C& F$ v$ \/ w, y' t - {/ {4 p9 N- K+ {! k
- while(1);
! r( Y* v3 v* [6 I, r! i- [ - }9 \* y1 S4 `" ]( @
- if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
( C- c9 z# f2 T+ a7 y$ C: O - {; @6 w. V4 z% R% @
- while(1);' d7 C! n0 b+ t: ~ k
- }
$ w; a: R- r; M" I; o - if(f_close(&SDFile) != FR_OK)
. f* s' P7 V2 a' m) A# w - {/ B- J- h1 f8 l
- while(1);
7 ^, G9 d; ^- }) M1 m1 V, C$ ~ d - } 7 Q( y' O! l$ ?/ T
- }
复制代码 " z0 k! F8 T: t, `. D) t8 f8 |4 H
SD写入结果:
" Z; z" b ~9 u' i
7 d. X: {7 k3 j2 l; I- F% W
/ S/ L$ ^, J' @9 ?% X2 C: C3 v* i& A, q
! g# \3 m, r& J/ V/ O7 Z | |