请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介3 p" D4 Q( t" C. v0 }% Q4 Y
最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。1 C! A( D( z" W
7 N  R7 ]. B/ e+ F7 k& m$ c
STM32Cube配置
* c, z6 s2 q8 g3 t; {# S0 rPinout5 Z& Y8 r  u: ~) B+ j, y
" S0 B0 q5 X+ p( K+ Q1 D. Q
20180521180114826.png
& ]8 K, e/ @5 m6 l8 R% o

: c- W! |2 ~; z% ~0 ~* k
20180521180129690.png

( m! v) e4 P, L4 Y
! I: l- s5 j% e" l6 z5 s# d; C只需要注意绿色部分的设定
) D- V+ V! X' F1 `, l# f. F2 f' K# N3 _( T- k6 y
Clock配置# @# `: U+ p* l' _& v0 X
20180521180815759.png

: w- A$ n) D! y9 O7 ~6 n$ {1 O5 W$ H# n1 f: H0 i9 g) ]
这里使用了最大的Clock,SDMMC1的时钟是48MHz
! P2 x/ v. ?5 r- F0 B6 [4 I: t
- l1 i- @) [  e" J7 jFATFS配置
; {4 }& L( x9 u! O  v. |4 u
/ g, H& }; l5 E/ E  V/ Q' Z
20180521181353894.png

* h$ s' k+ Y2 @, a4 d1 I) i9 j. M6 Q: s* @$ j& ~
Freertos配置- i/ c/ M! u( p" b8 T
- g! ?6 \8 c# e8 q) |, l
20180521183255134.png

8 r9 h2 S( T( b5 O3 ?9 ~) ?6 n3 r4 |7 x
这里增大了Heap size,使用了heap_4的内存管理方式。  i7 ^2 o; u0 s
8 J( Y, }8 Q4 A! l3 t" }0 ]3 r# F0 j
SD卡配置
7 E$ g: `5 S" o9 ?* w& c" q& \/ M: D; j, w8 R( _- q" r* r( M% p: t
20180521183527404.png

4 z: v+ j& n; }7 B" D$ W
" b+ s2 p) Q; M8 y4 X+ G: M" u* q
2018052118353658.png
9 A4 \- z% y  s$ g
# V2 I, u$ F* \1 h
在这里打开SD的全局中断,并使用DMA2的方式传输数据
& ?# A4 B4 K& ^# f* f' u. e+ j7 ~4 W8 f+ m3 \) @5 X5 V3 f
NVIC配置0 i" K6 |' ~1 }# ?% O' X" H
+ ^. M* t. J/ V8 g$ h3 J) N
20180521183735142.png

8 t6 L; ]; g# }
0 c9 a: B# }6 h, S, DSD的全局中断配置为5,DMA中断配置为6,5的优先级更高。
/ o! F; t' Y/ z  a$ t- [) R+ j% `$ A6 f6 C3 h! F& |
工程配置
' \! w; d! ]5 @' M
- ?* i$ f7 H6 X( v+ ]3 p
20180521184020944.png
3 B7 F6 \# L0 u& |+ j  a2 r5 C
1 O6 C4 `5 }+ h% B0 M  c
20180521184028381.png
. D) W  }2 z3 j7 L) H
! P' P0 \8 R' h. ~# @
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。4 z2 I! M" S* k. w2 D
3 j- Y" G  J! q6 A
代码修改
" p% X6 S7 q5 m+ Z% ~8 M初始化SD卡  }# k' R, v) D5 M6 S) h
我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。
+ w: g7 b' c2 ]; I
  1. /* StartDefaultTask function */5 _9 ^" t. Y# p; f' J( o& K6 c
  2. void StartDefaultTask(void const * argument)
    * X3 [# }$ y& K3 X6 h/ U1 ?
  3. {
    1 A& K2 W7 [# X
  4.   BSP_SD_Init();+ s. L3 V' r7 n4 w8 T0 k1 l
  5.   /* init code for FATFS */- P5 f5 D* z7 U4 k1 @8 \
  6.   MX_FATFS_Init();. z8 B1 T- a# t/ c2 Y
  7. + ^- P- {% E) z1 d/ u
  8.   /* USER CODE BEGIN StartDefaultTask */
    : d! i% m" K& i' j
  9.   /* Infinite loop */, p9 j% g# J3 m+ @2 X& O
  10.   for(;;)
    # t  z9 F0 O( Q5 X0 z; d+ R
  11.   {
    ( v& a: m7 T& T7 n  j* E* |
  12.     MX_FATFS_Run();
    ( Y  a1 C( N( [" p7 o" k3 }/ c6 Q% }
  13.     vTaskDelay( 5000 );8 s$ e( e- a9 i2 N' A, w% p" ]
  14.   }* [3 o, T( o. ]- N( ~. _+ h" d
  15.   /* USER CODE END StartDefaultTask */9 x* ]' c  l1 F
  16. }
复制代码
4 O3 M6 H) V4 \
添加DMA中断处理函数$ k, g' W  Q$ ~/ w: Q2 k
stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:* E# }& y" ~/ {
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)( U+ U' J3 u. b. f7 r' a: O
  2. {# `: w& p& ]  A$ e1 S' x
  3.   BSP_SD_WriteCpltCallback();
    " f* k9 u( g! a* T) N! U
  4. }
    ! ~2 A$ O4 G8 _! Z
  5. ( B1 y' R$ s$ P8 Q3 h
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)9 t# t, U& h0 D, O
  7. {6 T7 |4 g6 A9 [
  8.   BSP_SD_ReadCpltCallback();+ i- U! W, c8 u4 b  k! j/ |
  9. }
复制代码

& f& l' }( r7 R- E7 m创建Queue
$ {' o. B+ v# F% G' G8 i8 w在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。
; Y. V. i1 Z8 P
  1. DSTATUS SD_initialize(BYTE lun)
    - J8 X2 h- q% O
  2. {
    3 {4 n2 ^5 M$ x5 m; ^
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
    + y+ v( {6 ], ]4 F3 O1 k
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);+ l7 I: z  C" u3 y( ]( o) @! d
  5.   return SD_CheckStatus(lun);$ v9 V1 X% n; k4 N/ ^* C
  6. }
复制代码
  v* C4 W3 }7 _
将Pin的配置改为上拉; P- Y! k, c' K( F  P+ W6 F
在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:1 E) g7 M/ z. r+ k
  1.   /*卡在这个循环中出不去*/  L* n# ]7 G. h+ ~
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))( y  x1 u6 \3 T" J# F4 T
  3.   {
    4 L) y4 _# w6 t9 O
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))' @, g& G' }; ^8 }/ o( |
  5.     {0 |  x" f  n9 h6 m% j/ {, y
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
    # B* C, @/ P4 z
  7.       index++;
    $ s8 \% [7 E: F* C3 k) `
  8.     }
      r: D2 c& ^2 y, _
  9. 6 ]/ J1 L2 @/ o0 ?) ~8 H
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)9 c' A+ c) D6 q/ c! j+ x% q3 B
  11.     {
    9 e9 g; o0 B7 p- n. K8 r. N
  12.       return HAL_SD_ERROR_TIMEOUT;8 }9 {7 v  Q0 P8 a# \
  13.     }7 G& S+ E' T3 y. J4 f0 G2 R/ p
  14.   }
复制代码

& y4 K: u! \& \! I* a后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。6 t2 F& J" F- Q8 U
) X4 t3 i4 C0 o% ^; o
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
    ' C7 ]% a3 x9 Q8 u
  2.                           |GPIO_PIN_12;
    ' K+ v5 ^. d3 v; N6 m6 R% E2 Q! c
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;3 |. h& w6 `5 p; x  |$ E
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;6 q$ X' B5 Y9 R) O* P
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    - Y: \6 w7 ~# T- a3 s4 S
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    8 I; m9 b3 c( Q" d1 j
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);: a5 P7 \! v. H

  8.   ^$ z/ {7 @" z. ~* [/ X
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;
    & C: a" R, ?( J8 n* b( j
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;9 ^8 w, I* ?4 y' H/ w
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
    * k+ ~  \5 j5 q
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;& q/ C0 W9 h( v1 A& _9 e
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    ( N  v# k3 [2 r. V& s; C# D
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码
3 B; l+ T" X* g# S# g9 m6 O
简单Fatfs应用
: S) V/ i9 P: U" `: ]! h$ ~% \3 h3 }
  1. void StartDefaultTask(void const * argument)
    ( V" ~3 Q* @) L' Y* e# R" q
  2. {0 `. x& Z: Q3 ~8 B7 ~6 \
  3.     BSP_SD_Init();
    ' |% |: q# L9 H' w, |" q8 c
  4.   /* init code for FATFS */
    - R4 R6 }* Z) u( H( r  ]! u
  5.   MX_FATFS_Init();- ]9 S6 g0 {9 Y# k$ @; o

  6. * ^, p) B0 n& z& ?
  7.   /* USER CODE BEGIN StartDefaultTask */
    / T! }1 V4 q' A% b: x
  8.   /* Infinite loop */6 V2 s* T8 i) s" B3 X
  9. , D& @* P; G( e! c( m! y+ p
  10.   for(;;)
    4 X, B( ~/ A4 q
  11.   {) w+ r% U/ ^7 v  a2 L$ O; s
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/7 R+ \+ p5 U6 M5 P
  13.     MX_FATFS_Run();
    # F$ g. x. d9 g% H
  14.     vTaskDelay( 5000 );
    ; {. G4 g. A7 y8 P* o
  15.   }; A% h# I% j# U) ]8 V2 @
  16.   /* USER CODE END StartDefaultTask */2 N% k0 g% [$ d$ d, A
  17. }
    5 \  Z" ~4 h% i: r
  18. + x/ y  O; z/ O5 H% f3 y
  19. void MX_FATFS_Init(void) 9 A5 p- m+ O* H* W* V
  20. {% f8 ]* K( f3 N; e/ p
  21.   /*## FatFS: Link the SD driver ###########################*/
    ' \5 j6 w. I7 S8 f" ~' w
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
    ' W+ L3 a' h- w; X, g' W
  23. ! l, e. R; r2 x1 `- A  L  t! t6 ?! [
  24.   /* USER CODE BEGIN Init */1 X5 v; D, }4 e1 Y: K: v& F+ F. S) z
  25.   /* 在Init的时候挂载文件系统 */     
    2 U5 x: v. r5 |/ N
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)  $ N) u5 [; C. T
  27.   {  
    * z/ k8 S: i; T' l  o" Z
  28.     while(1);6 d  a: M6 H, @- Q5 W2 ]
  29.   }   ; p# N# G# }; D! z  ~8 C
  30.   /* USER CODE END Init */" u1 Y% i) K; m# s9 I* q
  31. }1 ]& N. y+ z+ F( J5 |& p0 }- z1 |" i

  32. % Q" \3 u0 v1 E# c. W2 B) w* a
  33. void MX_FATFS_Run(void)
    ( ^" R7 R5 p3 c# A: V  `
  34. {! F# V  V0 b* }/ H
  35.   UINT writeBytes;3 a# r! K3 b. @6 B5 E4 L( M& x
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/
    $ \9 h! ]  }$ j2 R* @
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)6 i: p; z% l* Q$ b, ^
  38.   {
    # g, y0 w  P# B0 N5 X
  39.     while(1);: q& h( l  m& Y
  40.   }
    ' L; _% z9 x- j; c
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
    9 x  n. O) q% p0 _( [. A. T9 z
  42.   {* [& o$ r9 l" I, ^0 t
  43.     while(1);. A- a+ E1 p+ G# i4 Q4 S6 u
  44.   }( z8 _: H( J8 c8 k# V
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)  X& z5 I' P4 h, l9 y2 p# {+ B
  46.   {
    # w7 n' Z/ r6 t  w
  47.     while(1);
    * Z2 M4 C  Z8 H
  48.   }
    2 r+ _3 v3 W9 @7 s& h2 B
  49.   if(f_close(&SDFile) != FR_OK)
    . s7 o7 W; e1 e4 Q6 m2 X9 M
  50.   {
    ) z! a7 K( V$ G  W
  51.     while(1);4 T  e, C! g1 e- ?2 F$ M/ D
  52.   } 4 f* J# {7 ~* }. J. O3 A
  53. }
复制代码
4 f5 Q; k/ ~5 V- a& F5 ~6 D
SD写入结果:
5 r3 Z) V& P' Z! S4 I
: o' F1 c4 D# ^0 |4 u2 b( T) h
20180521190454697.png
5 l" J# t% E0 O% r6 I8 Q( d
' X1 A: }! z1 z0 C9 x8 M
4 f9 ^8 x7 A6 `# {; f  y) \
收藏 评论0 发布时间:2021-12-16 21:00

举报

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