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

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

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介
6 Z) U6 I7 }3 ?5 R1 z最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。( X# `  i3 K& |! Z( A

( P. b# q) U9 P4 m" Z2 V! x( TSTM32Cube配置) I$ N6 B. E8 ~# s
Pinout9 H: q- d& b3 `+ N# Y! D1 |

& @& N5 P4 |) N3 N; j
20180521180114826.png

+ Z8 Z1 z/ z3 {: i7 d: }/ x- V( i
20180521180129690.png

/ E/ c5 z, o9 l! P* z  }1 s2 o5 w5 y% q2 e
只需要注意绿色部分的设定7 `9 t% ^0 F3 @" c& ~8 ?( r

+ |5 B$ r7 ?% C# J8 \3 }Clock配置
" ]. w6 W. Z8 J
20180521180815759.png

( E0 G; E# @* u6 l+ W( w* T
, O4 y- @: m3 p这里使用了最大的Clock,SDMMC1的时钟是48MHz  C7 V+ E. x) \' R, f

# E6 z& R9 ]" b* `FATFS配置9 ^2 O+ ]) l$ v& [+ S

2 r* e" i2 k- k: B( A; W3 p
20180521181353894.png
. O( \) {5 `5 ~- S5 z* n2 x* p
: f* g" |* d8 B* u& O
Freertos配置5 X" \! {- G( Q7 i, M
$ b! h( Q5 z+ z9 o; D
20180521183255134.png

- ~: b. J% v8 ^) H3 h, C1 H' D1 v. N1 j. J6 ^) i1 P5 i$ F2 t
这里增大了Heap size,使用了heap_4的内存管理方式。5 ~1 }* ~' T( L7 r4 V

- M- b+ i% D* W+ u8 V& ]& ASD卡配置
2 s  L. O3 v" T% c+ K# g& z0 @' d3 C
: ]5 T2 B3 x7 z0 K# X  A( ^& Q
20180521183527404.png
4 |  m; }% @3 L
) D9 y  f0 T$ B- P* v3 g
2018052118353658.png
. d9 n; u/ v+ \  w

) ^1 f8 }) q7 K& s: C$ C6 \在这里打开SD的全局中断,并使用DMA2的方式传输数据' ^$ e9 J6 n9 h6 I
4 a* P; \3 u1 r, Q4 n- @
NVIC配置
! K/ T( s  P3 W) }% m5 [* f8 B6 Z" o* Y
20180521183735142.png
' a" X. K+ m) _' w+ u
4 K( |$ Y7 k8 z: @  @1 u  ?, L
SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。/ D# o) q$ X# ^7 [3 R9 N
5 W3 g4 O1 |$ P1 _
工程配置
, Y- O; _8 a: G; `% v1 Q9 |. w
6 [3 ]& m8 q# C! o
20180521184020944.png
% U% e2 [3 X+ K& S& Y) M( l

! j, Z! E0 R3 a0 @! t
20180521184028381.png

- L. t9 |- n/ [$ X9 \+ W
" O% M% Y' a$ C以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。$ K8 W- u- l. r/ Z/ {; [& y

) z/ E4 w$ R5 M代码修改3 e/ n2 l- O0 d' N7 c' h4 m9 C. v; i
初始化SD卡
* b: o1 @( n1 `9 p! {0 I我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。/ g# B+ f  T- F
  1. /* StartDefaultTask function */) h; |' `( r, K1 x
  2. void StartDefaultTask(void const * argument)3 q6 ]- D$ |  G9 \8 e5 C. \. V
  3. {" q: _$ I2 S$ R3 Q% L' z
  4.   BSP_SD_Init();
    3 [/ U: `9 E" }& ]+ h+ x& a
  5.   /* init code for FATFS */$ o* i) b; _9 r$ r- q3 B
  6.   MX_FATFS_Init();2 @2 Z. M$ u, r! Y# C3 l" u6 a

  7. 1 Y* u- c4 J0 H; h
  8.   /* USER CODE BEGIN StartDefaultTask */' u" K- M+ v8 t$ @8 T# \) [
  9.   /* Infinite loop */
    ' E& P' n# V, S# Q  }
  10.   for(;;)
    + s* ~  k1 a7 d1 }$ p, Q- Q
  11.   {& f7 U: X; c5 J8 t
  12.     MX_FATFS_Run();0 U  R. e* q7 o  E: n
  13.     vTaskDelay( 5000 );
    5 @' s8 {( c, B0 u
  14.   }
    $ n' @1 d- m. P9 B% ?
  15.   /* USER CODE END StartDefaultTask */" l6 d# u; m% n' O) {0 ^
  16. }
复制代码

1 F# V- C* M8 U" E' K- \添加DMA中断处理函数
9 i, I2 X; m. J1 ?stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:! A2 A- {; y6 K( ]3 e
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd), m- b; W: C) E! }' H
  2. {' f8 D( _" Y- z- E) U
  3.   BSP_SD_WriteCpltCallback();
    + B4 Z" @: r& r4 u7 U- {; ?
  4. }
    + {% x5 [5 J9 ~- N! M
  5. 2 M7 D' G! Y7 e
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)7 U" w+ E% k3 ^4 J' ?
  7. {1 A; R. S& V' f, E, W" a( P
  8.   BSP_SD_ReadCpltCallback();7 K: |! k2 ]1 c) ~- t0 z9 z9 s/ n  n9 }
  9. }
复制代码

2 p* H- a$ W' @+ K创建Queue
2 k- |* K) k, Z在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。' g# c: P- y: E* |8 L
  1. DSTATUS SD_initialize(BYTE lun)2 w* G2 N+ |: |  [, ?
  2. {
    8 t% [7 v3 b1 @% E9 F
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);5 F5 h/ t6 U5 }
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);
    7 M6 e# n4 F3 q' q
  5.   return SD_CheckStatus(lun);. g( ~, j$ Y1 D7 W' S: |
  6. }
复制代码
" z$ K) z( p- T5 B/ K
将Pin的配置改为上拉' g% v8 y% O' R- {. l2 G: V# ~! e: C1 h
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:
- v4 Z2 i$ q5 V5 g4 e4 u! z
  1.   /*卡在这个循环中出不去*/" n+ N8 h! j8 n& @! R
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
    , ?9 P: g+ j3 n  w2 d% H
  3.   {. E% l& F1 \' X7 P* h$ Y2 O
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
    3 D6 t' n  F" O; y
  5.     {) ]) ~. y, r0 U; x- I+ K( L  T+ A. d# W
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
    + A" p' H2 R* P& z6 H  [
  7.       index++;
    ) O8 ?3 ~$ |( M5 R  W$ ?
  8.     }9 M+ Y: {6 R" x; {. t4 b
  9. " A* j$ N* Z: }9 l# r& n; Y; t
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT). ]) Q$ t! _4 |* [/ s/ [' `
  11.     {$ k/ {! X. r1 q, L
  12.       return HAL_SD_ERROR_TIMEOUT;
    & s! n5 x) b1 m, l+ y4 E
  13.     }
    4 I: Z" s) K! C4 p  Y, x
  14.   }
复制代码
0 \# l8 O1 z3 s: f
后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。
7 b* b" b$ D: ?' @' }& d' ]$ o
% [# {% L) {( j* @) _/ g' `
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    6 B) A! h# C0 b+ I
  2.                           |GPIO_PIN_12;
    + \( U- `& C. L; M* k. O, U7 V# R, T
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;9 {6 j$ ], C/ \0 U/ a1 A' s
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;& y% N' {. K2 z2 P
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;: n6 w& k. ?  b3 b" {* w
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    ' {; s' s  K8 L% _8 I
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);. }6 @$ E, m$ ^

  8. - p4 Z. q5 i" f4 C4 d5 I
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;
    - q: W0 m" S4 c& z! o
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    / X8 ?( A# \: t: x: p* j( j( r
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;8 F, h9 i. t" X  V. p4 o: l- Y
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    8 @4 C6 ]: a+ P2 W) g. o3 `
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
      N: {) ~% P" l& m! F6 Q
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码
7 u6 o2 Y* _# O; C3 B# \# ?* L
简单Fatfs应用
0 C  y# I- }* g" T
  1. void StartDefaultTask(void const * argument)
    " g9 @- G: {$ K( H
  2. {( q7 y1 d9 X6 B1 v, c
  3.     BSP_SD_Init();
    # N9 x5 p. c4 o5 m" T
  4.   /* init code for FATFS */
    ) v$ t: v4 _& p4 ]. f
  5.   MX_FATFS_Init();! t8 p: E  A- y4 r

  6. # L& D6 M3 _% H  S1 A2 t
  7.   /* USER CODE BEGIN StartDefaultTask */; [' s& h/ E$ n- d! ~' b4 I' J  _
  8.   /* Infinite loop */
    5 }( X7 V% }- G) O* }7 n
  9. 8 ]6 c6 z4 U5 i9 O
  10.   for(;;)
    4 s- ~( |! t7 x6 \6 f* X7 c7 y4 ]; L
  11.   {
    # v: |" l+ s2 h# h' J! x0 z$ Y. g9 y
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/
    $ Z) R# n& g) |3 G! R+ \) L+ a
  13.     MX_FATFS_Run();
    0 v- q  w8 X$ E8 m& r$ X4 Y
  14.     vTaskDelay( 5000 );5 u5 Z/ q5 ^' Q; p- p0 T% p
  15.   }# _' K: n  z8 e) E+ v
  16.   /* USER CODE END StartDefaultTask */: r2 S" r6 O/ N7 j8 V
  17. }
    $ [' D3 p+ w! \* s$ }' e* e! c
  18. 3 _9 k5 Z+ {7 K8 \
  19. void MX_FATFS_Init(void)   ^6 ^3 \( o. i4 |
  20. {% ]2 L( N: M4 E; o3 Y! p* p  G
  21.   /*## FatFS: Link the SD driver ###########################*/
    5 `& k5 R% r  j/ W& F
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
    : j" u$ W  r/ c! S7 p
  23. . \# X* R( r" B7 F5 O
  24.   /* USER CODE BEGIN Init */
    * ~1 q" P8 ~/ ^) K
  25.   /* 在Init的时候挂载文件系统 */     9 q3 U9 ?! B1 p0 j1 B
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)  6 E% O  ~: b3 t  P7 w
  27.   {  
    7 i3 \6 F% K4 q8 D  \
  28.     while(1);' C- W) m7 f' h. z! X
  29.   }   ) r! u$ D: e/ l# g! w6 M" M# g6 x6 E
  30.   /* USER CODE END Init */3 O0 G2 j4 D% D* H5 Q
  31. }
    5 I  C. t0 G0 H, E2 `* F

  32. $ M; C6 v4 l! g! e3 h3 D
  33. void MX_FATFS_Run(void)$ G$ D) ~$ @' S9 w7 l5 V% P' ^
  34. {
    + y- o( l- L5 c  m/ y9 L0 l" t5 `7 `& {
  35.   UINT writeBytes;% H1 L2 N9 E' m4 v% c" N8 v
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/
    . O* c" @  }8 \( s# Z
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)% X) U' U4 H# }5 I, `
  38.   {
    6 [3 P- s5 g2 I# d* @7 `
  39.     while(1);
    0 X) y( ^9 X( ^) u3 M  y9 T+ m
  40.   }; D& j" c6 @. ]5 w4 Z
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
    ( E# Y) C& F$ v$ \/ w, y' t
  42.   {/ {4 p9 N- K+ {! k
  43.     while(1);
    ! r( Y* v3 v* [6 I, r! i- [
  44.   }9 \* y1 S4 `" ]( @
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
    ( C- c9 z# f2 T+ a7 y$ C: O
  46.   {; @6 w. V4 z% R% @
  47.     while(1);' d7 C! n0 b+ t: ~  k
  48.   }
    $ w; a: R- r; M" I; o
  49.   if(f_close(&SDFile) != FR_OK)
    . f* s' P7 V2 a' m) A# w
  50.   {/ B- J- h1 f8 l
  51.     while(1);
    7 ^, G9 d; ^- }) M1 m1 V, C$ ~  d
  52.   } 7 Q( y' O! l$ ?/ T
  53. }
复制代码
" z0 k! F8 T: t, `. D) t8 f8 |4 H
SD写入结果:
" Z; z" b  ~9 u' i
7 d. X: {7 k3 j2 l; I- F% W
20180521190454697.png

/ S/ L$ ^, J' @9 ?% X2 C: C3 v* i& A, q

! g# \3 m, r& J/ V/ O7 Z  |
收藏 评论0 发布时间:2021-12-16 21:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版