STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
) w+ m2 B( ?2 a6 s- D' u. t
' X) p# ]( k8 ?+ B 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。$ W/ t, D+ k- A- x
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号; I \" g% q1 Y# {9 `
+ R) c1 @/ ?2 Y% s! H
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
- R' I5 t1 i2 B$ c# n; ^1 x 6 X2 P, y1 j0 g! `) G! t
- static void MX_UART4_Init(void)
! S& E# }; `/ X' C0 R% e - {
$ _& Z4 w3 Z: V* X6 X - * p7 |/ e @: q3 F
- /* USER CODE BEGIN UART4_Init 0 */( g8 a$ N5 n. r2 T
- & P/ e9 v0 r, M G% x. k: k0 c, N+ U
- /* USER CODE END UART4_Init 0 */- @, m6 `$ |( q3 P6 ?
- 8 u4 P5 p) D- ]( I' Q
- /* USER CODE BEGIN UART4_Init 1 */4 O1 ?5 d( j" P! A
- % b& \ \% X# Y* V( s, K* s
- /* USER CODE END UART4_Init 1 */
) }# G9 h$ U9 [; D3 G, B+ g. { - huart4.Instance = UART4;
* D9 L9 s) \. g" x: w - huart4.Init.BaudRate = 115200;
# O! T0 M. H0 T! u6 e% V - huart4.Init.WordLength = UART_WORDLENGTH_8B;
2 p$ d9 N- o% ]: g4 ? - huart4.Init.StopBits = UART_STOPBITS_1;
1 F7 L# M: D; s6 v" \! u! Q6 Z - huart4.Init.Parity = UART_PARITY_NONE;
7 P) z2 c6 @- \$ b - huart4.Init.Mode = UART_MODE_TX_RX;
5 T: X/ S9 s+ P) m( M8 R( g - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;! N" l! A9 c" P7 J* R7 q
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;6 i4 ?+ C+ ?& x6 t# n9 y5 {# L
- huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
4 W( m3 _( m$ p! |8 z - huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
- U/ v) [3 M) p - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
9 q6 E3 _3 z5 g; ]+ O - if (HAL_UART_Init(&huart4) != HAL_OK)
" D$ d2 Y6 Q, {2 n - {
! p! m* c) w% y: a/ a8 G; r* j0 N - Error_Handler();
' j0 _( G2 h( Y3 U$ _) l4 K - }
9 y* H: e' f* Y9 F* \ - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)& N5 m6 e J5 s# Y
- {
6 D1 x! f, q& } - Error_Handler();2 |, w6 S; A6 e m$ u+ p
- }, m- D; L: O. O. L$ c# T
- if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)& }3 t: Y: ~& u# i
- {* T& A2 l. H' U8 J
- Error_Handler();/ _! Z) W4 x8 @0 u+ y1 H1 a$ N" y
- }
* g+ D* C4 j/ T7 e$ g - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)# ^2 M2 K9 _* \) H* I7 g& h/ h
- {7 ]- N/ b8 K7 X& Z
- Error_Handler();
0 ^9 P1 N$ R( U5 D( o% r - }
" M) } [4 {, f0 }: t* p - /* USER CODE BEGIN UART4_Init 2 */
. U8 h) y* U, \3 v
s! G, M5 Q) L3 d# y3 V" {! }- /* USER CODE END UART4_Init 2 */0 h8 o, [4 c2 c- ~/ T
- 1 F$ r: t* m+ R, {
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)8 _, ^' e. D! Q) J: w* T( s. p
- {6 V1 ]! h' O3 f
- GPIO_InitTypeDef GPIO_InitStruct = {0};! [, \- l. n; E4 r+ b" o8 ~
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};' V" x2 W& {2 r! h
- if(huart->Instance==UART4)+ h) |. z: ~ l5 _* E! g. E! D/ P
- {
) |: v" K! k& E - /* USER CODE BEGIN UART4_MspInit 0 */ f- [& y9 T0 L$ K8 y) b4 i. n
- 2 O$ C8 I' Q6 V. L
- /* USER CODE END UART4_MspInit 0 */
1 C1 s; p/ c6 ]9 c w: O( _ - * k+ a; {, V- |+ @% G: \) U
- /** Initializes the peripherals clock
% j+ a/ ?: w2 i. [( O7 W/ z4 ]8 F - */8 M- {7 K4 x k
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;4 E1 ^" D' w5 N5 s9 I6 {1 v ]
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
. s2 D8 {4 T, v& V8 h+ P' P: z - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
5 u* v$ ?4 ]2 W5 T: j - {
- {( B* Q; m" e - Error_Handler();
# A( K3 N! d" p" H" A F/ P - }
: z2 y _' G, O) e8 G" W
' e0 }' j( s& t: T- /* Peripheral clock enable */
8 t1 M5 Z' W6 l1 `. y - __HAL_RCC_UART4_CLK_ENABLE();
* s0 U" u1 Z& l1 V
7 x5 _- Q( ?- z# ~6 h9 I! F- __HAL_RCC_GPIOD_CLK_ENABLE();
" x7 D9 i2 `* y1 T% F - /**UART4 GPIO Configuration
& Y; X& M, l) v5 a5 e* W% B - PD1 ------> UART4_TX
% }7 y$ I. ]( ]( p3 u' H - PD0 ------> UART4_RX
6 e- k& h5 \$ E4 p/ H1 Z8 g; h' H - */
. M2 P/ l; P" Y1 Q7 w' ?; D) M1 E - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
" |: S8 b" {' d2 O9 w4 v1 \ - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;" S# K N3 @+ [: d- X
- GPIO_InitStruct.Pull = GPIO_NOPULL;
! z9 v, \( ] O3 E - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;; r: d* b7 m' n, r0 i
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
) e) }7 m- f0 M - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);. U L7 i9 l ]: N
- 0 q3 r. U! Z T' w( k, _
- /* USER CODE BEGIN UART4_MspInit 1 */# X6 Y9 b' J+ y, a9 t3 j
- % Q& W! f# W! x) G! V, N
- /* USER CODE END UART4_MspInit 1 */
& c5 k. Y% p( W1 l1 D - . I' T" d- m- p/ X# A( \8 p
- }
, ^& w$ H1 D# e9 [# K. I7 S
( n+ |' @1 p I6 l3 t- }! y" Y% g# P) D0 U" ]: f- g1 k
复制代码- 使用cubeIDE+ r2 ^$ a/ E3 s$ y& Z
- __io_putchar(int ch)9 f F- z: `1 b0 N( t/ a, s4 a
- {* p& I, K- P7 m: z: z5 i/ @8 d
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);8 J: `; F% |: S2 Z! o! C
- return ch;
0 x: Q: y" R; f& T, D - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
/ {! q p$ ^& M3 z6 A" P! T" D
5 a1 o! d5 `& S- M% k2 m6 P
添加输入输出头文件stdio后,就可以试试程序如何了。
2 `& w1 L3 e0 M& U8 z( G! n: f
- D$ z; @7 w; t; `" N1 X. x 以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
$ D+ y3 b; Q7 ?1 y" y ) q/ ?* Z0 i( e w4 f0 ^5 c
- static void ViewRootDir(void)
) w; T; a3 @7 n5 r0 L2 n1 M - {0 s, `9 ~- y9 [ f
- FRESULT result;6 U( S: ?# `& V" a6 u( f5 S
- uint32_t cnt = 0;
0 B" V8 ?4 G' h9 J - FILINFO fno;
1 l) Y* z) t- n$ u: }
! A& q7 |8 ~0 b$ o3 i6 U9 E% }8 x; h& o- 1 I, { s0 U5 H! n
- /* 挂载文件系统 */. _, P- M/ \- y% k* f
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */! [9 v+ X" d/ z* Q( v3 Q% I
- if (result != FR_OK): i7 g" k3 g2 n5 n1 R& M& x
- {9 b' u& ^* b3 S9 S, R! D
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
0 f: z8 s* o! E1 l1 j( U9 r. o - }% E. d3 R) h8 w y
2 }" I$ D; O. ?3 ]4 R- /* 打开根文件夹 */
$ U( v& q: }8 W1 w4 b* l& t - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */- ~" H) d& Y6 c- H$ |: U
- if (result != FR_OK), K, [$ L2 R, i5 }
- {
6 Q, L& a9 _. h1 @* e% d( n9 t5 L - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);& r# F2 f- N0 E6 x- E
- return;
8 n: S% l0 A8 G' x& g1 t - }
' v) z5 {7 K ]7 |
4 _" p4 i S! O% E7 ?- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");
0 \7 z& X7 W1 T% k2 P$ R - for (cnt = 0; ;cnt++)
' G% c8 J0 C: t: }6 w R7 E - {
. a* g! n5 ?9 r& h% \ - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */: A: `" w0 O1 d: z
- if (result != FR_OK || FileInf.fname[0] == 0)2 V; U9 \' f. V' o+ U4 H
- {
5 q B6 J4 g' T, q - break;5 A% I$ A5 V* |# u" y: `4 X
- }5 T# [% H* p$ ^8 A: [# m( ]" S
- # a! m9 B1 L6 [
- if (FileInf.fname[0] == '.')/ h7 H/ `5 H* T8 H3 E% g& F
- {2 E/ f5 }$ U. X( n
- continue;- i6 l0 Q7 ~% ?0 T) @
- }$ W, G$ u6 M6 T, {% ?3 q1 x
' |1 W% S6 f0 |) G }- /* 判断是文件还是子目录 */
7 i7 ~3 t: _6 t/ u/ H5 C3 i6 z - if (FileInf.fattrib & AM_DIR)$ c1 [) t. T5 P( h: m+ T; f$ V, K' U" y" ]
- {2 b5 T" d. v4 Z% w9 B# }' D, V2 u
- printf("(0x%02d)目录 ", FileInf.fattrib);
3 W- ~) j9 e( Q* U - }
) @1 ]; s0 c$ W: L0 M - else' B# n! |" k0 ~2 C$ I, q
- {9 D) m) r4 L/ Y0 O5 a
- printf("(0x%02d)文件 ", FileInf.fattrib);5 s9 ^" s, s c
- }% S9 l( v& V) g o6 e" `2 u
J' ^# @. z# e; f1 M4 t- f_stat(FileInf.fname, &fno);2 i* M7 s# m) t3 _: b
) ?' e/ A- H1 q: o/ W- /* 打印文件大小, 最大4G */
P2 K& m( ^ C0 G2 t# e - printf(" %10d", (int)fno.fsize);
+ |8 Z& [% [: m/ I
3 R: M( k5 Z5 k& k& \2 r
* \1 v6 b6 |; ]8 j6 {- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */' ? B/ E1 ^' o
- }
3 x! |! q) {7 n" P& T% Q
" K+ o7 q! m* c& R9 n9 Q- /* 打印卡速度信息 */
" n7 P5 X- c. S' T0 I - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)- L+ T5 `! f/ X. u! E
- {+ Z( i, u5 t) h) @
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
) y. ^1 R( T6 U( ^ - }' v$ w" H7 L* ~6 P$ e
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
" H8 Y7 j/ w2 Q' @* s# p. r+ T - {. \ M: A: z& u8 U5 f! y- T" ]
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
/ x, l; A4 i% H0 D. g; @& k, P - }
; u6 ^% f3 v( _+ ~+ S8 S) w - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
6 t$ e% u6 T* [. s - {
! ~# [. x0 H# Z- i, q# L; `; @ - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
+ C2 y. K$ O4 q- ^ - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
) ?0 L4 R" B. L* ~ - }0 Z; B7 y$ V5 D5 _
% }. y1 m7 x0 d- P- ( C8 Q; q6 y8 d+ }, m9 e |$ B
- /* 卸载文件系统 */' Z; b( i: f' T; a8 Z g* d$ w) p
- f_mount(NULL, DiskPath, 0);) I* D" I" V# D. m) G
- }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
/ \4 _. s' m0 x# U
k3 S% k7 u7 g$ _2 o3 \) B& ~% m
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。3 o* x n$ I, O, @+ {# ~. g
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。 b I- F4 I+ S3 r; W
" [$ g. ~) g/ P s" z' T 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
# O: W8 p+ s/ f: B' Z6 n
& p/ N! X) B2 {$ ^" ^
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可 f) D7 d; E0 X
/ \& `% t4 k+ Y
料想这次应该没毛病了。结果,新的意外又出现了。" [# n- H9 a" G G
% L( r2 p R+ @- E9 o* u 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
( G2 H' G4 T8 \1 ^* g
T) V% J+ v" P N' x 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
8 [% U% [& ]7 W, S$ x- {2 I" S0 w5 E' z# d P6 ?* S
/ L+ @5 z4 [5 x- r$ u. N
1 R- E: h8 d% U" G9 o2 \+ k9 a( |6 b' J- W! j$ h
$ K8 b# a. v5 }5 ~8 R: z' d1 Z, F2 x
! |5 E; }& f: v/ J \, G |