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

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

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介
' M. I- E$ m. [7 A) @/ [% Z) @最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。
0 Q& g4 \5 R5 A+ e# F3 |1 v/ p# \7 [5 S
STM32Cube配置0 U# Q( X+ e, q- v
Pinout# s  F- A( _! t3 M

% A+ t  o! s  s3 M& M9 U5 q% {2 s
20180521180114826.png

, ~0 r) f+ x7 K" k* a5 [- s
: \8 H( e$ }, r) ]
20180521180129690.png
" n: g9 Y4 |" `! x3 A) r3 h& b

7 J* w+ q1 h7 Z- _" H8 `只需要注意绿色部分的设定4 ^; H( _8 a* q6 _
- |" a1 a$ T& K  Q
Clock配置. A5 C- k4 q  H0 B3 R
20180521180815759.png
# p& w  Z# E4 l- p' W
& T( f( u# D4 L& x- B2 R! O
这里使用了最大的Clock,SDMMC1的时钟是48MHz( c4 ]& j$ u% ]+ \- _) j" O

- z7 F% A! ?5 u) K8 QFATFS配置' {& Y( x9 P* j5 O9 C% \
* W* D+ G6 _; g
20180521181353894.png
3 N- E/ T5 e4 m, g
2 O% b1 q2 h* O8 _
Freertos配置
3 I$ D# N) `& @" f! n7 s1 C- r' [9 Y. R9 T! E) ]  W
20180521183255134.png

% {) _- t/ K' [% |: G
3 z( e0 G% D( [1 j& T$ O这里增大了Heap size,使用了heap_4的内存管理方式。
. W5 u# x) f+ F: V$ l5 }5 j- W9 C. N& U
SD卡配置* t- s' E, N8 A8 k, F, G

; }2 v, [" ^/ A9 t( p6 B
20180521183527404.png

( @- U  Q# X' C: s, }
' L. B. |/ m0 B
2018052118353658.png
3 i7 q$ O+ x/ \# j; J$ D

! E3 E3 R$ Z) b  T& C9 _. H6 G在这里打开SD的全局中断,并使用DMA2的方式传输数据
5 X) N) ^  j* W: ~
. ]$ v! E9 w9 K2 p2 c; tNVIC配置
, H+ x1 ~8 X% {$ i6 j1 `( m  |
1 x  `8 W1 b" d# G
20180521183735142.png

! H+ x3 c5 J* a8 A# d7 ]6 ^
& Y+ T' a4 H$ e' w3 L% FSD的全局中断配置为5,DMA中断配置为6,5的优先级更高。/ l: H% {, J/ V8 A, M

$ g' f  C, X. ~6 k9 Y  H工程配置
: a. f8 o. M# U# ?% }4 u7 j: Y0 h. a  v5 D* s
20180521184020944.png

! g4 ?& d* E8 r, y9 ]) b; {: e' l1 a6 F
20180521184028381.png
/ b5 s+ K) A% m

# Q+ L4 N2 l6 T, z$ j  c# L1 L* a以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。) }0 v2 V5 ?' p5 Y6 M/ H; M5 c

- I( n2 u2 {$ y6 ?1 W- k代码修改# @! ~5 {. g! ]: g
初始化SD卡
6 Q& U. }* i, v. w% d  _1 O. K" G- Q我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。/ e3 |9 g" h' B; ~  {) F7 m
  1. /* StartDefaultTask function */* e' Y: G. L8 I( w
  2. void StartDefaultTask(void const * argument)
    $ Y& j* p" Q) T0 e5 Q) d( E. @
  3. {
    ' `0 _3 y; R$ I2 `, x
  4.   BSP_SD_Init();# o9 B8 I3 y$ O! B$ w/ z; x
  5.   /* init code for FATFS */6 o5 F8 Y# U, u
  6.   MX_FATFS_Init();7 T+ d  ^0 n& u$ p
  7. 2 j2 X' U3 `3 j# I7 a
  8.   /* USER CODE BEGIN StartDefaultTask */) `1 j, p6 G$ w% I
  9.   /* Infinite loop */
    2 Q) X/ D2 ^" m5 O+ p! S9 P
  10.   for(;;)# U$ D" f* {! J
  11.   {
    $ G, o% e, ]+ ~1 F2 z6 {1 V
  12.     MX_FATFS_Run();
    # v2 \+ r" g  M5 L. J
  13.     vTaskDelay( 5000 );. `; Y- d: A, |) w4 y, O8 x+ G
  14.   }
    % G  K1 O* X. V
  15.   /* USER CODE END StartDefaultTask */! r. o( a. F4 l  \8 A" `
  16. }
