你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】使用STM32Cube在STM32F7开发板上实现SD+Freertos+Fatfs

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介2 X4 b7 Z+ V) ~5 e
最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。5 \: F# o/ @6 H

7 Q! N* a& N+ y( h& I4 X7 oSTM32Cube配置
& z4 u& a% z* N* E! J2 IPinout
. J$ ?; k0 R+ c* I$ l' V/ V: x6 M; i" R4 l& Y9 F
20180521180114826.png
8 K/ J0 l3 W6 X6 g- J- l+ `5 d

" m; x: V( ?/ D) l* W5 x( z
20180521180129690.png

: j3 c& b% z6 O/ V9 W) C7 s5 R3 a
. A2 N) o  G5 U( ^只需要注意绿色部分的设定9 j' \6 H0 P: l

; ]; \2 J! _& B4 `$ h9 d$ DClock配置
2 ]5 h- Q7 C. \+ x4 J2 Z
20180521180815759.png
( @4 T! T% g% ]* [' ]) v
5 Z7 e* B7 [, S
这里使用了最大的Clock,SDMMC1的时钟是48MHz
6 T8 |9 ^8 L0 S
% C/ J, y7 z9 `* N3 Z* |& wFATFS配置
& {3 h) u" E! M/ r" r/ R* ~8 Y' E3 U9 c9 {: i) E
20180521181353894.png
4 z( b% k5 p) d. \

: C4 F5 H5 @. ^% eFreertos配置- |9 U9 h( }5 {0 B5 g

; E8 `2 F9 R9 v' H
20180521183255134.png
  r* d$ l" J! w0 |$ i; r/ p% ]

( p4 x' h8 o; r+ G2 \这里增大了Heap size,使用了heap_4的内存管理方式。2 S; j  h. ~7 K7 y

3 j. O1 t7 y) |/ n* e/ V( ^SD卡配置
7 j5 d- i& Z4 u) l( V
/ z. F9 S8 q- X5 O8 \+ N& ?
20180521183527404.png

& K3 A9 c* i( v/ k9 @+ l3 f
2 q6 x/ T8 x6 {" K
2018052118353658.png

: ^! ]3 `* q  D0 c! f
7 X- z2 u5 M& Z& e" [- Z2 ]+ l在这里打开SD的全局中断,并使用DMA2的方式传输数据' q( [( g, i* W5 u( {# @% x

) g0 @3 a. I& F/ @NVIC配置1 ?/ g' b6 Y8 `" m# ^8 `& E% n
7 c* R+ O5 p' n3 _9 I2 D: j
20180521183735142.png
8 G. T6 f7 p0 \: ~) D, c

" n) @) m. Q! @. S7 F5 ^8 l3 jSD的全局中断配置为5,DMA中断配置为6,5的优先级更高。
& D; @6 h/ o* W+ C2 b$ \  i# }  X9 Y, |1 {
工程配置
" |' a% @* n- x( h! n, b1 b% Q% a% J+ |9 c6 K6 D) t! b
20180521184020944.png
0 p' _; S6 ]. o  J1 K7 ~* X5 d
& a$ m. m; u" l3 T: }* Q( L
20180521184028381.png
( ~; [# k6 H5 {9 u1 }

% u2 V& c; x& g$ ?: [& l1 O  \以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。* |/ H' o$ x9 P8 |3 b. ]: }8 c
5 J, r$ x" T3 @$ T
代码修改" p4 [1 D, J' H" z% H
初始化SD卡
" l* [. `' T0 V我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。
3 E! q: ?! I0 ?  Z% `: [+ B6 }
  1. /* StartDefaultTask function */
    + b( r+ L& {* h+ T! B+ }5 N
  2. void StartDefaultTask(void const * argument)
    9 P( l7 t- }- F( H2 p, f
  3. {1 ?, L4 q3 U  z) y0 ?8 S$ d# I8 H9 H1 U
  4.   BSP_SD_Init();
    . m- y7 |% s- K0 _, K4 M
  5.   /* init code for FATFS */
    ! g% k7 A: X( Q6 V( f
  6.   MX_FATFS_Init();, u# C! M1 Z7 b; q$ @7 T) ?
  7. ; O! N- i4 n  t2 P- v4 y; K
  8.   /* USER CODE BEGIN StartDefaultTask */
    ; M  z$ i8 E. P5 P! I
  9.   /* Infinite loop */0 p& t5 W. q6 G. L; l
  10.   for(;;)7 B/ D, t( V8 `  L, d% I8 y
  11.   {
    , ]6 W+ m& M  F- ?3 ]) P4 F& ?6 o
  12.     MX_FATFS_Run();
    1 k! n- Y0 h6 A3 o+ L, G" D8 V2 b
  13.     vTaskDelay( 5000 );
    $ g0 B4 ?9 y* S
  14.   }
    2 F9 O! ]7 x3 Y- h) D3 r
  15.   /* USER CODE END StartDefaultTask */
    . r! W0 o% }9 e( ~& @1 k
  16. }
