STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
+ \" |) m& n) A; m' {& u. r N; K
% S! `) b! D2 O- H H/ ~ 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
5 {+ l( \3 ~& _) a b 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
' H6 r) {- X2 D1 G. R( o/ w0 t
+ R% z. c* ^ a5 ~- T1 P1 e 手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
1 X) G: b+ Q# m& z
2 m6 y7 Y$ a6 B; N, }2 |- static void MX_UART4_Init(void)" {8 ]8 I/ D0 e4 G
- {
1 M3 A5 S$ x. J5 @3 P
, Y4 q) ^" R9 k. f5 D: W& ^& K- /* USER CODE BEGIN UART4_Init 0 */9 t( C6 K# L8 o) s* I
- / g, i& i, ^1 [' x" L
- /* USER CODE END UART4_Init 0 */
- P6 o' Y& q8 E2 _0 U - + C2 m) K, [8 v' O
- /* USER CODE BEGIN UART4_Init 1 */
) J8 t4 Z: x g" z3 w% W: A - " l# b# @+ p/ e3 U: m6 f
- /* USER CODE END UART4_Init 1 */) v* p: v( U, V5 J! Z1 c( c' J
- huart4.Instance = UART4;9 r6 E) ~% ~: q- g& u- }$ _
- huart4.Init.BaudRate = 115200;9 n6 d/ D9 S6 E" w2 C/ d
- huart4.Init.WordLength = UART_WORDLENGTH_8B;
8 K$ V' v% ^" m# e1 O/ H2 `4 H - huart4.Init.StopBits = UART_STOPBITS_1;" t0 P2 m0 J, z8 B! \9 w, }
- huart4.Init.Parity = UART_PARITY_NONE;
M, F' @2 Q9 Y4 S: r - huart4.Init.Mode = UART_MODE_TX_RX;
0 s( v% _3 I( i& c' X3 F+ o - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;* ^$ k5 F$ H! O4 X4 [* j4 E# M, _
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;8 k5 P& J4 m: Y* W/ P
- huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;. d( A. Z7 \1 R( q3 p! w
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
! b. \4 z( [& X+ V- b$ \ - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
, @. P; S" S" \% E6 @ - if (HAL_UART_Init(&huart4) != HAL_OK)
" ? O0 X0 F; S- H - {
G2 K4 B. t3 F1 o4 r$ B - Error_Handler();
5 Z" [" z* s" U7 G. P: {2 r7 d - }
1 t0 _9 s! M4 a& P( I - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
* j9 c2 j% i2 h; v; T4 k# m" d - { I* [6 I# o8 [7 g
- Error_Handler();
4 }4 S; g" m6 k - }
6 a- I) e. N. E- |2 {* K2 j - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)) p! u: P( v0 ?4 e2 E* c _/ A
- {6 d/ F* c) y3 \% S& w
- Error_Handler();/ a' h* h* e+ c: d1 p
- }
4 p$ ^6 z/ e& M* t- s5 C - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)7 G/ h2 O9 B* x6 d$ |
- { i$ K; N. R6 k' R( z
- Error_Handler();
o% W7 \- [6 |6 Q - }8 n8 _7 w, p6 y9 x8 r
- /* USER CODE BEGIN UART4_Init 2 */* G2 O: W4 y9 k& c; v r2 [7 u% H
: P: k& y" j5 h; T, w3 W% X" a! r- /* USER CODE END UART4_Init 2 */
3 Z) A9 L( ~3 ?3 W' ]" |7 C - 3 {) H/ v8 s/ F* }) d Y. H2 m
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
6 ^- e. p) k/ \0 U& Q7 d6 \ - {! Y$ i1 K1 ` Q- r E# F; i
- GPIO_InitTypeDef GPIO_InitStruct = {0};. A; u4 t2 R" L, g
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
% ?$ e5 w/ n5 W* L& ^& e: I - if(huart->Instance==UART4)% P) Y. k+ m- Z& x' K- I. }$ J5 i
- { B5 w& m7 q& x
- /* USER CODE BEGIN UART4_MspInit 0 */
0 y5 g2 G3 |- v% e; y( U* H; i2 d
( H+ G! {. d6 d+ Z5 A' o$ r- /* USER CODE END UART4_MspInit 0 */8 ]2 y# ~+ M- {' p
! w; {8 {5 p* ~, U2 o+ N1 @- /** Initializes the peripherals clock
/ J0 Q8 B& R/ {& U0 ~; u w - */+ K$ Q2 t! a) m, w7 p7 J7 }0 l
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
/ {& Z/ b& n7 c/ l - PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;+ F @6 h) ~1 N' l, t4 l
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
5 u/ m7 R5 u$ c1 [0 G9 C1 I - {6 v6 R7 B' H/ i
- Error_Handler();( E2 t! a9 f9 w/ G$ ^/ T+ c. i
- }
3 L. m) w3 y# B: A. U8 x
% x" ?' g$ w; a2 V* M8 V6 r: C& t- /* Peripheral clock enable */
1 J) y3 Y9 L* h$ d+ C8 ~( V3 P - __HAL_RCC_UART4_CLK_ENABLE();. ~( P0 `; L$ x4 S- f
% W4 r* ]; x* y5 P$ h5 h& k, K- __HAL_RCC_GPIOD_CLK_ENABLE();
& P/ R, _( J2 x! H3 y - /**UART4 GPIO Configuration6 L) h3 A* J# z- P L
- PD1 ------> UART4_TX1 v/ J6 i. R0 Q- k1 k2 m$ _: Q3 ]
- PD0 ------> UART4_RX
7 {+ e9 B: {( @( A7 Y - */ v8 k; V9 L% F3 G. S8 ^: l
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
' k, `" O: P9 ~& D9 q9 ?0 p9 D - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
8 H! c& Q( f4 X* f7 \ - GPIO_InitStruct.Pull = GPIO_NOPULL;. y4 v5 Q$ @! ~1 N" Z7 d" M
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;- w& Q9 n* w! b* C& g& C: h
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
" m4 b6 }' ~0 H* k - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
% F) N& {: P$ O3 ?, _5 b* L W# G - 3 g$ U( b7 |7 A1 s( A6 I
- /* USER CODE BEGIN UART4_MspInit 1 */
7 w* d! ]! m$ Q, {, ^ - . k" x7 `2 Z6 v' |: F2 r
- /* USER CODE END UART4_MspInit 1 */3 Y$ c' `$ H, V9 J
2 f" o6 C7 C6 h2 f0 d- }
3 }( X: L- { V/ I
- u. t3 G4 q- W& n7 {" |- }
* B7 f6 F7 y- Y7 g8 b8 C4 B
复制代码- 使用cubeIDE
; e7 }- d& F) h! s - __io_putchar(int ch)
! }* B2 t1 j2 c# f) h - {- `3 W! y |& z0 c- R& J
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);& n, y! p s. W/ U
- return ch;
7 J' n: y6 ^9 n( u8 F7 k; h5 `! T - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
5 H% p) h) [7 D$ u$ M0 H( H8 A
, h, q/ b- ~/ e: v% f
添加输入输出头文件stdio后,就可以试试程序如何了。: Q$ E% Y2 q/ `+ \- `0 _5 f5 T
4 |' Y. g- V" V3 V& v7 w9 Z; L7 S
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
9 F4 K$ @+ ]3 B1 V5 N& z/ D- u: C8 i
6 z: Z; v7 M$ w3 Q7 m- static void ViewRootDir(void)3 t; p2 G$ {+ R+ t4 q! h8 H& A! j
- {& n2 P7 L; q; o7 s1 R) o# ^
- FRESULT result;! H3 P2 }- m# l1 z
- uint32_t cnt = 0;
' Q8 e" b7 l- T3 S* a r - FILINFO fno;6 r9 U5 [' u- u) A& v
( J0 v6 X& _/ W
; s" X0 \1 u- |7 G9 t( [- /* 挂载文件系统 */+ b) O' e1 b& d4 M3 k8 I5 i
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */' {5 ^2 n! n6 w# n
- if (result != FR_OK)8 q) v+ |5 o! \( H; t! ~2 ?
- {: y7 Q) @1 X/ p
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
- w; D6 u8 J: ~: @3 }- Z0 m0 d - }
2 x4 p' R7 b1 Q _. [- X+ t M+ G2 f6 B - $ ]8 z3 ^, k g( j$ Y0 \) h# t/ S% I2 x
- /* 打开根文件夹 */, D, }. m" D; G4 e! [
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
) ?/ T3 O' w& `% y, N - if (result != FR_OK)% ^4 h+ s) E: @% S4 j# F
- {
5 V9 E1 o+ c1 B3 C% N* k - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);. R3 ?6 V( a5 |. J3 _6 n' [$ D
- return;3 l1 z! [+ U# ^9 @: \% D
- }( c# K7 G2 ?2 a3 h' s' P
- * A1 H7 @ U0 {( N: \
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");
4 g! ]' t) h( U# ]# e; |! ^' f - for (cnt = 0; ;cnt++)6 z; a* Q. ?$ o" B6 Y. _. w6 i* i) h
- {
7 M- i: R: |! {: [# B - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */
% x- B$ h4 b( }; N4 t - if (result != FR_OK || FileInf.fname[0] == 0)
/ C u9 Z. e' D2 M - {
' [( p& z) Z# V, n" D% }+ I/ J - break;# u8 D( v" v& {' v
- }+ p+ v$ R- K% @& I
- ; q- c& }& N5 Z! N6 |" q
- if (FileInf.fname[0] == '.')
) N! ^+ m+ x% p# { - {
, T7 F) f) \8 u' C/ @ - continue;) M- |, G, S- @( D* D2 j; s
- }6 `# P+ \: R7 o) Q
0 q; V- g8 j3 g* W5 D- /* 判断是文件还是子目录 */( c% F3 E) d v' P! @. p
- if (FileInf.fattrib & AM_DIR)
6 ]6 x2 z$ E0 _/ H/ w; B* m9 x - {
* e1 ^* X( {7 y% R( s7 q - printf("(0x%02d)目录 ", FileInf.fattrib);7 w/ i0 J8 \0 v. b- h7 Y3 @0 I$ j
- }3 c/ h7 ?+ o* C: Y" }% X- x
- else' P5 K7 b9 @. W, w5 }. Y
- {0 M' S, y" ?9 z; ^1 h, U* w+ L2 q/ j
- printf("(0x%02d)文件 ", FileInf.fattrib);
9 Z; ~: b" }* B) L. [, W# L% u - }5 j4 {3 [1 X$ N
& Y8 ]- U. e: P u3 l- f_stat(FileInf.fname, &fno);
3 g" q' y1 y: K+ \ - % w: ~' f, Q" ]* h$ b
- /* 打印文件大小, 最大4G */4 M( v+ z& H. K* j
- printf(" %10d", (int)fno.fsize);
7 @' ?! z& y) o9 l; ~( h/ K
- F0 k1 q2 d- L$ E" E3 n" z( N
3 Y1 M: Q0 t6 P% I8 j9 n" N- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
- P6 f. p7 `9 l6 v! _ - }7 _) o! F8 O* s& X2 I1 F
% \9 R# G1 m5 i; x5 K- /* 打印卡速度信息 */
1 C8 M' i" Q* j3 B; c: O$ b- k- ^ - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)& W% g. P8 R9 |
- {+ q- ]: e: Q6 U$ Y+ j O
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
9 X1 X9 j0 S- B+ P/ } - }5 Y* @5 l( f- U& w) T$ j
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)% M9 w$ t: B' J
- {/ B0 a0 r5 Z" C# `6 g: F
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
1 ^3 i4 T, G* Y' x/ T. c - }4 V8 c4 |* B r4 |8 i7 z
- else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)3 `! N F. j* _- b8 t- N
- {
$ q/ M+ v* a# h _ - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
9 v! i# R' @- h! I - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");# ~* X! r6 l2 P3 G0 X
- }
; [" h) v: H, x" V( M+ ` - ) D! _( x* Q' K6 s
% Q+ k1 ?' Q) [, V8 D- /* 卸载文件系统 */
0 g$ ?- G2 [# f - f_mount(NULL, DiskPath, 0);
4 n0 }0 G* m K5 H( B1 u& m2 I - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
+ V( { v g+ b2 F; ~+ O+ R
6 S2 t O0 P) v6 W$ j, @ 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
- s6 \9 _% ?, f; ?, j1 T( Y 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。2 k! j& [; k, p8 \9 o
- C3 r# _# M; G+ R 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
4 }+ Z+ a. d3 L8 B+ |( U; `
0 E T: M( f% `$ b+ [
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可* h0 k( H4 D8 \) U/ F. S
e- K4 \9 j( K* s
料想这次应该没毛病了。结果,新的意外又出现了。
/ Y/ f$ p$ X- h9 z, L t, V. Z$ J+ _
- S( Y/ i. Y. T- v 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。 y1 Q* E4 b5 }, B
0 h: j* \0 m& M6 W; G 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。4 w" h" J& _2 q8 \
2 D" t1 q. {9 G' r9 Q% U ; d! m( k- N. G w7 C( I
4 _5 Q# R& }: |: ^, p3 a
& _$ }. E' ^' s, D$ r( B
' d' A: b; M1 S; E
! G# q( V( D: R+ A1 v8 Y6 f |