复制代码

* I1 W9 r- B: }% [6 f& k添加DMA中断处理函数( f% Q* W3 ?8 B
stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:' v" z- n8 B6 X* Y
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
    % ?, Y8 Q1 P' J* e& l8 ]6 O
  2. {
    ; E$ f) x% e) Z$ O2 S+ z
  3.   BSP_SD_WriteCpltCallback();: G# n; ]: c0 W5 N7 O# ~$ R: r4 P# Q
  4. }# x2 e# w1 t  @8 e8 D

  5. 0 z$ y, n% o0 h* w# A* \& i
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)0 N* H. u8 }( V9 S
  7. {
    ) i% G+ E  x* c
  8.   BSP_SD_ReadCpltCallback();* T- e5 T0 M: f" q5 N# A6 \9 W
  9. }
复制代码

' q5 K; r; q! i: D+ X# U创建Queue0 ]2 D- H* f' l" T' e. `
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。
  p2 l: B' [3 ^; c1 W, C
  1. DSTATUS SD_initialize(BYTE lun)
    2 i# f0 |- [5 O6 T5 ~8 t- _! E
  2. {5 I! L3 u! s: x8 `& x
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
    " d6 v. o8 U# n: K/ m
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
    + k' y; i9 l: x; z( p  N
  5.   return SD_CheckStatus(lun);
    ! z4 u! s8 U0 v1 F
  6. }
复制代码

/ V" ^; l6 R6 s2 n( o/ A* {将Pin的配置改为上拉' n' k" \' b" e% C
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:& ]5 C0 p0 o5 n& ]& S/ r
  1.   /*卡在这个循环中出不去*/2 y* }/ M. R" e
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))" ?: X% z7 _! c; T* Q
  3.   {; I; r) D' g$ L
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))9 Q1 m1 F7 I9 L: d" C/ u
  5.     {- ?# @" d0 w3 b  d2 X* T6 Z! O
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);# D# U3 l+ ^6 _+ ]6 Z/ t7 r
  7.       index++;
    ' e1 q  Z/ m2 _$ W  _
  8.     }
    ' l/ D# ?. a. A" R/ x1 b$ O; y- @
  9. ! o+ t4 n2 Z1 d
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
    9 \6 y! h3 K% Q" t. ^  x, m
  11.     {
    * }1 f  v1 z, O( R7 G+ \
  12.       return HAL_SD_ERROR_TIMEOUT;
    6 i- s  I: |7 K' U! |
  13.     }, ?/ p' Y6 l, M
  14.   }
复制代码

* k8 C/ f) D  B. M6 i3 }, W4 H* a0 K后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
+ Y. }0 L# U; U5 i* G) r) V. l; t! ^" i! y5 h
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 : |1 e. K  p, G: u) d) m& o
  2.                           |GPIO_PIN_12;
    & s1 v3 y1 p# ~, p* y- d
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    4 i& X( ]. m4 J7 [1 O4 F
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;" m& b1 x  l- ]% ?1 Y- B7 G
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    # @5 E# `. l# i: c) [- j* x4 z- V
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    : l# J+ c- H: o5 r, n2 s
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    6 l9 \9 r" f* b7 |* b/ ]+ I3 A8 F
  8. 1 _1 n. ~7 q& S3 |1 ?
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;
    ) ~$ }. c( K/ L( {: G: s' K; U% K
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;/ Y  q' Y' u; d6 n
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;& _& L0 M. x, z: p
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    % F  \3 ^. q+ d+ J
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;$ a4 W  f4 T  w! H) _- F
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码

% B% B6 V9 A; f$ G简单Fatfs应用3 V8 \, M, @+ W0 R9 x. M8 j) X# I
  1. void StartDefaultTask(void const * argument)
    ( ?6 C% X. |3 s+ b
  2. {  D' K, G% J. ?' m/ O
  3.     BSP_SD_Init();; X$ `2 i( y# t4 R# o
  4.   /* init code for FATFS */- a4 K! E5 `( u0 A' L2 f
  5.   MX_FATFS_Init();  z5 k" _- ~: y2 X, @

  6. . L+ ~' ~: d5 d$ U  X! F. u" H
  7.   /* USER CODE BEGIN StartDefaultTask */
    ' I" W* s; m6 ^3 h7 }
  8.   /* Infinite loop */
    & W# O4 T  P+ J1 b* x- B
  9. ( p, ~: Z- W9 {# r' G/ I
  10.   for(;;): d2 {0 O, p# C- Z% U6 h
  11.   {2 N, g5 h/ p4 n2 [& _
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/( j1 l' p& {+ f
  13.     MX_FATFS_Run();: o* c4 N6 M4 b
  14.     vTaskDelay( 5000 );
    + k" m) V8 z5 ^4 J# y0 O4 x! g
  15.   }
    5 l0 d$ d% W, \/ ^' M
  16.   /* USER CODE END StartDefaultTask */% b, n' x5 u! g" ~4 W4 V
  17. }2 S3 o/ O, u6 t& @# e2 S0 {& H
  18. ! ?* x  j+ c  D3 i2 _) H0 W
  19. void MX_FATFS_Init(void)
    , t! o& T* f8 X& h$ ~: q. {. M
  20. {' k# g( q4 o% E, W8 ], N
  21.   /*## FatFS: Link the SD driver ###########################*/9 c/ n8 i$ F* ^, a" j3 j5 a# P' h) S; s# O
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);) R/ \' h: R3 Q, H  A4 W
  23. 1 Z* W. t: B1 M# D: I
  24.   /* USER CODE BEGIN Init */
    . N8 I. M4 B% _$ u8 \
  25.   /* 在Init的时候挂载文件系统 */     * R" P" u" {4 R4 N% S9 Q# f4 G
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)    R1 S% w' U) V* `0 ^% W4 m
  27.   {  
      Q/ x2 w4 S" z( H4 l- t' j0 ~
  28.     while(1);7 H5 _8 s+ W! `" X& }
  29.   }   
    3 K4 @% I( T$ \9 `. H
  30.   /* USER CODE END Init */1 V# n" U4 |  y  k1 ]. a- u
  31. }, ?2 O3 G- p0 Y% g
  32. * Q/ c5 R1 l/ a2 M
  33. void MX_FATFS_Run(void)
    8 @1 {* i' w# `' Y
  34. {
    . l$ I  g- y! E: |$ A# b  D
  35.   UINT writeBytes;) B% k& ]1 c0 B5 P1 m
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/& Z5 k0 u% o, N1 ]5 Y; p" i( V
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)
    ; h) K3 I; V# V  l
  38.   {
    # R- y$ b5 d8 F: P2 _/ @
  39.     while(1);* Z' Q3 |+ b4 q* u( n
  40.   }. O" g/ V8 z6 X" E8 [: @
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
    . T' J/ w+ q5 R; Q, p
  42.   {
    ( v% d7 r  J1 }8 G3 f0 [
  43.     while(1);; @) I# U4 s/ i0 y. o
  44.   }8 B7 @3 B! f) c7 `
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)% G, l) K  K7 R( R2 w7 S
  46.   {. Y8 }6 ?1 `; [2 X8 L2 @
  47.     while(1);
    7 j$ n, T3 x# }9 G
  48.   }
    & v9 E: h. @  W8 ^8 `, p
  49.   if(f_close(&SDFile) != FR_OK)
    9 ~1 h1 i" ~1 C4 y
  50.   {  {3 |* H$ H, ], X- z) r+ T
  51.     while(1);9 _" q1 `. ^7 L$ N
  52.   }
    : ^* @& Q+ ~/ |$ Q2 l7 v  n
  53. }
复制代码
7 c& @4 F. }0 [+ |  o9 c3 I
SD写入结果:, l+ K- @: B0 e' X. L

- u' A9 D; L0 W4 r& a5 r
20180521190454697.png

* U7 O, l2 o# d, q. l
& R) Z. g8 w! ?4 c+ A3 L; m" ?/ w( S! j1 N$ U# m- t0 t3 U  j# C
收藏 评论0 发布时间:2021-12-16 21:00

举报

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