STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
' O' m4 o7 i3 T- L' \1 X2 V3 D4 d
0 b' [. u9 t _* I/ n 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。0 `* z8 o( S8 y8 ]# ]" k% V1 y4 U+ S
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
+ j3 y/ V! W d1 j$ ?
2 |- J c0 k3 n* L+ i# k
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
' \+ E) _3 Y9 O2 x% O; o ) l8 g% C! C1 O2 z# @% D
- static void MX_UART4_Init(void)
1 G$ J# N- I3 x0 O! f, b) L! J$ j - {, X7 p* y1 P0 @) w1 S. R8 Q' ]2 |
3 A% h, n( e h% V* o" U. c- /* USER CODE BEGIN UART4_Init 0 */
2 S8 e2 @5 `+ [ - + N/ p8 ~- q' m3 ~* h7 ?7 D
- /* USER CODE END UART4_Init 0 */
$ O# Q9 A V- L4 |& ]) i( P( ]6 @
3 D! y% ?: j \/ U5 d- /* USER CODE BEGIN UART4_Init 1 */! y7 v& G0 h2 o; m: [6 `+ U, L. ?
- / `3 x! Q. x5 X! e/ E7 Q) _
- /* USER CODE END UART4_Init 1 */+ Z# H1 y; |$ C7 Z6 F3 B1 a
- huart4.Instance = UART4;
6 U9 @: h& m4 t4 \2 j2 E - huart4.Init.BaudRate = 115200;3 U# f9 k9 q1 h' j, K3 i
- huart4.Init.WordLength = UART_WORDLENGTH_8B;$ E$ d9 i: o+ x2 C2 }
- huart4.Init.StopBits = UART_STOPBITS_1;: j- \7 t" |$ {& w/ H7 E
- huart4.Init.Parity = UART_PARITY_NONE;
* G, g' E$ N4 P, R+ q - huart4.Init.Mode = UART_MODE_TX_RX; k0 h; j( ^0 Y2 [
- huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;/ k( K6 f6 m+ s, {; d- n
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;
, H+ G6 U T1 e% l9 V4 K3 Q - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;, g0 i& P3 x& ]2 Y, [/ W
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
/ ?: j* G" p `: A7 A$ ` M, v - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;8 @$ n& d9 S+ s4 U* v
- if (HAL_UART_Init(&huart4) != HAL_OK)1 S' |2 Q# \# s: O& K
- {- F2 d$ _0 J, J
- Error_Handler();
; q: M4 G" G$ R% F - }
! G( M3 H' s! _ - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
" Z: _' |8 v6 i1 B& c2 ?6 L8 ` - {5 z g9 g4 ^3 o( C7 `3 l; h+ {1 y
- Error_Handler();- C, h# e. U) s! d' x" S5 \
- }
+ K% n% f- G' @. C - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
6 s/ L$ m) q9 `. d! p4 v - {! X: h2 z5 G% V( R+ V5 [# ~/ F
- Error_Handler();8 @2 ^* h3 u2 t0 w; e; m4 P8 o0 I
- }! G: e% M1 ^5 b
- if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)! Z0 b; l7 q5 P+ `3 p9 T: x, C) ?
- {
6 O) d$ c" i% e; m - Error_Handler();" A5 E! h8 B. \* ]$ ]( ]
- }
& S' B! k# |; Q - /* USER CODE BEGIN UART4_Init 2 */
2 _. ]9 X" H* ~& p) a: Z
% n7 X( q) \0 c& g+ {- /* USER CODE END UART4_Init 2 */
8 J8 q7 v/ Q6 ^2 g$ t
4 e% G& o7 R- @# L. I- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart). w3 F, z6 @' R9 Y7 J6 f6 v& h
- {' p) \, K K, y$ @8 Z, g- U
- GPIO_InitTypeDef GPIO_InitStruct = {0};/ c" c& z6 T- W4 N" L0 ]
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
$ }) `# G: }+ c - if(huart->Instance==UART4)4 i3 a) M" l# J9 [, w9 e
- {
% N* C9 J7 d- T! @5 l( J5 h4 F - /* USER CODE BEGIN UART4_MspInit 0 */+ u6 ?6 ]% a5 B9 Z i
- 2 c, ]# v2 p5 ^, a% p. q- v
- /* USER CODE END UART4_MspInit 0 */
O0 t: d7 Y" d6 H$ _0 Z - / U2 J2 q3 s4 x/ O& U+ V
- /** Initializes the peripherals clock
' e4 h0 S$ I( t: p2 G - */* C' b$ T0 D6 I" Q4 \( }
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;( @( j+ F* N) _' w
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
- T- h" O! Z4 i* @ - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
, k/ q; N9 ?- l/ z - {
" M8 b1 a: ] M/ D( C5 W - Error_Handler();
: j0 w/ G& O8 x4 z% y' Y# Q. t# H0 K - }! W' D/ E4 b+ v
_7 l' E9 X/ ?5 |' x- /* Peripheral clock enable */! b, ~* a% N6 P1 N1 k0 R1 v8 O; `
- __HAL_RCC_UART4_CLK_ENABLE();
* I9 C; B+ i: T4 t* `# ]0 Z3 m) F - $ K" H. ]( @2 I I7 c! I& }1 K
- __HAL_RCC_GPIOD_CLK_ENABLE();
; p$ u# C4 F: c' X - /**UART4 GPIO Configuration
! F" N, L5 m( k - PD1 ------> UART4_TX
- p7 B( O0 ?3 h - PD0 ------> UART4_RX
" l/ b8 [! O/ A. u& q4 I - */+ T; w5 L* h8 k* v
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;2 ~" i: d# U7 a! f- @
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
* G/ O+ J" f9 i& L9 A" \! g7 Q - GPIO_InitStruct.Pull = GPIO_NOPULL;, n% o& J- I: E \6 @
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;0 n* A6 a# b; Y( K
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
' _! n" J5 Q( L4 u# g8 i- a, Q - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
; f! N2 q2 c L: n+ @) K
+ {( f/ F {$ {* C ]6 z7 i, J- /* USER CODE BEGIN UART4_MspInit 1 */& v" [+ k8 H" G Y
- % F+ B- `5 g- z% h! y
- /* USER CODE END UART4_MspInit 1 */+ s- b1 X h7 P4 K2 p7 r0 U& v
- 8 z; a7 A$ a5 K0 [6 m$ A
- }
0 @' f/ m+ D( {
9 B. [% N) U: |. s, r( a+ `9 D0 V! k- }
% g8 J2 C, e) n" g- f
复制代码- 使用cubeIDE$ F8 \8 u1 q) [& p0 y! j
- __io_putchar(int ch)( v6 c3 M3 \9 Y5 W
- {: X9 E) Y1 P7 X3 q* u* r& d
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
f6 K6 t- ?( l; \! Z0 v" c - return ch;6 d8 ?( W+ ]- W
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
* A4 I5 J* F$ w
d1 c2 t, B5 K5 h( Q/ ] 添加输入输出头文件stdio后,就可以试试程序如何了。
& x9 u& i Y) x' Q/ J9 m- B5 z! [
# x' t# H2 V4 B: W& H- [5 F r% C 以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。- ?5 k6 T2 b/ I" t! ^# C- ~
& }* Z3 q; [. Y3 a- static void ViewRootDir(void), m8 x$ T/ B/ h, N
- {5 y* T% ~: `- `" U1 Z
- FRESULT result;
$ r% ~) v2 D4 u: k$ M - uint32_t cnt = 0;
3 Y' K: q5 l2 F) d4 q7 z - FILINFO fno;# O3 R8 m8 N$ g3 |2 t+ y
- 2 z' V( |& n5 W! P
+ B3 |5 V6 O$ T7 S' v5 |- /* 挂载文件系统 */
" u9 A' c, _, b: L1 I1 p& h- i. }: B! g - result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */
6 l3 h# E K p - if (result != FR_OK)
' B- v B6 M( Y, C [+ T- R - {
$ H; q4 \4 ~ t: a - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
5 g9 v- H+ _2 E - }# `, S/ i* o: d- A6 S( m
- + d4 |: R5 e0 W; V' d
- /* 打开根文件夹 */# p: R. s/ o( z8 ~# [
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
: K% T; w+ \( `+ n4 v) e; O# J - if (result != FR_OK): h) S l: ?/ q* y1 |
- {
3 } d$ W: N" u0 A6 a3 F - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);4 y0 ~, Z) N$ w# R' a+ L2 }
- return;- ?: G# a$ l/ ~& O: N/ k4 {
- }: r- b7 p, d) f- W D5 N( f! `* Z
- 3 B1 e) Y5 N8 ^& |+ {% Y$ H
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");$ M6 @1 ?* |- E/ j' e
- for (cnt = 0; ;cnt++)
- I8 x* m3 X; v4 j, Q1 \ - {( S' B& l" o. _% b' O$ J% @
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */
# H& l+ ]5 m' G9 y - if (result != FR_OK || FileInf.fname[0] == 0). s& a9 r1 |! Q s, P& A1 v
- {
$ V/ o! R, j/ r - break;
% X- Z4 M% o9 g' S - }. h; H3 e( o0 T+ g# v% p
- * ?# q1 x, Q; X3 k
- if (FileInf.fname[0] == '.')
' w' F, I0 l; b$ d5 O. C - {* _% ~! z% Y" a5 ^, }) q2 D* [, k& B
- continue;, z2 I. D& ^& F! a4 o. d
- }5 J: T% K" |- d8 o; p2 w2 ~& _
- - _% z, `; r5 d" t* N6 \
- /* 判断是文件还是子目录 */
! J! ^9 _% |/ a, A8 H: ^ - if (FileInf.fattrib & AM_DIR)
/ U, z" F* W! T) s' z. d+ L - {) `$ p" _% R+ {1 E
- printf("(0x%02d)目录 ", FileInf.fattrib);
: p# d1 g$ E7 h# y - }
- S$ V6 } _5 O* S+ n0 \+ l5 C% K. [ - else, c, i9 W1 A% i$ f& G! f) V2 J
- {- H! m( o1 X: d; l! z1 f( D7 y8 J
- printf("(0x%02d)文件 ", FileInf.fattrib);
- V5 H5 V3 P- x - }. H5 q% T" ~/ `' k) @4 n
% ^+ C0 Z4 l, b: B( @( l- f_stat(FileInf.fname, &fno);
' H2 U, ^' ~( @7 A; {( g - : R8 A; Q9 f+ D
- /* 打印文件大小, 最大4G */
1 Z W9 X4 a. v' D3 s$ d - printf(" %10d", (int)fno.fsize);! |- g; Y4 Y( v, V: O4 K. K: X# O
9 e" t9 P" Z" v
' K2 J# K( Z2 K4 l( ^6 Z) B' M- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
! a! p# n5 s) N0 X+ U, x - }
) b6 M _3 A+ `4 z+ E
! b1 Q6 ^" C$ a c' E- /* 打印卡速度信息 */+ `9 z- B8 t1 i! o8 N- }$ D
- if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED). |# r4 {3 E1 ]$ j- U* z
- {9 K( x0 O* ?5 Q! } J
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");+ o" z! w5 a. }, }! l2 g
- }2 ~# M! u8 ~( @5 \( R' X' M
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
: Y z5 Z# S% ^& V( [, Q - {
, s5 e' R! D8 U; r- j8 W' D - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
* Z" H1 y( b3 P; i! H9 [" M - }" ?/ p- b3 E$ V* V8 t
- else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
: J7 G" }' ]; S& H - {
: ^5 S* J2 e! a6 L - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");6 b3 L8 w6 i( i, p# n9 s) H
- printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");; u( H0 V0 u& a# t% Z7 y5 X
- }! t8 c$ f; x( J7 Q! ^
1 F1 K0 |. ]& d7 ?6 e" R9 w
3 n" p- x7 r0 s, I6 P8 P- /* 卸载文件系统 */: K: J9 s1 v1 M A/ c8 ?
- f_mount(NULL, DiskPath, 0);8 g$ H- Y/ K* b/ a8 g- o4 y
- }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。- U+ S( |! k) u( N# F( V
8 q" {7 o) l9 V7 ?+ m8 X
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
. I! U6 I7 D! E 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。
( T! S; X; I" A9 H2 _( |
( _9 a% v% j5 s" `" @9 G) `" T1 E
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
, n- }# l, c8 ~9 l
$ Q0 Z/ p* n% m4 d 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
/ ~$ S% U+ g( ^9 t! F* B
2 Y( [6 H/ i; S) O R; w, D# D4 M 料想这次应该没毛病了。结果,新的意外又出现了。
1 W. p1 Z3 N; Q! p9 a& D
2 r' S9 f! h% n) u' A& o 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。; T4 y$ Y. e9 m( B; v
# l: O* N) X' w* K1 W 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
0 Q; J0 s& {; V* x: }$ S# N. v. G2 w" J+ J1 t1 W4 ~0 P6 x' W
3 P2 {% n; a6 W5 k0 q
. }- n) o7 I2 Q% K' y
L: P! t& _5 C2 X2 V- }$ T+ m/ [) z3 B3 z
' u6 P* E7 [9 F# ?4 J
|