STM32H7S78-DK板载WM8904耳放,有SD卡槽有屏幕,合计着做个播放器。首先读一下SD卡。
3 X) }& v4 k$ K+ q
3 G' e- U' F( {' e 鉴于该芯片从零配置较为复杂,第一步使用FatFs_uSD_RTOS例程进行修改做验证。导入工程后没有ioc文件,因此不能使用cubemx来编辑工程,遂手动添加。
1 X ?" q" W# d3 ]0 C9 l) j 增加串口打印,便于之后打印调试信息。从原理图找出调试器连接的串口号
0 J5 B' Q$ J$ l1 }+ |4 B
& F* X9 }0 T( h* B' d( O7 b 手动添加,需要配置串口参数,GPIO参数,重定向函数。分别如下
/ q3 {0 r0 @2 C/ k* j# M
8 m% Z) ?% C" j- static void MX_UART4_Init(void)
/ @" F! E- A0 g* n+ ^ S% B+ V - {
! o& A) `' r1 Z" s0 V - 5 m$ A- V* A4 E
- /* USER CODE BEGIN UART4_Init 0 */- S+ v. @2 I5 n4 A0 E% h6 J
- & g2 V9 e( K* Q+ \
- /* USER CODE END UART4_Init 0 */
7 _" g$ }3 L7 b" U1 k - - T+ d; [5 E% u2 \" n# }
- /* USER CODE BEGIN UART4_Init 1 */7 J' Q! ^( ]0 e
- 7 W8 c: l" G: P: E. A
- /* USER CODE END UART4_Init 1 */: x+ T$ c: F+ {
- huart4.Instance = UART4;
) b, Q+ {- d9 c9 P; V# L5 X. W - huart4.Init.BaudRate = 115200;
/ i k3 o: j2 M& F - huart4.Init.WordLength = UART_WORDLENGTH_8B;
# T4 A0 r5 V& ?0 d- ` - huart4.Init.StopBits = UART_STOPBITS_1;7 y2 U6 ~# h) J& J
- huart4.Init.Parity = UART_PARITY_NONE;
% P" O8 W9 ~. O; j @% R5 ^ - huart4.Init.Mode = UART_MODE_TX_RX;
% E. L; S8 V+ g2 Z3 ? - huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
0 v! {. m1 K R- n2 {% s5 i - huart4.Init.OverSampling = UART_OVERSAMPLING_16;
( M# }. E/ M; j# a6 I, K - huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
5 _3 I# C5 s% {8 d - huart4.Init.ClockPrescaler = UART_PRESCALER_DIV1;" k+ ~% ^8 P! `( n
- huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
; x0 T8 c5 l5 E/ J& Q - if (HAL_UART_Init(&huart4) != HAL_OK)) [% |% I: ^, X5 B6 N2 G
- {
+ X8 E' A5 ]6 x1 K6 N B - Error_Handler();3 X* {0 V3 B- f
- }" U" O. c8 e% b+ ^$ y1 {
- if (HAL_UARTEx_SetTxFifoThreshold(&huart4, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
* D% e( ?- f3 o2 ]3 }" I - {
9 n0 T% @7 I* S2 }% K i$ V - Error_Handler();
' ]$ ]9 t4 f$ N1 ^* l& l" w9 s - }& a6 `) M& a: F! G, N5 t' e4 _
- if (HAL_UARTEx_SetRxFifoThreshold(&huart4, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
) T. k# L* O7 j - {' I! \) r, s# C ]# a* r/ h
- Error_Handler();
) s q7 N$ ?6 f5 y - }( r) H w0 G' L* C
- if (HAL_UARTEx_EnableFifoMode(&huart4) != HAL_OK)6 L+ Q; P. l( I& w) x# R) U: }
- {
; a* p' s) G% `0 p. _3 M$ f - Error_Handler();
% a' ^% M1 K7 w) e& X5 e - }; o) r% ]! D# D6 K- D1 \: I
- /* USER CODE BEGIN UART4_Init 2 */
1 n3 G T" J) Z: W# c/ I. T
8 \ I0 X% h( i. Z! y9 U1 j- /* USER CODE END UART4_Init 2 */4 T5 r& T" B# @/ ]! H
- " i3 ?* ?) i. H6 m9 _( x3 }/ K6 M( L
- }
复制代码- void HAL_UART_MspInit(UART_HandleTypeDef* huart)
! o% i- {4 T+ q' s8 n% N - {5 X& D, @4 ]# o
- GPIO_InitTypeDef GPIO_InitStruct = {0};
# T" Q3 _' m# p/ H- F9 ]6 A( _ - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};; W6 `1 T9 f' t
- if(huart->Instance==UART4)
$ g% r5 M) C# ]; x4 ?- A9 e! G# | - {; ~( Y4 v0 O1 D3 k0 {% G) i
- /* USER CODE BEGIN UART4_MspInit 0 */8 {$ R* u& x7 ?+ f; \& T, `, r
! ]0 s5 O" q D6 Q- /* USER CODE END UART4_MspInit 0 *// t2 ~% J% {8 c$ F3 f, L
- ' L# F* H7 Q/ `3 R: L
- /** Initializes the peripherals clock+ p1 u% ]: D: `) z D
- */
5 A+ \, f) {5 D; g% h7 v! F4 o - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART234578;
7 H( N9 X- y3 l7 L! g: ]* | - PeriphClkInit.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_PCLK1;: H/ d4 P9 t% W
- if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)* r+ @* C4 Z' L5 {; R
- {& n+ c3 n8 u6 Z- _& m
- Error_Handler();
) z- X- K% B$ o' L& X7 \ - }1 L& y5 E: F6 E
- 1 M. \1 _3 F. I
- /* Peripheral clock enable *// c( E o E h( b
- __HAL_RCC_UART4_CLK_ENABLE();7 o6 _4 H+ B1 F9 H O! y( m
- 3 E# |" K( w; u. j$ u, a
- __HAL_RCC_GPIOD_CLK_ENABLE();/ }# J4 p1 d/ F+ ]6 Y- E
- /**UART4 GPIO Configuration& ~/ C, ?* S, q2 p4 V" D1 Q
- PD1 ------> UART4_TX9 }+ O( q6 Y; B3 b+ W
- PD0 ------> UART4_RX/ `) x' M" W9 k+ {" u9 Z
- */
) |- ]& d1 X2 m4 l$ T: H4 V" l - GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
8 @9 D6 ~1 r7 F - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
! a* `/ c+ x. J9 ?$ n1 L - GPIO_InitStruct.Pull = GPIO_NOPULL; J3 ]6 i. T1 T( c4 j
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
, n" A5 B- ~5 q) G' i2 h - GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
, F5 I4 r# w D1 ^) I, W% [ - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);8 j+ W5 H' O! J
. N8 ^- o5 Y8 }: V9 r! W m: k- _- /* USER CODE BEGIN UART4_MspInit 1 */" a2 q; q) L/ l! x
" @, B. p8 q: {) c: \+ ]- /* USER CODE END UART4_MspInit 1 */, h5 K3 M2 V: y! A- s0 C3 m
* M* b1 M" p4 W1 i& C" r; d) L; i- }
! w; i% U, Q$ o3 }0 A. I
% L& m1 [7 ?/ o2 y" M e9 h2 x- }% E7 G- v, c. p$ r0 n
复制代码- 使用cubeIDE% C; J! X" H) Q* W- [# i
- __io_putchar(int ch)
( d: ?& |5 x. V0 w' m( m - {
% o, h6 d# ?9 ?* S5 q! X, X6 I - HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xffff);
6 _$ B# S4 R- _7 M - return ch;; J; L+ `" m' y x1 P
- }
复制代码 代码修改完还是不能打印出信息的。需要IDE也作下配置,如下
3 @: ^ y. S- `/ e+ p9 A1 n
3 `7 p9 H- R$ ^7 ~, X, f* P 添加输入输出头文件stdio后,就可以试试程序如何了。+ B# C. w d! _* N4 G( x$ q: {6 N
8 _" ~+ q1 E% N3 P" }3 \
以上没有问题,接下来看文件系统。例程已经添加了FatFS,插入SD卡运行程序会在根目录创建STM32.TXT文件,并且写入一串字符。嗯,我已经测试,这是没有问题的。那要改成我需要的显示文件列表。SD卡我已经拷贝了一些歌曲文件,f_opendir(),f_mount(),f_readdir()等接口函数直接操作就行了。记得安富莱电子专门有做测试程序,拷贝过来适应下,对其开源表示感谢。3 G3 Q# |- Y8 O. s! A! U, N. |
9 h; y R8 ]6 B: Z s! ~1 R( k! b
- static void ViewRootDir(void)
, p V% B" m6 z0 J - {% o3 z) O$ H+ t7 ^
- FRESULT result;
! n/ P( w! k1 [& L; w4 g* j - uint32_t cnt = 0;
% r/ v9 ?# h- ?2 \/ W - FILINFO fno;+ w" t: x. g. s: r% t, f& I' F
- 6 { B5 |$ G! {2 i, ]$ z$ e) u, Y7 Z
- ' y! z% I/ i5 G
- /* 挂载文件系统 */$ G( U3 f* `8 w1 w$ b" d, W) d0 l
- result = f_mount(&fs, DiskPath, 0); /* Mount a logical drive */- r% o2 D: E& x7 V5 t2 j; z0 F
- if (result != FR_OK)1 }7 m" F7 R) W/ J: p9 |! x
- {# L% F; G- P3 A0 G A
- printf("挂载文件系统失败 (%s)\r\n", FR_Table[result]);. x! `+ \+ `4 A3 i* R
- }
0 s+ A# r2 a8 `2 _/ j( l - ' ~4 a+ P$ t5 i& O( Y* B
- /* 打开根文件夹 */: M! r# P* X( j& K3 s( _% @
- result = f_opendir(&DirInf, DiskPath); /* 如果不带参数,则从当前目录开始 */
1 M/ \( ?9 u" o* U. J3 q5 a - if (result != FR_OK)
8 l+ \5 Q! \/ ?( @' i3 }7 @ - {; V* w1 {* `- l( y
- printf("打开根目录失败 (%s)\r\n", FR_Table[result]);
* }& |- I+ h0 q, \6 G: r - return;
- ^6 S+ V3 G& E9 k6 n @' g3 t& s( Y; e - }
, n1 G' ?0 n/ O, }5 N3 j - # h3 a& O5 p# @( D% E g( v, N
- printf("属性 | 文件大小 | 短文件名 | 长文件名\r\n");0 t0 A, _' e' Q. H
- for (cnt = 0; ;cnt++)
, S7 D) |* s+ | - {. F4 ~9 S$ O9 ]0 E1 I( t9 c! A. ?
- result = f_readdir(&DirInf, &FileInf); /* 读取目录项,索引会自动下移 */
1 U+ F# @' _" |. d1 K - if (result != FR_OK || FileInf.fname[0] == 0)
/ ~& F/ }2 P8 j, B* h$ k - {
& G6 v: w, ]- l - break;4 A# Z9 d$ E/ r: z# p
- }
2 j, \' H: I5 O- [ - $ {0 n; { @/ i @! w: b
- if (FileInf.fname[0] == '.')3 z9 _7 Q `+ Z( r0 ~- G; K5 F
- {$ ^. M$ w1 [( h7 ]4 `( N, ^6 e
- continue;4 S! e! W: I' ~4 g0 T; Q3 _; g
- }
& K* t& l* B. t1 E% N# X4 v
$ u* C: H2 H8 @3 G X- /* 判断是文件还是子目录 */
2 _3 }2 a6 [0 v+ h6 O" z - if (FileInf.fattrib & AM_DIR)3 L( A" d, `& A& e' `/ J
- {
4 R3 ?1 Q" M% g7 B# I d8 l - printf("(0x%02d)目录 ", FileInf.fattrib);
) r2 t! p6 e/ ]/ S# V. m7 ? - }
8 m Q* \# f1 p2 J" h - else3 b" l4 \! I8 i0 G, K
- { _1 ~& [/ i- H. i; Q
- printf("(0x%02d)文件 ", FileInf.fattrib);0 c) D. u4 d' y3 I+ |5 F" O
- }
* e# o5 X; n$ o. ~6 o - $ K! P6 T( g6 U
- f_stat(FileInf.fname, &fno);) h# \5 W* z" K7 X9 I
- & c- w: X' w9 V X& [- D
- /* 打印文件大小, 最大4G */
+ t6 W; `/ N; ?& l- N2 X! k - printf(" %10d", (int)fno.fsize);4 u$ d- c% | B% S/ ?! t
- 6 O q" \. F5 i
9 r! m3 x+ H( X2 S- printf(" %s\r\n", (char *)FileInf.fname); /* 长文件名 */$ R% C5 R" h8 X( R' q
- }
/ i2 Q7 r* o0 }7 v0 G0 C8 E M2 S - ( u# f7 x/ k; ~0 e y% u8 m) }
- /* 打印卡速度信息 */
% U, W( C, E4 m6 }+ v+ p* l - if(hsd1.SdCard.CardSpeed == CARD_NORMAL_SPEED)( Y7 t. \' o7 K+ E. L! ]
- {5 q" Z& E0 K+ O3 P$ @) z& I
- printf("Normal Speed Card <12.5MB/S, MAX Clock < 25MHz, Spec Version 1.01\r\n");
: G1 D: e) S) ~ - }
- t6 X: f! f6 w( h$ a. T - else if (hsd1.SdCard.CardSpeed == CARD_HIGH_SPEED)
: w: x' S/ ~, D$ F' f - {6 r0 S% }6 W! [+ h4 |& x
- printf("High Speed Card <25MB/s, MAX Clock < 50MHz, Spec Version 2.00\r\n");
0 d( e8 @6 u2 |: n; s' K3 v - }( z' b+ M- \1 N9 X( a# ?. H
- else if (hsd1.SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED)5 P( @7 p( \' t+ _
- {
" [/ D$ L+ U O( A7 O - printf("UHS-I SD Card <50MB/S for SDR50, DDR50 Cards, MAX Clock < 50MHz OR 100MHz\r\n");
+ t+ Z' z' q( D' S, r0 s - printf("UHS-I SD Card <104MB/S for SDR104, MAX Clock < 108MHz, Spec version 3.01\r\n");5 R6 e: S) g# V0 M! W g" n
- }
7 ^$ c8 [1 u* M4 A( ~* I. N- h6 y - 0 h. j9 w' h7 z+ H
- " {/ B0 s1 X2 Y8 f# u
- /* 卸载文件系统 */' W' }& W* t7 l$ b' p T, @5 h
- f_mount(NULL, DiskPath, 0);
; W" \4 S+ f. T: n( l* O* T: _ - }
复制代码 函数末尾还判断了SD卡的速度等级。我这个卡和厂家配送的一摸一样,看看如何。不出意外的话还是出意外了。
8 ^- I& b8 @9 Z( r2 Z+ F
# E+ {2 ~* p! y* P: U8 e! m
中文乱码了。这个应该能够通过修改文件编码格式来解决,不过网上看了下,可以添加编译参数代替修改编辑器。验证了下确实可以。
& c8 Y2 ?4 \6 @ P 添加的内容为 -fexec-charset=GBK,还是修改编码的意思。: {. z7 W3 |6 Y; ]0 x: q7 g% p
' s) P& K- `/ u: ?0 q- R$ m
接下来直接使用有歌曲列表的SD卡来测试,看看意外如何了9 i8 P! N3 x( N! C- y$ t" R
% \+ d! O/ z& u 很明显,还是意外了,不过问题我也看出来了。应该是长文件命名没有支持吧。然后紧急打开文件名支持,宏定义修改即可
3 j* X7 W. P# `& a1 {( A) u
\+ D( Z+ b4 {1 ^1 m. o 料想这次应该没毛病了。结果,新的意外又出现了。, ]2 O/ @1 l0 a# w/ r! V7 {
( M3 F! V* X$ B7 [# e+ u
还好是我能hold住的问题,这文件看着也像是很接近了,看看ffconfig文件有啥没改好的。结果查看,发现code page指向了日文,难怪文字显示的内容参杂中文,这次总算没有意外了。. v1 _/ x4 Y% D' W+ A/ T) u/ b
. p5 y4 M, L' C+ K 满是意外的过程也说明尽管使用了例程还是有很多细节容易忽略,接下来计划添加解码器的驱动到工程里来。5 Y6 V" B. N$ \/ M9 X
8 X6 D; i- K/ J1 u/ @2 f
9 I: q$ D4 E3 H# |9 V8 z9 G0 l0 U! y7 L7 l6 z) G8 t3 b" D
9 {: L$ z5 |4 E6 Q
9 I' @* ?: L# z2 A# k6 ?) d. e( C& f/ G& [
|