复制代码

/ G1 m6 e8 i9 G4 N5 o添加DMA中断处理函数
6 C8 h% @* x& ?, L1 o, U8 v5 ^stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:
; v6 Y% X- E+ Q& n8 C; B
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
    7 j8 b6 W2 t- }! ?# p
  2. {
    # X2 W6 l& d3 A3 E+ |$ I
  3.   BSP_SD_WriteCpltCallback();1 F1 ~! N9 K, J7 Q( R
  4. }4 j, z$ i1 m' D# C

  5. ' |( r* q( T" v0 S$ @
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
      ^0 k$ C: n0 ]' I4 U) {
  7. {
    4 R; \9 |+ d& _9 M- ^" a# b) F
  8.   BSP_SD_ReadCpltCallback();: O4 r7 a; L( p& ?3 V
  9. }
复制代码
! P% ^2 @$ d- Q) c+ \( R
创建Queue
3 ~  t# z) O, |# B2 ~4 ^在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。
+ h1 z2 Y; P1 K, N% A' V
  1. DSTATUS SD_initialize(BYTE lun)
    % m; ~& r2 @9 G, ^$ X7 p  Y
  2. {
    9 g4 Z6 e- f# e! o- x* D
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);4 \+ i9 k" d3 [( S2 P' r9 J1 H
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);& ]2 B/ i9 J/ n9 F
  5.   return SD_CheckStatus(lun);) M+ s) U. n( }4 D
  6. }
复制代码

