STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。: M) s7 d1 @1 e( X" E4 a' Q
5 q. c+ p: a. G
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。: R! t4 F' e& z; h* i
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
# x7 h) S) s* D" r; c* U9 t3 D
" U* b8 e9 ]3 j- L& h
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
2 h# d7 t3 ~) [ : a" H( X6 T' \! P R. [1 L
- static void MX_UART4_Init(void)7 \+ @# z3 ]/ G m; |+ p3 M9 Q
- {
4 n$ C0 y/ p9 S" `# y/ ~% K3 ~ - 8 _4 k- [$ s; N8 P6 m! n$ i7 h+ l, S
- /* USER CODE BEGIN UART4_Init 0 */+ V: @: X z5 H6 v9 g/ q
- " P" g1 a" ^& ^* u7 ^# E- z1 k5 d
- /* USER CODE END UART4_Init 0 */% s& ^1 c0 D0 f( x; k2 P
) { `9 D( {, v- /* USER CODE BEGIN UART4_Init 1 */
/ ^. Z% ?7 \! b- d0 _$ f# d
$ T- G" S: `% r' j2 u, i- /* USER CODE END UART4_Init 1 */
$ z/ O% S/ B) n- B% } - huart4.Instance = UART4;
' i* B O$ q* y k: j! q& V4 q( E% {% q - huart4.Init.BaudRate = 115200;9 }9 Y# q% Y7 R: \
- huart4.Init.WordLength = UART_WORDLENGTH_8B;
2 Y# I% w, D, L8 U; v3 f, K - huart4.Init.StopBits = UART_STOPBITS_1;
4 z0 f& v) I% y5 F# y' K( E - huart4.Init.Parity = UART_PARITY_NONE;
- }: f9 o0 w. S9 S - huart4.Init.Mode = UART_MODE_TX_RX;
+ D' j+ s& j' Z8 C' A0 d" x - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;. i7 N7 y6 M8 w& N6 y
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;
$ ~7 ]( j& V2 ]4 H - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;8 \/ m# {0 H# \0 a- p% z
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
- o+ Z/ H1 @. B6 f! E - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; u1 Z6 s3 Z% ?' _" @
- if (HAL_UART_Init(&huart4) != HAL_OK)6 W6 I2 _7 A& v B
- {
: P* r# {- ~. @/ R1 t - Error_Handler();9 w) }4 x# e0 I- H
- }5 f. s" V5 _4 N/ O& P
- if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)) a( X- Z. t/ \4 P
- {
~8 n4 ^; ^: h! I - Error_Handler();, Y7 @4 \5 l" p W9 ?6 {! H9 ]! _* @
- }
) ^! E6 U9 L! s7 v - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK); P4 S8 |- b- U
- {
8 j( A; v* `- o+ f) F, b - Error_Handler();
# N. ?1 |4 _; X i8 | - }
6 T8 v4 d! w. [3 b% J - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)
! I4 n. _9 O' M - {1 j6 o8 i+ c# ~1 y; {1 I/ X; `; c
- Error_Handler();
0 r% c" a9 X% ~: @* g) D - }3 P6 E' n- x ~
- /* USER CODE BEGIN UART4_Init 2 */1 [6 G3 @6 B) C
1 W+ P! I4 E- `) A/ i& B' k- |- /* USER CODE END UART4_Init 2 */
; L ]& {8 b: a( {" J! T8 C
. [* ]* Q4 V+ v5 K$ |- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
: ?7 J: T! {6 L1 S - {* ~7 }! U/ Y* u2 ]
- GPIO_InitTypeDef GPIO_InitStruct = {0};. p4 W5 J2 l m. z& C0 z6 \( t& J
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
& z# P1 V+ t4 l2 U - if(huart->Instance==UART4)8 d+ {8 y5 ]) j: x: C
- {
) q& u! g8 `7 r9 H$ |' P7 a( { - /* USER CODE BEGIN UART4_MspInit 0 */4 n( O9 j1 ^9 H" ~& Q' a
- " O% ?( x9 F0 r; l6 E7 X* `
- /* USER CODE END UART4_MspInit 0 */
" f0 c0 P, ~- T - ' N4 d. ~- `. T4 |6 c
- /** Initializes the peripherals clock0 V: T6 o- N3 o; U$ G; Q: `
- */0 F5 b$ o* f. y. _, X2 Z; Z' S
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
' k v# W1 C/ B) h; M* S- I& Y - PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;0 w6 w& `2 W5 e, X& w
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
7 e+ V( \3 [/ A8 ? S4 U* o, \$ n - {
6 W$ R, U+ _) H( E; E - Error_Handler();
% o1 R1 W% D0 u3 I' t# D( t - }
' B' }3 t: Q: M0 F+ d# K - 1 z5 F7 M7 K, @, m, K2 P) _. K, U
- /* Peripheral clock enable */2 L! @! E4 l! ~8 u
- __HAL_RCC_UART4_CLK_ENABLE();7 `5 e0 E3 e. C
- 5 \ D, ~0 w/ P5 ^
- __HAL_RCC_GPIOD_CLK_ENABLE();8 _0 N0 o6 U/ p4 L8 \
- /**UART4 GPIO Configuration
( P; b4 H) k4 H0 w7 ^ - PD1 ------> UART4_TX
9 [* l4 y" S/ a# D2 V3 b/ D - PD0 ------> UART4_RX
q2 g ~1 U/ B/ A5 R$ X% d - */
0 W; M. \! R; Q6 s - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
7 U1 ? v4 d. K - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;6 `" C# \# ?& o+ D
- GPIO_InitStruct.Pull = GPIO_NOPULL;
. O) |, F* h7 H1 L* h+ C - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;9 p! ~" a) @4 O4 s/ ^
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;" `. w2 R! \" i/ o7 N
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);3 `2 h% }- K& _6 X- t$ E
- * f2 {/ m$ ]& S
- /* USER CODE BEGIN UART4_MspInit 1 */9 F3 F7 m* T& i, A4 t- D# F
- , _+ ^6 u9 |; I3 E4 z( z
- /* USER CODE END UART4_MspInit 1 */
+ u: a/ j+ h& z5 p/ H0 ] - & \6 I5 L9 n9 ?" g2 |( Y" {( H% c
- }
6 Y6 r3 E+ ^5 } - ( g2 V2 b* F; V6 I
- }
) k# y7 i2 S. ^6 B' T. m- z7 d* X6 f
复制代码- 使用cubeIDE
5 s8 Z: ]; g7 Z8 b$ n - __io_putchar(int ch)
0 r9 x, G9 f/ h t$ r# d" L/ L& \ - {) Y1 N7 D+ I. F" ]5 K, p( L- O% Z
- HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);+ f; o9 i$ v4 n9 E2 m
- return ch;; H$ G( N' \1 p
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下" o- e" w9 y' u4 t
3 `4 l% o& p+ O1 g 添加输入输出头文件stdio后,就可以试试程序如何了。
+ [ r2 [, H0 g/ a% {
8 |5 i" @1 R9 u) o 以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。( c4 u, b# ]2 P' u9 F @( `* j6 ?
( T- d3 }4 E8 \! {$ T4 Q7 ~
- static void ViewRootDir(void)
9 h2 t) o' ?* i' w! f - {
# c! B- q; Y$ G - FRESULT result;$ s$ d8 N5 P! p% P! [0 T0 O
- uint32_t cnt = 0;
3 T. I. q) c v9 U6 j - FILINFO fno;8 X9 f- b# e5 k* p/ L0 r9 e
* A8 k3 w4 E0 z9 ^& _
6 e% ?1 p( A6 |% x: O y- /* 挂载文件系统 */
( }; l7 c3 }# U4 K1 _ - result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */0 b; u9 q& F4 n
- if (result != FR_OK)4 Z$ D, `& U! C; \7 Z
- {* L. V( u- |" K5 e
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
( z H4 [3 V) t- e1 W5 v1 B* J1 A - }
& S: H4 Q5 U9 {! @* d: ~
3 R0 k, Y& }% g) ?1 a7 Y; q% [- /* 打开根文件夹 */8 }8 N* _- H! W3 A2 F
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */ V7 l, A8 J# ?
- if (result != FR_OK)
4 |! H% F3 ]8 Q9 |5 ^; ^$ @# y - { A% E: B3 M* i/ \
- printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
9 G W* u0 G) {. b5 B2 \ - return;
8 n# x& g1 B7 B$ y V& t - }
4 _% D# v9 R" d$ y9 Z - 4 Z- R8 W( S) h6 b
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");8 T" |6 n) Z% s, v2 d% G
- for (cnt = 0; ;cnt++)
. ^' I: W) }, q; z8 |/ O% i7 K8 I2 n - {
' [; n" k- a" D* U' `8 c" c2 P# F - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */9 u! M* M9 p1 j8 l1 S( T) w
- if (result != FR_OK || FileInf.fname[0] == 0)
1 L$ n& d$ w: E7 C2 `4 k+ R - {
* r1 V! Q4 ?) h N0 y/ }6 v Y - break;3 @$ h7 b! w X- X- A: V
- }
; p" W1 _2 L1 \" e0 T9 ?
4 t: S# f9 S. A# d g( J& y- if (FileInf.fname[0] == '.')
- O0 P* V# s3 L5 B9 y - {
- ?- L5 Z$ ?5 W - continue;
+ D* g2 S6 x N! Q1 Y1 B - }/ E1 I( d% Y1 z" x3 B) \5 w
$ ?9 Y6 V1 V- @3 P- J- /* 判断是文件还是子目录 */
; O) Y. B) T! Z7 D! m0 r - if (FileInf.fattrib & AM_DIR)% N( o9 Z! x* R% G3 W7 ]8 \
- {
# G2 x5 P: X" X& u% v9 L1 C$ R! T - printf("(0x%02d)目录 ", FileInf.fattrib);8 v! e0 p, v0 }+ S3 }
- }
6 o5 k4 x0 T; H. S" Y. M1 e9 F - else
9 o. g9 Z+ N2 t2 j8 g - {
2 \( W* D1 j/ k5 b m - printf("(0x%02d)文件 ", FileInf.fattrib);
/ C0 F' W! B7 c) d. n0 i5 \ - }: c4 U. s( v- u0 _
- 4 v$ @- j, c: e2 N: e
- f_stat(FileInf.fname, &fno);
6 N' M9 H# o( z, B Z - ' N% c. l1 U R# q! v# P: t& x
- /* 打印文件大小, 最大4G */
2 Y8 T. w4 u9 f' B# y9 C4 g - printf(" %10d", (int)fno.fsize);2 f; y4 F6 w8 H" L' ~6 m
- ; {# P0 y9 I0 c; X" b2 P
3 ~( [" \* P2 P1 B- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
7 W0 g2 O' L0 Z( { - } Q8 ?" g K/ F1 v( p
- * w, N2 @9 A( }3 h1 }0 \
- /* 打印卡速度信息 */
" ~8 D* }6 A; }+ p& w2 A - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)
. y# L5 v- C8 n, {* s" ]' c - {
7 P( {" r. x: L; R - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");9 Q7 D" W& E; g0 f0 d
- }+ t( W! b& X6 m$ [( o
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
! c$ _8 R+ N4 G% @, Q% G - {- v* H8 w+ a" N9 \" Q
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");5 p% r/ U; z, Z& f" A) `6 [' T- n
- }
& V, @6 T1 d' v" h. m: w) H - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)" w% r. | Q( |; \
- {: m: W1 L% D' C' B$ q9 G
- printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
0 b2 g7 u; L7 A' @* r, p+ ~9 [0 c8 O - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
* J# x- b8 N0 G* Y2 } - }
# j, R* p! J6 X - " @. T$ m0 {- c
- , u7 S2 T; b: X3 ~" X+ u- \
- /* 卸载文件系统 */4 n( E7 d+ b9 M
- f_mount(NULL, DiskPath, 0);
0 a0 r6 P$ B& N) @) N; e - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
8 d4 x% D3 R: o- f0 ~+ Q
# S* L! ?+ z# e" _( `: M/ t 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
& H# c6 k$ U# U# z! n ]8 a 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。
8 ` A0 u+ W2 }; ?6 C
' X9 m+ |) ]8 r4 M6 [
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了5 A2 v% o/ i" X% X8 I5 S% f) `
9 [9 v& u. D/ [1 |, S 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
( h: R0 ~1 ]+ {9 i7 R0 t9 \% |
" ?, b& ]1 R+ `8 k C4 n; H 料想这次应该没毛病了。结果,新的意外又出现了。% o9 Y4 W) k- \. d V
! P# b$ X' W4 U 还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
2 v+ [8 D, v* O# G9 P0 |0 X6 F
2 ~: W0 r1 G4 r. @
满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
, Y% N4 M. v! t: e# M* ]
4 ]8 v5 J/ X1 e; e& j- C' Q7 U 5 X& A, C% A' e* \0 Y1 r5 W
$ Q$ Y( U( z. d2 D% N' }+ f- M& s2 D" D+ W9 r5 A+ _7 r' B
" P4 u- J) {: V9 a% M
$ X" e7 q' c6 B* O% l; z$ B |