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

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

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介: `+ }, y8 N" [$ y' C0 j
最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。
) ^' T% R5 M' `) D1 I& [* i+ R/ W" J6 U! S' T+ B) K$ H
STM32Cube配置
: x! `) n8 g8 R# T9 wPinout( h& w, s& g+ k9 g0 Y

4 ~+ X4 y3 j* u. D; Z
20180521180114826.png

3 a* }5 P0 h! F7 d$ @
' J6 ~- V! y6 F! G2 w5 p
20180521180129690.png
$ o3 ~& t$ c. u! d5 u

% e* I& V% d! c8 m6 I+ I只需要注意绿色部分的设定
+ U3 W1 _, J5 M& s) L5 w1 x
; n9 ?- h9 B. Y# t9 u4 S: J2 D) dClock配置! C9 y2 B: Q8 o8 `* N
20180521180815759.png
% c0 A* J$ A: `0 `7 k2 ~
0 Q; Q5 P; m  a2 n
这里使用了最大的Clock,SDMMC1的时钟是48MHz. `8 F# L2 ^$ y  L- e9 p
, [4 Q) [, e2 Y
FATFS配置! F' r. F( X  v! t7 Z

. D3 V3 F2 P  P7 |* z5 h
20180521181353894.png
7 l' g6 T0 D& z9 p$ g; y

& I+ B9 W. c' q' A5 W9 PFreertos配置1 x0 \' ?3 f# g3 H, a
- X' c# E& f( s/ o7 g' X% d
20180521183255134.png

2 S' B; {' i1 S9 o. _; a! D8 U* A+ {9 H  y& _
这里增大了Heap size,使用了heap_4的内存管理方式。
$ C# z' u) H; V% a$ x( Y& c, }2 ~' K8 M" S2 w
SD卡配置/ c6 |) P7 S  h6 M

4 V! X7 x# F2 V! G: K8 x. `
20180521183527404.png

* m5 `( e2 F( R, c# n% `. P6 i& t: w6 w( P2 I5 _; m% M2 Z2 d; h
2018052118353658.png

, {6 q/ r6 ^* L/ g( ]" `
8 i! b8 y( f7 R+ W% h# Q! a在这里打开SD的全局中断,并使用DMA2的方式传输数据' x2 t8 ^5 R7 g" l
1 h5 b# w% D+ C# q7 \5 w$ Y
NVIC配置
) |; `3 B6 [0 a  F* u1 `
2 ~5 ?& N4 C/ X- k1 P6 ?: M7 v
20180521183735142.png

+ K! O, P9 T& f* z' Q- n) q" ~1 e) W5 [- V# U9 o! u
SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。
& {/ p1 ^' Q: E2 O; M
3 A' k7 |0 v4 C) h5 g$ m9 c- r工程配置
+ x' o  {# @: Y; p% M" q; ?0 t9 W# o6 T. \: Y
20180521184020944.png

' Z% ]3 y/ h" C7 N( U5 x0 h) `& m1 N6 E% O( j
20180521184028381.png
% I- D. G5 d8 l  J1 c  V
& L& p1 V! i: w! R- G
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。) h  `+ L# m. H$ o, {: [( |

$ G; V( y7 _& O: S1 \代码修改
6 c' g6 c9 n4 a4 C; ~, ^4 g' e初始化SD卡
4 D- `+ E: ]$ c2 }我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。
+ g4 U  C6 F8 a8 b
  1. /* StartDefaultTask function */
    - ^+ R. k( B" v% Y4 r
  2. void StartDefaultTask(void const * argument)
    2 |1 u$ P' p, b1 J* H* _* K
  3. {5 S4 m; m4 x7 O2 i/ h  p! [1 I
  4.   BSP_SD_Init();
    8 f8 B  \# _( p$ B6 R
  5.   /* init code for FATFS */
    : |# J8 }8 i0 [* o+ `/ {
  6.   MX_FATFS_Init();. u% Z$ d7 k) N& H

  7. # g& S. ^, B2 g
  8.   /* USER CODE BEGIN StartDefaultTask */$ B# p$ O: Q; R; L9 g1 n2 o
  9.   /* Infinite loop *// C( D* U9 ?1 m* n# c2 \- i
  10.   for(;;)+ F* ]$ K# z1 L5 e1 ?, \) Z1 v
  11.   {
    % ?) i; O0 f: M
  12.     MX_FATFS_Run();' h* a0 Y/ A3 }; W  I# q+ S# X4 H
  13.     vTaskDelay( 5000 );
    ( s6 A" j: ?! Z5 l2 v
  14.   }
    , Q8 _! F9 a; Z/ H! k
  15.   /* USER CODE END StartDefaultTask */
    0 `7 M2 }) Q; T( a- {/ V4 i, J: ^
  16. }
复制代码

" [+ S8 B% ?" X# Z5 E: F7 O添加DMA中断处理函数
/ Z- `7 q) R/ ]/ g% c- S6 m' Cstm32f7xx_it.c文件中,需要添加下面两个中断处理函数:& d! G3 _$ G! F3 c- L
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
    1 v/ V) v% x- u8 o' o; E
  2. {% e, ?$ o, X' s! `$ ~  Q
  3.   BSP_SD_WriteCpltCallback();& c2 Z# r! ?4 x* m- ~
  4. }
    & L. y, s# U# c; I9 l' k6 b

  5. & @, N; r# T. k7 @" n) t
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)  @: n$ W) y9 r( b9 R2 G# i1 o1 P0 M0 r
  7. {; G* b# ^4 G, g4 _+ O
  8.   BSP_SD_ReadCpltCallback();
    * W$ f+ S) w$ B; Z
  9. }
