STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。& o% {7 R% g& z1 h, b+ G) S' E9 F
+ Z! w' H* f( a/ Y3 q
鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。6 v7 \3 Q2 N t8 f6 A
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号& j5 S4 v5 `- l9 ~9 F; _5 h" @1 h
4 O+ J {; Y4 K! C( z( _
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下8 h7 |! ]7 v+ z0 V0 u
6 |5 F1 r" }2 N4 q; K/ Y6 z# m- static void MX_UART4_Init(void)" F$ d" j+ g2 `
- {* S$ C" \; p; z7 D
* o0 `2 M0 E$ @: p- /* USER CODE BEGIN UART4_Init 0 */( m, ^" c" j: ]5 j+ d e8 ^: w
- ) c" n* c% W, |5 V
- /* USER CODE END UART4_Init 0 */: {. h0 N: f* [8 Z
& L3 d) T1 D' j" Y- /* USER CODE BEGIN UART4_Init 1 */1 Z8 x1 Y" x' a% n v0 W: J
- 9 g+ }# y; E C
- /* USER CODE END UART4_Init 1 */! o1 R5 c0 ^8 v2 o
- huart4.Instance = UART4;
$ _4 J2 {% B1 {6 U5 M! c$ w" F) n$ ^ - huart4.Init.BaudRate = 115200;8 [- r1 J# ]+ Q* J/ q! Q }
- huart4.Init.WordLength = UART_WORDLENGTH_8B;, S! t6 S4 W3 v [9 N) \, E, H! {
- huart4.Init.StopBits = UART_STOPBITS_1;
7 a8 ~7 U4 n' p: k, j t' d - huart4.Init.Parity = UART_PARITY_NONE;
" [, Z& Z2 @1 R( w - huart4.Init.Mode = UART_MODE_TX_RX;
1 O9 ]9 _9 H( }7 m/ p$ \: n - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;+ x p8 w" m$ ^& v
- huart4.Init.OverSampling = UART_OVERSAMPLING_16;$ \7 v/ B: ?5 p$ X$ w7 f
- huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
, D% t ?! `5 M& E/ u! M. H - huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;; c; W2 _8 E! `
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;; m- i+ J: J/ Y y! @; }
- if (HAL_UART_Init(&huart4) != HAL_OK)6 c& @; _% d; H9 ^0 ^3 Z; |( T2 y+ ^
- {+ [6 ?! p) | Z& C* ~
- Error_Handler();
+ P( B% C5 i' k3 j' L - }
( ~+ U" U9 {8 W1 W5 u! \ - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
' ~! V+ j* b0 b$ z% q P3 c - {
. _5 a) |* l9 u8 q2 o# L& C - Error_Handler();
% U! [3 f+ t9 w. p1 m0 H - }" L- w$ ^! J ]1 j( i; o% I
- if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
0 ?* w: v2 ]; b' \ - {5 u& V# X( t1 d, H5 y
- Error_Handler();. Q% J0 Y4 R( z' j+ {
- }7 T9 [ ]+ I# P( `' ?5 ? u
- if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)' K7 V6 a5 O+ s7 x4 u
- {+ T! b, u8 j) u" [1 p. \
- Error_Handler();
) R8 U. |2 J9 |, F/ Z) b( m9 Y9 ] - }% d D2 `$ b1 Z
- /* USER CODE BEGIN UART4_Init 2 */+ k: d9 |( R, a ?6 ~
- / L- J, E, T! G% t G8 r9 }
- /* USER CODE END UART4_Init 2 */
p# `$ \- t4 Z - " Q9 L% Y* f2 Z" R8 d: _4 @, C
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart) ]6 ~7 b$ g( `) H* I+ o$ [: {6 m
- {
8 k# K8 z+ F K1 w - GPIO_InitTypeDef GPIO_InitStruct = {0};
/ B0 g: b% ]" h - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
3 n6 ]) l* H6 g9 ] - if(huart->Instance==UART4)8 F( ~" I8 f& Q* U! u. _! b3 i
- {
8 v7 R. ]8 V6 Q& a0 g$ p0 L; P - /* USER CODE BEGIN UART4_MspInit 0 */8 ?% h6 s8 \ g
( K1 K# v+ t8 q0 ?1 b2 Z- /* USER CODE END UART4_MspInit 0 */
4 a% N d+ [5 }2 h - * z L) A* |2 X& F8 R5 t* W1 s( N
- /** Initializes the peripherals clock
7 e. u- Y5 V1 ` - */5 T! k, | w1 {1 ]$ ^
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
( X4 @1 j+ n# T - PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
/ T5 k2 v8 r4 A+ `& q - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
* z, ?( `& I+ a' p: ?. h; y - {
7 o; X: h; l/ m - Error_Handler();
! P A" N. v$ J3 G+ r - }
2 ]9 t0 c `0 x) C0 K - # A$ R9 t" W% }: U4 Z
- /* Peripheral clock enable */
w& S& y: e$ L& k5 U u - __HAL_RCC_UART4_CLK_ENABLE();7 S G; `/ `% J" f
- 6 ]. \# B4 v U% B/ |5 g
- __HAL_RCC_GPIOD_CLK_ENABLE();
1 d- H& N4 D4 c% W - /**UART4 GPIO Configuration
4 E" T q* g) d4 v- q - PD1 ------> UART4_TX- D. N" t ~/ d8 w( x- F8 e4 z
- PD0 ------> UART4_RX% I7 Y# t* i1 B1 n6 A$ C- X
- */* W' v: ?% w; \+ e) L
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
; s# e4 H! w; i5 Y - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;: Y* d( i8 x% P' F3 }, a D
- GPIO_InitStruct.Pull = GPIO_NOPULL;9 b: K* b" n3 ^# Z- T
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;! i" C/ F: |& Q/ d+ R, w
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
' z" \4 B" A1 N4 y+ L+ c9 L [+ ~ - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
) e8 l/ j. }, C5 P7 ^6 Y4 } - " T1 a2 `4 E) T- N0 |& A
- /* USER CODE BEGIN UART4_MspInit 1 */& B" T) Q% A# `4 O
6 c" U! Q$ R" B" {. r) v/ b- /* USER CODE END UART4_MspInit 1 */
3 F% @( Q) H! \9 U- m; s i, P9 G
0 H% z0 s3 e. u# R, f) I- }
4 u: B. z5 F- o, n# E% d - 0 b6 ~9 v1 Q, p
- }
4 K9 q9 J0 e9 A9 {, c2 b4 q
复制代码- 使用cubeIDE7 B& s: I3 l6 p; _( O
- __io_putchar(int ch)7 P& @% n! f- }. m
- {
& a" l, [' Q( Z9 T3 l3 f A - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
i! C3 q% [, N6 A6 t* p' K - return ch;
: r- {! d, n2 a, H# n) t+ c - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
) p2 r8 l7 C- m2 c$ O+ k
! H0 G# ~1 M3 ~( G8 ~9 z+ B/ P
添加输入输出头文件stdio后,就可以试试程序如何了。6 A4 W2 g7 m T6 h, ~4 B! N# `6 Y! \
% W' M" |+ |! S* h& A' o' I) }! d
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。* b; W# C. X- G# F0 E9 J
+ j' t! {0 D3 `9 P& z! T
- static void ViewRootDir(void), D0 n/ v; W' C9 e
- {
, s3 M3 N* i- i" q1 M) g6 z/ p - FRESULT result;* E" \; Y* B# L
- uint32_t cnt = 0;
8 n5 j6 }: q7 b' p* x9 { t - FILINFO fno;3 ]) [- h* }4 L% @$ b+ A5 k: g; }/ }
- # d6 u {3 J3 Q3 ~. p
# D# ~2 s7 n! A% o2 \- /* 挂载文件系统 */, {0 P$ V4 i3 `8 G) D+ r/ h. s" t
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */
! c4 P& |; o' j- x - if (result != FR_OK): f$ N( C9 }- v
- {
9 M0 J0 N+ `+ J - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);- ]) z- C, N/ ]1 Z h
- }# f- E6 o! l7 [
* M9 j( c; j0 H$ E8 Q* F4 u- /* 打开根文件夹 */" \1 M" E; C2 z$ w
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
# ?3 w. F' `$ D3 f - if (result != FR_OK)
; s& x! c7 B& H6 ? - {
/ S) U1 V' P; j - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
6 ^& c+ E' N! A7 l% A: L2 g - return;. Q, F4 F( [2 O
- }
1 B( Q0 [5 Q9 F8 D& y; ?& m - 9 X! H! B9 X _5 P
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n"); q$ Y4 }6 A* ^+ ]0 P
- for (cnt = 0; ;cnt++), ^ R+ ~% l5 r4 u% b
- {
' a8 s7 V3 y/ K8 u+ p8 C: t/ v - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */* j+ i( j( ~7 ]
- if (result != FR_OK || FileInf.fname[0] == 0)
2 @* j$ `* T- r& a - {( {. E# \) p1 w7 [1 x; }; @' d
- break;
$ R# ~" b4 ]7 \7 Z - }
" {1 ?7 A6 h7 K# i8 _3 O - ) ^7 m+ Q! _9 }6 h+ }$ @
- if (FileInf.fname[0] == '.')1 D, \; v, s M1 t9 b
- { \" m7 Q% s, g- F
- continue;
2 M, Q( {7 W& X% B- \: D4 {3 ` - }
' U( t P4 B/ Y$ `! e1 D( d0 w
, G: U2 L, m0 x$ R" v4 b, f9 H' f$ r) e- /* 判断是文件还是子目录 */( b0 q& v2 J8 ]7 f$ c0 y* J
- if (FileInf.fattrib & AM_DIR)
% d2 |- w; T6 s/ ] - {
3 V) W( y) G$ V! m2 ~ R - printf("(0x%02d)目录 ", FileInf.fattrib);
" t9 |1 r4 e! ~# k - }
, d( M' \5 ]+ Z& e1 n9 k - else1 w8 X" |( ^. j$ D) ], C! \- I. ~; x
- {' L4 M* T9 p# v7 \% M- W
- printf("(0x%02d)文件 ", FileInf.fattrib);0 a2 P4 {+ p' G& h, A
- }
3 ~7 {7 R8 W9 f$ L
- W, b' \# b5 k. s7 V- f_stat(FileInf.fname, &fno);
6 t1 q/ \9 p) z: ?1 u7 X1 `: F# O
- @0 x1 A$ ]% t' g- /* 打印文件大小, 最大4G */3 h1 V+ K( o# @, u
- printf(" %10d", (int)fno.fsize);
& _: q5 K3 P2 o) z
6 X' j- i" |1 P+ n" k- 2 ]8 l7 P+ v: I4 S
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */
$ E+ [9 d% a, P0 N - }
. L' X4 x5 b+ ~. m# O' c - $ d( m1 @) e' o6 M
- /* 打印卡速度信息 */
- U, Y# h1 Q1 [5 h3 j a - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)
0 ?9 m% t6 p' p i e3 ]7 _5 h7 L - {0 r, x% U: Y% ^) L7 v
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
9 z! ?$ b+ [5 Z: c: U- t% ?: l - }
9 E' g9 Z) H4 A7 ?6 x - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)8 T" ?" N/ J+ W1 J2 J8 C
- {
: C [ j) q( \8 Y - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
7 w) W4 t) Z( s' ], I' N/ y, V - }
4 K% `0 W" w# A' Q% P+ f: I - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)
! \+ \4 I( l6 z) P) s - {' N0 o1 u4 K1 `0 ]
- printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
& z- k* {, X! G; r - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");; X7 R1 A- z1 k( \; |$ ^) x
- }
C/ u. \$ ]: O - $ [4 ]0 i+ G1 U0 j
2 V. p8 ~- G+ Y( C- /* 卸载文件系统 */
% l* Z4 r, Q) J$ P3 Y - f_mount(NULL, DiskPath, 0);
0 R1 R! p8 B# f6 U+ q2 x - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。+ Q) y7 `( z/ ~, E: p9 [4 O
2 ~ A" S: p1 J" ^. r
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。6 X. K$ V1 u- b3 I3 V$ s; \( G
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。
4 U* V. `* x j' V: {% R3 u
% ^0 ~# m$ l5 m& @! d) H8 C8 l 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了* i1 [; X e+ W2 X
! ^! K' f( e) S( L0 m! T/ `7 s* H6 E
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
" [- u& f& h. k# W
. J- x* x. I# ^% B2 V4 C
料想这次应该没毛病了。结果,新的意外又出现了。+ I; K/ c) D. o" f* }
A; n: J* Z) h6 M/ |- F" J
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
1 x3 n8 T; K+ B6 C$ f
9 D6 K9 J; x0 Z4 I) z: t 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
8 S$ i" `+ Z3 j0 `6 E$ v- L) b {; |+ r
; N. C1 l: v; i; [/ @9 l, n8 l: G7 \! X, K" \1 X8 r5 q
+ s) H \/ |2 U3 A/ B8 {7 j$ S$ |
8 H! E0 N' i% ?5 `6 W6 b: ]. a& R5 f6 Y5 L- j0 @& W, Y+ L6 g
|