STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
3 Y' C- u* @2 J, N x9 G; |
9 s* d6 _- Y S- N; G5 q( y( n: x 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。9 d2 x# l& _2 }, F
增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
s7 ?1 K; V* s5 D
& O4 S& s+ e6 q, w2 [ 手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
& e4 c5 C' k6 |) V + L( k' c& j+ U
- static void MX_UART4_Init(void)& _6 y1 S) u+ I' Z# U9 j
- {3 ?9 S7 {3 t) ^0 T4 O2 {. r: [0 V
' N; m s6 D5 n: O" l4 B: j- /* USER CODE BEGIN UART4_Init 0 */( N' d7 Y1 a; U
- ! ?0 Z0 b2 j) r7 d L
- /* USER CODE END UART4_Init 0 */, d8 v* g: P5 F: `. o8 W1 ] K
- L6 t v! I1 i+ g |) Z
- /* USER CODE BEGIN UART4_Init 1 */. w- |/ z% |9 G0 A, @
% K# b0 p3 ~' D- /* USER CODE END UART4_Init 1 */
. m1 i0 |9 p& K. z - huart4.Instance = UART4;! r1 p5 R- `1 ]* l% _" ~. [ H& k, E; P
- huart4.Init.BaudRate = 115200;) Z. {$ @3 ]$ C4 W+ @9 E0 r( ?
- huart4.Init.WordLength = UART_WORDLENGTH_8B;
/ P! e4 a0 a8 C8 ]- W/ r2 U - huart4.Init.StopBits = UART_STOPBITS_1;
7 `: Y& k) K3 v" R - huart4.Init.Parity = UART_PARITY_NONE;
0 G& o$ M# v4 q' O7 D/ Y - huart4.Init.Mode = UART_MODE_TX_RX;: t1 M0 G: I, w' a5 L* D7 V
- huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
% u0 z6 P6 j, }& s - huart4.Init.OverSampling = UART_OVERSAMPLING_16;: u* _$ q: V/ v" O! O( y4 ~
- huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;* Y* H6 s. p' K9 A- s4 V
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;
. K; \8 F& h2 d' ? - huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;+ F/ u# _2 w& q1 l8 L
- if (HAL_UART_Init(&huart4) != HAL_OK)
( p$ Z3 Z6 N; P. E/ A - {
# V# V# a% `5 r% V2 N- | - Error_Handler();
; @1 k, n& B. U7 m8 I% F - }
' j0 _3 K3 q8 w+ c3 |- \ - if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
7 e6 ~: @: a% U - {" k( E# j3 r0 U* C# p$ z Z: m% C2 _7 j
- Error_Handler();- z( k: }3 X4 }% Q/ H
- }
! Y# R9 E2 |/ Y1 T5 D; c - if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
6 ~0 d' O/ G/ I- L - {2 Z5 U8 l$ U4 t# V0 g" \
- Error_Handler();" w1 P0 c- H- ^+ k1 v
- }
/ _" }; V8 I, b' m7 p } - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)8 @4 z: J2 h6 k, A/ j. ^3 x
- {0 X+ }" i. h2 a9 J4 X5 [; x0 m
- Error_Handler();
( G% _; V9 Y" t$ M5 n* q( R4 D - }/ E- r5 ~( f1 q+ A9 j+ [" z, @+ C
- /* USER CODE BEGIN UART4_Init 2 */
4 ?; {& I; V4 h6 `% X - 1 |, a$ z0 ]* S0 U6 _
- /* USER CODE END UART4_Init 2 */; C& d6 A& ^' i
A5 | ^9 G" I3 b( a- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
' X) V* }3 _, A - {! \. W5 y! P! d% E. s
- GPIO_InitTypeDef GPIO_InitStruct = {0};
/ k4 Z1 D5 G: S- F5 r - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};- W1 ~: x: Q* N j$ Q% s
- if(huart->Instance==UART4) {2 Q) t0 ?3 \) b6 Y* ]# D r5 u
- {$ n3 L/ d% F3 {; d
- /* USER CODE BEGIN UART4_MspInit 0 */
/ ~5 G+ P6 g. d. ^2 q% Q6 f - * }) o$ B( g; |
- /* USER CODE END UART4_MspInit 0 */
4 z0 b4 Y1 {4 J7 K* R
9 L+ `% ]. o* s; O; n: }8 e- /** Initializes the peripherals clock" X. ~6 k' n$ s4 Z4 ~/ r1 y
- */, `5 F( p0 h( }( u. |
- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;: A# \$ `' R) z |* d9 A
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
3 a+ v# E3 Z5 H" z - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
" c$ y9 V* R# m - {9 b9 Z2 W0 C7 D l) Z
- Error_Handler();% b2 m/ P: {, E( X8 f8 l
- }
0 O8 y9 L7 M; a7 j
: a( W6 }, }& T" m- /* Peripheral clock enable */" Q$ \7 i; v. I" {, q
- __HAL_RCC_UART4_CLK_ENABLE();- Q% I( f6 ^& Q ?6 O: r
5 A' w B5 p& [7 P- __HAL_RCC_GPIOD_CLK_ENABLE();
+ ^( R1 ?# K- L9 \ - /**UART4 GPIO Configuration
2 h! e0 j5 y8 ?! ` C6 \* | - PD1 ------> UART4_TX( [& w. I3 B4 Q- u/ z
- PD0 ------> UART4_RX
4 e/ w/ r2 g3 }+ {# }: M, ^ - */
4 R, S! u6 t3 a9 y2 n" m& f - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
: g0 x+ L0 {6 v - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
% d, `1 D, u0 F2 }1 [ - GPIO_InitStruct.Pull = GPIO_NOPULL;
3 T9 [, s+ G0 d6 [ - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;) @9 b% Y) r7 a% `2 M: D$ t
- GPIO_InitStruct.Alternate = GPIO_AF8_UART4;$ E5 p' n J: k% W
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);: a" a: I8 I) H- S* }$ j
8 _! {* j4 z- M& [* Q, P- /* USER CODE BEGIN UART4_MspInit 1 */3 \) i* b5 J8 o; H
- K N/ j* D" `$ ]
- /* USER CODE END UART4_MspInit 1 */
, @& U% z- }4 O4 H* }
) g4 N& I5 a5 Q9 U- }
5 W y( @* l1 h5 _+ b
! L9 Q, x. j+ J9 v8 Z6 z Y( l- }
, {6 ]- F ^$ C
复制代码- 使用cubeIDE0 |6 ]4 L* _4 d3 E6 Y
- __io_putchar(int ch)" V& u$ p8 W# M0 i* c
- {
$ K5 c( P% L4 n8 n6 g' f3 y* ^( Y( G - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
3 ?; B# o) I0 T& C* A - return ch;8 N; o3 Y, ?: v7 [! [
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
1 ~1 V. m& j% _ O8 D: |
- I, a' s( k: j0 {) A
添加输入输出头文件stdio后,就可以试试程序如何了。, a% q/ w4 j! A$ I
5 \3 E, U: ?& u
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。+ c9 D7 x* h& K9 p3 ?2 {, u; N) b7 B
& m2 [- s- w" e2 B* A5 k u- static void ViewRootDir(void)
- l1 R% z! T. h% n$ {4 H- Z - {# Y- p$ D# B0 k1 i
- FRESULT result;
; m& x6 d; @. R5 r: B9 u9 _( X - uint32_t cnt = 0;
8 r7 y" D. q+ P0 j+ ?5 |2 n9 V - FILINFO fno;
/ d; J. a2 `: n - 6 O- i& s# M2 \2 C4 V: B) R
7 O0 q5 k! m, O: ]/ S- /* 挂载文件系统 */
+ t, g9 F3 _) R- R; a - result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */" a# _& x% `! v( G4 |/ F- v$ y6 [0 T
- if (result != FR_OK)
# y% S9 w2 {- k2 g" b; R - {
' p8 y- A* T+ ]" K" J& e: L - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);
9 |( v: }% Y9 Q e: V+ y* E - }
, }$ a) s( B( u& M. H
0 R% S% ]$ k+ a. o; {- /* 打开根文件夹 */9 ^& T: P! j3 J% a6 x6 ]
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */; `' \+ H' F" Y" u- {9 I5 `; `' }+ k
- if (result != FR_OK)
, A y0 q7 D' ~( M( G% H+ p - {0 o3 o+ I9 d; D/ y
- printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
+ W! _- V* K% O$ y8 Z - return;
) X- {3 U) l& Y C6 c R - }
' v5 @! n. m0 c - - o! h% |4 E8 x( z4 z6 V# y
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");9 D, f7 e! ^ H7 y* |1 @
- for (cnt = 0; ;cnt++)
2 j; }) C. w8 [9 M6 k% A; s - {
2 W+ r2 {7 L: S! Z' O - result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */& q G9 ]' [, a0 T, b/ ]
- if (result != FR_OK || FileInf.fname[0] == 0)
$ @0 `1 S8 G' x/ c F - {
0 s8 _. D% l& k, O. t3 O - break;
& Q) c2 c9 ?5 i: u5 t/ a( I - }( I) a& Q9 f( g1 _2 Q3 K4 V: d, H# ^# q3 u
. Q: X8 N _, m: i, c4 Z4 s1 X- if (FileInf.fname[0] == '.')
+ x) k! S% l8 \- S - {
$ R K/ T: p3 H. X( M6 E - continue;
9 [8 C6 n9 _3 K, e, A9 Z - }
' \' ], B5 P6 Z0 r$ D6 d5 e
) }0 C4 N U6 @; z- /* 判断是文件还是子目录 */
+ d; { F. r& h# y& k - if (FileInf.fattrib & AM_DIR)
# A' ~ Y3 U4 j* p: ?/ D - {
; e4 s! f- ] W7 I; D( H6 ~ - printf("(0x%02d)目录 ", FileInf.fattrib);4 H0 ]5 K6 h8 p6 Q+ V/ S# P2 w
- }
. q7 g8 n" L4 k3 u; @' K - else. n/ N7 n$ B( s! E3 C8 _
- {
+ H, b. \$ |% e( p- P! d' N+ v - printf("(0x%02d)文件 ", FileInf.fattrib);& j3 `; I0 \1 c* T- p
- }( x: d3 ?( N( ?0 K% x( q
" `% s4 j9 v& ?8 L- f_stat(FileInf.fname, &fno);
- ?# {) f" b1 L \! k9 S
- S0 S2 \- c2 I9 S, }' ^- q- /* 打印文件大小, 最大4G */
2 x n! T- G% L0 V - printf(" %10d", (int)fno.fsize);1 `6 G9 J, s2 F% J
- ' j F; p+ A# j6 a
- 4 G/ ^% n6 o! _* \' u7 O2 b
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */3 y( F, M6 U# Y
- }
7 O# Y& A7 c, E2 O! J; l( h% O
6 |, B& {5 f* ?$ _* X6 W- /* 打印卡速度信息 */' u3 K0 b6 i. ~
- if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED); T$ l6 |1 u+ Z7 Q
- {
+ w; r6 @1 Q- `! n0 n' b - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");4 t/ } Y _, g8 t) o
- }0 U y% D: t! f; ?
- else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
5 T e- V/ W& E" y - {
4 D3 C, J8 r/ D/ ^+ C - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");/ t+ c4 O- o f6 _1 |5 [+ f3 v7 q
- }7 P/ R, v8 I H9 X) t
- else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)) z- N2 j3 C, E3 B. w0 T
- {8 ?8 B/ b; s' _! B: R! Z; b
- printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");& {/ ?8 `& B5 F0 }4 x o) j
- printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");, u; `2 y, W1 M$ j7 \1 t" \/ a
- }" E7 P+ X0 ]; P' p- x5 B
, j" } ]: Z% P, ^
4 r: Q9 N0 z! u7 Q. g. ]- /* 卸载文件系统 */
6 x9 `! z a& J( o( h - f_mount(NULL, DiskPath, 0);
8 d: T0 ]9 b8 s6 | - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
: X& ^% | [9 T9 ~& @
5 ~4 S) p& ~, Y1 b" \( X- B8 }
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
2 ~. c5 z W: b' f3 ^0 v8 a 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。/ B; |$ r, l$ q4 ~
" L$ }4 {( n, D- n: P- L. N; u7 w 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
4 s# F% ?7 H. V& u
/ i L$ K7 u2 |. S6 `7 N 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可+ X6 W0 o$ O+ M9 q
. A# X' G8 u0 g# M7 A5 n
料想这次应该没毛病了。结果,新的意外又出现了。$ S7 @4 [6 j* _+ d4 Q }( m
# `: U; D( E$ i3 i
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。) X, ]1 A0 |* s
' M8 [$ t4 k, s5 H( W+ ~$ J 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。
- `4 Y# [5 t$ g* g& N& l5 z4 N% c! J3 X" ]! Y4 E4 V
, j' G$ |. f2 p
. [, I* F# D; a. o7 H' X
/ e& Y& c6 C- q' c4 Q9 I
7 E# N. F# v/ U' S. P; ^
2 @3 T- [: h( A* j |