STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。& P+ Z' A8 O! z8 o4 u
' H- J M0 s; l+ x& B5 p+ e
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。9 \* n% [4 e& l" `
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
% k3 Z6 [, V* } f$ \
) k: E# [. H% F' C 手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
4 b+ I4 K; C9 j2 V
* P4 w* J7 N( d1 K2 J1 t/ S- static void MX_UART4_Init(void)
1 |$ H8 {4 {7 L; w - {! F8 z, }/ Q# r8 L
/ Y3 q2 Z. ^* x, W1 o) T- /* USER CODE BEGIN UART4_Init 0 */
! y- X' X7 H( r- A
% ~, U+ h1 P6 ~$ _4 q- /* USER CODE END UART4_Init 0 */
- }- ]# J% C7 Q$ q
, _5 s$ e8 {7 x# ~9 T2 V- /* USER CODE BEGIN UART4_Init 1 */
) Y- y- l2 E8 ~
! w2 R. a& R# ?1 ~7 }- /* USER CODE END UART4_Init 1 */0 n& \9 ], u- N/ S3 G3 V' a+ f
- huart4.Instance = UART4;8 x& w7 _- a1 [
- huart4.Init.BaudRate = 115200;; S5 B8 i3 u% W
- huart4.Init.WordLength = UART_WORDLENGTH_8B;
- R3 Y4 u4 _: f3 Z* o$ |9 O4 \ - huart4.Init.StopBits = UART_STOPBITS_1;$ ^) a, }! j# ]" ~! \, A0 {
- huart4.Init.Parity = UART_PARITY_NONE;/ d8 q- e4 J" Z1 I b9 k% R
- huart4.Init.Mode = UART_MODE_TX_RX;4 B8 i8 h8 s& {) i6 F1 y" _' L$ y
- huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;/ V" b+ i) `3 z( H' R' P
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;
) w% Y6 v' u( O. \ - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;( u. i1 n4 ~) C5 N
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;" y4 s, R h! z7 [, A8 e7 }
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
& w% r% _5 L3 K+ o, ]; M - if (HAL_UART_Init(&huart4) != HAL_OK)
) g2 v" g h8 Y4 w: t( a9 s& A - {
0 m1 n& V: z& O - Error_Handler();3 f6 q) S: F9 T$ X
- }
! F! d, ]0 m! L9 w. X5 G - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
. j, B7 B7 `. B( c+ q% S - {. q1 j& u f3 K2 u3 b6 o( M+ D( W; ~
- Error_Handler();
0 l; @% {8 J% t3 @6 }& F - }
- `& o- A! {, x - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
0 T# z! A6 U+ f- w4 K - {; D) i8 D3 k* J; |- k
- Error_Handler();
6 v6 Y4 K W7 L - }
( H( J3 a; `& a$ s6 s9 c - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)( N3 b B6 W5 S2 z2 Z$ N
- {
: c& [) B# w4 J+ D - Error_Handler();
% q( Q! C3 A! y# o - }) t) X7 H4 @1 W9 S0 M
- /* USER CODE BEGIN UART4_Init 2 */
* D/ M e9 L5 B' q& ? - , B; S! k1 B% p' i' j$ } e
- /* USER CODE END UART4_Init 2 */
5 E) j- p1 g) x+ G - 8 i( R& I2 c) {
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)+ i5 }! G3 n9 `
- {* k: L* f! ]' \: z
- GPIO_InitTypeDef GPIO_InitStruct = {0};: [0 r3 @. D( P' V+ y& R' k7 K, z
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};: q; z4 E0 }9 p1 C: f% D# w
- if(huart->Instance==UART4)5 A l+ t6 h1 u+ M
- {
3 ~% U2 ?( z' W2 s* L% y2 c - /* USER CODE BEGIN UART4_MspInit 0 */2 P3 j8 ]9 d" Y# v
- / \1 g& y( C* e0 X( ^ {+ ^( G
- /* USER CODE END UART4_MspInit 0 */, A7 w( D' k! I& s2 j
- , M( X* ^1 ~6 u" Z" g, L. ^
- /** Initializes the peripherals clock
% S6 c7 k, _( d% ?9 v- v - */
9 M' r$ s5 a9 Z; [" Z" N - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;( t7 x8 [! x) O* f" q: E! A
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;! C: Z w9 O& G+ V+ V3 c1 Z! c! a
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
6 V5 n. O5 ]8 ]: s7 { - {
8 N7 n4 D8 l$ p6 H! T - Error_Handler();1 a: l% j m( ^% L- i# \* E% E8 S
- }1 Q* D- s) L& H
3 h2 g/ J( H% F& R- /* Peripheral clock enable */
6 F. m2 M, j$ R- d0 Z1 P - __HAL_RCC_UART4_CLK_ENABLE();; Z, d5 H$ ^3 N# @$ [
) z% ~( m4 N+ p6 I- __HAL_RCC_GPIOD_CLK_ENABLE();
1 B7 P( K2 l+ q+ ? - /**UART4 GPIO Configuration. w% t* t* z2 l
- PD1 ------> UART4_TX
& c) h- F, W( Y5 u F - PD0 ------> UART4_RX" v, h4 E7 j7 N( N/ z) @6 Y
- */
/ r9 R( U6 { {. \$ B - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;" o1 M2 y% U- V) {" @( T
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;& e& d1 b# `9 r
- GPIO_InitStruct.Pull = GPIO_NOPULL;
( t( ]- g/ d( N p! Q5 S) g - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
7 D( m( q0 ]3 n/ i - GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
6 { O- O0 ]' u. i. R3 P7 V; B - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);% m, |6 q0 M+ {" a5 M
" B0 v1 ~+ s1 p1 K) B- M7 L- /* USER CODE BEGIN UART4_MspInit 1 */
7 u- E" t% @* K# @/ w
. R# T7 X' M4 ]& ^- /* USER CODE END UART4_MspInit 1 */1 w* T: c& |$ V8 g; M Z/ O. l- k
8 ^! X. U7 h3 F6 o2 L4 g- }4 o ^5 J8 r/ n6 O
4 P8 y1 d3 Y# P I, j6 [- }
; s. j* o# @( K- z- m2 y
复制代码- 使用cubeIDE
7 O2 U7 {) O, Y9 S+ E+ ~* @ - __io_putchar(int ch)
$ W7 H* ^- [, g# c f, c8 A( J - {
. V/ _2 K$ {6 e' T - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
. |6 g2 b9 [! |3 K8 y( X - return ch;
0 c6 |( ~4 s7 ?- }8 f - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下1 _' m! z% V& O# N
8 n3 ~' s+ W4 M0 Q
添加输入输出头文件stdio后,就可以试试程序如何了。9 h6 X5 t" h! z: g( B7 i
1 H, n! k$ D2 ?) i
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
6 a, T7 Z" X3 Z6 y : K4 V/ M) U& p$ g8 S& _" Z E
- static void ViewRootDir(void): b) Y- H0 {" S' g# m
- {0 t) D) ^7 \5 v% w. {
- FRESULT result;3 l$ E; u' j) t* K2 Q1 C7 Z
- uint32_t cnt = 0;
# S" B7 E z* j- W# } - FILINFO fno;
2 h( _+ ~# q; i4 I; y( _6 Z3 l - 2 V& Q# s0 s# H/ I8 p9 k
- - _- h# A7 n3 [
- /* 挂载文件系统 */& j, \ L$ o/ H* ]# _
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */* V- r( v' V, x0 U
- if (result != FR_OK)
' ?! g1 p8 l1 b9 h - {
5 G& U1 }; d$ R, v, K$ j6 j - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
# t6 a! y; U3 h# ]9 i - }. n# R1 x: x2 b. N" G5 Z" Q
" \0 W7 D; `2 H, x. W' P- /* 打开根文件夹 */
" E5 q0 T1 |7 m; j - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */6 P/ N+ n' u3 |3 c$ Q
- if (result != FR_OK)
1 J- D& Q3 S+ C7 \$ c- [7 T& B - {
. g; ] f& `/ N) p7 ~9 r6 k7 P) B - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
, x3 G4 j' f' W7 d - return;) V- G! l( \1 U6 [
- }
- d" B- g# V/ D4 N' y7 |. L - 9 |$ W# O& ?& @4 m1 e7 h, ~7 q
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");
1 W- J! x; d# V* e! C - for (cnt = 0; ;cnt++)+ x% A% Z3 o1 s6 @$ o' N; V
- {: Y1 h& F. f7 I* l
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */8 ~/ r/ _( F# g$ \) B
- if (result != FR_OK || FileInf.fname[0] == 0)
3 A8 @% i j' e9 `! |& q4 r: ~ - {
q& h- a, n7 a1 W k - break;
* w7 j6 K, c+ R' R - }
9 ~" J! c/ l) I+ J- A1 V2 Z% c - / S1 Z3 B! a* u. }* X% n2 R+ m
- if (FileInf.fname[0] == '.')) T% ?" Q: h# f, X. G
- {
2 ~& x2 A% ^& T, T5 a( N - continue;/ N% r" r0 B/ m1 l2 X. t5 ~. |
- }
7 J( W; }' {4 _4 Y) ^& U - : q* N# I. S" f' |* `7 ?$ E
- /* 判断是文件还是子目录 */+ t( [8 q0 x% P
- if (FileInf.fattrib & AM_DIR)
% r4 B9 k; Y. v# E3 r - {
; W: l: Z! D( j) ?5 g# U/ p+ g - printf("(0x%02d)目录 ", FileInf.fattrib);
* X( F( n, M3 J* V/ ^% e* {' | - }
, ?% i" f& \- w. f# V' n - else
0 S4 W7 _$ M' S' C2 Y5 B/ } - {
$ J" y9 i( V& n - printf("(0x%02d)文件 ", FileInf.fattrib);2 k: R2 A8 G/ i) @9 H
- }
8 B1 H! t8 w9 W. ^ - ) M1 H: Z3 h7 R7 ~$ u4 _
- f_stat(FileInf.fname, &fno);
0 b- O s( [+ h. ]' G - ( J/ Y) ^3 U! u. i- m% w( I8 `% x
- /* 打印文件大小, 最大4G */4 ?& T" s5 w' M- x# e" G ?
- printf(" %10d", (int)fno.fsize);$ ?2 s; |; Q4 H% M1 j$ N0 a' t- r- s
2 B" w# s; y6 P* M9 |7 d" m- ) R, b- y! j7 G$ e! G
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
1 q& y# l4 Z% ? Z1 p% e2 r' ? - }; `$ r4 D# M+ o
- ( G5 ~; L' [$ E( D
- /* 打印卡速度信息 */" p2 n T/ S# q# k. R- r
- if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)) Y @8 { ~+ ]
- {, T3 l6 O+ e9 k/ H3 x% Y
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
: Y2 c5 ~9 p |5 ^! Z' O" J - }
6 j. X! s' U. Q7 [. c - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)+ E! H5 N. ]( H3 ~* w4 A
- { Y) L% b" T, u0 R: H: Q$ K
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");' Y) N) n1 B& B1 g7 p* L& A- q
- }
8 M5 }5 I! n0 F4 { M - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED): d: P2 G t1 X
- {8 r& p% Q \2 l" f
- printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
8 }( T/ Q' W; {* ?' ]5 |+ t - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
& O4 G; [( _6 ~2 y/ g% P - }
3 [! j" G/ }- `) f' ]0 `5 ] - + f, s; z; B4 p7 Z- ~: @, M5 Y
( g9 t% x Z) x- /* 卸载文件系统 */
; q7 @9 n. S; v! X2 k6 i; U, V - f_mount(NULL, DiskPath, 0);
5 m2 M, v5 w# D# b# b - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。& G; Z$ k% z+ h. Y4 l9 J
+ k4 F$ O! {, v Z# ?9 e
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。! H. N/ P0 m) I
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。3 A3 p2 G k4 C+ }" M: N
^' i9 s9 H7 h2 Y) W! W) a
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了4 e% T/ I) r9 T- K4 Z
& p7 [) x R s7 `) M 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
* F, a3 K( Y) H2 [# u1 h
N6 U; x* a5 ~5 L( }: k' F
料想这次应该没毛病了。结果,新的意外又出现了。
6 g, c' i3 q- G5 ?: j: J/ C
Y# V2 }+ L9 D/ p. r" `
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
8 D! [; y( R2 l9 ^" q
F: L1 S0 _" n! [4 ] 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。+ P9 Z8 ^% J1 L+ t$ p
4 E8 F; c- n% D) i% z5 j x 6 X4 M- P7 I$ F; \
- T8 n; C7 a3 N/ a: V
. E* Y2 E$ }. \6 G9 g
- _5 [" s W' h" C* ]5 u
]8 G& T# b4 K |