STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。 r# e2 M, ^; c c+ R
7 v1 T0 Q& l5 v) {
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
3 {% f) \1 q% K0 L9 p9 J* w 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号3 D. ~6 j. P0 R" A7 N
8 N$ c- e, r" n @9 `
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下1 L1 w7 ^9 n) `. V9 f, M; c5 q
! B1 Q( d3 t) y6 Z
- static void MX_UART4_Init(void)
1 b" j. w* R/ _2 K# F - {1 N+ j& W: K2 X3 K3 o @
% r* T9 f7 O6 A8 N1 d- /* USER CODE BEGIN UART4_Init 0 */
- m* S4 z6 y) C# I$ x
2 u% [! F8 s; W: M5 W7 h6 O7 }3 B- /* USER CODE END UART4_Init 0 */$ |6 d+ H# Y# Y8 d+ Q6 F- f% R
- % M* Y& x+ Y; ?! j- J! V
- /* USER CODE BEGIN UART4_Init 1 */* w. Z( `8 x' R
# h- C7 d; _% ?4 |3 |0 p, \) H- /* USER CODE END UART4_Init 1 *// G+ v! \4 `- H/ p4 t
- huart4.Instance = UART4;* t- J# j% n/ Y
- huart4.Init.BaudRate = 115200;/ H4 T& q1 m* F, F( ~7 e# }/ w4 U
- huart4.Init.WordLength = UART_WORDLENGTH_8B;
! @. `7 p5 t, r1 \- n5 F - huart4.Init.StopBits = UART_STOPBITS_1;
8 R- u0 j4 x* H5 `3 i7 a - huart4.Init.Parity = UART_PARITY_NONE;0 P" U, i6 H! m, a
- huart4.Init.Mode = UART_MODE_TX_RX;, [6 \$ {) r! U+ M9 p" u# D
- huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;, ` \3 t7 v9 {* V* n8 o( O# @/ w
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;7 q+ d! L, S) y( E% M+ l8 {
- huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
) \2 S' j# j; `% o$ ^3 G: G5 U3 U - huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;3 X5 }. Q% G& C% @# I' H( r9 p
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;; _' G& T' `4 v" h
- if (HAL_UART_Init(&huart4) != HAL_OK)
) h* n$ p# s: c8 z7 O - {
( x8 ]3 c7 g: x - Error_Handler();
2 m, S7 O; B6 c+ i; O! j - }
" T, U( Y8 J0 n* z1 n - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)" e" `" T: p, M8 ~9 o2 ^
- {: L% @1 S( y) W* o
- Error_Handler();+ i- j) x3 P6 V3 E+ R/ V
- }
) a' p. x! C# i/ h - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
( ]1 {& N( o) \ - {/ P1 j$ }$ e# q: ?
- Error_Handler();. J5 J" R% `$ ]3 j- h1 b) L
- }
4 A' i. R1 F+ i7 C8 H- h% X- D - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)
6 G+ ]4 [- p3 ^3 m$ Q+ W( Z - {
2 T! @7 z4 G) |9 h" | - Error_Handler();
& S. Q0 I* e+ E. S# _9 W - }
7 ~0 | o* |) R# L+ R9 T, y - /* USER CODE BEGIN UART4_Init 2 */. Y. j4 _; n$ X' t( ?* i o: g
; T7 n/ H; v: ~8 n- /* USER CODE END UART4_Init 2 */
" s5 @- M9 a, H; k+ k5 D+ D0 l
% U! U' N& L; R( Q- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)4 [8 ]: b$ Z# p* m/ ~
- {
3 O0 o: \. Y7 w - GPIO_InitTypeDef GPIO_InitStruct = {0};
- O' S- j1 i- C$ `1 h - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};) T2 i( Z) H( E9 l+ w# M' e
- if(huart->Instance==UART4)
9 [5 Z& R0 k4 C( x! ~$ J - {! F8 V9 J( r2 d6 L: G7 O: z2 |
- /* USER CODE BEGIN UART4_MspInit 0 */, @& h3 y( N6 C
- # S2 R0 b: g) S. x3 W
- /* USER CODE END UART4_MspInit 0 */
, P) @( G; w1 d G( Q7 p* U - 8 t" } v7 s1 U. s
- /** Initializes the peripherals clock
. r4 }1 G' n) T* O, w! o4 r - */
& K$ D. L2 }8 k6 `3 E - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;) F7 S5 d5 p- A X
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
# u5 S; T: E$ M, k: ]# B: n - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
z. V9 p# {5 m - {
/ Z& m& x9 a6 S" _ - Error_Handler();
/ Z" k6 K4 p8 D1 C% A6 v' N' ] - }/ t( t: j" y) P/ \9 `( t. l
5 E6 w' ^0 i9 L- /* Peripheral clock enable */
, d+ @' Z* U; f, K, w - __HAL_RCC_UART4_CLK_ENABLE();
9 @# L7 }: E( [& i. {3 k- u
$ i" {+ Q5 e. D3 y. X2 f4 v7 f- __HAL_RCC_GPIOD_CLK_ENABLE();
; o; s5 b$ w* ~: ] - /**UART4 GPIO Configuration
3 l+ S' _1 Y2 p; f - PD1 ------> UART4_TX/ l+ G& n* p4 n5 v! k j
- PD0 ------> UART4_RX# U+ o4 r I- a
- */! l: o7 R4 ^4 }9 n. ?9 h
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
( X0 f' k$ @+ W - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;; J8 \. J0 M8 _6 Q1 B8 ^! f
- GPIO_InitStruct.Pull = GPIO_NOPULL;
* f# T9 J! `/ s9 W) m - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;& C; R' L7 ^) H8 V9 [/ t
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;8 } R$ e' q0 [* `3 `
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
- d4 N1 g$ @& o( R \! s+ f1 c
$ C8 W8 m7 c6 G% I+ l1 c! W$ g1 D- /* USER CODE BEGIN UART4_MspInit 1 */
) g& h( Z8 F3 b$ H. s - % C0 y$ d( ?$ l E. Z* W
- /* USER CODE END UART4_MspInit 1 */
& G9 {# Z' ^) a) U+ W, G: w - / {5 b* j) K. K0 p! c- `- S/ T
- }
1 Q3 _! x% H: i( | - ' A o9 m! u7 K( L
- }
2 V1 H! P5 d. s' x) g
复制代码- 使用cubeIDE
; C# f' b j$ x( l - __io_putchar(int ch)8 e8 N9 c$ y) \
- {5 ?" \ \: U" Z) n; z0 h% X- m+ h8 ?
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);. q/ y3 @3 u. P# S8 X7 _1 W: v0 n% M
- return ch;+ b: \! B; N4 u' Z1 ^2 v
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下1 {1 _* R# @3 s9 m! @
m; V e6 \7 J4 V/ s6 m
添加输入输出头文件stdio后,就可以试试程序如何了。6 x7 s/ }' P' D& T2 N, f7 X+ Z
" H; B( p- A/ d$ [
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
- m9 I* F; P2 y% W1 ~3 t3 W : U0 A7 u6 o5 H p
- static void ViewRootDir(void)7 J' Z8 O* d; U
- {* A% C: i" y6 Q
- FRESULT result;
% U8 F7 f2 }8 ~* N2 ^( x - uint32_t cnt = 0;, A8 C1 U6 r, Y- W& _: e" j1 F
- FILINFO fno;
- C$ e, Q5 ^* y. r% a, P5 c1 k
1 S' i. w1 j+ G8 Q- & o/ Y+ @$ ^) f" z8 }" \
- /* 挂载文件系统 */; ~0 E6 D& o( D( b
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */% T# F4 N$ G* m4 ]0 j! O9 M
- if (result != FR_OK)
( Y5 o; Z2 t6 K; d- k - {, ?1 C d' \% m- i9 w: b4 p7 v
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
* D% v4 R* d* p6 P# [; ^ - }; C* ?. W" ^, Y) X
- . ^9 `8 r; }) g$ i2 O
- /* 打开根文件夹 */
8 H; Q c h7 U) k: C4 S$ m - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
7 G0 s& P* F, X' ? m7 Z - if (result != FR_OK)
7 A& P9 o; ^/ j7 h( L5 Y$ y - {
7 L3 ` ~- j- _+ C2 ]5 e - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);8 _$ ` K) g+ D# j) J1 F7 u4 t
- return;
7 y$ {% D' O& t! T+ z4 v) | - }
4 |; r2 {! {% d& x! r - p* e2 \0 v8 o
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");$ n9 s- R$ f* m+ k! @; r
- for (cnt = 0; ;cnt++)
9 p3 x+ r' J, L! z" I9 l7 X+ k - {$ x5 }3 w4 Y: N/ B
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */
: L' R s# P' {' Z. j - if (result != FR_OK || FileInf.fname[0] == 0)
3 z$ L7 W7 M5 ~1 ~# b% Y - {
1 O$ n' A8 x3 ^7 v - break;& ]. b6 k+ h9 I& i- k: D9 j; n
- }
* d6 r+ k3 m7 F
, C/ i! u& f9 P, O/ }. S7 S. k- if (FileInf.fname[0] == '.')
, u: q& m6 g9 Y5 K( ] - {7 H( { `4 i {4 ?7 s
- continue;
" I( C% ?; x4 m - }
5 w3 c Z/ e& i, h% X
! ^1 F- {0 X3 F5 U! [" L- /* 判断是文件还是子目录 */
! c9 U* ^/ V) x a0 q$ V - if (FileInf.fattrib & AM_DIR)( W ]% l3 r' b, |; V* w
- {
4 i; @5 B# k3 j, c/ j2 Y# G - printf("(0x%02d)目录 ", FileInf.fattrib);9 E6 V8 m7 `. Z$ ~1 O
- }
/ s" n# ?' l. \ u5 r - else& x% V& S7 K5 n
- {& `7 ]& k0 z/ k- _3 m! A
- printf("(0x%02d)文件 ", FileInf.fattrib);
# ?; Y: v+ c! {. z/ ~ - }1 \; i8 t- H4 O# S4 l
- 8 [' s$ `/ [5 W2 o7 u7 k! M
- f_stat(FileInf.fname, &fno);
/ f) V, [2 H4 |( W, q: |: B
3 M3 L; r9 z- p1 X( O- /* 打印文件大小, 最大4G */" U2 A# @4 V2 j" k
- printf(" %10d", (int)fno.fsize);
. A3 s7 p2 s1 w; Q" }$ j$ `
' \1 q% l4 H% C! c2 R8 P- % S$ H) H3 F* Q- X7 d# K! o+ \% F
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
, \1 n5 d+ b0 \5 Z/ _ - }
. K8 ~7 ] B `4 K* K
- F* [. V' s- l$ m( F" r+ m- /* 打印卡速度信息 */8 H D/ J7 I# _+ M$ {
- if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED), }% ~3 @( h% P$ l' z2 E
- {
- g6 o C3 x1 [9 j4 M4 t. R1 C - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");' v0 j/ w4 Q3 K. E
- }7 a4 q1 h, x0 t4 w9 R- Y
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)* U: W1 u' e. K" G( V7 \
- {
* }0 W2 p7 d# Z% z - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");( E" c& S$ t3 U0 `$ @2 ]- L0 s: t i
- }
( D: N. e& e) W, Y0 F3 C4 R: [1 @ - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
) f7 N, c) F5 i, `* w+ [' N - {
; K7 l; r) f5 j; y3 ]! C - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
; m5 c: b" ~% e* q; a$ X* o: f - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
4 o, b. r* O& T - }
0 i: h4 r0 @5 J0 e& K1 }5 c) n
- H2 Y6 F5 g" A9 p( u" G& L: O, R- & v$ t: l$ k; A0 P
- /* 卸载文件系统 */
7 s( ^: V8 x& s: G- D- S - f_mount(NULL, DiskPath, 0);- `, }& c: n) z* ?7 Y' a$ ~) j4 J
- }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
. G3 a; _' I- ?; [6 K5 W! Q; r# u
- u6 u) | z" d* c. h 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
1 n7 ^- O2 ^' e" Y 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。
: A7 n6 g' L5 g: [
+ {( K @/ h0 |# |2 e 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
, t3 M! A$ o" p8 S5 { y7 _; m5 U
* t' }! }, F9 o+ O$ D
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
) l6 H- e* X. ~# F2 I
8 {2 D* X8 L0 X 料想这次应该没毛病了。结果,新的意外又出现了。, j h: [. n; `4 X
) N5 \; r# e( a8 E. p% g
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。& q$ X! w. ? L; c
9 o- N N: l$ q9 Z 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。8 ?3 b& @; B2 p. a9 Q' q/ A5 x" P
) T9 Q+ W9 A$ m / k1 D, k: R$ K/ g; Z$ }4 p. r2 w
/ {8 |! s4 S( L' P: N4 ]0 O& z
+ A4 r0 [( Z5 h Z
4 D2 n, S+ _8 p/ a/ @; _: e9 |/ K+ i+ t. r# M4 t V% Z
|