STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。3 U7 w3 Q& C, b3 R; S- \
! [; f! ]9 M$ g+ D 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
; E& i& e9 O1 O5 H, b 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
: {& n: Q% F# _/ C5 p
8 A' Z; I4 O1 u+ i" `; } 手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下# q: M2 P' _& u6 F% ~
E! r% X4 e$ M2 V- static void MX_UART4_Init(void)! R# x. B& I& h' }
- {! J( ?! z& R& o. q) z
. q" x% o5 L* W$ ~7 s' i5 O- /* USER CODE BEGIN UART4_Init 0 */# k' u( S4 O, H3 O& K
0 }1 @# y, h" p: R- /* USER CODE END UART4_Init 0 */7 A5 L @% O" Z! V* }- u, `
( `5 e0 W4 j) u8 P2 D9 o! \! a4 H- /* USER CODE BEGIN UART4_Init 1 */
# o6 y/ S7 T% _/ \
& Q: t4 T4 t/ u! A; q/ y, ~. E- j- /* USER CODE END UART4_Init 1 */ W; j8 c8 K( W+ e# q' F9 B
- huart4.Instance = UART4;
$ B1 K$ v- ~# x" Y" R2 U - huart4.Init.BaudRate = 115200;
/ k' Z% J6 K4 O3 f. E( D9 c - huart4.Init.WordLength = UART_WORDLENGTH_8B;. a7 e. Q5 C7 A
- huart4.Init.StopBits = UART_STOPBITS_1;; B' R! |# O2 {' V5 L3 s
- huart4.Init.Parity = UART_PARITY_NONE;
4 ^- r, [0 L# O& p |+ x - huart4.Init.Mode = UART_MODE_TX_RX;
6 B( v$ r" i$ ?* c3 O. A7 s2 y" r - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
5 s, P; t/ t& ^* D: [ - huart4.Init.OverSampling = UART_OVERSAMPLING_16;
& D* z6 d4 \0 h" ?/ |0 `4 A - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;( |) ?* C$ ]/ l. c
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;. z0 Y s* v7 x* F
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
: N2 a1 a* K: C' s& m2 N; F - if (HAL_UART_Init(&huart4) != HAL_OK)
" O' x! f `: T - {% L7 r' Z/ G0 V
- Error_Handler();2 z; W' h: {' o% U! H& V X
- }
3 ^5 Z4 I9 k- D - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)( Q$ V" {% m8 k- j' O5 |
- {* ^ A* X8 X! t
- Error_Handler();
9 I, G2 [, {/ X - }9 S6 p ^* B* p9 f; @. u7 H0 p
- if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK), o& @+ y" R- O: a% ?9 B4 X* Y% F
- {
/ G0 }# N+ r" }: g" A) }/ }& |& b - Error_Handler();! u W$ ]' S1 y- w( `/ X
- }
9 X4 Q9 G ^6 L# ^ - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)
* B K% m2 ]! q! |9 i! F - {( y' y( k4 T- F. M" J& X
- Error_Handler();
( D2 z) o4 n5 L, \) h& O - }
3 v9 ~% M. q7 R7 s, E6 c% ?6 ^4 B - /* USER CODE BEGIN UART4_Init 2 */6 {3 v4 \ G7 T) s" C4 ^
9 o2 P* w) W* A; e- /* USER CODE END UART4_Init 2 */9 J! ~3 _6 D4 x4 p
" [2 `" }1 n8 c: Y) \! z- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)3 u8 z0 g" l1 x b5 @) \( Y) G+ M9 W
- {$ r V& a0 b0 n/ P- W# x
- GPIO_InitTypeDef GPIO_InitStruct = {0};
8 F7 ]+ d% ^5 t. a C - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};7 `# e! k' ^, H
- if(huart->Instance==UART4)
( ` G8 i' v# q) |# p$ i - {8 N% D3 u$ D8 o) B
- /* USER CODE BEGIN UART4_MspInit 0 */! o3 J. a! m4 o! a4 c
- / N3 r# G: Y- y
- /* USER CODE END UART4_MspInit 0 */% j( o" ~: B3 g! }0 _/ P! X
- " _) D6 r9 k* `/ |% q, p; M
- /** Initializes the peripherals clock
/ J7 Z8 L+ k ^ D - */
8 N5 I: H9 ]8 H, i - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;; T4 u* S- O/ C) j: d( u
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;& A4 L U- O1 Z. t$ T$ Y* N
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
) r! c7 A" j9 T4 A* K - {
" k* T7 f+ _7 t- j - Error_Handler();
% d A- C8 B" R; y* f: M - }. l" z/ o' D% G4 U: _& _$ R1 P5 V
- ; `8 o' D" I+ Y5 `
- /* Peripheral clock enable */
1 ]+ x8 x! G& U - __HAL_RCC_UART4_CLK_ENABLE();0 P q7 T1 d# ^
- " q' U. ]" {8 f
- __HAL_RCC_GPIOD_CLK_ENABLE();
, P: {) D: c* v+ }7 k3 H2 `* f! i - /**UART4 GPIO Configuration
2 \: U6 }* d+ z7 v - PD1 ------> UART4_TX
8 N( ]& o5 M! C - PD0 ------> UART4_RX' a: D3 [5 d% n6 p- }
- */4 y8 C% g: s2 T% B8 Z+ u/ p
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;8 l1 k7 S4 R+ c* H: `. D/ k+ D
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ P2 W6 y4 P9 B1 Q - GPIO_InitStruct.Pull = GPIO_NOPULL;+ x, Z% {* `+ z0 U
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;2 H7 ]/ Q- Y d- U2 j9 d; i3 r% _7 v9 N
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
' F% M! r$ b, ~) l2 s7 Z' i+ k" g$ l - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);$ L( g3 h4 ^; F! z1 E3 V
- 0 |' ?# g: k U! F- r
- /* USER CODE BEGIN UART4_MspInit 1 */% F* s# L( }: p) U( G
- * L, P$ K3 V2 W
- /* USER CODE END UART4_MspInit 1 */
A8 e6 l" }' y+ U
& ]$ E3 Y' S" i- }" i3 Y) b$ b- k3 k. O# |
- b. T" [) }4 }9 F1 r, N
- }+ J+ x. A% x) q. k# p9 B$ e
复制代码- 使用cubeIDE i" z5 V8 \: \" e7 v+ R
- __io_putchar(int ch)) h$ C; t4 s b5 c R
- {% }) `* ?+ x9 a7 F$ ^, Z
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);' ~2 p( Z' s2 b1 e z' B
- return ch;# E8 z, F' z! ?
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下 D2 R' K1 N& Z) H% J
$ }3 b9 [1 T' E9 r. A
添加输入输出头文件stdio后,就可以试试程序如何了。' E2 I% {' q! Q' t
8 h# ]& w7 c4 l1 ?4 H+ q* S
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。) T8 x) R) k) V5 x( x
+ L4 V- q7 i, ?9 [9 s. Z |
- static void ViewRootDir(void)" f" f. V; U! X8 N5 T% U
- {* u& Y$ ~4 T& h; V
- FRESULT result;# `( A, k5 E0 N; q
- uint32_t cnt = 0;
) H2 A+ W8 d6 p/ h& {1 \# B - FILINFO fno;9 }3 f$ t+ a5 |! K$ B8 ^
4 r* v0 O, O: @% x- , {7 K, R% Y9 P0 {2 d" K
- /* 挂载文件系统 */! ?1 C+ o2 L# q
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */
1 i/ U, Z* |" X" O - if (result != FR_OK)" ~: `9 |7 l, A7 T* q0 q
- {. M) U m& ^# M9 I+ @3 E4 q6 c( K
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);% B- X3 L! i1 k) }% s3 }" U; Z
- }% [- B# C2 m' t7 d* z
- V" A! o3 Z: g3 o
- /* 打开根文件夹 */
/ e2 c3 G' Q' a( i" j# n$ |9 ` - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */! e5 o) w5 S& m' ]* G( }
- if (result != FR_OK)
2 K" z+ k% l% p% H( i, b* A; c! A, A - {
+ t! ?( v7 s' B9 V/ ~$ F - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);8 A1 D8 I3 D3 p+ J! y) Z; H
- return;$ p' b* ?9 ~3 O( K [
- }
" J- Q/ L$ c$ c% Z" {7 d3 E* C
. F" s" t5 x, N% i- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");* R( ^7 S+ q9 y
- for (cnt = 0; ;cnt++)
3 W4 x! d: P: z W& S - {6 l& H; W5 A: ^0 f% B- e" k
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */1 d1 J* g4 d! V9 }
- if (result != FR_OK || FileInf.fname[0] == 0)
7 E/ E" h# S" |5 H4 _% r - {$ q: d* r' x# u4 y: D0 I4 L
- break;
) Y6 k! C; d4 X- d4 j; x- e - }
; R6 {! a4 F% N% y; \
5 z7 T4 u. Y! U2 t' J- if (FileInf.fname[0] == '.')1 k7 G- g- g; X* }0 N! ?7 C
- {6 z/ a; k1 M$ P
- continue;+ c- o( i* f6 }
- } p ^4 q2 o8 `( s( z4 p0 F
* L% {" \: s! z% q7 V3 ~- /* 判断是文件还是子目录 */
4 h ?1 _7 O, b# C" F5 X - if (FileInf.fattrib & AM_DIR)
, {0 o. E% h$ Q* G - {
% _0 v$ ?6 z0 n4 l9 R( T - printf("(0x%02d)目录 ", FileInf.fattrib);2 M) a# ?- W/ j, `, @% `
- }6 I R- Q: x$ s- @' U% \/ S, }
- else
- U9 F& X ? \- W, x - {7 x' e# O: `: u" _
- printf("(0x%02d)文件 ", FileInf.fattrib);
6 f9 J6 {& @5 x) j# d - }
6 X7 c8 f" P- R P' S( u" ?
- ]! |" y/ H9 f* h5 A9 |1 R- f_stat(FileInf.fname, &fno);$ W9 R/ b/ C" `! ^* b
- , y9 J' m+ f2 G0 F0 O3 _
- /* 打印文件大小, 最大4G */
; [ e3 z$ o% C! x/ v; v0 Q6 p0 U1 p4 C - printf(" %10d", (int)fno.fsize); C F; s0 ]. S: {# M- Z
, U# ]2 B: f+ m2 q2 i- 5 \, S. | F+ A: H
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */! \; a7 |/ k8 `/ W7 Y4 ]" ]- X; B
- }
8 B, }$ Z8 p. q
- b2 h5 \5 O N5 p9 @3 e! M# F* M- /* 打印卡速度信息 */' X8 D3 u: d3 y! I+ i
- if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)/ |9 _$ f# D$ y# u9 S
- {
, k; t! w5 S) n0 W5 h - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");: v6 @( q' P* t) X, q: g
- }
# {$ e4 R9 c: i3 M- B - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)( i* d1 x3 u2 {) }$ i- z0 b* G
- {( j* c0 X2 a! v& E$ \. P
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
5 L. m' b1 S. o. M5 H8 v - }
" V! }6 ]' J" ^2 ]$ ~8 G - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)7 {5 o4 R( x% V+ c
- {
4 k5 m. z! Q3 N/ Y8 G. a, [( @ - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
( R# u- H% X G$ q z% C - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
& E. L1 f1 }8 q0 n. e0 P' p - }
. Q$ S1 U U2 i3 P9 P8 L9 a - . n: E# k7 C5 O# T. ~, p! G
4 d) Y6 U2 y, X. ~: d) q4 o- /* 卸载文件系统 */
& d+ S. z* T; r/ i- I - f_mount(NULL, DiskPath, 0);( _! x# v8 c: t) H! o, o" r% T6 H- r1 q, ]+ B
- }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。5 g9 `# q. M' y E q+ U+ o
( q4 a1 ^" a- m" U0 M7 Z% s 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。$ D9 f; f/ v% [, d* U* p
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。
4 h1 |6 |4 p- f3 U
2 {+ G, {4 {: w& s" c* ]
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
9 t* V: c ^, k9 b
7 [4 {( V$ E1 `* O) c 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可* }, {; ^2 J$ R; g7 p# x
) K( B* q, \* H) m 料想这次应该没毛病了。结果,新的意外又出现了。2 T8 n4 j" {8 u- ^! B
( V3 b2 |; f0 [+ w( q# j1 \& { 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
( ~& n& X( x S8 R
2 L' i0 \! }8 D
满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
! H" n( Q" G, w5 C2 h6 u& ?' G/ E+ J a2 h. L
8 e( h6 ` U- l
; ]! E9 `5 ~$ `0 O) Y8 Y' w5 u* G1 A
( S6 o+ r& W; g' U/ U* A8 Q2 B3 v$ {# i9 _3 ^' N+ M
6 k" W/ q3 q3 x; z6 ~. E6 \" X5 K m |