STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。+ M& J6 z! q; P
3 ~' b9 S+ c' S; R# Q$ n3 b) _
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
) [) |. T, O4 `. I6 |$ a6 | 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号9 m. O' b4 c% V# H
/ e7 A3 c- a+ g& f* M. ^
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下1 [( }( Y/ e! ~3 j3 S) Y
0 ]0 K% U9 E0 H3 B4 m
- static void MX_UART4_Init(void)
W. ~1 f( H8 b! _/ U2 X - {
# r& F, f% @, J& ]% }' z9 Y
# G; U, Z: a3 V8 m& E7 s- /* USER CODE BEGIN UART4_Init 0 */
4 u5 w% k B) t6 N - % m4 m+ P' j" ?8 v
- /* USER CODE END UART4_Init 0 */5 ^, ~( ?0 z+ G( b& E+ C
- - u' ]( B1 i+ i
- /* USER CODE BEGIN UART4_Init 1 */
7 k; q6 ^+ W; P/ B; G2 z2 b* s0 I( G
$ G. a' a! q0 j# M' @8 f- /* USER CODE END UART4_Init 1 */" }. m0 y9 ^! R- d5 H6 V$ H
- huart4.Instance = UART4;& D0 W- B/ D# Y6 r1 v% k
- huart4.Init.BaudRate = 115200;
, g8 G+ R. i, U$ Y: v! q! l8 m& ] - huart4.Init.WordLength = UART_WORDLENGTH_8B;
, j4 z$ z1 R+ ^ - huart4.Init.StopBits = UART_STOPBITS_1;
- [1 e$ p& e1 \4 V4 S7 e( C* p! P - huart4.Init.Parity = UART_PARITY_NONE;! T4 Z# H$ E6 |4 O }
- huart4.Init.Mode = UART_MODE_TX_RX;
! b) u/ L3 g! ^) v - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
3 Y; R7 ^# m2 {% C# N$ { - huart4.Init.OverSampling = UART_OVERSAMPLING_16;
0 {/ n1 s+ }" a1 K5 l2 I - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;! A, r8 \$ T9 U( }5 M" _- P
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
+ L. y$ X" D' A - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;8 P1 S$ e P" N
- if (HAL_UART_Init(&huart4) != HAL_OK)
q/ a$ U' @+ d: B4 k - {/ ?* k3 Q! S4 c4 O$ q# T+ g
- Error_Handler();
7 u4 K# P9 ?: M& Q% @9 L% r% h - }
* l0 a4 Z! J7 \. o$ u - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
+ a- z: m3 j- _" D+ B5 n K& [ - {+ ]6 j; ?- o7 G7 i+ |7 |
- Error_Handler();/ E$ s$ t; M3 @6 |$ C& Y4 u
- }
u& q0 L; \. _( x - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)$ p2 p! ~; l: C! p4 x5 f- O0 }
- {
; l# b( S+ ]" z& R4 M - Error_Handler();
x; W* I1 Q2 ~6 f# u - }7 k2 o/ S3 J+ b7 d. v }/ o4 C
- if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)
* A) ~- X6 c, Y( @ - {
2 W; D0 s0 m6 S$ l; o8 m - Error_Handler();$ J# X* @( H9 o4 N* \# [
- }
$ H6 b, z& C! l5 T2 ] - /* USER CODE BEGIN UART4_Init 2 */5 K* U- D. r8 }* t
- 2 |9 C+ H. _7 O8 C! N6 z7 y
- /* USER CODE END UART4_Init 2 */5 {5 u2 l% m# @1 o
* |- f. f7 B k! E- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart); h; U. F: T% z7 E6 r2 ?' d
- {1 `3 g" M: I0 b/ W% V) c
- GPIO_InitTypeDef GPIO_InitStruct = {0};
# e- I2 q% ~" \' r8 b. v5 h - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; z% q5 i# J0 Z, _( d5 R9 I
- if(huart->Instance==UART4)
' V+ J$ | c8 l& P, J - {" o2 S( R4 o* X3 Z) j
- /* USER CODE BEGIN UART4_MspInit 0 */4 ~/ e5 d" W, ]$ Y6 l) e" N ^4 J" n
- ( g# j) _; J, A1 Y7 J
- /* USER CODE END UART4_MspInit 0 */
( Y. |+ \2 F/ O) F; o - 9 `, P2 x1 [2 y5 w3 }
- /** Initializes the peripherals clock
5 A0 }, e5 R# f0 M) S$ w! [. Y4 C: t3 N - */
* Y9 e, w3 G8 g3 Q2 R( o. R% z& o - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;1 A$ X4 \* {6 A t
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;" u. t& L; n g+ y4 Y
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)! ?8 w8 E% D& Q- X* H# @
- {
! j3 E% h9 X. Q% j; a2 U4 s - Error_Handler();$ u+ S. L, G% V/ X4 v4 R3 p& G
- } V6 J2 `4 N8 u7 |6 R, s- Y
4 a# q2 m |7 R! E- /* Peripheral clock enable */- s" J; b. p' o" N4 ~" T
- __HAL_RCC_UART4_CLK_ENABLE();
8 X$ P7 S0 M( M# J - 8 X$ `2 M& {3 U, n/ e
- __HAL_RCC_GPIOD_CLK_ENABLE();: p: K7 |2 U! f& D# c- r9 w g2 C
- /**UART4 GPIO Configuration
1 Q4 ~, Q( w% I' C" ^ - PD1 ------> UART4_TX
- I) P s& o' a' u- s - PD0 ------> UART4_RX: _* v2 M# l+ [, m& C" [
- */; @( n, a) `: U) V
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;2 ^5 W1 p9 U5 U0 c
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
$ X% ]; L$ ?" a m) Y* J5 A3 z - GPIO_InitStruct.Pull = GPIO_NOPULL;
& Z9 q% F2 S& w- y - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
$ |% t9 g) {- q$ I* \) M - GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
) B; C- R( Q! X* `+ J" s! U1 j# s - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);; M+ ^) ~2 v8 z! R* b
- * m5 y$ j! P) S3 G( J+ W
- /* USER CODE BEGIN UART4_MspInit 1 */
i9 r8 ?6 p: f5 P d, Z - 0 s3 c1 E- R2 }9 o
- /* USER CODE END UART4_MspInit 1 */7 s5 u* b- C, I7 t& A v1 r, ~' l
- $ S% V Q9 v! W& r# d
- }6 C! A) d# ^ D4 N2 @: F: m% r
$ V, ?+ `: T' F7 j4 m3 c, p* I7 g- }
8 [* a. ?% u5 w8 C
复制代码- 使用cubeIDE- c, O. \, n1 g, k( M
- __io_putchar(int ch)
. H6 v( k3 k7 e) P( T: q. | - {; e- U5 \9 u: `2 j1 J/ ?+ t
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
0 Q/ w/ p- ~ e) y! `& K - return ch;
, v* U) _! a; `* M; t - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
/ R% r2 |2 Y1 a! I+ g
) I0 V& l6 [+ z* }" d0 G; Q- f1 D d
添加输入输出头文件stdio后,就可以试试程序如何了。/ B$ z! ?2 i2 z) N4 z% v
; |+ z a k. q5 e 以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
6 a t! t' \' N/ b) c 4 \: a$ e4 J& Z' v# n5 x/ t
- static void ViewRootDir(void)
- W1 I" I- U" i - {. F- U$ a& D9 m2 U
- FRESULT result;0 H+ [% t! k* x7 W, A0 R* P$ j/ B
- uint32_t cnt = 0;) I# e& E X E. a& x
- FILINFO fno;$ r7 |# `2 b( }) D
1 u; Y. m. t2 F4 v& c7 I- % \% a$ F, ^, b2 L& o. S( H
- /* 挂载文件系统 */
1 m/ f. ~4 ^1 x9 T/ B - result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */; S% s' E- |" w
- if (result != FR_OK): h0 s; p1 u, ]: W3 r w9 v
- {
0 f# U2 o( M2 x9 H - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);) ]# r- X" N; f- r! \7 h% z
- }; P* M- H* c% K1 x/ r# O
- ) b0 k! {: g0 d4 z0 E
- /* 打开根文件夹 */
: O! q! R% m6 t* P# a& @" g - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
1 o3 `& s/ G" t4 D I7 G5 h/ }/ | - if (result != FR_OK)0 n/ I1 }2 n1 C8 b
- {# k: L- S' k% U& Y
- printf("打开根目录失败 (%s)\r\n", FR_Table[result]);5 g# z, r0 I8 x, _0 W. U
- return;' i+ k' ^/ L! a$ A! c
- }
2 ~: b* Y8 w0 }! B& T - 1 a# E7 t: U+ S3 ^
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");7 O. n/ L3 w& H; s% W0 V; S3 `
- for (cnt = 0; ;cnt++)4 I0 q, @" x% v) a) t9 n0 Q* T
- {; Q. K# F, \ C) [9 r1 Y
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */
4 L( _: ?/ {/ e" c6 f2 W) e - if (result != FR_OK || FileInf.fname[0] == 0)' M1 A! A% h# P
- {
) P, K4 r" G+ r* j - break;- A" U6 q6 Z4 \
- }
$ ?, y/ A' d# ^8 {7 v
1 P" o0 V p9 n/ a0 g- _- if (FileInf.fname[0] == '.')
2 w9 J$ {* R4 F" W - {
9 E- P9 X! _. M% u, L - continue;" L: W! P, |% Q. j8 t
- }- u$ ]: J4 u/ g1 R
- ; l( x+ [; |8 }6 w
- /* 判断是文件还是子目录 */. T E( x% K! J( {: o# y+ T
- if (FileInf.fattrib & AM_DIR)
Q. g% q7 i0 L& q+ ] - {- R! m4 P" G, O$ F
- printf("(0x%02d)目录 ", FileInf.fattrib);
$ X1 f2 Q2 i7 l3 f - }
! [& A& M- g5 j; ?* N1 y, l3 C8 G - else
( r% z5 [6 d9 m% X: U8 h - {% \3 |+ E4 [# ?& R9 I, K( O
- printf("(0x%02d)文件 ", FileInf.fattrib);' C5 r+ S q/ A1 z
- }# K/ D2 c9 c- p" O, R2 p; ]
/ R' \, t! Q* s* w! t* k; m- f_stat(FileInf.fname, &fno);6 C2 k5 b; U, k, w: |
- 0 K! C; S, j5 R/ q/ v' o
- /* 打印文件大小, 最大4G */" Z6 w' u$ J; o$ l9 P; b
- printf(" %10d", (int)fno.fsize);
* g f, y+ }) ?( p3 ^- ~ - $ p$ o4 N/ y# o" F
, d3 D5 I, W$ w9 P% z- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
3 Y7 o5 E2 M9 W% q! S5 c' T - }
6 |+ [( c0 J: ?( ]* a - / P* z8 X/ O/ m$ u) X
- /* 打印卡速度信息 */
, N0 S& B! U2 F' a, y8 J" _6 _/ r - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)( V8 T! b, M. L
- {$ k; `; w! |" R1 u, ?3 D1 P A
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
; I1 `* n# _1 r$ |5 m - }
' I z' ^4 ` H7 X! ^6 f - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
. ]; [$ {7 g. ]7 H! r; y/ o; Q - {
$ H) t) o# _2 r; m - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");- t7 G# Z' y! q% I# s, e
- }
$ _( |" c+ A+ P! A$ k1 E* e- Y - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
4 Y% y( s5 c0 F - {; t& D3 G' n7 A& U8 g
- printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
6 y* F% K! k& { v. P b! u# w1 b7 p/ F - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");/ z" |( l. o) z6 |" m7 G: ?
- } X8 d4 w; _0 Y8 S+ @
- ' }2 Q. K4 E9 O( ]& {1 R
$ b. p: G* N3 r3 E- e/ j- /* 卸载文件系统 *// A5 Q# x8 x5 s. _& J
- f_mount(NULL, DiskPath, 0);
7 U: D: |7 d' Y) T) E; l- v - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。* M( p% d$ O' a/ Q
: @" j1 v3 U, e- a( T 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
$ y; K, |5 c0 ?# Y) P" u 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。9 K1 r6 ?- `5 j2 w2 q5 e5 z
, v3 |( l7 Y; o! S ^. t5 i; Z9 F
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了 x( W, ?5 n: m( T. u7 ]
. x5 n0 H1 ^8 a9 m' d/ `: @% e
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
/ [( J3 P. O' `/ P/ F
; ]' k! U$ ^& g, @. O
料想这次应该没毛病了。结果,新的意外又出现了。6 x" S) K$ z5 `0 G: E4 l! Z
" [ p2 T' }" W% g8 w. y5 v
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
# Q) V$ M& n* t. T6 g& f
F/ \! \. H% R! Y% S0 p* Q |# W
满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。1 d% @- o" |, j0 ]" B) E
* [( P u4 R# O* L, Q) D& P7 L
- A/ P: O# q7 w( s. _4 T3 O" f0 j$ x4 u
$ ?! C! q! Y* y( _4 x+ V& ^* S9 I* x# b
. E2 v5 [5 t1 s/ ?
7 f9 n/ ^- w8 a. @7 H |