复制代码

# K5 Y% E4 X: H% M创建Queue* H0 }( P% i" P- v  C1 ~& T
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。- J& R# x. v4 B' T: v
  1. DSTATUS SD_initialize(BYTE lun)
    : T* A% }, }5 u+ s% m3 q6 x% ^1 ^( `
  2. {+ v6 I; z6 R* L, |* t
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
    ( D$ h  _6 V, h4 Q  @8 U( w
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
    , _0 P: m$ H7 @/ o3 @6 p4 ?' w
  5.   return SD_CheckStatus(lun);/ N2 {, H9 `; [4 Z
  6. }
复制代码

" A* `6 i  E% t; U/ P; m将Pin的配置改为上拉! ?8 b3 q' Y9 h% j& R+ e8 g
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:. ?. E8 [* \6 @
  1.   /*卡在这个循环中出不去*/+ O. J' ~% B5 h
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))/ t% c/ r( n6 Q+ B
  3.   {
    # S$ V0 i/ k" g0 m" H
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))8 t7 ]6 ]) ~1 I/ B- L; n/ S, M. ]- [
  5.     {. Z3 N. T% L& ^4 Q
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
    " x5 _* G1 B" |( n
  7.       index++;
    ; n( k$ R  e! [" O
  8.     }
    " d3 p8 t' V7 V/ l* `* c
  9. 1 V# P% U- b& u* \1 X- ~
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
    % h* E" K+ s' U
  11.     {
    * _8 r& b  s' q" }
  12.       return HAL_SD_ERROR_TIMEOUT;
    % L2 M$ ~3 S% h! B0 s: @
  13.     }
    8 [3 T) m; d8 \4 g5 h; [* k
  14.   }
复制代码
8 g# l+ h  J8 B) L3 ]
后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
3 }6 J1 g& R8 s2 {
6 u$ s+ Q# k6 h
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 # o: D% U# f. K+ ~* l% b$ C  x
  2.                           |GPIO_PIN_12;
    7 R0 G# F4 k4 |8 s6 r1 T
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;$ y1 J' s% ]; n  W9 n: M" M
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
    , B8 N6 X3 g! I- i+ g" `) B
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    % A2 c! R% v( |! C' H+ L, b
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    $ ^, c' L5 O4 q2 \& m# ?
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    & G8 N% c% H; B" ?

  8. 3 o5 \; @6 ?* [+ }# ^! k! w/ e* a
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;
    # ^' |6 k  a, A, I3 {# J
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    6 ~) S1 v  ]  g& h% e# V
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;- r2 K  r! E8 e  p
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    & F, g' d0 i7 l6 F& D  ?
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;) _9 o% D2 `) j/ ^0 T: D- Z2 `
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码

; B0 k( @9 b; \& Q# L, v简单Fatfs应用
" L  {8 I6 x( d' m4 _
  1. void StartDefaultTask(void const * argument)( g+ S( i) \7 N6 W5 ^5 x& j; e3 h
  2. {
    9 f- V  A/ I) o. c; ~
  3.     BSP_SD_Init();
    ; C' t, P5 `: k3 R" J
  4.   /* init code for FATFS */! z6 w2 A0 _6 c" M1 a0 b
  5.   MX_FATFS_Init();
    3 M4 N1 v# ^: L4 _! g, w. a

  6. 5 `- _: q! E! i% s) e% b
  7.   /* USER CODE BEGIN StartDefaultTask */8 P/ W1 i; S4 d1 J% ^5 O0 E
  8.   /* Infinite loop */, [& Z& x( T% a8 ?* |) M
  9. & `  ?7 \7 j& S' i9 q# E0 _$ p
  10.   for(;;)
    * `" h5 n0 {6 T! |2 T8 @& J
  11.   {7 m0 a9 M8 J' ~/ ]3 `: c
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/9 |/ `6 D8 p6 y& Y. Y
  13.     MX_FATFS_Run();7 [) S8 l. L0 e5 p4 h* y
  14.     vTaskDelay( 5000 );: ~/ [7 Y/ Z* u1 z
  15.   }& N5 v2 J  |! U3 x" J& L( c2 v
  16.   /* USER CODE END StartDefaultTask */
    , ~1 o3 [( T' d
  17. }
    $ c9 L- c4 Z% Z, @- \3 `
  18. ( J- \& K# e9 S# b. U6 D8 T
  19. void MX_FATFS_Init(void)
    , I- \3 {0 D% C$ f# |+ s8 H. a
  20. {4 \$ w2 j/ _* b( e% K4 m. `8 d
  21.   /*## FatFS: Link the SD driver ###########################*/
    , Q% Z- c) [2 _9 A/ B: e
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
    ; W% i+ m7 J, x
  23. ( Z4 E/ A7 V3 z1 r& l
  24.   /* USER CODE BEGIN Init */
    ! c- n+ W1 \# R+ f) z& m* S
  25.   /* 在Init的时候挂载文件系统 */     6 C, x# b% ]9 y
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)  
    ! }2 _! s- }8 |& n! F5 Z9 X
  27.   {  $ Y* E# a4 K. V  ~- y, Q: S+ N3 E
  28.     while(1);
    , y% _: u! f2 K& ]- @
  29.   }   ; f* e, x! D0 \" t( [4 m
  30.   /* USER CODE END Init */, X5 G9 C0 L* d9 @: K
  31. }" \2 @* X/ O' U# v) Y

  32. & F' M9 a. |! ^! ^* H, K7 P" c/ P: S" |
  33. void MX_FATFS_Run(void)
    ! V. A; `* z! d- v7 g$ [4 N  e) V
  34. {. S% x8 G; g& c8 x2 Y9 w. U
  35.   UINT writeBytes;
    " \1 q4 n# g; H. D7 G
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/) M+ ^5 L( k  G: q& c
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)) a  }% J7 R4 ]9 i
  38.   {6 ?7 N6 I* P2 @$ E# x4 x2 }8 g
  39.     while(1);
    / F; l4 L6 v8 ^  W5 R
  40.   }
    ) S( ?6 f& K! Z
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)- j# z; X) N! p
  42.   {- Z% K  \- b0 }  Y" ]
  43.     while(1);$ c) G9 A( D& w! R
  44.   }* S$ _  S: Y4 c# a) D) M" a* Z
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK). \; z  k  C. I
  46.   {
    9 i- O2 u( [. n4 H
  47.     while(1);
    ! _, g1 d5 c6 W. t+ _% n! W
  48.   }# z$ g) Q, z% Z2 J# s/ a
  49.   if(f_close(&SDFile) != FR_OK)) S' }/ V9 G2 t- Y2 Q2 S' G5 [
  50.   {7 R$ C: a' ?% r% B# |6 C2 W# B5 H
  51.     while(1);2 D8 G0 j/ m8 f7 B; U+ m& N: o
  52.   }
    % V4 i' }0 B4 _8 C& B. u) O( G5 N
  53. }
复制代码

; X/ Z4 X) {/ q$ I9 @SD写入结果:% x+ G  q/ d! f' f: @- g
! O  }5 b( E) H2 ^
20180521190454697.png
( p! ?8 h  C% B; T- U8 ^

; A( p& G! F4 q" A& _3 e  K
! ?9 A& J" _: [' \- R
收藏 评论0 发布时间:2021-12-16 21:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版