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

【STM32H7S78-DK评测】使用FatFs文件系统读取SD卡文件

[复制链接]
BinWin 发布时间:2024-8-19 23:43
    STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
3 Y' C- u* @2 J, N  x9 G; |
9 s* d6 _- Y  S- N; G5 q( y( n: x    鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。9 d2 x# l& _2 }, F
    增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
  s7 ?1 K; V* s5 D      b.png
& O4 S& s+ e6 q, w2 [     手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
& e4 c5 C' k6 |) V      + L( k' c& j+ U
  1. static void MX_UART4_Init(void)& _6 y1 S) u+ I' Z# U9 j
  2. {3 ?9 S7 {3 t) ^0 T4 O2 {. r: [0 V

  3. ' N; m  s6 D5 n: O" l4 B: j
  4.   /* USER CODE BEGIN UART4_Init 0 */( N' d7 Y1 a; U
  5. ! ?0 Z0 b2 j) r7 d  L
  6.   /* USER CODE END UART4_Init 0 */, d8 v* g: P5 F: `. o8 W1 ]  K
  7.   L6 t  v! I1 i+ g  |) Z
  8.   /* USER CODE BEGIN UART4_Init 1 */. w- |/ z% |9 G0 A, @

  9. % K# b0 p3 ~' D
  10.   /* USER CODE END UART4_Init 1 */
    . m1 i0 |9 p& K. z
  11.   huart4.Instance = UART4;! r1 p5 R- `1 ]* l% _" ~. [  H& k, E; P
  12.   huart4.Init.BaudRate = 115200;) Z. {$ @3 ]$ C4 W+ @9 E0 r( ?
  13.   huart4.Init.WordLength = UART_WORDLENGTH_8B;
    / P! e4 a0 a8 C8 ]- W/ r2 U
  14.   huart4.Init.StopBits = UART_STOPBITS_1;
    7 `: Y& k) K3 v" R
  15.   huart4.Init.Parity = UART_PARITY_NONE;
    0 G& o$ M# v4 q' O7 D/ Y
  16.   huart4.Init.Mode = UART_MODE_TX_RX;: t1 M0 G: I, w' a5 L* D7 V
  17.   huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    % u0 z6 P6 j, }& s
  18.   huart4.Init.OverSampling = UART_OVERSAMPLING_16;: u* _$ q: V/ v" O! O( y4 ~
  19.   huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;* Y* H6 s. p' K9 A- s4 V
  20.   huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    . K; \8 F& h2 d' ?
  21.   huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;+ F/ u# _2 w& q1 l8 L
  22.   if (HAL_UART_Init(&huart4) != HAL_OK)
    ( p$ Z3 Z6 N; P. E/ A
  23.   {
    # V# V# a% `5 r% V2 N- |
  24.     Error_Handler();
    ; @1 k, n& B. U7 m8 I% F
  25.   }
    ' j0 _3 K3 q8 w+ c3 |- \
  26.   if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
    7 e6 ~: @: a% U
  27.   {" k( E# j3 r0 U* C# p$ z  Z: m% C2 _7 j
  28.     Error_Handler();- z( k: }3 X4 }% Q/ H
  29.   }
    ! Y# R9 E2 |/ Y1 T5 D; c
  30.   if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
    6 ~0 d' O/ G/ I- L
  31.   {2 Z5 U8 l$ U4 t# V0 g" \
  32.     Error_Handler();" w1 P0 c- H- ^+ k1 v
  33.   }
    / _" }; V8 I, b' m7 p  }
  34.   if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)8 @4 z: J2 h6 k, A/ j. ^3 x
  35.   {0 X+ }" i. h2 a9 J4 X5 [; x0 m
  36.     Error_Handler();
    ( G% _; V9 Y" t$ M5 n* q( R4 D
  37.   }/ E- r5 ~( f1 q+ A9 j+ [" z, @+ C
  38.   /* USER CODE BEGIN UART4_Init 2 */
    4 ?; {& I; V4 h6 `% X
  39. 1 |, a$ z0 ]* S0 U6 _
  40.   /* USER CODE END UART4_Init 2 */; C& d6 A& ^' i

  41.   A5 |  ^9 G" I3 b( a
  42. }
复制代码
  1. void HAL_UART_MspInit(UART_HandleTypeDef* huart)
    ' X) V* }3 _, A
  2. {! \. W5 y! P! d% E. s
  3.   GPIO_InitTypeDef GPIO_InitStruct = {0};
    / k4 Z1 D5 G: S- F5 r
  4.   RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};- W1 ~: x: Q* N  j$ Q% s
  5.   if(huart->Instance==UART4)  {2 Q) t0 ?3 \) b6 Y* ]# D  r5 u
  6.   {$ n3 L/ d% F3 {; d
  7.   /* USER CODE BEGIN UART4_MspInit 0 */
    / ~5 G+ P6 g. d. ^2 q% Q6 f
  8. * }) o$ B( g; |
  9.   /* USER CODE END UART4_MspInit 0 */
    4 z0 b4 Y1 {4 J7 K* R

  10. 9 L+ `% ]. o* s; O; n: }8 e
  11.   /** Initializes the peripherals clock" X. ~6 k' n$ s4 Z4 ~/ r1 y
  12.   */, `5 F( p0 h( }( u. |
  13.     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;: A# \$ `' R) z  |* d9 A
  14.     PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
    3 a+ v# E3 Z5 H" z
  15.     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    " c$ y9 V* R# m
  16.     {9 b9 Z2 W0 C7 D  l) Z
  17.       Error_Handler();% b2 m/ P: {, E( X8 f8 l
  18.     }
    0 O8 y9 L7 M; a7 j

  19. : a( W6 }, }& T" m
  20.     /* Peripheral clock enable */" Q$ \7 i; v. I" {, q
  21.     __HAL_RCC_UART4_CLK_ENABLE();- Q% I( f6 ^& Q  ?6 O: r

  22. 5 A' w  B5 p& [7 P
  23.     __HAL_RCC_GPIOD_CLK_ENABLE();
    + ^( R1 ?# K- L9 \
  24.     /**UART4 GPIO Configuration
    2 h! e0 j5 y8 ?! `  C6 \* |
  25.     PD1     ------> UART4_TX( [& w. I3 B4 Q- u/ z
  26.     PD0     ------> UART4_RX
    4 e/ w/ r2 g3 }+ {# }: M, ^
  27.     */
    4 R, S! u6 t3 a9 y2 n" m& f
  28.     GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
    : g0 x+ L0 {6 v
  29.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    % d, `1 D, u0 F2 }1 [
  30.     GPIO_InitStruct.Pull = GPIO_NOPULL;
    3 T9 [, s+ G0 d6 [
  31.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;) @9 b% Y) r7 a% `2 M: D$ t
  32.     GPIO_InitStruct.Alternate = GPIO_AF8_UART4;$ E5 p' n  J: k% W
  33.     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);: a" a: I8 I) H- S* }$ j

  34. 8 _! {* j4 z- M& [* Q, P
  35.   /* USER CODE BEGIN UART4_MspInit 1 */3 \) i* b5 J8 o; H
  36.   K  N/ j* D" `$ ]
  37.   /* USER CODE END UART4_MspInit 1 */
    , @& U% z- }4 O4 H* }

  38. ) g4 N& I5 a5 Q9 U
  39.   }
    5 W  y( @* l1 h5 _+ b

  40. ! L9 Q, x. j+ J9 v8 Z6 z  Y( l
  41. }
    , {6 ]- F  ^$ C
复制代码
  1. 使用cubeIDE0 |6 ]4 L* _4 d3 E6 Y
  2. __io_putchar(int ch)" V& u$ p8 W# M0 i* c
  3. {
    $ K5 c( P% L4 n8 n6 g' f3 y* ^( Y( G
  4.   HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
    3 ?; B# o) I0 T& C* A
  5.   return ch;8 N; o3 Y, ?: v7 [! [
  6. }
复制代码
      代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
1 ~1 V. m& j% _  O8 D: |       c.png - I, a' s( k: j0 {) A
       添加输入输出头文件stdio后,就可以试试程序如何了。, a% q/ w4 j! A$ I
       d.png 5 \3 E, U: ?& u
       以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。+ c9 D7 x* h& K9 p3 ?2 {, u; N) b7 B
      
& m2 [- s- w" e2 B* A5 k  u
  1. static void ViewRootDir(void)
    - l1 R% z! T. h% n$ {4 H- Z
  2. {# Y- p$ D# B0 k1 i
  3.         FRESULT result;
    ; m& x6 d; @. R5 r: B9 u9 _( X
  4.         uint32_t cnt = 0;
    8 r7 y" D. q+ P0 j+ ?5 |2 n9 V
  5.         FILINFO fno;
    / d; J. a2 `: n
  6. 6 O- i& s# M2 \2 C4 V: B) R

  7. 7 O0 q5 k! m, O: ]/ S
  8.         /* 挂载文件系统 */
    + t, g9 F3 _) R- R; a
  9.         result = f_mount(&fs, DiskPath, 0);        /* Mount a logical drive */" a# _& x% `! v( G4 |/ F- v$ y6 [0 T
  10.         if (result != FR_OK)
    # y% S9 w2 {- k2 g" b; R
  11.         {
    ' p8 y- A* T+ ]" K" J& e: L
  12.                 printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
    9 |( v: }% Y9 Q  e: V+ y* E
  13.         }
    , }$ a) s( B( u& M. H

  14. 0 R% S% ]$ k+ a. o; {
  15.         /* 打开根文件夹 */9 ^& T: P! j3 J% a6 x6 ]
  16.         result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */; `' \+ H' F" Y" u- {9 I5 `; `' }+ k
  17.         if (result != FR_OK)
    , A  y0 q7 D' ~( M( G% H+ p
  18.         {0 o3 o+ I9 d; D/ y
  19.                 printf("打开根目录失败  (%s)\r\n", FR_Table[result]);
    + W! _- V* K% O$ y8 Z
  20.                 return;
    ) X- {3 U) l& Y  C6 c  R
  21.         }
    ' v5 @! n. m0 c
  22. - o! h% |4 E8 x( z4 z6 V# y
  23.         printf("属性        |  文件大小 | 短文件名 | 长文件名\r\n");9 D, f7 e! ^  H7 y* |1 @
  24.         for (cnt = 0; ;cnt++)
    2 j; }) C. w8 [9 M6 k% A; s
  25.         {
    2 W+ r2 {7 L: S! Z' O
  26.                 result = f_readdir(&DirInf, &FileInf);                 /* 读取目录项,索引会自动下移 */& q  G9 ]' [, a0 T, b/ ]
  27.                 if (result != FR_OK || FileInf.fname[0] == 0)
    $ @0 `1 S8 G' x/ c  F
  28.                 {
    0 s8 _. D% l& k, O. t3 O
  29.                         break;
    & Q) c2 c9 ?5 i: u5 t/ a( I
  30.                 }( I) a& Q9 f( g1 _2 Q3 K4 V: d, H# ^# q3 u

  31. . Q: X8 N  _, m: i, c4 Z4 s1 X
  32.                 if (FileInf.fname[0] == '.')
    + x) k! S% l8 \- S
  33.                 {
    $ R  K/ T: p3 H. X( M6 E
  34.                         continue;
    9 [8 C6 n9 _3 K, e, A9 Z
  35.                 }
    ' \' ], B5 P6 Z0 r$ D6 d5 e

  36. ) }0 C4 N  U6 @; z
  37.                 /* 判断是文件还是子目录 */
    + d; {  F. r& h# y& k
  38.                 if (FileInf.fattrib & AM_DIR)
    # A' ~  Y3 U4 j* p: ?/ D
  39.                 {
    ; e4 s! f- ]  W7 I; D( H6 ~
  40.                         printf("(0x%02d)目录  ", FileInf.fattrib);4 H0 ]5 K6 h8 p6 Q+ V/ S# P2 w
  41.                 }
    . q7 g8 n" L4 k3 u; @' K
  42.                 else. n/ N7 n$ B( s! E3 C8 _
  43.                 {
    + H, b. \$ |% e( p- P! d' N+ v
  44.                         printf("(0x%02d)文件  ", FileInf.fattrib);& j3 `; I0 \1 c* T- p
  45.                 }( x: d3 ?( N( ?0 K% x( q

  46. " `% s4 j9 v& ?8 L
  47.                 f_stat(FileInf.fname, &fno);
    - ?# {) f" b1 L  \! k9 S

  48. - S0 S2 \- c2 I9 S, }' ^- q
  49.                 /* 打印文件大小, 最大4G */
    2 x  n! T- G% L0 V
  50.                 printf(" %10d", (int)fno.fsize);1 `6 G9 J, s2 F% J
  51. ' j  F; p+ A# j6 a
  52. 4 G/ ^% n6 o! _* \' u7 O2 b
  53.                 printf("  %s\r\n", (char *)FileInf.fname);        /* 长文件名 */3 y( F, M6 U# Y
  54.         }
    7 O# Y& A7 c, E2 O! J; l( h% O

  55. 6 |, B& {5 f* ?$ _* X6 W
  56.     /* 打印卡速度信息 */' u3 K0 b6 i. ~
  57.     if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED); T$ l6 |1 u+ Z7 Q
  58.     {
    + w; r6 @1 Q- `! n0 n' b
  59.         printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");4 t/ }  Y  _, g8 t) o
  60.     }0 U  y% D: t! f; ?
  61.     else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
    5 T  e- V/ W& E" y
  62.     {
    4 D3 C, J8 r/ D/ ^+ C
  63.         printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");/ t+ c4 O- o  f6 _1 |5 [+ f3 v7 q
  64.     }7 P/ R, v8 I  H9 X) t
  65.     else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)) z- N2 j3 C, E3 B. w0 T
  66.     {8 ?8 B/ b; s' _! B: R! Z; b
  67.         printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");& {/ ?8 `& B5 F0 }4 x  o) j
  68.         printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");, u; `2 y, W1 M$ j7 \1 t" \/ a
  69.     }" E7 P+ X0 ]; P' p- x5 B

  70. , j" }  ]: Z% P, ^

  71. 4 r: Q9 N0 z! u7 Q. g. ]
  72.         /* 卸载文件系统 */
    6 x9 `! z  a& J( o( h
  73.          f_mount(NULL, DiskPath, 0);
    8 d: T0 ]9 b8 s6 |
  74. }
复制代码
     函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
: X& ^% |  [9 T9 ~& @      e.png 5 ~4 S) p& ~, Y1 b" \( X- B8 }
     中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
2 ~. c5 z  W: b' f3 ^0 v8 a 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。/ B; |$ r, l$ q4 ~
      f.png
" L$ }4 {( n, D- n: P- L. N; u7 w     接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
4 s# F% ?7 H. V& u       g.png
/ i  L$ K7 u2 |. S6 `7 N      很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可+ X6 W0 o$ O+ M9 q
       h.png . A# X' G8 u0 g# M7 A5 n
      料想这次应该没毛病了。结果,新的意外又出现了。$ S7 @4 [6 j* _+ d4 Q  }( m
       i.png # `: U; D( E$ i3 i
       还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。) X, ]1 A0 |* s
      j.png k.png
' M8 [$ t4 k, s5 H( W+ ~$ J    满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
- `4 Y# [5 t$ g* g& N& l5 z4 N% c! J3 X" ]! Y4 E4 V
      
, j' G$ |. f2 p
. [, I* F# D; a. o7 H' X
/ e& Y& c6 C- q' c4 Q9 I
7 E# N. F# v/ U' S. P; ^
2 @3 T- [: h( A* j
收藏 评论0 发布时间:2024-8-19 23:43

举报

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