STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
9 E4 a, X0 }' w d+ g# C( d( B7 ]+ l- k5 x' W" R
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
0 X" q" _; c# u 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号& @0 H6 d# ~! K; E k6 n3 g
F) ` m2 ]( D0 b" K4 X
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下) n, w" _. ~& V
, d- _( q2 H( G- static void MX_UART4_Init(void)
6 J8 N) W- A6 A - {" ^- Z. q' \: V& q. ?% P3 n
+ h. t* S) r( X5 S6 Z$ _- /* USER CODE BEGIN UART4_Init 0 */
; \9 D' B0 [; ~9 p, |. X
. w7 _0 D0 ]2 O& ^+ S- /* USER CODE END UART4_Init 0 */
( H4 j, l$ [3 }: @& |: A$ G
$ S1 o2 K5 V: z f- /* USER CODE BEGIN UART4_Init 1 */
4 ]) b1 _5 n: {# f/ a' Y7 S( [& } - 0 U8 y; I3 m2 z1 X9 a% }
- /* USER CODE END UART4_Init 1 */' J# C& F7 N! I/ s- e" S1 v
- huart4.Instance = UART4;
% a; m/ ]$ V( {' P5 R1 l% T - huart4.Init.BaudRate = 115200;
8 x' u ^) c8 K$ J - huart4.Init.WordLength = UART_WORDLENGTH_8B;
- U/ a. g0 g; Z: b( b - huart4.Init.StopBits = UART_STOPBITS_1;/ c! f/ N5 B3 P1 W
- huart4.Init.Parity = UART_PARITY_NONE;
) L+ |9 U" L T: t$ v, g, F - huart4.Init.Mode = UART_MODE_TX_RX;
# u; N$ @2 c6 }+ K5 q$ u! v$ R - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
) |' W+ W) J4 y: A4 } - huart4.Init.OverSampling = UART_OVERSAMPLING_16;
; W4 u4 W& y% g6 ^8 G/ E - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
! Y6 s& I2 b2 R - huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
* s7 _" w8 ]+ U/ l - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
! c- W) N; i1 l; H' H0 D4 j, M4 S - if (HAL_UART_Init(&huart4) != HAL_OK)& k! D3 t3 Y2 X, ^; J: }
- {
" F, H1 J/ j! o/ Q - Error_Handler();
m! B4 e F5 g9 m - }% X! K5 m& r3 r- w* c1 e& [
- if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
) a- d& C" U8 [3 L6 y/ K - {' C4 C/ o' ^) g! L3 O. L: {
- Error_Handler();
: @. s- e& B6 T3 c$ { - }
3 F% O' F6 M. W. l( b - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK); C, n( f: F' x6 }. d3 {2 ~( U
- {. s, \+ ?7 o v5 a0 J' T
- Error_Handler();
) w8 L: Q- `1 ^2 l - }5 n0 E1 a, L( O/ ^% {
- if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK); i! @' O- y+ S4 H: a& r, l
- {
- Y1 X6 \' e7 ?$ A3 I1 o - Error_Handler();) `' Z+ I m+ A6 N( z5 a, X
- }
/ q/ B6 H6 p, g H/ D - /* USER CODE BEGIN UART4_Init 2 */% _$ j" W; a1 O7 t) }% h" y
- , @( l4 }, y7 e: P) f
- /* USER CODE END UART4_Init 2 */* k8 {" u9 X1 z1 \; `: f
7 p2 Y" N, Y$ t0 S: u/ a- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)0 d. j6 u9 w* z
- {
3 `; z V: X3 u& H0 ]; U9 W - GPIO_InitTypeDef GPIO_InitStruct = {0};2 C0 u% p% ]3 ~
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};6 r4 f+ r8 i& G" q3 _" a
- if(huart->Instance==UART4)4 Q x8 |9 I$ U- \. E8 r/ ~$ f
- {* ~" D$ M2 q D" [
- /* USER CODE BEGIN UART4_MspInit 0 */
% u% ^! C3 e- R# B$ \
8 J/ u7 r( q X- /* USER CODE END UART4_MspInit 0 */
: |. n) ]4 M$ Y& D
4 K, y% K; p+ \; a& B: {! r- /** Initializes the peripherals clock
( r6 S! H `/ ?# S# w7 }0 \ - */
- m( `" e/ Y* [ - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
+ R7 P5 b7 R7 e( U0 v# }8 F - PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;! }/ X+ ?0 O1 m( ^
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)6 n1 e/ m2 T' }# x
- {
' i) F6 h1 R: }% \( k# J. b$ e - Error_Handler();- D9 n+ q1 x5 s4 U
- }
: Y1 b0 r% j% W- m: [3 y; S8 g6 A" I
4 d3 R: E: P! K. V/ U b- /* Peripheral clock enable */
1 H1 Z g E$ R, M. W - __HAL_RCC_UART4_CLK_ENABLE();* Z# J- S+ t8 a8 n+ h, H8 [
/ b/ q: h' P1 U9 k- __HAL_RCC_GPIOD_CLK_ENABLE();0 z. @# y* X+ I0 | j6 [- `0 M7 I
- /**UART4 GPIO Configuration2 Q/ M, P0 V; s3 _/ B. C+ b
- PD1 ------> UART4_TX K! i/ I$ [( m( L- ]
- PD0 ------> UART4_RX; V! |) `1 }! h5 J0 ]6 Z' a
- */$ l: I# B0 d8 E) L1 j8 F( D9 E3 F
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
: i* O& S% S1 R9 _$ G7 s, ^ - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;; [) N% r+ A3 E p+ t: i- @& F
- GPIO_InitStruct.Pull = GPIO_NOPULL;, A: Y, k) C! f2 t% Y1 J
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;1 J: y( V; }$ j8 k, t- X* X' h
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
$ V" f" I( J9 V+ @+ `$ |: l5 I2 X - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);" Y- E& T% k5 n' o
2 E! D3 J% C0 @- /* USER CODE BEGIN UART4_MspInit 1 */
e8 ~7 Y2 R1 w3 h7 V - , y5 y* X: q; d/ P1 U* p4 W
- /* USER CODE END UART4_MspInit 1 */
5 ~ J8 q4 x) S4 W/ E8 C - 4 b3 n/ M) ~& c0 R; d ^0 d
- }: T( X" m4 q5 P* M2 Y1 ?( ?
- % T6 I1 V9 x4 }6 D" L% G
- }# F' s9 V0 L2 p
复制代码- 使用cubeIDE
+ | Q/ I6 W, n+ q4 T+ |! V: z. h1 s; w - __io_putchar(int ch)
. H1 ^7 |% D7 W- c' |8 F) ^. c# { - {
# T* d+ I' p6 F2 m* L - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
; |5 h9 _# F: P# s! x5 j, i3 P - return ch;
! w z- A: v8 d) \8 T - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
% C6 z3 F& m/ m
5 b1 B. \4 f, F' m5 Y+ Z* |) i4 T, C 添加输入输出头文件stdio后,就可以试试程序如何了。
( Y6 m4 M/ ?5 L. w% i
8 E Z3 E3 M# k7 f4 r2 P 以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。, Z! T! } F" u
: [1 R8 F: C3 a+ X' p9 e+ u6 t- static void ViewRootDir(void). h2 w% \4 a% @0 o
- {; \4 U7 h0 A& z/ }
- FRESULT result;; z n" [0 ^- O2 H: I
- uint32_t cnt = 0;/ U9 l2 @; s. r/ p( }/ [
- FILINFO fno; [+ S& b% f3 ~1 C, e
! e& _. A9 H6 G3 C, i! G0 o$ D5 R. |" k
) g ^ T \# J- /* 挂载文件系统 */$ {) y/ e! g- N; r
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */
% G( `6 W4 k/ _! q, c - if (result != FR_OK)# l+ L3 X4 i3 o) d& Y! W2 u
- {- U. H' l, U. S7 B# [& c( U( n. S
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);8 R+ ]+ \1 `# B' u: R
- }
* c+ T2 r! p, R. U$ k8 `
$ w! I1 d% Y' { T2 @7 M$ v! r- /* 打开根文件夹 */* v: W! h4 t- {, l
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
8 N0 j6 t& V" B# c' |! C4 u - if (result != FR_OK)3 ~) @- K8 b$ H/ L( S6 {
- {
% X3 M+ p' t5 s# D0 D. u0 X - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);# ^+ [5 m) @, U$ t! O
- return;/ Y: g* A% i( s, b& t1 r
- }* M8 ]* I% z: b$ l8 R" E& i/ q
. Q/ m+ T8 n% I1 q+ j3 a6 N, i- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");: I2 ?% D: p' x, E6 x
- for (cnt = 0; ;cnt++)- {2 N4 R4 M; ~: ], t9 S* h
- {
4 F1 z( d- O6 r - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */' Z* y$ U! p5 B' V+ y, Z% y0 w
- if (result != FR_OK || FileInf.fname[0] == 0). @- T. f3 i9 b! @
- {* W# |6 w6 N2 p( f
- break;4 T A# H/ k. c
- }
( F) N8 {0 T8 ^7 t - 6 f# I% k1 v+ b& r' T
- if (FileInf.fname[0] == '.')
7 h: S: r) ?3 V; c) M - {- x2 j5 B+ ]( y! ^2 }
- continue;
) N. R! y1 b) X- ^; M# _7 b - }, x4 X0 s( a- D4 U1 v) H0 Q9 N
' x8 |8 c: J; z- /* 判断是文件还是子目录 */
, u3 S3 h x& w' Y3 i - if (FileInf.fattrib & AM_DIR). |8 @* c$ x1 w
- {3 O2 ` b6 |6 ]! F! ?6 i- C4 m
- printf("(0x%02d)目录 ", FileInf.fattrib);. p r& w6 j% Y3 l R
- }
2 E# J- S# F4 Z6 |( i - else( L D& q i( Z$ M. B: ?
- {. ~5 G! ^; d# k: V
- printf("(0x%02d)文件 ", FileInf.fattrib);
) G+ p. O/ l% g8 n+ I! g; h - }
1 B2 b- I6 N, h7 O/ N, s3 a - * N) M$ p, h; B& H
- f_stat(FileInf.fname, &fno);
. [1 I0 E& Y" }& c7 I
, D; }' P- o: r, @1 b, ]# g8 E- /* 打印文件大小, 最大4G */* w7 I3 c5 C; v! x
- printf(" %10d", (int)fno.fsize);
7 b! j* l @9 K/ p$ |
* |$ H; u$ ^6 t- K- 8 m4 q. s1 n: ~
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */$ O6 V2 X( o0 C# U- ]
- }2 m5 P4 {, F/ e
- & u2 ~/ j' z& B' d1 q9 j, [- x5 Z
- /* 打印卡速度信息 */
% {9 z7 c- h% n4 K3 L' `# Q- W& e8 m - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)0 @! G5 V; m- |" o0 L
- {
$ O5 r+ K0 Y$ V - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");3 r( p2 {. @3 {- }7 V x4 r
- }
# g3 o8 }/ {( q& G c7 y$ O - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
4 {, u. b0 T; ]5 p4 x2 ~6 l* j - {8 b* X! Y5 }( I. H6 G- E2 H# N+ g2 f, _
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
( m) B M; ^! g. n - }
7 ~9 ~* |; U3 D! m - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
1 w+ I$ Y# h0 k* p, G4 D - {
. ]7 `" t/ ^* a. w. o; W0 A, x4 v - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
: q* L. R( Q" _2 ?$ l - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
1 }3 {8 F: n! x e% T: x( e - }# ~% l9 ]) z' S# }% \
9 P/ W8 k! A) l' ^
- J" l3 s: o @, r9 L, j- `: k- /* 卸载文件系统 */7 R; Y' j. K1 D6 k" W7 M
- f_mount(NULL, DiskPath, 0);0 v6 y. j9 @/ ?, T" D
- }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。9 G& e9 h# l/ `6 Y
, M. p. t/ U: G) d: w& C 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。$ f6 |+ ~* A6 A }
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。; T! \" r2 h- Y& w, _2 D
Z g, H" g" M3 v0 A# N
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
5 G# D5 h- Y% G1 l/ B
/ [+ A$ L# U9 a0 e$ d 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
. Q/ t; i" K! J9 v" N
/ k6 p' o0 r4 {0 K
料想这次应该没毛病了。结果,新的意外又出现了。6 S7 `! e' v8 B# m( a3 g
# v r. @8 R1 b 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
2 p; o6 Q! x8 i r& u4 n. b
& ^, T; O' o; e 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。% q+ T: K w6 t4 S0 o
" O: I" n1 S+ E; T+ M p
3 I F$ L) O" A2 ?6 Y- L0 E/ H" t9 W0 J8 S" v7 S- @
3 g& }" D- `+ `* D6 E
$ Q( v$ x i$ `0 k6 q
7 @2 K7 `8 @/ f, K0 g4 ] |