简介- v3 f8 R1 H2 R* _
最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。
0 Y2 b* V0 y5 S
: H* j, d/ P- D8 h; qSTM32Cube配置0 J( t+ f7 {; W+ k" k" z( U- g, `
Pinout# a. J+ B( m) A. F" v: @6 x [; S
o: ?, N" T! a* M3 ^- M+ Z4 v
: |4 g; F1 R/ y
z) v, b8 t2 d
# W: w# h4 l; |
* b+ q6 Q% \( x* N/ v) ^3 g: e只需要注意绿色部分的设定
3 T4 s+ e: n" @
$ X5 @- o1 D% g8 B- cClock配置
1 ?% Y& n/ ~! G( u& V* @
% M4 U! N. t. x r9 K4 C* t6 ~# N9 Q+ e2 V
这里使用了最大的Clock,SDMMC1的时钟是48MHz0 }( F& A. y) m; n1 _
; d$ |6 E6 ^, d4 c0 g( bFATFS配置
Z8 r k1 Q _+ D9 I5 A7 Y# T; e. ^
) C1 m9 t3 U( ~6 E( F. B4 y/ K. D# t, M
Freertos配置( _$ \3 I/ y7 x7 ?) T4 q4 M3 |7 S) R; f
7 i/ o9 p1 n7 E0 J W* i
( O, ^. F S% p2 v c5 {, R
2 Z8 P# w( v& `; m1 q' c! t* p这里增大了Heap size,使用了heap_4的内存管理方式。: G9 y* ` R1 t T$ \' L3 T
0 d' `1 f. P. l! u- eSD卡配置
# h' }5 X9 r! f8 G5 ~6 H+ i9 V& h! t7 ?! v/ Y6 |7 `) L
& P: \$ H3 Y7 \+ C
& C8 O m4 m% H2 r8 t* v; ^ z+ s) K) |9 `4 ?" U c% @; R; c8 e
& Q B4 C9 u) j
在这里打开SD的全局中断,并使用DMA2的方式传输数据5 M7 u5 j5 m% ^; D% @8 {# O, u( P
/ z. @6 ]% ?/ {" _1 q5 \( p/ A7 }NVIC配置' v1 u5 h# ]: h( x( X+ s
$ e3 r b/ G; q" D* G7 L# Y* u
% n, l; v+ Q# w I! h
. s1 p( e( N/ XSD的全局中断配置为5,DMA中断配置为6,5的优先级更高。, S; [- Z) Q9 E$ V) I$ A
" C4 r' C* t6 v: }* D工程配置; [9 r) I& H: x: h
; z8 Y' G+ x4 e' M* `; \
7 j( W+ C; M# S0 Y1 d+ M. L
* P% q% B, Q; T2 l; S
Y8 {% c5 _+ K$ C) T' [8 ^' D! P& \1 Q3 u- t- j) _
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。
2 a& j, F0 h/ | h! ]* t4 a- x$ E" p" }; g) D
代码修改
/ w% U8 ^9 M8 T$ H初始化SD卡
# b4 h! I9 T1 N3 W我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。! A- W3 N' J. _4 Q5 U3 @6 t
- /* StartDefaultTask function */! Q' p1 m# u1 D
- void StartDefaultTask(void const * argument)
; d( k9 ]9 I& i' ]9 B' } - {% n+ s& K3 }4 ~8 R" { H
- BSP_SD_Init();/ r5 {: m2 s6 U9 x% ?. \
- /* init code for FATFS */% p8 G9 g( h, E* y
- MX_FATFS_Init();
- G5 `3 ?' E9 U6 Y3 Q6 Z% g - + Q, f* C' y4 W4 [% M
- /* USER CODE BEGIN StartDefaultTask */
: @) K6 N+ u5 `1 ?8 q7 A - /* Infinite loop */: d4 f6 X& M2 i$ g. g
- for(;;)
( d, O/ J# t$ k9 N+ W! L8 G2 f. q; [ - {
: }: W) i( d7 e p7 N! Y% F - MX_FATFS_Run();
; p2 B9 m0 w& U9 r8 p - vTaskDelay( 5000 );
' \- Y @! C- f1 p5 L - }
O v8 I$ i6 a R - /* USER CODE END StartDefaultTask */% L2 D) P" {2 f9 y
- }
复制代码
9 v* }6 q1 U4 O% M* l添加DMA中断处理函数
. Y" [ b2 a- f+ Xstm32f7xx_it.c文件中,需要添加下面两个中断处理函数:
* a+ }' o2 L: U9 I' l: U& B- void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
* l3 m. I. W: }$ o. Z" _ - {
. d! ^( b$ l0 h" ]+ D( u - BSP_SD_WriteCpltCallback();
. |( N1 E+ V3 Q: l) y - }
+ D" G, y) x2 ?8 o
& N a4 |( r4 Y" G- void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)+ S, b4 G. L3 X9 F8 M4 O. J/ p- V
- {
7 R+ X! N: w5 w1 Y - BSP_SD_ReadCpltCallback();
+ ^/ x' J+ |. w6 [! L# a8 F. L - }
复制代码 0 `* t. \5 m$ I
创建Queue8 o, f, h1 q1 R
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。
8 x5 l& h9 V1 K- DSTATUS SD_initialize(BYTE lun)
) g5 _! b' J5 y - { s/ j6 Y$ Y! g& z
- osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
, v/ l% N& ~: o, L- J/ [5 s - SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
O4 V( k* [6 t F3 b8 f; _ - return SD_CheckStatus(lun);
" N4 z% {4 u2 k3 @& M6 i: G8 s8 Z! v - }
复制代码 $ A# d* R% p5 ^6 F3 m
将Pin的配置改为上拉5 h. f2 V8 W# x' x
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:0 g6 V+ j! |6 N% T: }3 ~$ N
- /*卡在这个循环中出不去*/) G& K# i+ I/ V# c6 d
- while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
z" ~0 E% \8 U - {
O" P4 t% d2 G. J" O @. |2 k - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
U6 T$ |" t7 u. b+ Y) h - {* a8 k$ F2 p- u$ S
- *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);% f! {3 g3 D; h% V* Z# ^! _: i
- index++;
' Q" q% E- d, \/ g: Q, f - }! v( `# V+ l3 G7 I1 K
" D: g$ n. O' c, P. c8 ^7 y+ u- if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT)
@7 S5 O' w7 m) O - {( {" r2 u2 D% D' O
- return HAL_SD_ERROR_TIMEOUT;
. o2 j+ D+ T, r/ Y) L - }
+ Z. G9 M; M! r. g - }
复制代码
: S0 B4 K/ h$ Z( J( \0 i" P% v后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
* t' Q2 a+ g/ O( ?; X, K0 o
z, g" N4 b2 u4 h: X9 H" m- I- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
8 `& m0 S9 l. t3 \ G2 r. k& f - |GPIO_PIN_12;3 x0 C0 Z, A) g% ?9 V3 Z1 S# I5 j5 A
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
# M9 Y3 _. t# J; k - GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
2 R; V, Q- t; a( W5 ?+ V. d+ C - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;" d, k8 n! I6 J# s0 K1 D( E/ L/ s
- GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;- B+ t7 u3 u+ p! i
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
1 b0 x3 J0 O/ m9 V. T/ ^: X4 W
9 c) @" ?( L- z5 V& ^7 ~& G- GPIO_InitStruct.Pin = GPIO_PIN_2;
4 I' [& x5 o8 | - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
7 P$ k/ B2 O0 s4 T0 ^: H: D - GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;: r! I' Z0 A: g/ H$ L+ c
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
4 P9 R9 s- d9 S1 j* o - GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;+ _/ V4 }, Q- [5 `5 X) M
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码 4 a# J' j/ \1 q# Z' y$ t% o/ T& C
简单Fatfs应用- v9 D1 w H" `. x8 |
- void StartDefaultTask(void const * argument)
7 h5 z$ W) r/ }% j# |) o0 N) X - {1 h: P, @% ~; @" \+ B' ?$ ^
- BSP_SD_Init();
( y' a; u0 I4 ]1 |. ^ - /* init code for FATFS */
$ c& ^/ [$ f' \# _" R8 b! j1 I - MX_FATFS_Init();4 Y$ C+ s( T( s
- & G+ W x9 k ~3 i( U
- /* USER CODE BEGIN StartDefaultTask */3 d* \7 @, Z) ~) N, {4 w1 W2 e
- /* Infinite loop */2 h9 ]6 ]( R- Z: O V
5 L9 a& E/ o4 d4 q9 r; ?+ C- for(;;)( P9 u* q( O2 O/ F( T+ m
- {
4 u8 v( g! B0 g$ ~ r2 _/ K - /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/
' i9 x1 u/ Y( K - MX_FATFS_Run();
0 E6 _' m& F6 e; X% K; _6 W - vTaskDelay( 5000 );; E6 T: R9 h# A, A F2 z- O+ c
- }7 k9 {0 c! h9 h' @/ X
- /* USER CODE END StartDefaultTask */
* H) _9 ^3 h% }. e9 N5 G1 x - }
V2 c: A6 U2 P) ]! h0 E
. D2 l1 ~8 C' |& l' e9 u- void MX_FATFS_Init(void)
( z: G7 W% r( p6 A" t - {
" E4 y- K0 g. i2 [3 g0 {) n - /*## FatFS: Link the SD driver ###########################*/
; W/ O# ~% ?3 M g - retSD = FATFS_LinkDriver(&SD_Driver, SDPath);3 k8 J7 s2 z" w' z- u/ ^
2 i' e! |) c" B- /* USER CODE BEGIN Init */
; j& _9 q L" u& R [, k, U - /* 在Init的时候挂载文件系统 */
) G$ i. X7 c; `4 O5 k2 ^! j - if(f_mount(&SDFatFS, SDPath,0) != FR_OK) 9 H7 K: v8 u8 P) u6 u1 P1 b' M% k
- {
2 {. B$ ~2 K- J$ d - while(1);
! j4 g' V) S8 ^4 [/ V - } + G5 z! u4 H; n6 r' d/ z. [
- /* USER CODE END Init */
# n. [; h9 v" \. _ - }
8 P2 D/ `1 {& U( {: H! E$ J - $ Q4 |# [- L3 G h
- void MX_FATFS_Run(void)
5 H" p+ Y6 @/ ^1 J) j+ x - {
* b% J8 G, y# g! _* N9 S9 y7 f - UINT writeBytes;
4 B; ~. V( S% y4 L - /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/$ S8 T( C6 g# i' W& N5 N
- if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)# g' E; l. e s, i
- {
; x5 ~8 O: p. f3 w' V& a [ - while(1);, s7 N7 }" I& X) E- ]" F) F
- }
3 i9 }/ l) ?$ i+ {9 f - if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
% H1 |6 G8 }$ F* U% `0 r) v) } - {( D3 r9 [( o2 T
- while(1);' |" J# D l( O4 Q% ^% L
- }9 ~2 h; R! B, S3 S! b, l+ y
- if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
8 ^% o {; E% Z) l - {) T4 k$ `( L* V3 P0 d* M! P/ B% A
- while(1);
7 l* G7 B, t6 a* G, m2 [ - }9 E4 X/ d- S7 d" }! G3 Y
- if(f_close(&SDFile) != FR_OK)7 D( N" @( T9 t& n/ _. z
- {: {. M& K: s" I8 Y
- while(1);$ f. d6 Z- n$ e& C4 V% M
- }
' z' o; r4 z; g2 z* T5 k N) Y - }
复制代码 ! S7 r; P, J* e* y+ h
SD写入结果:8 Q$ L1 Z+ w$ c8 f x
% \! o J/ y) J5 R
0 y; S# p+ K. S# L$ b) h; o6 _3 e; c( J7 L+ |+ ?
5 e$ G& t! A4 X$ v! v' U, Q
|