简介
0 ]: p$ O" }! d6 h8 F/ d最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。3 P6 s/ c4 F- j; c
0 A# |6 D: R4 |: u- f4 y! D
STM32Cube配置) e2 \6 r1 w/ I! H+ L$ e. q
Pinout
: ~1 B, R2 F- r5 x" S( c) ?; h4 x: X) i# `! x; C
9 B& o1 d, A( Q7 Z; i% r5 F
M8 w& G5 i# _! ?8 z" p* K8 T& ^( I) B, Y' _; P
0 g, @1 G, @! t, M4 Q只需要注意绿色部分的设定
4 z3 p1 I: o/ h4 U5 G/ s' z* @% q0 w( a' q. L& t3 l1 \
Clock配置4 e: ~, K5 y' C; F" A
1 y* t6 p; t* S
! o- f% h" x( n: v: q这里使用了最大的Clock,SDMMC1的时钟是48MHz0 a! H+ f' V' R5 d6 o
* q" Y4 l8 \% Y2 {+ d6 o1 tFATFS配置0 i9 k+ S7 {0 r3 ], X
" Z. [; i; E0 V
3 z2 k* W2 L2 O, c
5 B" [9 t, e) v) WFreertos配置0 o" [8 o, g, b1 Z1 a
5 A. X; q! ]- }4 l# r. ^
4 `; ~) ^: M0 k8 O5 A+ n( A
8 j# D$ y9 H+ m2 `9 b1 z这里增大了Heap size,使用了heap_4的内存管理方式。; g! J( D5 f- w1 [: U
% `5 m1 \9 q- a( H' `/ `
SD卡配置8 O& ?3 ^) @' b2 J4 Y
5 H8 {, r* C; ^, G/ A/ L2 @* ]4 i
, {% K* Q" v5 ]
- b9 H; x( y; k; e3 T# ]( w( {# c$ W! W, o
$ _' L( y. [. _) Q% O9 R# A
在这里打开SD的全局中断,并使用DMA2的方式传输数据
4 P7 I% \4 f1 B$ X
+ A; O' o" I- n: y: ZNVIC配置
7 J4 r# `* L7 K: D1 E. D
3 v4 F* r3 }: J/ t* o& h, L: R" {
+ Q! i1 \5 { V
, q( `0 t- Q) P# @4 ?SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。+ \( o: [* C' o& [( | j
- ?2 h- d9 C7 O8 M6 v7 b
工程配置3 w$ x6 D5 ^: c0 t" r2 `7 s" s# Z. N
! ^ Z( C4 K! ]( ?( f/ I" N2 M3 i& w* O1 s/ a t2 E3 @: t7 x
? H8 o1 q* d4 I& X3 }+ C" R
+ ]' d6 ?, k0 G% ? O; @, Q- ^4 ?* v5 s
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。
1 e8 t" `9 E' c. B
4 X4 g: T3 J# ?; w: |* y代码修改
1 y' L% H0 n P/ m" ^0 X初始化SD卡
6 a5 {, P1 a( a3 b我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。- t" z! y9 M/ S$ }; o
- /* StartDefaultTask function */
0 N9 S- @ r6 F0 b) V$ x6 U0 _; L - void StartDefaultTask(void const * argument)$ A' z& q9 N y$ W- g% Z" s
- {
- w. L {( K }4 L - BSP_SD_Init();
6 e d& i/ V' L( u0 d [9 F5 w - /* init code for FATFS */1 l5 T! N( H/ ^0 w
- MX_FATFS_Init();# g. e: Z1 u& K
! ?+ [1 ?0 i4 W4 I6 i3 B w8 H0 e- /* USER CODE BEGIN StartDefaultTask */7 G: ^3 X- |: ~3 ?1 `
- /* Infinite loop */
# ~# Z/ l( d& P! B0 I - for(;;)
A4 c6 E5 Q5 H - {
+ r& F- ^& K' K( o$ {/ k Q - MX_FATFS_Run();
- ~, _1 U; f! r$ X* H - vTaskDelay( 5000 );
) z B& F7 ?2 u3 K: r; ^) D - }5 s+ }* P, s* W! P3 z
- /* USER CODE END StartDefaultTask */
5 \1 f; ?& G0 W - }
复制代码
! i, k- y5 y) I2 y: z% y添加DMA中断处理函数3 b/ f" A, ~- @) Y
stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:
6 L' w" d$ X3 j+ @- void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)* W; [0 o6 } A
- {
6 m- y% D* N5 b- Y3 b# f4 z - BSP_SD_WriteCpltCallback();
* z! e( L6 X" k5 J - }
/ e3 }% K4 x# Y - % }* u o r! Q3 X
- void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
. L* x/ V8 F, ^$ v8 M5 b - {- l+ S& C+ t7 C+ Y
- BSP_SD_ReadCpltCallback();$ t1 v6 i( v( [) h; B) B" o( `
- }
复制代码 8 b; ~' f3 V# {9 [! B0 q
创建Queue# d) w' i; W6 d" h+ Q0 F0 R
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。) m) s+ \( K3 e) ~& Z2 h2 ~+ L! u) m; C
- DSTATUS SD_initialize(BYTE lun)
$ \2 H+ f! e/ g( ?: s/ ?) \ - {0 [9 T7 X. _0 Q( W* T5 d3 L
- osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
( y! K8 B% @3 e( r" r - SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);# P) ~& z# u/ X; }/ @) r% T' A
- return SD_CheckStatus(lun);
. [. F |% X3 l3 r! i - }
复制代码
' B, P6 e! j' j/ {将Pin的配置改为上拉
& h2 S: l4 r0 s在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:
2 Z* t f6 M3 E- /*卡在这个循环中出不去*/9 a) P0 H5 ?$ B- Y+ p- r
- while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
; P: H; H8 W; c - {
/ C6 m6 m' s( F$ r8 A) d - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
, x. {/ H/ X; Q! V4 u) E' A! }' s - {9 z; S* j/ m( ^8 b
- *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
- m' W% o" }1 N9 l9 U% x* r9 v - index++;
4 [) {% n$ G7 w @, g - }
9 E) t+ D' \- o
6 }9 \- B- C; \; V- if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT)
/ Q4 c6 B5 w; [; h# D8 l, L& F, ~: y/ G - {8 q4 C8 p D& g1 \3 u2 M( \7 F
- return HAL_SD_ERROR_TIMEOUT;/ ~+ \3 J3 E$ x
- }
! `5 m1 [) P J- N9 E/ { - }
复制代码
" N9 {6 _( s$ X- m; x( L! w8 q后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。# s0 C$ e9 c# P, p) B9 L( T8 r
' d# Z4 B* @: X6 ~4 U; e- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 1 C- x6 C) T! ~' L9 A
- |GPIO_PIN_12;0 c- `( h9 }$ R; n
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;% ?$ F8 V) R/ h1 D C5 D0 |
- GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;4 A; I' ]' l8 P" h3 `5 `
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
& N& S1 u8 @# |4 q: I# M - GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;( b/ c, f9 f* n! L8 y1 B
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);0 w% R0 C4 p. ?5 A& N
- 3 J# \4 V) s! _2 {$ h5 m
- GPIO_InitStruct.Pin = GPIO_PIN_2;# U5 O3 Q' {/ ~
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
( L q: |9 F8 T2 g; ]' A - GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
4 |$ o: ?6 E$ [! \! j: k5 j/ F - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
* g% P }8 {5 x - GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
: a3 A9 b0 P' G4 z" r - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码
2 m y; b; S @5 s* \+ {6 |3 V简单Fatfs应用; G' P: [7 ]$ ^9 D
- void StartDefaultTask(void const * argument)+ M. c$ L6 |9 m
- {+ c4 L( x' \! o- [9 K ~4 N, O
- BSP_SD_Init();
+ |- k2 ?4 ]2 C, w% t - /* init code for FATFS */4 O9 I1 Z' ]' r* _, \0 w
- MX_FATFS_Init();
5 v# }) L* r- h' }+ V
' B% m* Y3 [- F# N7 o5 `- /* USER CODE BEGIN StartDefaultTask */
5 i5 ~7 U) G# @! F4 J9 v0 ~ k - /* Infinite loop */
2 m5 z! d! w& W, ?
* [0 H1 v. d$ O1 U. K% C9 E- for(;;)
! k/ d$ M* q! c( ]! w+ e* Z - {
5 u. P" P7 O j - /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/6 w" ^6 P1 k; l; Z
- MX_FATFS_Run();
- ~+ J0 I; n# y( N - vTaskDelay( 5000 );! }1 a- T- L% I4 z
- }/ e# _/ \' B: r9 @% U5 V/ s
- /* USER CODE END StartDefaultTask */
) N0 K" a y& V1 W, R& Y% L, D - }
! ]* x5 B/ w) _6 H# _' h - 3 }1 h% C7 O, W4 T* ]% L" y
- void MX_FATFS_Init(void)
3 E [4 H! l Z5 C2 a - {
$ J6 ^, Y' ?# M* [- {. ] - /*## FatFS: Link the SD driver ###########################*/# j6 S3 G2 h+ x& l5 [$ V
- retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
3 o* R v) X3 C9 p/ H: l+ S: w - $ G+ H6 c/ g4 t3 T* p
- /* USER CODE BEGIN Init */% A! D. p4 P) b7 S
- /* 在Init的时候挂载文件系统 */
0 [9 p' P! h7 ?: l% O6 H - if(f_mount(&SDFatFS, SDPath,0) != FR_OK)
# R8 B+ S; O2 ^ O. ]# f - {
2 v/ D+ {7 f$ y% c - while(1);
! p, h _( V, ~4 F - }
& H: K+ P ~1 r$ q/ s - /* USER CODE END Init */
: Q; m8 [6 w: J. ^- `, w* F - }
) u0 f% @1 Z$ x! C - & b* b5 _3 d7 t- {- x2 e4 `1 d" l
- void MX_FATFS_Run(void)+ Q9 m4 V$ U, _ g# ]! F
- {
9 h7 n) A' K2 [ - UINT writeBytes;
1 V; y: S+ J, j! v# L. B" o - /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/+ X1 D8 ]/ _, |4 o: H
- if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)' U# I! z: q6 T/ b+ Y
- {2 I \: Q% d" }0 L, g
- while(1);
/ {! M' ^6 K _& A6 G - }7 a3 J% A# P3 q) h$ n! J
- if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
' ?1 S0 ]* `3 r, P* r3 C2 X - {
/ v7 _: P6 M1 \+ ^1 o, \ - while(1);+ }/ \% C. F% Q
- }
" b& ]; n( `" B9 o* w - if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
) |9 V! _5 q B - {- D/ Q% E# W6 Z% b' a
- while(1);
2 ^& }/ v3 }3 @5 K) J5 l4 v$ C - }
6 c) B3 u# g* q - if(f_close(&SDFile) != FR_OK)
5 D- O/ P2 P/ v! N4 h/ E5 ? - {( p. W/ }3 s* `* C- e* d
- while(1);5 I: B+ t f& @! M; F/ ^5 X
- } 3 o: z. t# s: V- y# ]3 G
- }
复制代码
- U3 \- q/ `* M( W \9 B' DSD写入结果:$ ^4 z; r, y4 c% \: s, V; v
; Z0 H5 R% A3 _& L& L, U
% J4 S7 f1 b( b- H5 l( q6 M8 K
2 c% ?1 J; e9 k; L% |; b8 E8 f% _, y& ]6 t
|