! p4 R  h/ e3 {% P: q, {( w' F) k将Pin的配置改为上拉8 K& f( p% F2 v
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:+ D0 |8 C1 m" T9 q. Q
  1.   /*卡在这个循环中出不去*/0 D, P2 j3 h- l4 u
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
    ( J5 X% Q: ^3 _* e3 s
  3.   {* B5 _! T! L/ g  Q
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
    % j- [; Q: I: Y1 I0 {
  5.     {
    1 j. ]7 b$ S- V# g
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
    + l$ k" z0 R/ l. a0 e
  7.       index++;
    7 a8 W0 H9 _/ u8 v
  8.     }" c! i, J1 I$ ]! x: K
  9. 8 g8 y" Z( p; F3 y* t/ h
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
    0 X$ _8 o; N2 c. ]8 D: ~/ h. I
  11.     {
    * T6 w* o& y, C# j" _5 n
  12.       return HAL_SD_ERROR_TIMEOUT;, U* d  a5 ~" `
  13.     }
    + G" U2 L/ k5 I, R9 a9 y' {
  14.   }
复制代码

; {4 E& |3 c& q7 k- V9 z后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。5 S0 w0 C$ h* u- ^# S6 }  l$ {

! S- c% k: R0 F
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    1 g* ?! C( |: R& x% J
  2.                           |GPIO_PIN_12;! b  B& y* {( [. C0 G% p
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;" O/ G: ?! K' e' a% F
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
    , a% j* _5 x# r+ u+ \: ?
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;4 L' d2 u8 D% a2 }
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    " D( a  F8 F- H0 z# W6 I1 |- }* y6 Q
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/ C! X8 f; y; p0 H) W. y
  8. # w+ b2 o' q& Z- _' e6 j
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;6 s# t# A. i( i
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;2 S" _) z+ V7 U
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;" b: z$ C3 g$ Y: _
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;" j; O8 y" ?+ m3 q7 N7 w
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    4 U# U; j! j  y$ ~* \' ?
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码
) |, v! y( v. @
简单Fatfs应用9 \. u& X4 V$ C5 s2 T8 j% |( r
  1. void StartDefaultTask(void const * argument)* s+ `+ J/ i5 q, L) z
  2. {
    & H- Q% c5 O6 Z' B& @6 c1 z
  3.     BSP_SD_Init();/ g6 ^& `/ a( |  A
  4.   /* init code for FATFS */
    : v, |1 i$ W- t; ?& @7 I: A
  5.   MX_FATFS_Init();
    % v  P$ a7 x5 A2 }; R

  6. . v7 t" e# G6 y5 [0 S' K) @
  7.   /* USER CODE BEGIN StartDefaultTask */+ o- D0 A4 B8 t0 L4 V
  8.   /* Infinite loop */3 |0 Q3 m, @: O) n% b
  9. 5 B0 @! M% C' B) i+ C6 l" b7 a
  10.   for(;;)
    8 L- ~' Z" w# f5 W: p
  11.   {% {5 j$ C% `9 y* v
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/
    / t. T% }$ v# c& G
  13.     MX_FATFS_Run();/ m' O( ~3 z6 P
  14.     vTaskDelay( 5000 );
    5 ?9 W1 g8 t" I, d
  15.   }+ S1 M5 c2 l- E2 [# k
  16.   /* USER CODE END StartDefaultTask */' g$ N% ~- y/ ~' v8 j' p7 O6 w
  17. }
    ; Y. g$ Q) R6 C5 B# d( S

  18. ; j, ^  a5 n, D' G. d: i) s
  19. void MX_FATFS_Init(void)
    * f3 a$ E, Y3 t6 }8 g8 {, C
  20. {
    3 s7 J0 k7 M; l7 F% Y" m* ]
  21.   /*## FatFS: Link the SD driver ###########################*/9 f6 ]/ v! B$ T6 o# m1 b
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);  H/ x: w/ R7 n- \

  23. 0 _& p$ z9 [) `1 t
  24.   /* USER CODE BEGIN Init */
    ! M- {0 w- q$ Z: q: ?0 _0 I
  25.   /* 在Init的时候挂载文件系统 */     4 w6 B6 R) d2 U3 E
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)  - w/ G* B# `, _4 @
  27.   {  
    + d2 Z) ?% c- C- @) D$ s. M( T! x
  28.     while(1);% h6 X$ V: c) C8 o
  29.   }   
    ( ~5 Y; Z  O1 O" P. w: C# \! ?
  30.   /* USER CODE END Init */( X4 A' v5 l4 B- X- s3 ]
  31. }, A8 s3 P1 ~' H% K
  32. - w2 X5 q; |+ p
  33. void MX_FATFS_Run(void)7 h$ S+ S$ f0 K" O0 {8 Q
  34. {  a; f8 y+ C8 `
  35.   UINT writeBytes;" p* C' X4 S9 W" q) Z. _
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/7 C9 W5 [. c9 ]+ b5 b! Q
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)
    . C3 M, W( E( I. A9 ], O1 X
  38.   {1 @9 }% a2 o& k, ]/ |
  39.     while(1);
    * `2 U: z8 Q0 M, Z- U0 l6 }: `
  40.   }8 U/ d" P& J  I$ h0 y0 M$ Y1 p  g
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)5 @0 N6 m: ^. o4 O- p* g
  42.   {; n. g5 e5 I6 h' B
  43.     while(1);
    * i2 m% c* _7 s( w
  44.   }
    + H3 I, h4 \8 {' {, i
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)& O  j" f. m) y" w3 i; O. g) \8 M% Z
  46.   {
    ' i: G! q1 ]% d! |! |( }& r9 H
  47.     while(1);2 u( {% |! E9 v7 O, T+ `
  48.   }
    9 z! F! Y' E  F* }' D
  49.   if(f_close(&SDFile) != FR_OK)4 x9 t- c( d) ^# L, ]$ [
  50.   {
    % l* Q4 ~0 l' d, Q4 O$ a
  51.     while(1);
    7 F, }& h" m2 k5 ]$ E3 j7 u: i
  52.   } * [/ Y& z7 i8 g$ `- U: }
  53. }
复制代码

1 v4 a' ^4 U! A0 L% p/ D8 P8 @2 I! \SD写入结果:& n* o3 }' [6 i5 [
9 [! G+ x! |) U4 {2 l/ j! u' D
20180521190454697.png
1 H# m; G6 n5 M9 }& \
; y: a+ z, L' ^: L
- i2 X" H8 C% L4 Q
收藏 评论0 发布时间:2021-12-16 21:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版