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

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

[复制链接]
STMCU小助手 发布时间:2021-12-16 21:00
简介
0 ]: p$ O" }! d6 h8 F/ d最近项目中可能需要使用到SD卡,所以需要对SD卡的配置和使用调研,在配置过程中遇到了一些问题,在此记录一下。3 P6 s/ c4 F- j; c
0 A# |6 D: R4 |: u- f4 y! D
STM32Cube配置) e2 \6 r1 w/ I! H+ L$ e. q
Pinout
: ~1 B, R2 F- r5 x" S( c) ?; h4 x: X) i# `! x; C
20180521180114826.png

9 B& o1 d, A( Q7 Z; i% r5 F
  M8 w& G5 i# _! ?8 z" p* K
20180521180129690.png
8 T& ^( I) B, Y' _; P

0 g, @1 G, @! t, M4 Q只需要注意绿色部分的设定
4 z3 p1 I: o/ h4 U5 G/ s' z* @% q0 w( a' q. L& t3 l1 \
Clock配置4 e: ~, K5 y' C; F" A
20180521180815759.png

1 y* t6 p; t* S
! o- f% h" x( n: v: q这里使用了最大的Clock,SDMMC1的时钟是48MHz0 a! H+ f' V' R5 d6 o

* q" Y4 l8 \% Y2 {+ d6 o1 tFATFS配置0 i9 k+ S7 {0 r3 ], X
" Z. [; i; E0 V
20180521181353894.png

3 z2 k* W2 L2 O, c
5 B" [9 t, e) v) WFreertos配置0 o" [8 o, g, b1 Z1 a
5 A. X; q! ]- }4 l# r. ^
20180521183255134.png
4 `; ~) ^: M0 k8 O5 A+ n( A

8 j# D$ y9 H+ m2 `9 b1 z这里增大了Heap size,使用了heap_4的内存管理方式。; g! J( D5 f- w1 [: U
% `5 m1 \9 q- a( H' `/ `
SD卡配置8 O& ?3 ^) @' b2 J4 Y
5 H8 {, r* C; ^, G/ A/ L2 @* ]4 i
20180521183527404.png

, {% K* Q" v5 ]
- b9 H; x( y; k
2018052118353658.png
; e3 T# ]( w( {# c$ W! W, o
$ _' L( y. [. _) Q% O9 R# A
在这里打开SD的全局中断,并使用DMA2的方式传输数据
4 P7 I% \4 f1 B$ X
+ A; O' o" I- n: y: ZNVIC配置
7 J4 r# `* L7 K: D1 E. D
3 v4 F* r3 }: J/ t* o& h, L: R" {
20180521183735142.png

+ Q! i1 \5 {  V
, q( `0 t- Q) P# @4 ?SD的全局中断配置为5,DMA中断配置为6,5的优先级更高。+ \( o: [* C' o& [( |  j
- ?2 h- d9 C7 O8 M6 v7 b
工程配置3 w$ x6 D5 ^: c0 t" r2 `7 s" s# Z. N

! ^  Z( C4 K! ]( ?( f/ I" N2 M
20180521184020944.png
3 i& w* O1 s/ a  t2 E3 @: t7 x

  ?  H8 o1 q* d4 I& X3 }+ C" R
20180521184028381.png

+ ]' d6 ?, k0 G% ?  O; @, Q- ^4 ?* v5 s
以上就是所有的配置内容了,配置完成后,直接使用Code generate功能就能自动生成keil工程。
1 e8 t" `9 E' c. B
4 X4 g: T3 J# ?; w: |* y代码修改
1 y' L% H0 n  P/ m" ^0 X初始化SD卡
6 a5 {, P1 a( a3 b我生成的工程中需要手动添加BSP_SD_Init()函数,我是在MX_FATFS_Init()之前添加的。- t" z! y9 M/ S$ }; o
  1. /* StartDefaultTask function */
    0 N9 S- @  r6 F0 b) V$ x6 U0 _; L
  2. void StartDefaultTask(void const * argument)$ A' z& q9 N  y$ W- g% Z" s
  3. {
    - w. L  {( K  }4 L
  4.   BSP_SD_Init();
    6 e  d& i/ V' L( u0 d  [9 F5 w
  5.   /* init code for FATFS */1 l5 T! N( H/ ^0 w
  6.   MX_FATFS_Init();# g. e: Z1 u& K

  7. ! ?+ [1 ?0 i4 W4 I6 i3 B  w8 H0 e
  8.   /* USER CODE BEGIN StartDefaultTask */7 G: ^3 X- |: ~3 ?1 `
  9.   /* Infinite loop */
    # ~# Z/ l( d& P! B0 I
  10.   for(;;)
      A4 c6 E5 Q5 H
  11.   {
    + r& F- ^& K' K( o$ {/ k  Q
  12.     MX_FATFS_Run();
    - ~, _1 U; f! r$ X* H
  13.     vTaskDelay( 5000 );
    ) z  B& F7 ?2 u3 K: r; ^) D
  14.   }5 s+ }* P, s* W! P3 z
  15.   /* USER CODE END StartDefaultTask */
    5 \1 f; ?& G0 W
  16. }
复制代码

! i, k- y5 y) I2 y: z% y添加DMA中断处理函数3 b/ f" A, ~- @) Y
stm32f7xx_it.c文件中,需要添加下面两个中断处理函数:
6 L' w" d$ X3 j+ @
  1. void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)* W; [0 o6 }  A
  2. {
    6 m- y% D* N5 b- Y3 b# f4 z
  3.   BSP_SD_WriteCpltCallback();
    * z! e( L6 X" k5 J
  4. }
    / e3 }% K4 x# Y
  5. % }* u  o  r! Q3 X
  6. void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
    . L* x/ V8 F, ^$ v8 M5 b
  7. {- l+ S& C+ t7 C+ Y
  8.   BSP_SD_ReadCpltCallback();$ t1 v6 i( v( [) h; B) B" o( `
  9. }
复制代码
8 b; ~' f3 V# {9 [! B0 q
创建Queue# d) w' i; W6 d" h+ Q0 F0 R
在自动生成的Demo中,使用了SDQueueID这个Queue,但并没有自动创建它,所以需要手动创建一下。我是在SD_initialize()这个函数中创建的,具体创建的地方可能需要再仔细考虑清楚。) m) s+ \( K3 e) ~& Z2 h2 ~+ L! u) m; C
  1. DSTATUS SD_initialize(BYTE lun)
    $ \2 H+ f! e/ g( ?: s/ ?) \
  2. {0 [9 T7 X. _0 Q( W* T5 d3 L
  3.   osMessageQDef(myQueueSD, QUEUE_SIZE, uint8_t*);
    ( y! K8 B% @3 e( r" r
  4.   SDQueueID = osMessageCreate(osMessageQ(myQueueSD), NULL);# P) ~& z# u/ X; }/ @) r% T' A
  5.   return SD_CheckStatus(lun);
    . [. F  |% X3 l3 r! i
  6. }
复制代码

' B, P6 e! j' j/ {将Pin的配置改为上拉
& h2 S: l4 r0 s在默认配置函数中HAL_SD_MspInit()对SDIO的Pin的默认配置是GPIO_NOPULL,但我在使用过程中发现,程序会卡死在SD_FindSCR()函数的以下这段代码中:
2 Z* t  f6 M3 E
  1.   /*卡在这个循环中出不去*/9 a) P0 H5 ?$ B- Y+ p- r
  2.   while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
    ; P: H; H8 W; c
  3.   {
    / C6 m6 m' s( F$ r8 A) d
  4.     if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
    , x. {/ H/ X; Q! V4 u) E' A! }' s
  5.     {9 z; S* j/ m( ^8 b
  6.       *(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
    - m' W% o" }1 N9 l9 U% x* r9 v
  7.       index++;
    4 [) {% n$ G7 w  @, g
  8.     }
    9 E) t+ D' \- o

  9. 6 }9 \- B- C; \; V
  10.     if((HAL_GetTick() - tickstart) >=  SDMMC_DATATIMEOUT)
    / Q4 c6 B5 w; [; h# D8 l, L& F, ~: y/ G
  11.     {8 q4 C8 p  D& g1 \3 u2 M( \7 F
  12.       return HAL_SD_ERROR_TIMEOUT;/ ~+ \3 J3 E$ x
  13.     }
    ! `5 m1 [) P  J- N9 E/ {
  14.   }
复制代码

" N9 {6 _( s$ X- m; x( L! w8 q后面我将GPIO改为GPIO_PULLUP后解决了这个问题,具体原因暂时还不清楚。# s0 C$ e9 c# P, p) B9 L( T8 r

' d# Z4 B* @: X6 ~4 U; e
  1.     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 1 C- x6 C) T! ~' L9 A
  2.                           |GPIO_PIN_12;0 c- `( h9 }$ R; n
  3.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;% ?$ F8 V) R/ h1 D  C5 D0 |
  4.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;4 A; I' ]' l8 P" h3 `5 `
  5.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    & N& S1 u8 @# |4 q: I# M
  6.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;( b/ c, f9 f* n! L8 y1 B
  7.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);0 w% R0 C4 p. ?5 A& N
  8. 3 J# \4 V) s! _2 {$ h5 m
  9.     GPIO_InitStruct.Pin = GPIO_PIN_2;# U5 O3 Q' {/ ~
  10.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    ( L  q: |9 F8 T2 g; ]' A
  11.     GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
    4 |$ o: ?6 E$ [! \! j: k5 j/ F
  12.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    * g% P  }8 {5 x
  13.     GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    : a3 A9 b0 P' G4 z" r
  14.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
复制代码

2 m  y; b; S  @5 s* \+ {6 |3 V简单Fatfs应用; G' P: [7 ]$ ^9 D
  1. void StartDefaultTask(void const * argument)+ M. c$ L6 |9 m
  2. {+ c4 L( x' \! o- [9 K  ~4 N, O
  3.     BSP_SD_Init();
    + |- k2 ?4 ]2 C, w% t
  4.   /* init code for FATFS */4 O9 I1 Z' ]' r* _, \0 w
  5.   MX_FATFS_Init();
    5 v# }) L* r- h' }+ V

  6. ' B% m* Y3 [- F# N7 o5 `
  7.   /* USER CODE BEGIN StartDefaultTask */
    5 i5 ~7 U) G# @! F4 J9 v0 ~  k
  8.   /* Infinite loop */
    2 m5 z! d! w& W, ?

  9. * [0 H1 v. d$ O1 U. K% C9 E
  10.   for(;;)
    ! k/ d$ M* q! c( ]! w+ e* Z
  11.   {
    5 u. P" P7 O  j
  12.     /*自己实现一个Run方法,每隔5秒往SD卡中的文件写入数据*/6 w" ^6 P1 k; l; Z
  13.     MX_FATFS_Run();
    - ~+ J0 I; n# y( N
  14.     vTaskDelay( 5000 );! }1 a- T- L% I4 z
  15.   }/ e# _/ \' B: r9 @% U5 V/ s
  16.   /* USER CODE END StartDefaultTask */
    ) N0 K" a  y& V1 W, R& Y% L, D
  17. }
    ! ]* x5 B/ w) _6 H# _' h
  18. 3 }1 h% C7 O, W4 T* ]% L" y
  19. void MX_FATFS_Init(void)
    3 E  [4 H! l  Z5 C2 a
  20. {
    $ J6 ^, Y' ?# M* [- {. ]
  21.   /*## FatFS: Link the SD driver ###########################*/# j6 S3 G2 h+ x& l5 [$ V
  22.   retSD = FATFS_LinkDriver(&SD_Driver, SDPath);
    3 o* R  v) X3 C9 p/ H: l+ S: w
  23. $ G+ H6 c/ g4 t3 T* p
  24.   /* USER CODE BEGIN Init */% A! D. p4 P) b7 S
  25.   /* 在Init的时候挂载文件系统 */     
    0 [9 p' P! h7 ?: l% O6 H
  26.   if(f_mount(&SDFatFS, SDPath,0) != FR_OK)  
    # R8 B+ S; O2 ^  O. ]# f
  27.   {  
    2 v/ D+ {7 f$ y% c
  28.     while(1);
    ! p, h  _( V, ~4 F
  29.   }   
    & H: K+ P  ~1 r$ q/ s
  30.   /* USER CODE END Init */
    : Q; m8 [6 w: J. ^- `, w* F
  31. }
    ) u0 f% @1 Z$ x! C
  32. & b* b5 _3 d7 t- {- x2 e4 `1 d" l
  33. void MX_FATFS_Run(void)+ Q9 m4 V$ U, _  g# ]! F
  34. {
    9 h7 n) A' K2 [
  35.   UINT writeBytes;
    1 V; y: S+ J, j! v# L. B" o
  36.   /*文件系统基本操作:打开文件,定位到文件结尾,写入内容,关闭文件*/+ X1 D8 ]/ _, |4 o: H
  37.   if(f_open(&SDFile, "SDTest.txt", FA_READ|FA_WRITE|FA_OPEN_ALWAYS) != FR_OK)' U# I! z: q6 T/ b+ Y
  38.   {2 I  \: Q% d" }0 L, g
  39.     while(1);
    / {! M' ^6 K  _& A6 G
  40.   }7 a3 J% A# P3 q) h$ n! J
  41.   if(f_lseek(&SDFile, f_size(&SDFile)) != FR_OK)
    ' ?1 S0 ]* `3 r, P* r3 C2 X
  42.   {
    / v7 _: P6 M1 \+ ^1 o, \
  43.     while(1);+ }/ \% C. F% Q
  44.   }
    " b& ]; n( `" B9 o* w
  45.   if(f_write(&SDFile, "sd Loop", sizeof("sd Loop"), &writeBytes) != FR_OK)
    ) |9 V! _5 q  B
  46.   {- D/ Q% E# W6 Z% b' a
  47.     while(1);
    2 ^& }/ v3 }3 @5 K) J5 l4 v$ C
  48.   }
    6 c) B3 u# g* q
  49.   if(f_close(&SDFile) != FR_OK)
    5 D- O/ P2 P/ v! N4 h/ E5 ?
  50.   {( p. W/ }3 s* `* C- e* d
  51.     while(1);5 I: B+ t  f& @! M; F/ ^5 X
  52.   } 3 o: z. t# s: V- y# ]3 G
  53. }
复制代码

- U3 \- q/ `* M( W  \9 B' DSD写入结果:$ ^4 z; r, y4 c% \: s, V; v
; Z0 H5 R% A3 _& L& L, U
20180521190454697.png

% J4 S7 f1 b( b- H5 l( q6 M8 K
2 c% ?1 J; e9 k; L% |; b8 E8 f% _, y& ]6 t
赞 收藏 评论0 发布时间:2021-12-16 21:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版