STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
" M. k) }+ j9 O0 q' a2 x0 O1 r
! k4 R7 c G7 N6 ~+ j9 v) a' M 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
- o7 c; T: ~: a; S/ s 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号; u( e1 ]9 h7 \9 O* Y
0 ]# b: P6 O2 \5 x- X$ W, P
手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
6 x1 h( p: F6 I - K B3 P4 `1 X: J/ U4 Q6 T0 S C
- static void MX_UART4_Init(void)
, r! @: Z- b, q - {) N3 y$ y% B" g! P* S
- ( p' B, p: T& u+ I- J* O
- /* USER CODE BEGIN UART4_Init 0 */$ [" S: {. [1 h% N6 j; v9 S
- 7 |1 T. Y; l: `0 M
- /* USER CODE END UART4_Init 0 */
8 R% F! C9 Q; v. U Y
( m; H" Q f' f* A' u/ l/ l6 \4 @- /* USER CODE BEGIN UART4_Init 1 */3 c, W" j% Y; _6 ~4 C7 g" F
- ) \& s; P4 f- A- a# U6 Q3 ^# K
- /* USER CODE END UART4_Init 1 */2 W* b4 c" h1 `( L
- huart4.Instance = UART4;9 D. l( k) v: e7 C, I4 [
- huart4.Init.BaudRate = 115200;
7 u0 P+ C) t7 u) O6 s) R! s- S - huart4.Init.WordLength = UART_WORDLENGTH_8B;/ j& {1 ~$ R. g8 I" i3 u
- huart4.Init.StopBits = UART_STOPBITS_1;
% f) i& h# @0 C* t8 ]& c, R - huart4.Init.Parity = UART_PARITY_NONE;, E& d8 O8 c3 t- c
- huart4.Init.Mode = UART_MODE_TX_RX;' H' l' l O6 J% b0 A0 U
- huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
8 A) Q* \) [- I, S, w0 O7 N/ y0 N - huart4.Init.OverSampling = UART_OVERSAMPLING_16;
5 }. T" N/ r& P; z - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;$ H( q$ E9 v- y8 P0 S7 m$ l2 N
- huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;0 K+ _/ d2 ~, t- ?" l+ l: o7 s) p# j
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;' c+ Y2 s, ~3 c! C1 u$ Z3 p
- if (HAL_UART_Init(&huart4) != HAL_OK)
- H3 f6 d$ l- \$ O/ g* a" X - {" n) ? p: w* s' I- w& j7 c! _
- Error_Handler();
" P0 E' p8 I. l$ {1 b- G1 | - }) R3 q$ u a ? m' z" F' r
- if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)$ h$ p9 m, C" n
- {
) m$ V' w: G' |0 Q1 P2 C2 g - Error_Handler();
. E3 g- V3 {5 u5 r, A - }4 @' c6 d* ^9 @$ R8 W0 o
- if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)2 A- m8 S" \1 Q5 T- ? k" q
- {
; Q k4 g& p' |7 C% N. _. x - Error_Handler();
K, |7 \# H( b. g - }
! K" y s s5 w - if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)* I7 |) w3 _' x/ q
- {
+ V" S1 @5 ^) `' r5 n w - Error_Handler();0 n# I/ X, J& b/ \% O. x) e
- }: ] o* G/ u3 B5 E4 Y, ~" L
- /* USER CODE BEGIN UART4_Init 2 */( T( Y7 ~$ N9 I! u( x
6 T* i0 q3 I3 u- U& j1 G- /* USER CODE END UART4_Init 2 */
( ]! _% b( y9 S6 p# q+ R8 R! Q" _ - 2 ]) ~3 q7 ~, n$ Z4 j
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
: |4 i. c; _) ?: g. M: a - {; q; ?8 Z* N3 i1 r% c
- GPIO_InitTypeDef GPIO_InitStruct = {0};
. M$ l" {9 S. R* J0 e4 K' G - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
+ r$ B' V4 Y* N% k6 W - if(huart->Instance==UART4)8 [9 O5 i+ u* |: ^/ O
- {
5 B6 U# L A3 Y, F# \; Z# l - /* USER CODE BEGIN UART4_MspInit 0 */2 h5 Y) H& k( k7 M1 X7 [; F
- - {6 ?- U- y" C8 c- D
- /* USER CODE END UART4_MspInit 0 */* @# c9 H1 w2 B0 E% K# v
" U1 W. p+ x; k! X- /** Initializes the peripherals clock8 b9 W5 @/ {! L& P3 g& e. m
- */
1 ?3 i% k' `) X2 M - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;: R& o h9 [3 f2 k. m6 \! I" g: G
- PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;
& C# p; t, R+ a5 ^ - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
c7 H3 V9 w2 |* ~. F - {
0 }% P! ` F8 I+ x6 P9 }5 m - Error_Handler();
2 J% A- k4 f8 _: F7 h7 P! ` - }
( p: L: c: m$ l( U3 s - 0 W Z: Z5 f; B3 j+ s1 z i/ p
- /* Peripheral clock enable *// E/ E+ d( Y5 x5 y
- __HAL_RCC_UART4_CLK_ENABLE();
. w$ B0 s4 Y) V3 I3 ?7 B) S/ w( b - 7 j- R) y+ V+ j
- __HAL_RCC_GPIOD_CLK_ENABLE();
4 v, K* e1 {* ^7 ? - /**UART4 GPIO Configuration
. W7 e! J! `. F( I$ L4 A1 `1 o - PD1 ------> UART4_TX5 S7 M9 C* u# @6 l
- PD0 ------> UART4_RX
- Q1 ~* Q( A U' w9 U& J - */* [; d9 d8 Q' l2 G
- GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;: A; a8 V/ j' @
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- U) R% o( n/ ^2 L$ }3 k - GPIO_InitStruct.Pull = GPIO_NOPULL;
6 u4 h5 y3 A7 m. L - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
0 Q% {1 M0 c7 z/ O. a, L - GPIO_InitStruct.Alternate = GPIO_AF8_UART4;4 y* N# c& i J1 Y4 r* H5 |' Z4 q
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
& }; F( k! B! C4 ~ - 4 Q$ {0 M8 e3 L
- /* USER CODE BEGIN UART4_MspInit 1 */
7 _! m& t, J/ E. T8 T
+ X( D# T& O7 w$ Y- /* USER CODE END UART4_MspInit 1 */3 W: i8 f' _( l
- $ ]6 ]" g5 s+ f
- } M, j+ S! N$ _7 d! k6 O
- / F p% Z |" e% n- L* Q
- }
0 ? n" W0 b7 N" o& H( S4 L
复制代码- 使用cubeIDE
s) f1 M: O/ W5 Y" H - __io_putchar(int ch), k- Q% q6 q7 r
- {
: r: z$ P" L. P5 ] R" j) ]7 _ - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
; w' W0 X+ K7 @3 S& b - return ch;
2 k$ B! L3 i% a0 |) f# b) Q" [! b# E - }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
9 K7 M* a: N& t( V4 F
3 t% T U z5 _2 d$ V, _0 ^+ L 添加输入输出头文件stdio后,就可以试试程序如何了。 F$ B( S9 d4 }! f, s9 V
! R9 E0 v: i2 t% v1 S: n; x
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。
, M" e3 S$ T: @; [% O' t8 k
3 a! F8 I7 {& _3 Z: l- static void ViewRootDir(void) z# ~, P; w/ d7 M7 R# B8 _
- {
6 ?6 d k( t2 b1 k# d - FRESULT result;1 m ~( l# H, Q: k$ K
- uint32_t cnt = 0;
( Q% K) f, I7 Z - FILINFO fno;
( @/ L5 P2 L) [# X% p) B' e
. V, c) v- o* _+ x5 O; b+ E
( V2 u" J3 Z0 ]! N3 b- /* 挂载文件系统 */
. o$ f. s" |) m6 K1 ~4 E2 o - result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */2 q* H h1 t5 d' O
- if (result != FR_OK)/ P0 i% A% F9 S) n9 C
- {
X2 U6 {( O" ]8 {/ x$ D. ^, Y - printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);7 o. r! b4 p' i* Y- g1 V6 E, u
- }% u1 m9 b( r b \2 C6 w% Z! o9 j
- 4 D5 p- D) R0 Q$ {( m. Q. d
- /* 打开根文件夹 */
& N. j& U+ f4 S' h ]2 Q+ u - result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */" B0 o2 t3 t) P
- if (result != FR_OK)& E. G8 k9 d/ S3 T5 \* _! a
- {
5 R4 P( s& q. e s9 W - printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
. Y* E2 H" p( u - return;+ q9 e" {4 s! K6 y4 W Q# @
- }" G# K- V( T. v% K1 a# v5 X
- 7 {; F5 }, a- y0 ?; b2 h. {
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");) W, {9 P7 q2 Q: M' G! n
- for (cnt = 0; ;cnt++)
1 Z" h; O, u2 J. @ - {3 j3 Q6 V2 `9 _
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */% P2 O0 f3 W2 p& I( r; C5 F
- if (result != FR_OK || FileInf.fname[0] == 0)
) u" Y+ ]" r1 k) D; u5 G2 i2 y - {) ? g Q- o; Y1 E& K3 Y4 o' I
- break;% I) k9 [, R; B H* ^
- }8 A0 o \7 v, P2 J$ O" S
- 5 g; x( V8 O0 z% e
- if (FileInf.fname[0] == '.')
1 L% g# B& T, V& _ - {
- k% m; c. h5 K - continue;
8 W: o! r: ?# I) y( | - }5 _, X% R* T8 |: y' _5 \6 }
4 |* @& l6 R6 O3 [' A! W+ d' V- /* 判断是文件还是子目录 */ P* {. g8 F4 y1 u1 W/ |& x9 N
- if (FileInf.fattrib & AM_DIR)
3 R6 V$ }; p8 y - {
( Z; z; T* E* U" h+ W - printf("(0x%02d)目录 ", FileInf.fattrib);5 m" U% `& p/ D' {# K/ W
- }
; W; A& n. c" y; m9 b9 E2 }/ l - else
& Z1 J5 P) [4 X - {1 D( o3 ?) t5 L+ j+ y
- printf("(0x%02d)文件 ", FileInf.fattrib);
" }4 ^9 A* A& F - }
, p5 t2 r6 S; s* i! t& {/ @4 F
' E8 n s$ @* m0 l3 [, H; X& C- f_stat(FileInf.fname, &fno);- r w L# K- [0 \
- + N( p/ E' W. ]
- /* 打印文件大小, 最大4G */
- B/ J8 `/ \5 X/ j0 O5 A; y5 h - printf(" %10d", (int)fno.fsize);5 n$ q" s* x4 F$ t' I8 t
. x! ~. w9 z4 m! Y* I. m- 1 k2 i: k" N0 L ^7 y
- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */$ G+ D o2 n) A
- }
4 V, \8 v5 e8 t7 Z - 3 {$ c4 z( J( k2 \
- /* 打印卡速度信息 */
) ~& f' c& B/ b: T3 | - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)/ _4 B" D. q# n* g% Y: x
- {
* V8 u9 k% h! a# f* ?# m" [4 ~. Y' R - printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");6 I2 h1 ]7 L* D7 T
- }
) y* E" {$ q! Z3 m - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
% u: C8 E$ C- h, `6 Q+ B - {
8 D% J2 O% u) q) l - printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");4 K. h) N& j& w1 W
- }
! a" k& _+ V2 a; ?% ~+ v/ o& n# p- N- ] - else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)6 j# a! ^ Q8 U! T/ t$ B0 y
- {
* p; ]) @! `( E# L& v - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");$ y% N. ~+ `* w7 {
- printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");
% @0 }$ S% A: D - }
3 V& o' k) ~3 f) ]- S+ P c8 a - ) h* U; u( I* ~2 X& n8 D
/ f# Z3 N% ~. ?- /* 卸载文件系统 */" A+ Q& |$ h9 W" O1 s
- f_mount(NULL, DiskPath, 0);
, x# e2 q4 g/ p% w W - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
# Z8 T/ P5 S% B) ], E% H
" u) i% z8 W' F1 n 中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。- e. c* W) o. T8 A
添加的内容为 -fexec-charset=GBK,还是修改编码的意思。- o0 h7 A$ z1 `. q G f
+ ~4 F% g( @; Z% f$ E 接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了
9 U( H( |; w0 G
+ `0 f1 ]/ ?( ^0 W( Z& k
很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
W. q8 j2 V& A$ F+ z' }# B
/ Y# G$ R4 U p' b, i" f/ t! a% H) x 料想这次应该没毛病了。结果,新的意外又出现了。8 d2 }. D) k' g# A) m* h2 B
( A# s& y7 L8 p6 i! _; C
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。
# U8 Z! U9 Q1 \1 I; o
! Q7 E1 \3 z7 ~1 @/ `* ^
满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。. V4 y: y$ h0 z( a, P
* H; K$ S2 n. X; i5 c! S3 c) r
4 U* {' ~ }& y: X+ t
' }6 |7 n2 U K6 W' ^
' X+ j1 M' `$ T3 H5 V' a
. {% W4 a3 h* V3 U* b$ U
# J, D$ P$ Y' A; E" c7 P |