87.1 初学者重要提示+ O( w, N+ Y! q- a. R1 D4 w# n
对于SDMMC控制SD卡或者eMMC,掌握本章的知识点就够用了,更深入的认识可以看STM32H7的参考手册。
$ D9 Y0 q7 w# k' H7 A! g2 b% E 注意,操作SD卡是采用的函数HAL_SD_XXXX,而操作eMMC是采用的函数HAL_MMC_XXXX,也就是说他们采用的函数前缀是不同的。 V$ g t" W6 g% Y' S O
SDMMC驱动eMMC支持1线,4线和8线模式,其中8线模式的最高速度可达208MB/S,实际速度受IO最大速度限制。4 ]( f$ Q" B" _, w! q
SDMMC驱动SD卡支持1线和4线模式。2 B V1 Q+ c, I
STM32H7的SDMMC也支持eMMC:
- N) u% s5 S3 J) z& u$ c * q4 z6 Z3 d: g( r4 r o
87.2 SDMMC总线基础知识: @7 E) p* L- o
87.2.1 SDMMC总线的硬件框图0 Z$ H9 P3 {% r8 y8 l
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解SDMMC的基本功能,然后再看手册了解细节。0 Z0 I F: x$ I1 C) w0 a
{& v7 U) @5 }4 a+ K. N. ~1 V# m/ ^1 x
& h4 h. d$ s- F6 l) a通过这个框图,我们可以得到如下信息:
3 x7 H, Z: j& [3 h( x( e/ M; z. v7 |
sdmmc_ker_ck输入
) K* i: E7 R1 O0 x. d. @* uSDMMC内核时钟。
6 @+ ? E( F) c# w! \
o$ l7 N7 G* j/ c- _ A sdmmc_hclk输入, O$ O/ S+ Q3 x6 Q) ]$ ]
AHB时钟。
8 T* ?& t5 O- {' X5 |9 W7 x: M+ y; i, O' c' D' m
sdmmc_it输出
- d0 }% V; h" G/ QSDMMC全局中断。
8 ~% b, v w9 Q* L- ^# L2 m& q) l$ y8 _
sdmmc_dataend_trg输出
9 P( f9 J" E4 I" IMDMA的SDMMC数据接收触发信号。
I+ F3 k/ I3 z# T, h4 z
& ]" f0 c1 K6 ~ SDMMC_CMD
2 B/ {/ n6 p6 Q* o" \" B$ mSD/SDIO/MMC卡双向/响应信号。
6 X6 z* `6 v& b. R5 o4 v B
' [- a' K! M: y% r( @1 r9 | SDMMC_D[7:0]
- r" }$ f0 o3 E1 ]: lSD/SDIO/MMC卡双向数据线。
5 D c3 n" J" K6 ]" t) Q( T: g- B b$ O
SDMMC_CKIN7 ]- B- ?- N5 U# J
来自SD/SDIO/MMC卡的外部驱动器的时钟反馈(用于SDR12,SDR25,SDR50和DDR50)。* ?+ E4 ~9 I; r5 D' O+ {" T
+ Z7 l- g6 v: e! z1 K5 r SDMMC_CK/ t+ e- Q5 f7 i" G+ {
SD/SDIO/MMC卡的时钟。# P4 x' P0 o7 d3 A4 i
2 A3 e. P0 b# S SDMMC_CDIR
/ h S1 H( `5 p0 Q; rSDMMC_CMD信号的SD/SDIO/MMC卡I/O方向指示。# `+ i; t/ j: ]! t
& |5 i5 k0 e) ` SDMMC_D123DIR
! ~4 r3 H. w; i: pSDMMC_D[3:1]数据线的SD/SDIO/MMC卡I/O方向指示。+ i9 r9 G) d A; d4 s+ {
& n5 n. L- ]+ e2 d$ ` SDMMC_D0DIR& T( ^. A, X; j. S6 Y. I6 E# f& B6 Z
SDMMC_D0数据线的SD/SDIO/MMC卡I/O方向指示。
1 B$ h2 U4 `' E6 p
6 `2 X* `3 G7 g6 m( Q" a* d- @STM32H7有两个SDMMC控制器,SDMMC1和SDMMC2,这两个控制器支持的功能是一样的。
7 T- I2 p' _7 M
4 C8 L3 _4 d u' ~6 x- a87.2.2 SDMMC时钟) t; n; a2 t2 U( i
SDMMC控制器的时钟来源:
* c+ ^0 @) }; g/ T- l6 C
M3 p$ p, |$ J& v( ~/ e: X9 |1 g7 Y' E* q q9 V4 B( t
" ]8 N* Q5 x" x) X+ t% u' \. j
SDMMC1和SDMMC2时钟源是一样的:
5 u9 k7 ~# N3 e5 \& B, O+ K/ w5 `0 k `8 K" s e1 m- C
# U' w8 _0 o) e! v2 C) `( r4 E
) P( }6 e0 d B# _1 ^
87.2.3 SDMMC1和SDMMC2支持的RAM空间区别
, B/ T# j2 x# o( G& Q9 O' }注:大家应用时要特别注意这个问题。' O) q! X# C# P# L
% M; r3 q! b8 U使用STM32H7的SDIO1仅支持AXI SRAM,而SDIO2是AXI,SRAM1,SRAM2和SRAM3都支持的( l, c2 ~ o2 @- g& f; s* v
6 y; x' `9 J% d* s
/ A5 |- d( A" l) n$ N
7 M% l7 U" [2 O, ~2 p
87.2.4 SDMMC支持的速度
5 m6 K z, W4 ]# \驱动SD卡支持的最大总线速度:( p4 z: g6 L, F/ e% E
7 K) [1 ^" d0 J- k B/ ]
" b/ T W X( V0 R( p
! T0 f7 G& u. M& J) Z% P驱动eMMC支持的最大总线速度:
, f" ^0 O- W7 L! C8 G
( ?% }( v4 x7 ^3 E# w8 d0 N$ E4 p, `, a+ _4 ~4 p
# ^& c0 r1 d. r关于这两个数据表,注意以下几点:1 O x: q" B: T7 N' z. U
a, y, |7 `, p, T# M5 t% X 驱动SD卡最大支持4bit,驱动eMMC最大支持8bit。 J4 J2 D4 i9 @1 y! P. \1 J
针对信号电压1.8V或者1.2V,STM32H7需要外接专门的PHY芯片才可以驱动。
7 _$ d/ h# S* B& C, v$ G 最大IO翻转限制说的是SDR50,SDR104这种高速通信。平时用的DS,HS这种,无压力,刷满速不成问题。. y) z X6 m1 c% u" `4 {- {- \6 A$ u
87.2.5 SDMMC支持UHS-I模式
% n6 p; y4 \. J1 M& T; qSTM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器。STM32H7参考手册给了一个型号ST6G3244ME:# c. G0 ]% T8 k# y
, V8 J u5 V) j3 z, x" J+ U
0 y1 F/ S9 O# X" o7 |
6 H! m5 L* V) J$ b/ h; h
9 n/ I% }$ l. }# }9 o3 `5 ^# @& H6 `; r; O9 @% h
87.2.6 SDMMC自带的DMA控制器IDMA
$ [5 r/ y1 N- c/ u' ^5 K" kSTM32H7的SDMMC自带了专用的DMA控制器IDMA,支持突发,也支持双缓冲。为什么要自带DMA控制器? 主要原因是STM32H7的通用DMA1和DMA2已经无法满足SDMMC高速通信速度。在本教程的第62章专门为大家测试过。通过让SDMMC自带控制器,这个问题就迎刃而解。
# M# c, z3 |2 Z7 K3 h) X1 T: h6 M6 M4 f. @: N+ w; q
87.3 SDMMC总线的HAL库用法8 R b; r* ]: X0 M3 t* r, G
87.3.1 SDMMC总线结构体SD_TypeDef
. ~0 ^8 I, v2 q) r( J1 _+ S% JSDMMC总线相关的寄存器是通过HAL库中的结构体SD_TypeDef定义,在stm32h743xx.h中可以找到这个类型定义:
. }5 J. `" \$ l' W
# H0 y. I5 n8 T. D! h t# d% G- #define SD_TypeDef SDMMC_TypeDef$ Z# s4 @6 t7 @7 ]' s
- typedef struct
- y* E7 P. x" i, x& G - {- w0 o9 n$ ]5 z. p \+ P8 y2 Z
- __IO uint32_t POWER; /*!< SDMMC power control register, Address offset: 0x00 */
$ P5 S7 G3 A7 U) O/ [ - __IO uint32_t CLKCR; /*!< SDMMC clock control register, Address offset: 0x04 */
/ u# T( h; x- u/ x5 V - __IO uint32_t ARG; /*!< SDMMC argument register, Address offset: 0x08 *// f$ s/ h7 Z8 g0 g, Q. O" D
- __IO uint32_t CMD; /*!< SDMMC command register, Address offset: 0x0C */
" P$ U' V' K6 }) O - __I uint32_t RESPCMD; /*!< SDMMC command response register, Address offset: 0x10 */) ]& q/ K1 J B1 k( |' s
- __I uint32_t RESP1; /*!< SDMMC response 1 register, Address offset: 0x14 */3 i: X% g# u( u% F& W8 e$ A- o# m
- __I uint32_t RESP2; /*!< SDMMC response 2 register, Address offset: 0x18 */7 G4 R3 V5 Y. a5 g
- __I uint32_t RESP3; /*!< SDMMC response 3 register, Address offset: 0x1C */
$ n0 O {" N5 ]- y - __I uint32_t RESP4; /*!< SDMMC response 4 register, Address offset: 0x20 */; }4 P* D3 s J/ E6 r3 m
- __IO uint32_t DTIMER; /*!< SDMMC data timer register, Address offset: 0x24 */% O" _# K+ h( q$ m; ~
- __IO uint32_t DLEN; /*!< SDMMC data length register, Address offset: 0x28 */% S. R& c% I0 q, ^3 h+ T7 d& C' Z
- __IO uint32_t DCTRL; /*!< SDMMC data control register, Address offset: 0x2C */5 U) s P8 ]: g1 R; [$ m L
- __I uint32_t DCOUNT; /*!< SDMMC data counter register, Address offset: 0x30 */
/ x: j& W5 h, m7 I" b. V - __I uint32_t STA; /*!< SDMMC status register, Address offset: 0x34 */
7 T) Y& @: l5 e4 N1 Z* v) l5 d - __IO uint32_t ICR; /*!< SDMMC interrupt clear register, Address offset: 0x38 */
& ^- _* V2 i( J( G6 P - __IO uint32_t MASK; /*!< SDMMC mask register, Address offset: 0x3C */6 O" G% ~0 P' v' ^. W
- __IO uint32_t ACKTIME; /*!< SDMMC Acknowledgement timer register, Address offset: 0x40 */
2 V$ z. c" Y) \& u! T, z - uint32_t RESERVED0[3]; /*!< Reserved, 0x44 - 0x4C - 0x4C */
$ ?( }( {4 E6 @) K! _1 S - __IO uint32_t IDMACTRL; /*!< SDMMC DMA control register, Address offset: 0x50 */
2 W% D- k/ h6 g6 J/ G9 G - __IO uint32_t IDMABSIZE; /*!< SDMMC DMA buffer size register, Address offset: 0x54 */& M! L9 ^2 |' O: Y) C* s* q( s
- __IO uint32_t IDMABASE0; /*!< SDMMC DMA buffer 0 base address register, Address offset: 0x58 */$ @$ D' R* `7 e- j/ R, l
- __IO uint32_t IDMABASE1; /*!< SDMMC DMA buffer 1 base address register, Address offset: 0x5C */2 H' @9 R' e3 s' l
- uint32_t RESERVED1[8]; /*!< Reserved, 0x60-0x7C */
1 _% {6 x0 V+ G' x% z0 { - __IO uint32_t FIFO; /*!< SDMMC data FIFO register, Address offset: 0x80 */
# g; F7 l1 r# g - uint32_t RESERVED2[222]; /*!< Reserved, 0x84-0x3F8 */
2 k+ q) A- c& [% r0 A$ W% N4 s6 ^ - __IO uint32_t IPVR; /*!< SDMMC data FIFO register, Address offset: 0x3FC */! h9 ~ y5 w. c N! ^
- } SDMMC_TypeDef;
复制代码
. ?2 s2 C2 {- _5 O这个结构体的成员名称和排列次序和CPU的寄存器是一 一对应的。- w$ Z ^9 E) l9 y5 \5 p
2 C! p( g5 v2 ]- L! Z }
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:' f6 a9 A$ z" F+ Z; r2 h h( n
+ e3 c. R }% ~! N- ?
- #define __O volatile /*!< Defines 'write only' permissions */
! o* [7 x( b: D - #define __IO volatile /*!< Defines 'read / write' permissions */
复制代码 0 Y) f8 J7 u+ n7 R7 E) A
下面我们看下SDMMC的定义,在stm32h743xx.h文件。
4 ^6 a5 ^ S* C9 O" @+ b4 y9 r
5 Q4 [# h: w% e- #define PERIPH_BASE (0x40000000UL) % _+ M$ g$ s4 Y. t }/ i
- #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000UL)
9 F- l5 }- T5 W5 ?+ G - #define D2_AHB2PERIPH_BASE (PERIPH_BASE + 0x08020000UL)! s" H) M* S$ r% E
- * [$ N# r, ^" m5 ]; ^
- #define SDMMC1_BASE (D1_AHB1PERIPH_BASE + 0x7000UL)
0 P* d2 I f) K/ u3 s8 L( W - #define SDMMC2_BASE (D2_AHB2PERIPH_BASE + 0x2400UL)
' O# W$ z7 D% R. {3 n4 @1 B3 |
* y3 U8 b( Y; T) ^2 c0 o) W1 ^: u- #define SDMMC1 ((SDMMC_TypeDef *) SDMMC1_BASE)
; E$ W& J- U& t+ T: p& ~1 ^ - #define SDMMC2 ((SDMMC_TypeDef *) SDMMC2_BASE) <----- 展开这个宏,(SDMMC_TypeDef *)0x48022400
复制代码
- [5 O9 I' k/ B) d0 p6 u3 a& ~" E我们访问SDMMC1的CMD寄存器可以采用这种形式:SDMMC1->CMD = 0。
% j8 v) J4 ^ H5 T
6 L: O; N$ C5 t$ Z5 J& ]7 x87.3.2 SDMMC总线初始化结构体SD_InitTypeDef
* b) A" X+ \# t5 m& m5 ^- q下面是SDMMC总线的初始化结构体:% o, } s8 o: Y7 j' p4 n5 p
% w4 _9 t: M& j
- #define SD_InitTypeDef SDMMC_InitTypeDef
! s' U8 Z; x \( P - typedef struct8 C7 G% D+ c. {. H$ b8 x
- {
6 C! q# [4 V4 m; R& f0 Q8 P - uint32_t ClockEdge; $ R: w1 r- `! g- d) R' \
- uint32_t ClockPowerSave; , }% `! P( G' V) R' y& v' n
- uint32_t BusWide;
* J$ h4 I+ Z I+ B. M2 a - uint32_t HardwareFlowControl;
9 Y* J0 f2 w! w) i- Q, E - uint32_t ClockDiv; 7 e: k9 J# O' n" G# H
- #if (USE_SD_TRANSCEIVER != 0U)
" v% M" d8 X$ _1 k7 {! u: ~ - uint32_t TranceiverPresent;
8 G8 L5 T; y/ X; D! F - #endif
& B* P1 I8 L; G' j7 M - }SDMMC_InitTypeDef;
复制代码
: T3 m9 [5 k+ k2 h: i9 H下面将结构体成员逐一做个说明:
, \: \: b! V& ?! O7 }; x" h+ ^5 C& l' ~
ClockEdge
8 |6 T; a9 E$ J! @3 m: S用于设置SDMMC的数据或者命令变化的时钟沿。, m9 N; g, a& n5 w- c" t/ S
- #define SDMMC_CLOCK_EDGE_RISING ((uint32_t)0x00000000U), I7 w! k9 y* m( m- s5 G; ^9 Q
- #define SDMMC_CLOCK_EDGE_FALLING SDMMC_CLKCR_NEGEDGE
复制代码
a6 i' L$ {" _: q ClockPowerSave \, M9 [( [& Z+ W
用于设置空闲状态,是否输出时钟。
( M: [+ J, {, E- #define SDMMC_CLOCK_POWER_SAVE_DISABLE ((uint32_t)0x00000000U)
, m: s2 t B& R& H, r1 ?4 N - #define SDMMC_CLOCK_POWER_SAVE_ENABLE SDMMC_CLKCR_PWRSAV
复制代码
; ]0 ^3 Z# j R. B BusWide' D# Y: J2 j g( V
用于设置SDMMC总线位宽。 \3 P ]' t) E4 ]4 @$ H
- #define SDMMC_BUS_WIDE_1B ((uint32_t)0x00000000U)
/ N, e- P2 S6 T' `3 c7 X9 P% ] - #define SDMMC_BUS_WIDE_4B SDMMC_CLKCR_WIDBUS_0- F0 B, m$ y4 e! d% G7 i s
- #define SDMMC_BUS_WIDE_8B SDMMC_CLKCR_WIDBUS_1
复制代码
# O6 `- T# Y' {. p& B7 f7 q HardwareFlowControl8 B/ o3 e2 W4 d! ?
用于设置时候使能硬件流控制。
3 @+ I: N* W5 m6 Z' m2 t. k6 [- #define SDMMC_HARDWARE_FLOW_CONTROL_DISABLE ((uint32_t)0x00000000U)% ~# t2 Q' {, r: @! M' m d
- #define SDMMC_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_CLKCR_HWFC_EN
复制代码
% ?8 G0 j/ `- O# d ClockDiv
0 n( O/ ^0 a0 _- N. B ]+ p用于设置SDMMC时钟分频,参数范围0到1023。4 a+ [' Q) g* \7 ^& `7 m
3 y# B. a" n P! }
TranceiverPresent
0 Y6 T$ \4 p: C- a1 j% l/ p8 O用于设置是否带1.8V收发器。( x9 G( j" Z, `
- #define SDMMC_TRANSCEIVER_UNKNOWN ((uint32_t)0x00000000U)
5 y3 r( [3 z. X* s6 N* F+ W& G8 h1 o' i - #define SDMMC_TRANSCEIVER_NOT_PRESENT ((uint32_t)0x00000001U)1 b+ X0 e g. B) q6 q$ G. {6 i
- #define SDMMC_TRANSCEIVER_PRESENT ((uint32_t)0x00000002U)
复制代码
& D" P& p! I, h. m( I; R87.3.3 SDMMC接SD卡信息结构体HAL_SD_CardInfoTypeDef
9 ^0 v% F: h6 l z下面是SDMMC总线的卡信息结构体:' o) d+ \+ _: e3 f' X: `0 X: G- P4 {
- typedef struct
' R" z; Y0 L& ~4 @ s; o - {. g; w! X7 h7 P3 \6 w
- uint32_t CardType; /*!< Specifies the card Type */
8 C3 _ w5 [! k. t) R" {" d - uint32_t CardVersion; /*!< Specifies the card version */
b" W. Z5 O- ?$ [ - uint32_t Class; /*!< Specifies the class of the card class */9 F2 n" c, o7 i# ~
- uint32_t RelCardAdd; /*!< Specifies the Relative Card Address */
. \" q' e+ J* j8 z+ s - uint32_t BlockNbr; /*!< Specifies the Card Capacity in blocks */
! n3 N# r$ h9 ?6 m1 T - uint32_t BlockSize; /*!< Specifies one block size in bytes */
% p3 Z8 C. }9 z+ o6 A9 P% p. e - uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */
8 M) P: s, X1 z: m - uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */) {2 N" b' S9 W. x9 q: l1 e
- uint32_t CardSpeed; /*!< Specifies the card Speed */, _9 _& L) `( v$ O/ X& f1 f
- }HAL_SD_CardInfoTypeDef;
复制代码 $ `3 i# P. i: l
下面将结构体成员逐一做个说明:
' E; v, [. ?- G; a9 }" a W$ @ s1 O }) k
CardType
, M- l( f2 I5 y卡类型。
* X5 c* a) s% \, P; I- /*!< SD Standard Capacity <2Go */- d5 C* U8 p/ b1 L$ M! d
- #define CARD_SDSC ((uint32_t)0x00000000U) : C0 V, y: k& a- c4 i$ i
- /*!< SD High Capacity <32Go, SD Extended Capacity <2To */5 A7 Z2 Z J* E; C* A, E
- #define CARD_SDHC_SDXC ((uint32_t)0x00000001U) : y& o! O2 v2 d, i
- #define CARD_SECURED ((uint32_t)0x00000003U)
复制代码
) b4 e- O- ]; R CardVersion
: M5 p- ?6 j) y/ X4 g7 F/ ?卡版本。
% _: {! S- [/ [- #define CARD_V1_X ((uint32_t)0x00000000U)2 y6 X; { n/ }
- #define CARD_V2_X ((uint32_t)0x00000001U)
复制代码 ) e+ U2 b" [4 W$ i5 f0 R% C1 F
Class
* s) [0 r7 M9 K) ]% n卡类型。1 ?/ o7 f/ U: _" a7 q* ~) s/ p8 V
8 T* M4 O+ D v RelCardAdd
C2 k3 @3 r* N6 ~* o卡相对地址。
. g4 X8 P4 O3 L! |& N2 i, d0 D
8 c6 k# Q' w5 D2 ]( n4 Y BlockNbr
/ }+ X* o- K; O$ V% \ n* t整个卡的块数。
* `$ h8 }1 {8 l) @+ L. ~& o* K. R0 K$ t& i- O3 m" E4 [$ C/ R" u. a/ o" i# A% S/ P
BlockSize) H1 a, [5 Y' ^. n
每个块的字节数。
4 J. N! B3 h0 W* [& [9 `
3 V* {* Z% H3 c( t! t9 R: Z LogBlockNbr! _1 Z6 p3 O( {+ \
整个卡的逻辑块数。
2 c& L. |) w$ x$ U& J f: k$ S \1 b& ^3 H: H9 V6 n
LogBlockSize) G3 M6 D2 b5 ], n+ E, [
逻辑块大小
0 |3 I# |& j. M8 D+ z- #define SPI_FIRSTBIT_MSB (0x00000000UL)
" ?9 I4 u8 ?9 O1 f: @2 p4 L - #define SPI_FIRSTBIT_LSB SPI_CFG2_LSBFRST
复制代码
) I0 o; m/ g3 j; |8 B: y CardSpeed
8 ?# J7 r; K- e" o1 t1 p用于设置是否使能SPI总线的TI模式。, k+ [' o! t- D# _, K$ e
- /*!< Normal Speed Card <12.5Mo/s , Spec Version 1.01 */$ D7 E7 f2 M/ @( N
- #define CARD_NORMAL_SPEED ((uint32_t)0x00000000U)
* y- h# g$ Z6 A h0 b% C8 j- ^& `" D
( u& b: p! C5 C& y* G% v6 y& _- /*!< High Speed Card <25Mo/s , Spec version 2.00 */
$ g z0 f6 _5 u0 W/ d) K+ M, N - #define CARD_HIGH_SPEED ((uint32_t)0x00000100U)
3 d3 c( t6 N3 e - j/ _) Q' d* ^7 m
- /*!< UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards
, ~' c$ k7 D2 M+ y7 y, x - and <104Mo/s for SDR104, Spec version 3.01 */
2 q/ X( @: }& F6 W - #define CARD_ULTRA_HIGH_SPEED ((uint32_t)0x00000200U)
复制代码 1 _3 S' d* j" ~9 N
87.3.4 SDMMC总线句柄结构体SD_HandleTypeDef
! l$ t. n T- t0 K下面是SDMMC句柄结构体:, Z, W3 d" H5 F& B5 J5 A: x- x
0 z+ t, I8 C$ ^; D- #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
2 l! w- L1 w/ v0 @6 N; T - typedef struct __SD_HandleTypeDef
/ F2 R7 b& q# R# h+ T( Q' ]8 w - #else$ D t% f/ ~& {) c$ d
- typedef struct
6 \5 l6 r1 y" I2 G8 C) N, N - #endif /* USE_HAL_SD_REGISTER_CALLBACKS */; R9 d J- i6 S3 T0 U: o9 c d
- {6 e, Z/ S! O# N
- SD_TypeDef *Instance; /*!< SD registers base address */0 S: j$ _) G& w1 f
- SD_InitTypeDef Init; /*!< SD required parameters */
7 S) n7 v, x8 |# h: E$ k! X' E - HAL_LockTypeDef Lock; /*!< SD locking object */
" y0 Z* |$ l, n! A$ V - uint8_t *pTxBuffPtr; /*!< Pointer to SD Tx transfer Buffer */$ ~: C9 G& K+ Z& L% M$ g/ Q' z6 l
- uint32_t TxXferSize; /*!< SD Tx Transfer size */
5 C" Q% W3 x7 P) K j8 W; U' b, D - uint8_t *pRxBuffPtr; /*!< Pointer to SD Rx transfer Buffer */6 e. U o; N# i2 L, y9 l8 M
- uint32_t RxXferSize; /*!< SD Rx Transfer size */1 \ ^& l: ~% d: C; c
- __IO uint32_t Context; /*!< SD transfer context */
% a3 {. W; d6 |9 e% z6 Y - __IO HAL_SD_StateTypeDef State; /*!< SD card State */( `! `4 l. s* n9 @% |; T: o
- __IO uint32_t ErrorCode; /*!< SD Card Error codes */
+ p. |/ G* m4 z% Z! C* e6 w - HAL_SD_CardInfoTypeDef SdCard; /*!< SD Card information */6 p- ?/ M9 R# f! `8 p5 P
- uint32_t CSD[4]; /*!< SD card specific data table */3 [" u* C1 L9 o) e9 E& A, r
- uint32_t CID[4]; /*!< SD card identification number table */6 N' D- ^1 g2 s& v4 G% ^ i5 r3 ]: M4 [
- ! n$ i# F5 W! Y$ E' F
- #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) O0 v8 c7 l3 N* F
- void (* TxCpltCallback) (struct __SD_HandleTypeDef *hsd);
9 H) e8 ~' J* B - void (* RxCpltCallback) (struct __SD_HandleTypeDef *hsd);
/ A, Z/ s6 v8 p& f+ O - void (* ErrorCallback) (struct __SD_HandleTypeDef *hsd);9 i% _2 f( M( m3 n
- void (* AbortCpltCallback) (struct __SD_HandleTypeDef *hsd);
, R: ]( U7 d8 _ - void (* Read_DMADblBuf0CpltCallback) (struct __SD_HandleTypeDef *hsd);
! _8 J, Z% g# e7 E, J7 r$ X - void (* Read_DMADblBuf1CpltCallback) (struct __SD_HandleTypeDef *hsd);
& l1 \. |7 R5 f, E - void (* Write_DMADblBuf0CpltCallback) (struct __SD_HandleTypeDef *hsd);! G, m7 }& P1 c& v* p
- void (* Write_DMADblBuf1CpltCallback) (struct __SD_HandleTypeDef *hsd);
. U! K' }0 l4 {$ }% | - #if (USE_SD_TRANSCEIVER != 0U): ?+ S" s7 ^$ K( i
- void (* DriveTransceiver_1_8V_Callback) (FlagStatus status);
7 S) {7 L+ |8 r - #endif /* USE_SD_TRANSCEIVER */% h' @# Y2 h' `- X
- L$ ~; ]3 F+ x. |
- void (* MspInitCallback) (struct __SD_HandleTypeDef *hsd);
' {. O6 J/ l: h/ j - void (* MspDeInitCallback) (struct __SD_HandleTypeDef *hsd);
9 F5 L B0 u: Y" N; w3 W - #endif /* USE_HAL_SD_REGISTER_CALLBACKS */
`+ |" a" ^. U5 z5 ~* f# H0 g - }SD_HandleTypeDef;
复制代码 9 _- a" |2 G& D- ?8 u+ |# g3 q
注意事项: i: f" t' o: U" O {, G: \* v
: ], ?# ]: s3 ~% I% V条件编译USE_HAL_SD_REGISTER_CALLBACKS用来设置使用自定义回调还是使用默认回调,此定义一般放在stm32h7xx_hal_conf.h文件里面设置:
/ |+ q( s" D. N. N8 H9 U; T& e( t2 D: A( H8 {: S8 b5 V! ]
#define USE_HAL_SD_REGISTER_CALLBACKS 1
8 E, ]4 ? T( F8 u% s
[/ d! O) b% }: e. {% ^* \通过函数HAL_SD_RegisterCallback注册回调,取消注册使用函数HAL_SD_UnRegisterCallback。% X7 q$ t# L" Y
7 c# U0 I, u5 ^0 a' t
这里重点介绍下面几个参数,其它参数主要是HAL库内部使用和自定义回调函数。6 b) I' O- i7 m" @
& b; v1 q3 H$ A/ A8 U
SD_TypeDef *Instance; ^! v( W! ]5 X. n5 _
这个参数是寄存器的例化,方便操作寄存器。! u4 J9 m/ Z) C4 Z$ X
8 B, A" V% F% k1 I7 u
SD_InitTypeDef Init" K' [) Y# ~5 s/ ^: m2 O) Z4 x
这个参数在本章节3.2小节已经进行了详细说明。
1 I5 I- J$ u7 j: m" j9 G8 V% Z" O ]& E1 F h# j
87.4 SDMMC总线源文件stm32h7xx_hal_sd.c
2 d' h2 n% G% M) |- b# s此文件涉及到的函数较多,这里把几个常用的函数做个说明:
& W! V" I2 g( I r
) w' @) \/ F4 a( s$ H HAL_SD_Init% _. e! r; m3 c1 \- `- Z
HAL_SD_DeInit- e2 D7 S o- @& e; J; Z
HAL_SD_ReadBlocks6 d) B% ?" V% e- o
HAL_SD_WriteBlocks9 m) |+ {! r- u: p
HAL_SD_ReadBlocks_DMA
0 l+ B% G! g( n8 z HAL_SD_WriteBlocks_DMA
: Q' y1 x5 e! f, Q7 _6 ~. z1 y HAL_SD_Erase& b0 ]' F# @, [) u
87.4.1 函数HAL_SD_Init
( {+ G1 k6 G& e$ \: [! e函数原型:
! Z" h& E" C% w8 f( [4 m; q
+ R+ m" g2 x8 [+ k3 O7 f- HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd); t4 T0 ]4 B }8 g% O
- {
5 N/ ]' ?" p4 j) J# { - HAL_SD_CardStatusTypeDef CardStatus;8 ` R1 @, Z ?+ }
- uint32_t speedgrade, unitsize;' K7 ]0 {5 ^0 P+ M9 z, o0 G
- uint32_t tickstart;
_" N ~2 i' M( a0 i - 4 Q! T$ e6 b3 O& A9 ^& s' T! Q
- /* 检查句柄是否有效 */% ], u6 h1 H e" g( G
- if(hsd == NULL)
3 q8 Y+ T' D) m x: }9 |9 ] - {
0 G. L! V% E* z0 Q* V6 ] - return HAL_ERROR;
/ e- d7 y2 E2 A% o9 H2 Y; T - }
& X+ D, g$ c. G' X
* R/ f/ v1 t+ R4 A7 G- /* 检查参数 */: }* {: j1 e) }( ~
- assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));' I* ~& I7 `/ t
- assert_param(IS_SDMMC_CLOCK_EDGE(hsd->Init.ClockEdge));) e% N& q# v; s/ a6 ^: T j
- assert_param(IS_SDMMC_CLOCK_POWER_SAVE(hsd->Init.ClockPowerSave));4 d! Z5 @# M# {( X; f
- assert_param(IS_SDMMC_BUS_WIDE(hsd->Init.BusWide));% E) M( `0 H1 L" ?/ i; y [
- assert_param(IS_SDMMC_HARDWARE_FLOW_CONTROL(hsd->Init.HardwareFlowControl));
% \3 C& m% Q4 ^ - assert_param(IS_SDMMC_CLKDIV(hsd->Init.ClockDiv));7 V1 a9 S; R2 i
- V& W4 E& `* w8 c6 Q- if(hsd->State == HAL_SD_STATE_RESET) T' p! R( ?% K, W) ~
- {8 b% n' a; x$ K, m0 h% Y9 H1 v
- /* 开锁 */
' V& y0 e' n/ a6 Z: g& F - hsd->Lock = HAL_UNLOCKED;, } ^& J# v c( L* d" B; l q
% Q, V, o# |, J5 e$ C- #if (USE_SD_TRANSCEIVER != 0U)
6 z0 i8 y8 b k% d% A - /* 兼容 */
; }/ w2 T6 _3 X& { - if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_UNKNOWN). G! N3 I8 U- D( T4 T
- {
7 C5 `- g$ y, g - hsd->Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT;
; ]2 u; C8 K% A' H5 C- R' | - }
- q( ^, H4 }+ I/ M6 N; ~% s - #endif
6 e3 _( e, J! \, m& V2 \ - #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)) j: j, o7 h# O1 U7 e/ \3 x7 O% F, S
- /* 复位回调 */
+ J4 W- I0 z4 m( @9 t# R/ r% ? - hsd->TxCpltCallback = HAL_SD_TxCpltCallback;
( K6 y5 d$ @$ I6 w5 a$ [& H - hsd->RxCpltCallback = HAL_SD_RxCpltCallback;% @& v& ]4 ^" E( \
- hsd->ErrorCallback = HAL_SD_ErrorCallback;: }# S' m: [ f. Q) s
- hsd->AbortCpltCallback = HAL_SD_AbortCallback;
& J7 g2 O4 l- I2 e; ^- u4 ` - hsd->Read_DMADblBuf0CpltCallback = HAL_SDEx_Read_DMADoubleBuf0CpltCallback;
, W3 f- R! b4 \! D4 M - hsd->Read_DMADblBuf1CpltCallback = HAL_SDEx_Read_DMADoubleBuf1CpltCallback;# s$ p. }5 g2 h) m
- hsd->Write_DMADblBuf0CpltCallback = HAL_SDEx_Write_DMADoubleBuf0CpltCallback;
# y% d4 y( A- \& ^ q, J/ o - hsd->Write_DMADblBuf1CpltCallback = HAL_SDEx_Write_DMADoubleBuf1CpltCallback;
( H' s0 m4 T( e" ^7 h0 z& m - #if (USE_SD_TRANSCEIVER != 0U)
1 l g6 ?; j A$ c - if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)5 y, d7 u F: t; b& [$ v: x
- {
+ q% f- f$ _- F; l8 ?; Z0 f - hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;
/ h; L6 G! a* E( h' X5 N - }
( ]: V- e, z; K* H0 L$ t* p - #endif
" [8 H) s, m& q5 _1 a+ w/ P; t( U - 2 a1 G, Q, t9 h: z
- if(hsd->MspInitCallback == NULL)
5 U) o7 A. c- M" T - {
' X; }; R1 N; e' h* o5 F% g - hsd->MspInitCallback = HAL_SD_MspInit;
) o; N. J, E' { P6 h5 N - }+ V2 s/ P4 G$ b) S
- - Y2 |4 J4 b2 U
- /* 初始化底层 */
) Z6 f. a- j5 i, B2 ]% e - hsd->MspInitCallback(hsd);
+ R# ?1 h# e- H* K% @$ r* h - #else
4 K) K! W; A( c" j7 W - /* 初始化底层硬件 GPIO, CLOCK, CORTEX...etc */. Y' a; z% N+ N; S
- HAL_SD_MspInit(hsd);7 u, ?7 g( R8 {, J8 d
- #endif /* USE_HAL_SD_REGISTER_CALLBACKS */
, ?/ |2 ^& I/ ? R; p# D - }
9 `! y0 V' r9 r9 F - : C# \" d0 O- j7 S& }4 R
- hsd->State = HAL_SD_STATE_BUSY;" x* w6 y i8 t& @( \" { h# h! a
) a/ g# l! g) l- /* 初始化卡参数 */5 w( j1 O7 Z1 I! f
- if (HAL_SD_InitCard(hsd) != HAL_OK)
, m* d8 N1 [' y2 m! a - {4 u2 F- N4 H+ a/ V/ s
- return HAL_ERROR;1 O' W" h( v* z
- }; Z. p$ N# V# l, Z; J. l! s! \
7 i- v0 O2 A4 V4 H$ Q/ ?- if( HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK)& T5 [4 G- b6 s6 N* J: c
- {( x8 r0 l: h8 U/ w
- return HAL_ERROR;1 Z; h! V' t2 [- I. R R2 F( v9 U5 R
- }
- H, m, M. a% k# N% B' U - /* 获取卡速度等信息 */2 Q ]2 A3 |/ b$ z( H) d8 m
- speedgrade = CardStatus.UhsSpeedGrade;9 `3 l! b9 y! {/ I+ n1 s0 e
- unitsize = CardStatus.UhsAllocationUnitSize;
" R0 T! L8 J" A) J7 N/ X- ] - if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U)))" ?' ^3 W! D% A- D
- {* _/ n8 a+ Z# r
- hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED;
+ Q ^2 i% T3 A! `4 Y- f2 D8 N5 L - }
~5 u0 O2 p" P; \( b: e" \ - else; D+ t3 w* A8 {7 K1 A
- {
& ~+ y: J# y2 g) ~9 z - if (hsd->SdCard.CardType == CARD_SDHC_SDXC)
4 B& x8 Y I+ Y! d; j! Z6 o$ }, m - {7 o! g# k% d3 q' ~' _
- hsd->SdCard.CardSpeed = CARD_HIGH_SPEED;: S5 [% d! y% O& \3 F
- }
/ j# o( J. C3 c$ g# n - else
" e6 w6 Q( D6 Y, y2 d4 P9 V; X - {
1 l) T7 d0 F( ]( S; D( c - hsd->SdCard.CardSpeed = CARD_NORMAL_SPEED;# ^! B6 k2 f$ g9 Z4 ^
- }
s! r: t) m+ S: M, B - 7 x! d& V! a: I F7 H2 U# ]
- }( J0 o, h3 a5 s, e
- /* 配置总线位宽 */
8 p# E- c# m" ~& n - if(HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK)
n0 u& k9 f& `2 }" W - {
# t) J/ ~6 j( z' \3 ~ - return HAL_ERROR;' q8 g) u1 {+ |( Z, i6 [9 W
- }* s. E' S* v: Y( u9 D2 d
: \% w" N$ O3 @5 d. }9 C: F- /* 验证卡初始化后是否就绪 */- p6 E# R! Y! b/ ~* E. T: h. y
- tickstart = HAL_GetTick();; ]4 H g2 v# W$ w+ {" R: P
- while((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER))" V& G, B0 S8 z8 S, p; k* ~
- {' N' R' Z$ q8 \: E7 K* A
- if((HAL_GetTick()-tickstart) >= SDMMC_DATATIMEOUT)
( z) s" W0 p p& ^- a - {
: e5 Y+ n' l* _' X+ M - hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT;! i4 E/ k V4 a# F" W
- hsd->State= HAL_SD_STATE_READY;5 u6 P- X. N% a8 y: v3 S" s) n
- return HAL_TIMEOUT;
( ~( g- e7 W/ C - }
. O* x3 K1 d! c3 D1 j - }/ ]% g5 c, x: ?+ _( m, _' _
- * v8 n/ ~9 t$ K9 V- F r9 W v4 r
- hsd->ErrorCode = HAL_SD_ERROR_NONE;7 e+ K) e# T; ~) e- d5 a- |1 x* \
" Q; B) I! I# ]# C @- hsd->Context = SD_CONTEXT_NONE;* O& k: \! Y+ {# l% Q: C8 h+ S7 P
& A# [/ `2 M3 T% L l. ]2 T- hsd->State = HAL_SD_STATE_READY;$ t2 n2 ^6 {# L7 g, R8 s- d& g% v
! f8 ]) ?4 W" D$ f# A. h! h- return HAL_OK;
* ~: A5 e# ?8 p1 g3 d3 \% P, h - }
复制代码 0 h8 C( E1 D/ A- y# v
函数描述:( k: L: u! i& R. x* D( g' z
$ e9 c4 E# d! @: d
此函数用于初始化SD卡。7 ~4 \% M, @9 e' T9 v( C
% h& k' L0 \1 t; w. p
函数参数:! [4 L* x8 p0 Q
& Q' w# z' R, I 第1个参数是SD_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数。
) E, \5 [& i: l0 \4 s 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。9 k7 `; u S# L5 F+ B9 m
注意事项:1 k; ~# s: _2 z0 T1 n/ E
$ J4 ?* J" A4 u+ ^8 q: M
函数HAL_SD_MspInit用于初始化SD的底层时钟、引脚等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。+ M/ W5 G' ^$ `! @
如果形参hsd的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量SD_HandleTypeDef SdHandle。 S* O' a+ `. W
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_SD_STATE_RESET = 0x00U。
, @/ J4 E+ _1 e
0 f8 u7 N) i" N; w3 l解决办法有三
9 u1 g- v0 B3 _8 a! y6 M |% ]9 |' p' ~9 t
方法1:用户自己初始化SD和涉及到的GPIO等。- a2 I; `" F: v5 f& {8 O* z
" s! V+ ~' ^) F$ I$ i方法2:定义SD_HandleTypeDef SdHandle为全局变量。
) p0 P: u" }+ W! C% H8 t+ V
. H- I3 B) M( m" \8 k方法3:下面的方法
8 H& Y4 f5 j+ L$ m
7 V1 Y& i# c! J) J( Q- if(HAL_SD_DeInit(&SdHandle) != HAL_OK)) j1 `, h [$ R% f, |
- {0 I4 ~+ q" D/ l. }" L3 r
- Error_Handler();/ e% U4 K: L6 Q8 E3 x
- }
% {' B# w9 `- C - if(HAL_SD_Init(&SdHandle) != HAL_OK)
0 G7 L$ ?- ~& a2 C, F/ G - {! q9 y$ C8 u4 I0 Q9 h9 ?
- Error_Handler();
. `. }1 b- Y7 }8 V s& g; x - }
复制代码 + _% B5 n L3 J
使用举例:' r$ E% D! U. Q/ l$ A8 n6 o+ A
% n) J# B8 y, W6 J& N( q
- SD_HandleTypeDef uSdHandle;
1 ^$ j: K1 C- E' O" g1 i
) A" `4 o, i1 @1 U- uSdHandle.Instance = SDMMC1;
5 _+ x6 m% `- D
% P" @ C# q8 Z& X. W- /* if CLKDIV = 0 then SDMMC Clock frequency = SDMMC Kernel Clock
& P8 R) \1 `1 b! c9 m9 [# I, g - else SDMMC Clock frequency = SDMMC Kernel Clock / [2 * CLKDIV].- ], U' T* {9 V! M4 F
- 200MHz / (2*2) = 50MHz
w3 ~- P4 P& [! Z* B - */
# f: {' Z- \& Q. j - uSdHandle.Init.ClockDiv = 2;
9 b% ~' \) D6 d/ w8 T8 s/ t0 [9 K - uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
9 Y$ b2 m; P2 {1 Q q - uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;& o+ u3 D6 x* o; g
- uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;9 F9 _; ?" q! c& S
- uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_4B;! l6 V+ }: l9 Q. a
- if(HAL_SD_Init(&uSdHandle) != HAL_OK)
6 l( \5 Q4 ]% t: W e% ^' h - {
3 [, i$ E# X% V& _2 J3 n - sd_state = MSD_ERROR;
) |7 M0 i" o& s5 n - }
复制代码 5 j$ E7 [( c3 q" B8 O9 o+ d
87.4.2 函数HAL_SD_DeInit
+ G4 Z4 U3 q2 e7 s e& j) S函数原型:4 W+ z2 N1 y7 K( K, N4 |
% G4 m1 @: S; v; w6 h) Z- HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd)
8 R6 i' d* s @5 q9 ?* {% D- y - {
5 r+ v6 {! ?$ \5 k- ~ U+ o( l - /* 检查SD卡句柄是否有效 */( N A7 C& J5 t8 b( p$ f3 C+ v
- if(hsd == NULL)- U( A6 J8 [# R% K) Z0 V0 I' J
- {8 L2 D4 {* b( y3 g/ [5 d7 R0 @7 e
- return HAL_ERROR;
N% b( h4 X' [1 K" }- _6 J - }
( x8 s) x! s9 {, j* P - 4 K+ V) H) U7 q9 z) k* q
- /* 检查参数 */; m9 j, V. _" l2 R
- assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance));- W; Z2 W5 X, i0 _; u
- # ^4 A8 m# M5 z, F4 x* ^
- hsd->State = HAL_SD_STATE_BUSY;; a7 {! w2 i" }1 ~( q' C* l
8 ~ V) d" s: `" U' k9 E' W7 V- #if (USE_SD_TRANSCEIVER != 0U)- m2 Q) i" O8 X8 g
- /* 关闭1.8V模式 */
( N% j+ P& }; o: s1 Z: m# r9 L5 H( r - if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT)
h5 ]" H5 K1 R. f1 j2 F* z9 b. K! V - {
. Y9 t" N6 j2 D) Y+ g6 j: B" n - #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U)
' \1 z# |3 Q. {3 Q - if(hsd->DriveTransceiver_1_8V_Callback == NULL)9 V. ?) U0 J7 ~9 ?8 c: ^ c
- {
4 E( w0 L% V8 |, d/ z" r: K; F# J* f - hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback;% y1 ^* h, a9 D% S; ]) n
- }
9 B% a: C/ ^% Q - hsd->DriveTransceiver_1_8V_Callback(RESET);- v) k, g5 O: ~- n% p' m5 k6 |; e
- #else
4 ]9 O: E6 a4 d4 ^- @ - HAL_SD_DriveTransceiver_1_8V_Callback(RESET);
7 _1 Y j3 c2 a9 j - #endif + o/ n" A3 g7 S8 Z7 I2 d% x% ^
- }
% Y% x7 q; } @6 f - #endif! I ]# w- L' f
3 H; w& c% w, H+ p% V( i8 i6 A- /* 关闭SD卡电源 */2 `( \5 M) Q6 {2 c7 O8 M* N
- SD_PowerOFF(hsd);3 l( ^$ s0 y A/ S' A% i
% I5 ?& n% v/ P% `2 t7 u- #if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U); W5 z, }' r6 Y) |% b1 x4 ^
- if(hsd->MspDeInitCallback == NULL)
0 o4 ~* _1 P( W) y1 w" O' o$ Q - {
7 m$ n; W. o n! @. U - hsd->MspDeInitCallback = HAL_SD_MspDeInit;
6 p% \* s* W/ o% _ - }/ C9 r4 e+ b6 Z
9 M9 U, p) M, }. i f4 M- /* 复位底层硬件 */
$ z& \& f- Q' A5 E1 r3 ~4 k - hsd->MspDeInitCallback(hsd);
' _. [0 X, x& y' L - #else
) N, v: t c8 W2 U - /* 复位底层硬件 */
) s/ j; ]' y% _. r0 N0 D0 ? - HAL_SD_MspDeInit(hsd);
. Y+ l8 y% v( m$ h. n - #endif
" |, h! |/ o# O3 G1 d
+ j2 N- A3 j1 G6 c9 R$ _8 a$ k- hsd->ErrorCode = HAL_SD_ERROR_NONE;& G! `) u+ q$ ]; P: @; K2 `8 f, p+ B
- hsd->State = HAL_SD_STATE_RESET;) y6 m6 j) r" L' M8 i, E
" P% q4 w+ Z& u, y' r& Y/ A: x: l' z- return HAL_OK;4 z3 q% N& Y9 Y3 n5 O/ |
- }
复制代码
! y$ Y' r$ R% |' |函数描述:
' J5 K1 f/ y% E! f# U9 @" `
6 L$ @- U% ?$ \+ \3 k用于复位SD总线初始化。) k' U6 `5 Q1 G9 v" b
( f# ^6 Y/ [: y9 ~; r I+ V8 s函数参数:6 T" e2 Z$ {" D% G
7 L% V! N5 }3 s5 C! ~! y0 a
第1个参数是SD_HandleTypeDef类型结构体指针变量。
, B% F h, A2 m2 ~# l6 L 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。& b3 w. d0 l- H+ L8 Y- X: n
87.4.3 函数HAL_SD_ReadBlocks4 P! [( R0 [! L2 Q
函数原型:
, A: u! z: _# z4 K4 y
5 X( G. N2 `9 O, T, e0 P: L- HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)% y6 I8 u8 B0 `* T0 U
- {% W3 T6 Y: k) d. @( P
- SDMMC_DataInitTypeDef config;
8 b$ |+ @. Z/ \3 A4 U$ f& A N - uint32_t errorstate;" W( u1 J$ h) f
- uint32_t tickstart = HAL_GetTick();, W8 J. B2 I7 @7 D+ y
- uint32_t count, data, dataremaining;
* ^; v7 Y/ l3 ^# a - uint32_t add = BlockAdd;
: `% P' J; D1 w( }( H2 \+ y" X - uint8_t *tempbuff = pData;
; i4 T6 n3 ?6 d3 P
4 E3 G: A3 @* l6 _ R- if(NULL == pData)4 Q% o' n' ?, L( R
- {5 h3 h" D/ n# n$ Q9 q) M
- hsd->ErrorCode |= HAL_SD_ERROR_PARAM;0 Z, r2 g& L( ~3 e
- return HAL_ERROR;
5 h X2 u* P/ r" E, x7 i" } - }
, Z5 O! _8 `# F6 `1 M, y
% W* l: j% n6 q7 F( Q. ?% n c- v) K- if(hsd->State == HAL_SD_STATE_READY)
. k# A" O" S9 D - {$ n# \7 s3 [. L$ ^' c o3 c
- hsd->ErrorCode = HAL_SD_ERROR_NONE;
3 i0 E4 H& O: I4 f
7 [: n3 c: h: f/ w3 p- if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))% F6 Q0 g( r6 U, S% Q
- {. F( q/ P$ u& _2 k) H
- hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
3 n% `) P/ |# p* z0 V4 a - return HAL_ERROR;
7 H" |- w9 l0 p6 B3 p - }8 ?: D7 P. h. i# L
% B8 f4 @3 D, [: M% ~" e- hsd->State = HAL_SD_STATE_BUSY;3 S$ K# t8 i. b; |) L: O
* j0 | h2 v$ M$ o1 R# |+ j* s- /* 初始化数据控制寄存器 */
& y' b& k/ \. Q8 E - hsd->Instance->DCTRL = 0U;: n. `0 `4 H- G& O/ ?! I
- ! ]6 B; N( k4 C. a* R: F
- if(hsd->SdCard.CardType != CARD_SDHC_SDXC)1 T7 ? M4 a! `, @* A0 O
- {$ V+ z ], A4 k/ e+ \$ n9 A
- add *= 512U;1 d& _5 Y: K/ ^3 w/ P
- }5 ]2 X) F( P2 L/ K* F
' W& b% m3 e- ~" F& |0 h$ Y- /* 配置SD DPSM (Data Path State Machine) */
. T: Z" P5 g) E. I; R& W# r: D - config.DataTimeOut = SDMMC_DATATIMEOUT;* D$ B1 w3 R. y( R; |- k) V$ o
- config.DataLength = NumberOfBlocks * BLOCKSIZE;
' C, I }- E) o3 q7 C( V - config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;3 l, U3 o4 l4 A: r$ Y
- config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC;; g+ C S& L+ ^
- config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;- O0 r9 `/ i p$ W( K7 o
- config.DPSM = SDMMC_DPSM_DISABLE;
& X0 p3 s( e' l# ?+ d6 S4 r& r - (void)SDMMC_ConfigData(hsd->Instance, &config);
# Q5 J3 w$ ^9 y& R - __SDMMC_CMDTRANS_ENABLE( hsd->Instance);' c0 W7 K0 k/ B5 q* S& r
- # n8 {. W+ L6 K# l+ y% |) [% `! H
- /* 查询方式块读取 */
& O) y1 y4 u) N) l - if(NumberOfBlocks > 1U)
' M7 c5 T1 m; J - {
" h1 P! ]. k3 q7 h% c& b - hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;
( i) ?9 @$ H. {/ w
4 D5 h7 p$ m" H# }! o- /* 多块读取命令 */ b/ u; j$ F: }
- errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
- f/ A* z" p+ Y2 D; c8 M/ X - }
* t$ g! ~5 s W - else
; A$ I- `5 u# I9 c' }5 t - {
9 }: _6 h1 ]; V% A2 ? - hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK;# k0 Y% V: V# C4 I( K9 _
- # i2 F; k) I. s" W. N* ~5 y7 i
- /* 单块读取命令 */
1 P- y9 E* y% c: G - errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);( d- a6 Z1 K# u+ g/ a6 s# \
- }4 [4 P& G6 g, c E! X3 j
- if(errorstate != HAL_SD_ERROR_NONE): z) x5 o/ n1 O1 _8 O
- {
1 X6 D$ Q6 c g# O- m7 i6 @ - /* 清除所有静态标志 */
" {# F% }# v. _ - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
/ E9 C3 W( a, F { - hsd->ErrorCode |= errorstate;5 Y% m+ j6 F! Y. o1 k# C6 X
- hsd->State = HAL_SD_STATE_READY;
0 S0 I3 ^. C# x9 G1 {6 D - hsd->Context = SD_CONTEXT_NONE;
~/ `2 W' n- Y! A' [( |, n - return HAL_ERROR;
. e1 P1 Y0 {( J4 r7 {- x: H6 [ - }
/ W& S1 l9 I9 Q$ @" G; P
% o/ n4 c/ D6 J2 ]2 \6 h. ?" p- /* 查询SDMMC标志 */' ]3 N" |$ D' p- @( }
- dataremaining = config.DataLength;
" Z1 q e6 ^3 R4 k I - while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))
9 ^0 ]1 B1 ]5 Z6 m - {
5 e; @- k6 W+ q* n9 r' u - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining >= 32U)), ~8 B* c1 @7 R
- {
3 f! {( X: o* q8 E - /* 从SDMMC Rx FIFO读取数据 */
7 P. @, u: d6 x) i& `- G - for(count = 0U; count < 8U; count++)
9 ]% k9 q9 Y; V! a! ^" g) l( W - {. V5 \# w% C+ u' ~3 e( x
- data = SDMMC_ReadFIFO(hsd->Instance);
! _& G+ y6 m8 z/ G, J4 W/ M! ~5 ^ - *tempbuff = (uint8_t)(data & 0xFFU);2 \3 C0 W/ y+ R
- tempbuff++;. S, Q) \: v. W2 X
- *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);) L. g* J" B( g3 n6 M! f# y9 Q2 S4 r
- tempbuff++;
# L9 h$ n/ \0 c* V8 ]! ]6 U - *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
% e G' C% m" v - tempbuff++;
, t6 S) ^. S9 e& E9 b6 I - *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
+ o1 `. g/ Q1 X6 m$ y& v/ O$ Y - tempbuff++;/ j& F" U" y! x6 Q( P
- }: N& {8 u( k4 }4 k( I9 Q
- dataremaining -= 32U;& J5 f3 A/ \! v0 N, u
- }% y; O8 G: P; q) C6 h5 Y' A
- 5 }7 e. \- d J& @' O; N
- if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U))) ]* E9 E- O/ x8 F7 f" k2 y# c
- {: r Q( M; ?3 ], K
- /* 清除所有静态标志 */
, ]$ N& H J1 ]! C* o - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);/ s% `: T. z7 E: T
- hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
) i" W7 G2 Y' g - hsd->State= HAL_SD_STATE_READY;
1 c' X' o) U5 ?/ y/ d/ y! M9 c1 i - hsd->Context = SD_CONTEXT_NONE;
* b- T$ }) ]# r6 m' Q" j - return HAL_TIMEOUT;
, q# O* s- V* @ - }$ l- P0 h1 d- q* V' A0 z8 L
- }" l' f/ Y, i: V3 @$ |) f
- __SDMMC_CMDTRANS_DISABLE( hsd->Instance);9 X! U1 }7 q! Q6 b8 y
- / L0 T! h) |% Z0 z- k- j* r1 V
- /* 多块读取发送停止传输命令 */
, I7 o6 P0 ]8 x; e - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))% [" S1 K; B% i: O1 E6 i; }5 M4 v
- {" |# J4 O( I; {7 x/ ?
- if(hsd->SdCard.CardType != CARD_SECURED): Y- Q' L1 n( }3 u6 ?* J2 d
- {
7 W: {. v' A: W% K3 J" i - /* 发送停止传输命令 */
. ?1 R2 }5 Y1 M - errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
/ A/ ~' A4 \1 a+ m' D5 Y0 {# p, r - if(errorstate != HAL_SD_ERROR_NONE)' N8 w; S0 T* i
- {: c2 `: k2 E" ~) T% L }
- /* 清除所有静态标志 */
% D# L8 p1 J( G" O - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);: C4 m8 v! P& p# n# q
- hsd->ErrorCode |= errorstate;7 j/ c, `4 S/ ~
- hsd->State = HAL_SD_STATE_READY;( x) V4 V* ~% R0 s. H5 K* B$ g: _
- hsd->Context = SD_CONTEXT_NONE;
4 D$ g. M: x6 Q; J$ x - return HAL_ERROR;. g( P* _5 [$ f9 h0 q
- }: s+ h7 j9 a0 P# t& _
- }6 R4 r" Z/ e! z; @- N
- }
+ t: J1 Q$ B1 q! W7 D" R
& e* X- T- J2 s* w5 _1 d- /* 获取错误状态 */$ r1 a# C h6 n5 k3 n4 f4 O3 w( l
- if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))
# L% w( q6 i+ |/ L - {' s% I' c$ [& N8 z3 {& J% K2 n
- /* 清除所有静态标志 */
9 J5 I! A* j0 o' U! Z - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
8 J9 ?$ w$ B: o( ]. ? J - hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
& c% s% A! j: Q' c; s5 e% u" [ - hsd->State = HAL_SD_STATE_READY;
6 H/ o, y8 G7 \7 g - hsd->Context = SD_CONTEXT_NONE;7 c% ?6 _3 v: n; l6 ^
- return HAL_ERROR;! z$ Z; o1 d6 q/ D5 {9 D2 ]9 N
- }2 k m4 e4 z9 X4 B
- else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))
7 [! F. u* Q) M0 X8 X8 L* F - {, B7 r9 D0 P2 [. m/ q, E
- /* 清除所有静态标志 */
) H X' Y: o/ z1 v8 a - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
5 ]- c, ]2 s4 S - hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
0 D+ r. g: G9 v( h# T - hsd->State = HAL_SD_STATE_READY;
7 X4 e' d- s0 J) _( ? - hsd->Context = SD_CONTEXT_NONE;
( A0 ]3 }" w. n - return HAL_ERROR;
# g' y/ Q" Q+ R+ Z. |+ V0 U - }0 N4 c8 t% C( d; e
- else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)). W1 g$ D8 }- X& K
- {
8 s- s7 w4 R: v# a - /* 清除所有静态标志 */
7 e$ N# W! t: D) Q7 S- F1 J - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
: ]: D8 c' \* j; D3 u3 C7 a - hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;* v5 N9 S" A6 J
- hsd->State = HAL_SD_STATE_READY;
M% Z% r# c' t: A9 O, }: [/ P$ a - hsd->Context = SD_CONTEXT_NONE;% B; @2 W" K8 w, n% D) U1 d
- return HAL_ERROR;, W! e" R$ {/ N6 D; e2 \" B/ M. A) P
- }
( y& f4 v- m$ y( Q% O, B9 q - else2 A1 o. J }0 Z6 {% U
- {9 r, m5 J T5 f- ?- M
- /* 什么都不做 */
; |$ a' t3 [5 Y7 T3 }0 q7 Q - }% B) \) w" E* \& ]# A0 |& L4 J. a
0 n' f+ U. C7 k+ L4 q' G" Z1 p- /* 清除所有静态标志 */) q& e# d+ `* u& T/ s9 E0 n8 I6 h( W
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
- g1 _( t, u2 ?) M( g. O* J2 k
1 W4 }% e4 A9 I8 b1 ]4 x: l- hsd->State = HAL_SD_STATE_READY;$ {2 U4 Q# X1 Z7 ~: H: }+ C3 M; s
- ! g0 p0 M8 u# j/ ]$ N" y
- return HAL_OK;8 O8 U2 |7 ^4 D. V
- }
. o3 K- ?# s/ N6 Y. f4 _; } - else
! z* X N' ~9 g# d; z% A - {
& O! }" T5 U- ~$ N - hsd->ErrorCode |= HAL_SD_ERROR_BUSY;, l" w( c) L! k3 }) s
- return HAL_ERROR;
" S; f; T$ _0 | - }8 @) q' T: R- C: q3 P7 W; `
- }
复制代码
& o( @: s# s$ V* }5 g) T0 A函数描述:
( }# ~+ Y+ U7 \: g) P" w" Y: x3 K0 [ j7 ^
此函数主要用于SD卡数据读取。* y% G- z% o4 u! h1 r9 X2 m
5 H Q8 _) b5 M U函数参数:
2 b* _* I8 J0 Q
* \2 ^& }& d. f# p9 t 第1个参数是SD_HandleTypeDef类型结构体指针变量。$ V5 L3 i1 D0 z' |" p4 Z9 P
第2个参数是接收数据的缓冲地址。" v$ U, m% c, S# L4 g
第3个参数是要读取的扇区地址,即从第几个扇区开始读取(512字节为一个扇区)。 x# r, @, f4 k+ p! o) i7 E
第4个参数是读取的扇区数。, R4 d: n* S) T
第5个参数是传输过程的溢出时间,单位ms。! o! f6 S X w% v
返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
7 |. a1 G. [- H: X使用举例:
J' z9 Y( ]- G
( \4 O; `3 |9 ^9 Q. q( m- /**
2 [% Z) x: W3 N1 h& M - * @brief Reads block(s) from a specified address in an SD card, in polling mode.
0 m: T& e8 ^4 k( y( `$ k. k - * @param pData: Pointer to the buffer that will contain the data to transmit
9 d6 d) f6 j. f! c# C& e/ f - * @param ReadAddr: Address from where data is to be read. E0 Z0 q: ]# L' ^6 d2 ?- C" p% m
- * @param NumOfBlocks: Number of SD blocks to read/ f3 K5 I: l% y/ e* \
- * @param Timeout: Timeout for read operation: K* @6 V% B9 X$ C- s0 l$ s) q
- * @retval SD status
3 `& u% d( O* z% N( [4 D* J M - */) W; P3 K5 V' T3 I( K
- uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout)
* K! i `4 H3 f7 D2 E# L/ w - {
6 S* s+ x; s8 g0 N+ o1 n
, c; @/ U4 F! S+ ^; @ ]- if( HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) == HAL_OK)2 Y% K; |& L; o
- {2 R [+ \) N ~1 _- ]# C
- return MSD_OK;1 C: J4 ?/ b g3 d' u* \7 r
- }- p" T& X, ~: B! \
- else, \. R/ E7 Q# y5 q
- {
2 l7 m. O' D- v! b/ O8 Q - return MSD_ERROR;
* g% l! @. W- N6 P - } a$ S7 k: j( o: {: I% x* v/ P5 e
- 2 u& c z; u2 I1 g4 Q) k+ ]8 j" s5 W% e
- }
复制代码 ( P4 o* F9 [: e' X6 K6 M! M
87.4.4 函数HAL_SD_WriteBlocks8 \: h# B, s2 \4 }
函数原型:
# h! y% s% \. ~! N8 X S' ]% u: J/ f8 k
- HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
3 o: }$ F5 |- L- R% D - {3 u; ]3 V) G3 v- x) |5 M5 B/ q
- SDMMC_DataInitTypeDef config;3 I6 H5 I4 z6 K6 _6 k
- uint32_t errorstate;
) z0 f6 m s% N+ n - uint32_t tickstart = HAL_GetTick();( Y/ k% u2 [) [8 h) U! M
- uint32_t count, data, dataremaining;6 G2 `8 q3 A/ Z# ~/ M
- uint32_t add = BlockAdd;
9 I) j# z1 |& D- E) i - uint8_t *tempbuff = pData;+ ]. R. m+ M( O
7 c, x ?+ X, T# h1 q( j2 E- if(NULL == pData)
. [# q% `) |0 ~ B" a - {2 r+ [( ]# F$ k4 H. V
- hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
, H- e& b# f n! r8 {3 D' B& | - return HAL_ERROR;
* e% j( R( E1 r. q - }0 B$ K9 Z& k( W! b% l. f v
- 6 \" q7 F/ k1 ?* b
- if(hsd->State == HAL_SD_STATE_READY)2 G8 Z b0 {( W
- {
4 s- m* P% F% W+ U& ^$ Y& V+ [, Z - hsd->ErrorCode = HAL_SD_ERROR_NONE;
! Y; }1 u# l' I( V5 A0 E0 E - & o" P7 O5 W3 e& M
- if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))1 w. X6 U* E* `, X
- {3 a7 S* B* |! E: s7 f
- hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;; z+ W. v" c3 J |" q5 Z
- return HAL_ERROR;
" A% n9 b' u2 Q1 Z" t - }
. Y2 ], C: e, R4 w6 F. t1 z - ; I7 X* b/ }0 O1 Z0 X9 i8 _
- hsd->State = HAL_SD_STATE_BUSY;
$ k" Y1 L( N0 b) N
$ E5 C) Z0 `7 }' f- /* 初始化数据控制寄存器 */; p9 g0 l/ D' Z2 h2 o: Q& [+ |
- hsd->Instance->DCTRL = 0U;% Y) Z) G* q! f7 r# _
- 8 P7 i8 }9 M" \6 U! v
- if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
* O+ N7 [ T" m - {% R+ M# s3 A( \! n- z: d& C7 x
- add *= 512U;
K/ {: K% v' a; Y8 z! r - }: t7 a6 V* V/ i" ^8 c. C) d. F
+ P$ e9 e( N5 h0 D z, x0 N8 F/ @6 o9 _- /* 配置SD DPSM */$ H+ b+ F+ I& a" s
- config.DataTimeOut = SDMMC_DATATIMEOUT;( y0 D* H5 s: o& S( @! R
- config.DataLength = NumberOfBlocks * BLOCKSIZE;: D8 i# L8 Z- v( W2 g* Q
- config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;; H" f9 S$ W, d
- config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;* }$ G D2 D: w# p; b
- config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;$ o/ f$ @/ O- T
- config.DPSM = SDMMC_DPSM_DISABLE;; Z: h6 U9 O7 ~) Y
- (void)SDMMC_ConfigData(hsd->Instance, &config);; F& X5 z0 C4 _. _+ D
- __SDMMC_CMDTRANS_ENABLE( hsd->Instance);/ c2 ^2 K' {! B' @
- * h, N' `6 v- Q3 {
- /* 查询方式块写操作 */4 z: y( F) |# y5 v+ U
- if(NumberOfBlocks > 1U)0 V1 Z7 v; I& s- m& Y5 N. M) I
- {4 v8 f$ K2 X* r& ~9 X9 [
- hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK;/ ], B% d. ~* N; }$ f, p& o- G% R6 |
- 2 h3 B: U+ _1 v, b
- /* 写多块命令 */' j0 s& O1 I9 `( d# } V- b3 R
- errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);5 L0 \) E$ y9 s0 U1 |( J
- }
- [1 j2 g. T$ _1 O2 j3 \( d - else7 E% `/ N8 z: b1 s* M
- {
0 j. U3 N7 V! l6 I4 V5 H - hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK;
. [0 C6 @8 i+ D* w& p
$ d% U) d5 ?# m7 B- y1 k( a- /* 写单块命令 */, h J( O, `" c: \' |4 Z3 L7 H% S
- errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
" N- p2 l6 S! l' g; E+ |5 W - }3 \* |+ m# X4 p- r" W
- if(errorstate != HAL_SD_ERROR_NONE)
+ }( e# z% f. N9 x6 ` - {
& G; l) P) ~+ o - /* 清除所有静态命令 */
! x0 h5 R/ e M* k! ]7 V' g - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
5 Q- F: E* U) H' z0 x$ G+ B7 g - hsd->ErrorCode |= errorstate;
& Z# e. p7 G4 M3 }1 Q$ l - hsd->State = HAL_SD_STATE_READY;
- i( ~& E$ K8 ]0 L0 a3 h' ~. @ - hsd->Context = SD_CONTEXT_NONE;
" _9 `. I& _0 Y' K: i7 T - return HAL_ERROR;
2 N% @3 Q4 r0 \5 ?2 ^! D - }) V% b: j! C$ l5 A3 w0 [& Z+ S
- + ~5 p3 M+ \; s9 |/ ?1 b6 }5 R
- /* 查询方式块写操作 */+ D0 ?$ ~' h) B9 ]6 u
- dataremaining = config.DataLength;
4 ^+ g- ~+ b3 |0 M1 \0 N* O7 p( x - while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))
5 E1 ~4 H& v" o. {# ?' S3 f% y) W4 M6 a - {- [% X( ~: O! @2 D: p9 f
- if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining >= 32U))
6 b7 }. J, ^$ B5 l+ g6 q& F - {5 ~5 N! A" Z- C; Y4 ?0 u/ [3 \
- /* 写数据到SDMMC Tx FIFO */: d/ C0 s- S( w4 T
- for(count = 0U; count < 8U; count++)
. Y `* Y! J: D3 S: q9 G8 R - {) j" l4 c) A* v1 a
- data = (uint32_t)(*tempbuff);
+ m4 ?( y' O8 T - tempbuff++;0 n0 j; c1 R8 M/ p- S/ L
- data |= ((uint32_t)(*tempbuff) << 8U);, ]2 [. O/ [2 |/ E* a
- tempbuff++;, B2 e5 N+ E" g/ y/ |
- data |= ((uint32_t)(*tempbuff) << 16U);
: J! H2 Y' U9 t& M( m - tempbuff++;/ g1 z) f& ]( x3 \6 a9 o
- data |= ((uint32_t)(*tempbuff) << 24U);8 z- t6 a% E8 z0 N+ @, H
- tempbuff++;
: G/ H* b7 W B4 i - (void)SDMMC_WriteFIFO(hsd->Instance, &data);) m( y9 _8 V# C. @! P( C
- }! U. q/ f v' A8 j" r$ |8 T
- dataremaining -= 32U;( r [7 _3 }! H& {
- }
3 l* r) K, a6 P# n - 9 h- m/ M7 D* Z1 t, J4 O
- if(((HAL_GetTick()-tickstart) >= Timeout) || (Timeout == 0U)): t7 R" ^3 z" J
- {# f# X& B6 ~; R* H& Q7 e
- /* 清除所有静态标志 */
( ~3 @( `9 z! ~2 j - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
; `% i' O$ q1 W# Z7 A/ K5 `3 [: x$ q - hsd->ErrorCode |= errorstate;8 {! Z b- U9 f4 i; a
- hsd->State = HAL_SD_STATE_READY; H3 B$ L3 g, r; I
- hsd->Context = SD_CONTEXT_NONE;- S6 s+ P+ z1 j/ E
- return HAL_TIMEOUT;( R, Z! m& f/ d; X
- }
2 }: q. B- y& N) t+ } - }
: b' P0 F1 ?' }: H% a - __SDMMC_CMDTRANS_DISABLE( hsd->Instance);1 |1 z; n5 q3 R R( S" P# f
- U: D5 [* B5 [; ?- /* 多块写操作,发送停止传输命令 */
8 m8 ^6 ~* W: h0 B. [1 ~+ a - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U))7 O9 [/ e4 n! d3 W; k
- {. `! v: s( R8 o2 i
- if(hsd->SdCard.CardType != CARD_SECURED): F( [' p; x7 i+ @8 |4 t
- {
4 ~& _" h7 S+ Y - /* 发送停止传输命令 */- x, x9 J3 J2 i
- errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
2 d6 a* m) y G. Q- J - if(errorstate != HAL_SD_ERROR_NONE)
: V0 _2 [3 j! v( H) o - {
8 o ~5 P( w* G: z/ j - /* 清除所有静态传输标志 */
5 N4 z! Q/ ^$ k8 _! r- [: Q - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);9 a0 m. @, B6 N R! x' I
- hsd->ErrorCode |= errorstate;
( S6 p% Z* l# J, A3 c: I - hsd->State = HAL_SD_STATE_READY;
; Z7 a: p2 K+ e4 M1 X# |( i# r - hsd->Context = SD_CONTEXT_NONE;& b/ W* s4 m# w
- return HAL_ERROR;2 U" n+ D M0 }: ~
- }4 @* h8 e# y$ Q
- }% p- V z& k" D9 w' T8 S
- }
3 ?7 v/ s0 @% y) |
& O( M3 O k- ~% {+ T O# c6 q- /* Get error state */
1 C6 b4 V2 y( ^% b" ? - if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))6 P+ y8 D# `- F/ J5 K
- {- y [' ^$ u! }- n9 }5 t8 V3 F- Y
- /* 清除所有静态传输标志 */
S# Z: y( R2 ^$ ~) u - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);( v5 O! l4 q! ]. ~/ y U; T
- hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
- _5 E. M* t e# R+ }, ` - hsd->State = HAL_SD_STATE_READY;
5 j {4 d9 H; t4 ~1 N U$ K0 X1 ~ - hsd->Context = SD_CONTEXT_NONE;- q3 v- R. T5 }4 r3 ]1 g5 x6 b
- return HAL_ERROR;6 g7 \2 R+ V0 G2 \0 O
- }
" M5 s& i7 h. c. j J' X& U - else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))0 P' n x' K$ j0 x$ h+ {
- {& ?8 f# f- n: K, ~! G
- /* 清除所有静态传输标志 */
. Y7 P2 M5 |1 U - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
$ Q* `4 Z. h' S+ V5 ~! ~ - hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
0 M* f6 J, U% L. u6 C' n - hsd->State = HAL_SD_STATE_READY;
$ |0 h7 O) a1 }, x" W6 |( V% C - hsd->Context = SD_CONTEXT_NONE;
; E3 L6 U* x' w" F$ Y9 d - return HAL_ERROR; X E7 T( W% k+ S
- }
; C. f! a' l p1 I, v - else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR))
' Q0 P" B. Q2 ^5 r! C! I - {
! w# L( @+ l% T5 O9 Y - /* 清除所有静态传输标志 */
. d) M# T& K8 _ m" d1 t% m - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
; _: F2 R$ |; A7 Q - hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;
. B# R6 |4 K9 G- W3 |3 d - hsd->State = HAL_SD_STATE_READY;. Q N8 v$ A9 u! d' n m
- hsd->Context = SD_CONTEXT_NONE;
! Q/ c. v% \0 k - return HAL_ERROR;4 E" O& g+ J( _. a/ K& {- x$ H
- }
3 f3 }' S. X( o$ @% _& q - else/ n! \' e) j8 W$ }) \3 g+ {
- {
4 D8 T7 {; m/ v& H2 Z- z: I L4 k3 ] - /* 什么都不做 */
' K0 F- p4 ?: K - }+ N0 q$ Y6 A& ]' `9 a* ^
- ) g7 L% [) X7 d+ p7 B8 g
- /* 清除所有静态传输标志 */! |% s7 z" P; A' a
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
1 f0 k4 B$ i- U* S
: H( ~, R$ J: v' _' n' V- hsd->State = HAL_SD_STATE_READY;
: J$ y( Q8 \7 e- X! I( d' ] - 4 T% d/ Z, P8 t( q5 t
- return HAL_OK;1 M- X8 ?4 o- K" P4 q$ v2 O
- }
7 t1 j1 Y1 Q9 J6 F- R5 w - else
; O$ K$ Z- ^: H - {
3 Q N$ q! _# D/ C& |. \( j - hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
9 N4 Q" Z" _; S% _9 x6 v7 o! t - return HAL_ERROR;" G8 \- b9 Q/ Q$ N* f
- }0 d1 l% E c! R
- }
复制代码 6 r8 r; u2 `2 Z- h2 B* q$ o
函数描述:) T, R h4 m6 b0 G, e$ n- R+ u( p: m
( }8 I8 L, |% `( V; r( ^& T9 k4 F此函数主要用于向SD卡写入数据。' Q3 I$ j; x+ y
7 A* L+ _& J" | k" c函数参数:
2 x; H( H/ _ S( G# \% Q9 r! U1 e3 ?* T' d; k) ?8 l/ o
第1个参数是SD_HandleTypeDef类型结构体指针变量。
" {7 R( i2 f3 k8 k' |% w) U 第2个参数是要写入到SD卡的数据缓冲地址。
# v& p! k: K+ b 第3个参数是要写入的扇区地址,即从第几个扇区开始写入(512字节为一个扇区)。6 M: h% Z: o3 Z' c7 X
第4个参数是读取的扇区数。
/ {- Q8 w" ]2 u/ U* Q- ]$ Y& t. l 第5个参数是传输过程的溢出时间,单位ms。
3 Q( ], u: Z, \' O! d6 u+ ^, c 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。% a1 S; M4 b& D/ F
使用举例:
8 U( T/ f' x* i4 ^2 f
% t/ l& n* O: @% _- /**
) U! \( a, t+ [9 J/ a4 z7 u - * @brief Writes block(s) to a specified address in an SD card, in polling mode.
" c1 L: ]: V7 S4 x: b0 w5 v( M - * @param pData: Pointer to the buffer that will contain the data to transmit' F# [* z. F, D% h
- * @param WriteAddr: Address from where data is to be written
6 L9 I- c0 A f3 y/ _, L - * @param NumOfBlocks: Number of SD blocks to write. ~* O+ u3 k, E3 d/ c
- * @param Timeout: Timeout for write operation3 S% V, v& w3 V5 U
- * @retval SD status. r$ L% d# V* p, j
- */ P) [+ D8 c8 I7 f3 c1 r
- uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout)
% ~ y3 m1 \4 t+ U& ]; R - {
" t' ^; F8 w( ~ - 7 ^. q% B; S8 X6 s# ^+ R
- if( HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) == HAL_OK)
, _' Q x4 }/ _7 d% L$ U* p7 D - {3 I y. O. \$ f) Y. O' p/ F
- return MSD_OK;+ Z- ?; j0 _# T0 F$ e. n1 }4 o
- }
; C! l( y9 T# {: N t6 L( B - else
6 l8 L4 k) \" P4 U/ p M! m - {! E. q) d6 P8 M2 @ @$ [
- return MSD_ERROR;( f. {+ F; y! g3 [% a1 G( @
- }& Y) d+ y2 ]9 T" I* y W: S; }' u+ o
- }
复制代码
4 T8 l1 T: o1 `' r9 h0 z: U1 X$ z87.4.5 函数HAL_SD_ReadBlocks_DMA
) U0 Y, U& v) G; u- ~函数原型:
8 \; J) ?" J3 i6 Z
/ G9 P6 h$ E2 Y$ |8 a; }( d) O1 @' {- HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
7 L: ?. B: p/ h) [ - {0 P3 A) ^3 V, Z8 p
- SDMMC_DataInitTypeDef config;3 b% r: g2 `3 r! Z
- uint32_t errorstate;0 y B, K! e, Y0 k; C
- uint32_t add = BlockAdd;. A* p0 K* z& Y5 E: B8 R
- ) n' H( o/ y2 ~9 k8 W4 m
- if(NULL == pData)
, }1 R. Y' B$ g7 { - {
c9 [0 C8 Q" @ L. q2 u1 m - hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
# b/ D! s1 |4 g: u - return HAL_ERROR;
) m1 B- v& Y/ X, E# @ - }
% M. _4 @- _" l0 b
% Z3 u" G, Y8 T5 ]. n7 q- if(hsd->State == HAL_SD_STATE_READY)
# W- \) H' T/ P% \, Y - {$ b( k3 u4 a y
- hsd->ErrorCode = HAL_SD_ERROR_NONE;
! ]% ]4 h* F2 g5 }6 _3 K
+ B7 i+ j" [3 C# n" x% o2 {' m- if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
- A- ]6 D7 d: ]3 X" ` - {
( P, @9 U/ P6 \, n - hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
2 P7 x' @/ @8 P - return HAL_ERROR; J- b8 N0 {* J/ d5 O1 K) L
- }
# X5 r. ~, ?5 I, `- M& u - 0 G. e# B! ]/ K, a. O; _' J
- hsd->State = HAL_SD_STATE_BUSY;
" J( r/ ]6 q5 Z& Z' a - ) z# H! }" \1 S; f5 F
- /* 初始化数据控制寄存器 */
1 P' S8 p+ `9 Y1 }( h+ E; M - hsd->Instance->DCTRL = 0U;
0 X3 Z3 q, N4 v! k - . F3 V7 n" [* W8 o* p" h
- hsd->pRxBuffPtr = pData;4 u" L' A0 v2 Q4 p- b/ H: b
- hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks;
* \8 P# a3 y4 ]( q3 `
- x/ o! @, m" a$ ^* T) d- if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
! u3 k* Y, I) s0 f3 d - {
. i* I, ~7 O& s2 ]- Q$ O - add *= 512U;5 A0 {6 j* @; F
- }
5 t( x ?8 ^" ~4 A$ F F0 B
+ o! H0 s3 t- r( s- /* 配置SD DPSM (Data Path State Machine) */
$ P; t* t+ A2 D% S. Z; g# @ w - config.DataTimeOut = SDMMC_DATATIMEOUT;; c/ J5 Y$ i7 d& y& N: s c; c
- config.DataLength = BLOCKSIZE * NumberOfBlocks;
4 [- @' N5 `, M% k) @1 W% a - config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;$ x+ x0 D; X# j, g1 g0 }
- config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC;
. v# h' T1 o& ` N8 {* ^& d - config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;2 @* R( K' n! B) m0 E/ ?
- config.DPSM = SDMMC_DPSM_DISABLE;
1 T8 ^/ w/ d! \ - (void)SDMMC_ConfigData(hsd->Instance, &config);) p9 w3 h# b7 X! z, N1 D
- . V0 H* c% @9 q0 t( W0 N
- __SDMMC_CMDTRANS_ENABLE( hsd->Instance);
. } z0 j: j/ j# d& H; c - hsd->Instance->IDMABASE0 = (uint32_t) pData ;) b$ r5 d/ Q0 R8 W
- hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_SINGLE_BUFF;
; m/ t& G8 U7 i8 O* x - ) w- U4 e/ ]( E. r
- /* DMA方式读取多个块 */' @6 f# d6 U ^5 Q
- if(NumberOfBlocks > 1U)' t; }' L1 T: [: o y
- {
/ T% ^- Q) j# E9 |0 K2 s - hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA);
7 X0 l; m" ~ P1 d
# C) |8 L! Y ?% x1 V! g6 S% G- /* DMA方式读取多块命令 */6 o9 y& ~: C. `- `% S6 C1 a" A6 Q
- errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add);
m5 p/ ^2 ?6 D. d. p( w3 l6 O - }3 |) `6 P+ K8 @
- else; v6 L& j! [6 Z w5 Q# L" A
- {
' d- b3 Q: p2 r1 B" O8 d - hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA);
6 Y# u7 `" l9 v! M6 i7 t - $ S' {6 h0 R! v; F0 n. ]) D8 M8 W
- /* 读取单块命令 */) Z& z2 f; H/ q' [, R' f, B
- errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add);
5 `- n5 E9 p3 u" ~ - }9 Y; F P0 W3 L" G
- if(errorstate != HAL_SD_ERROR_NONE)
: O6 |! [6 m. r# d1 v - {' @# Z% X6 d5 h7 `2 U' j. ?4 K
- /* 清除所有静态标志 */4 v, F5 F7 M3 R- s+ x1 S6 R; e
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
, N# [# c8 ^+ x2 l; y - hsd->ErrorCode |= errorstate;5 p, _ x$ y7 Q' ~! Q8 G- p& ?
- hsd->State = HAL_SD_STATE_READY;
7 c/ Q! o8 `) @- m - hsd->Context = SD_CONTEXT_NONE;
W! T. k2 R& d! h, V: S - return HAL_ERROR;
+ L$ B) T2 x! C) Y6 r; t4 l) J+ ~ - }
- T7 n: o) M' M$ f - " j' {3 L: I5 D0 _
- /* 使能传输中断 */: e7 {# D9 I" j0 E$ p: x' a$ A
- __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND));) A- F3 W0 w- I6 N; V
- 3 Z( X: Q( \" K( g$ E
- , E4 X y9 o, K0 G: r
- return HAL_OK;
0 H F v8 B+ {% o - }
$ G8 \2 \6 q3 \7 D - else- B# \5 [. w! M6 A
- {
# r$ F! x7 g* H( V K - return HAL_BUSY;+ R" D D7 ^; V& }% Z
- }( i; _! n2 U9 [- P
- }
复制代码
0 P1 k' t5 X$ i2 q6 _函数描述:
$ a, P2 X0 a- B) [
- ~' Z/ ?" {) B此函数主要用于SD卡数据读取,DMA方式。4 v0 D3 D+ z7 i8 q& S
/ c# ?1 s2 i1 f; x) f
函数参数:" j* r7 H* i# N$ _$ j* r/ ]' [
# J! k3 F, R# s! c; p, Z 第1个参数是SD_HandleTypeDef类型结构体指针变量。
R5 a7 I- \! U9 A% M* \/ } 第2个参数是接收数据的缓冲地址。, ~2 h+ E }+ v+ E
第3个参数是要读取的扇区地址,即从第几个扇区开始读取(512字节为一个扇区)。
" G' I: A% M3 M1 E 第4个参数是读取的扇区数。
, v0 O9 V/ N/ @6 ~# n 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。9 v4 U% U& t$ f! ]1 ?
使用举例:% V5 Q P& S4 ~) j- C, v
1 C2 _5 m" H) k2 F& p- /**
8 T4 w M5 _/ j7 {- c1 C - * @brief Reads block(s) from a specified address in an SD card, in DMA mode.
( z0 D( p" ~; b7 k$ Q! I - * @param pData: Pointer to the buffer that will contain the data to transmit F9 q2 V. g: [6 Q9 }/ S
- * @param ReadAddr: Address from where data is to be read
K4 K9 S, ]4 q% ` - * @param NumOfBlocks: Number of SD blocks to read. l7 \* m8 Y: m. u( T
- * @retval SD status
& K1 O# n/ r1 Y3 z; b1 d1 T - */
- _2 d2 w4 G7 _3 `) P7 p* o - uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
- m5 b! L) L9 \5 g - {1 u" K$ L1 {2 Y5 [! k3 G
, X# ~4 i& `2 f! v# ^- if( HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) == HAL_OK)
9 i9 B1 H2 j" C4 q) n( V - {
5 I$ a0 g% _3 m$ Z3 T5 p4 Y/ Z& ` - return MSD_OK;
8 a5 w# L8 _5 l& t% E+ v - }# } H. t$ G5 w8 ?6 u
- else
! r# R2 b! Y9 S' u& i - {; m& G2 A/ N8 ?9 O2 G5 V
- return MSD_ERROR;
$ `5 z. i* t0 n2 ~- m - }3 I3 D& P1 m7 n4 L2 }
- }
复制代码
4 E5 g2 L' z; p$ J+ i87.4.6 函数HAL_SD_WriteBlocks_DMA
3 A& ]* f6 k6 @; c8 E函数原型:
7 g- N3 c$ @/ h& H0 o) k" a( [+ R4 o7 _9 _
- HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)0 M t) O3 K4 T1 C
- {
s5 F- R7 K; @9 G6 G( w0 b5 B/ A, Z - SDMMC_DataInitTypeDef config;
! a% P0 x; I. m) s% T6 w7 q+ s - uint32_t errorstate;
. T2 g0 U& l# f - uint32_t add = BlockAdd; c$ _- _, k K) H" Q0 _0 C
- ! }" n! N: R/ J+ E9 D- X$ Z
- if(NULL == pData), H* i. H/ Y/ i* |+ Q
- {3 ]1 D @/ p& ^
- hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
n. i' Q9 l* |6 Z, ]9 ?# j - return HAL_ERROR;
1 ~/ }1 ~3 I% G I - }
: W' |/ Q2 T# A g. U$ R - ]0 P: Q/ P! k/ P
- if(hsd->State == HAL_SD_STATE_READY)
# L9 P; `% Q! t3 e2 U; f* p/ c# K - {
" l1 Z1 b- O$ b3 g( r* u - hsd->ErrorCode = HAL_SD_ERROR_NONE;- G+ K( Q9 `2 e0 |- }
- | y( G5 F5 Z$ ~) b- if((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
7 y6 B5 B* q1 A) D- i3 C, i - {
, {# Z& G" C9 T- ]* P - hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;0 {- d( W ?5 S- w% o6 n& q: \" P2 M, H
- return HAL_ERROR;, @& ^! m2 R4 q
- }
( F: c5 T0 k" U" I - / l' j" v3 H# D6 N5 f
- hsd->State = HAL_SD_STATE_BUSY;
+ d0 \+ g) W J: M* X6 @ W - . d L( U! g9 l
- /* 初始化数据控制寄存器 */
0 m3 V; a9 \+ r - hsd->Instance->DCTRL = 0U;
7 \1 l8 [- v' p+ F: u& Y. e - # B( E5 }' |7 z; ]' S
- hsd->pTxBuffPtr = pData;9 x! x2 f( _" M0 I% ~; c/ d; @
- hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks;8 l7 O! k; K- T
- . W! p+ L Z7 J- C+ a% }1 _- y3 p
- if(hsd->SdCard.CardType != CARD_SDHC_SDXC)4 Z/ s2 {( F3 e9 ~* N
- {
; A3 B4 U1 q7 A- o. T7 ^: Q; ^) ^ - add *= 512U;' B+ i0 m5 m$ i/ z) v4 W' _; Q) a
- }
( w3 d& f" K2 x* W
$ z5 N( [6 T! ?4 ]4 r7 Q- /* 配置SD DPSM (Data Path State Machine) */# X9 Q# C I: X- r4 ?, ~4 ?
- config.DataTimeOut = SDMMC_DATATIMEOUT;1 U4 v! R* f8 S" b: y, {
- config.DataLength = BLOCKSIZE * NumberOfBlocks;
& _9 P% B# R/ c2 K' s1 Z$ f% w3 C) J3 H - config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;6 {: b, a- C2 @2 }: a: G
- config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;
9 J+ ]* p- Y+ o. p - config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;6 c4 B$ P. D: V5 Z& M2 M
- config.DPSM = SDMMC_DPSM_DISABLE;) B1 M, Q3 m% X7 c- }* i
- (void)SDMMC_ConfigData(hsd->Instance, &config);
, X8 M; H5 A& T: N+ W; {3 l1 t - 9 h! `2 N7 P. r% Y
- $ A. a! ^# N: N* [6 J
- __SDMMC_CMDTRANS_ENABLE( hsd->Instance);
3 v5 f- o+ v+ C" c @* X/ w
4 q+ t0 X7 M' R6 |5 J# W- hsd->Instance->IDMABASE0 = (uint32_t) pData ;' z8 V1 _$ C$ ~! F0 e
- hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_SINGLE_BUFF;1 X8 f2 I- X' l( v. e
- 9 Y2 ` ] P' E. P) t8 I' F
- /* 查询模式写块 */
1 |. \( l% \& d" g5 v! G - if(NumberOfBlocks > 1U); }5 E2 I8 x |! S5 C- G) [
- {
1 e6 ?* K7 _7 r7 A - hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA);8 I" t# {2 u4 c+ {# X: R% G4 Z
- 8 w+ t. V8 h: g5 Z
- /* 多块写命令 */7 G! s: m: \6 x. |* F. @
- errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add);- {' ] n1 y1 S+ e
- }
! s. ?0 j5 u* ?1 k7 j; ~ c. ` - else; ?. X4 m$ n0 [! y0 s
- {* {3 r9 T- E1 n
- hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA); `+ u5 l1 v, S. f C( I% }, M2 Y- _' q
- : M' G# O7 Z5 C
- /* 单块写命令 */& J6 c1 d P9 S
- errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add);
/ F7 r6 p, P( c! Z - }8 `3 x' P$ E* @4 c3 q7 L6 ~( A
- if(errorstate != HAL_SD_ERROR_NONE)
' o/ x* h4 F6 Y/ j7 M - {) P5 |+ _( z$ k a0 `/ ?, {8 O
- /* 清除静态标志 */
6 v, ?7 I' j, b4 K& V- | - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);0 R# ~. ]% q! |2 a$ Z
- hsd->ErrorCode |= errorstate;
# J4 X( ^8 m6 K3 M2 g$ Q" S( B$ M - hsd->State = HAL_SD_STATE_READY;
) S' X" Q; b* f/ H4 U' l0 V - hsd->Context = SD_CONTEXT_NONE;9 s$ J9 c; b) T) @1 J5 _) v
- return HAL_ERROR;2 K& x! T3 I+ p3 F' [; d
- }
) K& [! i% ?- r4 V5 O; ^ - . J" a! o* o0 u, g
- /* 使能传输中断 Enable */& R: A0 m" i% F& Y# A
- __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));
5 j* D0 ^/ U, a. N* D+ j
! D/ H5 q0 G) n# S8 Z- return HAL_OK;
: | _9 S! O3 w' j7 L. R; b - }
2 W9 f5 H: C2 f5 G - else
. q8 @, C# Q- {% _4 ] - {" S. l- _9 M% F6 [
- return HAL_BUSY;
- D" ?8 o- S7 j9 |4 F9 ~- F# } - }
6 A" g' c( d$ s" ~. Q - }
复制代码 # r( \9 n A. J n* |$ T1 g
函数描述:8 Q9 }6 r) \# |4 p5 _( y9 |
. i6 q6 A* U7 b) }, A
此函数主要用于向SD卡写入数据,DMA方式。
3 H9 s# S' Z. l% N- ]5 V9 d+ }& g4 O* q8 [
函数参数:9 A3 A6 L( x7 j8 s* ]7 W
) C$ B! N5 t2 F6 j, u2 P3 p
第1个参数是SD_HandleTypeDef类型结构体指针变量。" V! B% |6 L) c K6 L- b# I
第2个参数是要写入到SD卡的数据缓冲地址。
* |0 Z; Y( T/ I' V 第3个参数是要写入的扇区地址,即从第几个扇区开始写入(512字节为一个扇区)。
/ m6 t) L0 Q' z9 k7 U 第4个参数是读取的扇区数。
+ ^# S) P( P4 Y" z+ N 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。
e- F! K0 i8 ^- k使用举例:
3 ~) h, Q4 k3 P# R$ m8 H
. g; y- V& W/ _2 U) G/ D- /**# @; ^' q$ \' x# O# ]+ g, E
- * @brief Writes block(s) to a specified address in an SD card, in DMA mode.% C3 R: e( {' r8 q9 v$ E( ]. Y; G7 L7 n
- * @param pData: Pointer to the buffer that will contain the data to transmit
: i/ E7 E' r) m3 W- ` - * @param WriteAddr: Address from where data is to be written
% ^% u/ ^$ ?/ |9 k/ Z: h - * @param NumOfBlocks: Number of SD blocks to write
) @1 H0 ~4 z! d4 Z; g" ~# C; [ - * @retval SD status N3 @3 Z% X$ T9 I4 A( Y
- */7 Y8 y% N, S6 y9 h: B+ c, u# |
- uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
' d8 K1 f# Y6 b - {
6 [2 G8 O/ b- }: R - , `7 ^. \/ n- [% [! e) a# n I: Y
- if( HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) == HAL_OK)
2 w' `5 o ?4 N- W) k4 l+ _ - {
1 e! G* _9 P' P9 Q - return MSD_OK;
/ ?( j+ a7 h* L5 V - }
8 b* u' z4 d$ B+ a - else
% m; r' m2 `6 w! F+ |% e - {, M3 q; D3 W. Y* t
- return MSD_ERROR;
( N& Q+ w& D3 \& B$ @5 t* E - }; |" u; E. A# Q( }$ N/ k4 ]) k
- }
复制代码 % q3 o) F+ H- p! u
87.4.7 函数HAL_SD_Erase
6 K* C5 Y: \2 t函数原型:
8 |' B1 f1 r* U+ X) e( }2 m3 N$ H/ V+ E2 g- X0 ]$ }! r& Z# v
- HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd)2 r8 g& v9 W& }4 k% {* X7 d/ f
- {
" ?- F3 _- U% f. v8 i6 \ - uint32_t errorstate;
) Z% b! I y* g5 W( b$ B6 |6 B - uint32_t start_add = BlockStartAdd;
6 H/ H1 ]" G$ R7 E+ s% P - uint32_t end_add = BlockEndAdd;
2 ^( _9 W$ @. l' Q3 S0 W - * L2 A6 d" d/ |3 u' M
- if(hsd->State == HAL_SD_STATE_READY)" r+ _# [7 H! G
- {
) v, Q* c4 v0 S" i( @' q - hsd->ErrorCode = HAL_SD_ERROR_NONE;! z' E* }$ r9 o1 d+ T) ]5 t3 u2 \% w
" f2 Q1 O- `9 T+ [- if(end_add < start_add)5 G' s+ | I1 _$ A
- {; e: z/ v7 C1 ^# f+ e
- hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
% x; D9 E. i$ Q$ H4 O3 P - return HAL_ERROR;3 p5 d2 @) w+ {3 [1 g0 H
- } y- D6 l) E& M- v! ]& c$ }2 g
3 d# @% l$ p' R+ j9 X# t# @8 H- if(end_add > (hsd->SdCard.LogBlockNbr))* G H: i( M- y6 K' z
- {
0 q6 A Q. K# f3 i6 b: O - hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;" R0 i# ~! E% l7 V
- return HAL_ERROR;: \5 f% W; X7 u/ ~" P
- }/ o* j. _ M8 v6 r# c
7 P- S7 Y. D- t8 n4 n, W4 H- hsd->State = HAL_SD_STATE_BUSY;9 R0 g M% q$ j3 I- x% |& J. k3 u
- + c: _: l: y' n' O
- /* 检测是否支持擦除命令 */! @6 u9 f. P: x# K/ |8 [7 g& M4 n7 m) e9 Q
- if(((hsd->SdCard.Class) & SDMMC_CCCC_ERASE) == 0U)
+ |7 F% U" }6 j - {
, t. r5 u( g! K - /* 清除所有静态标志 */* E( F" M% H3 B s3 M+ l# k9 v
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
! S. V' e6 P. V {. @$ R - hsd->ErrorCode |= HAL_SD_ERROR_REQUEST_NOT_APPLICABLE;& n0 a4 C" Y g$ T
- hsd->State = HAL_SD_STATE_READY;
7 h( J$ _) V4 g* \ - return HAL_ERROR;8 S4 Y( v2 [ e7 d7 l8 j: v
- }
8 c U7 F; d: @$ ] t% j4 o* i% T* m - 4 U. H0 w; X6 ] s i( Z- F0 q3 U" k$ j
- if((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED)
3 l; x: I" D' b- J( P5 }2 _ - {
( Q+ e( _- E- w5 C - /* 清除所有静态标志 */
4 d8 Q1 h! J8 f. N7 [6 O! z - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
0 K& n5 T9 A/ L) i# G: X! f. \ - hsd->ErrorCode |= HAL_SD_ERROR_LOCK_UNLOCK_FAILED;
( [3 {1 T" g- t& A1 @" j: A - hsd->State = HAL_SD_STATE_READY;
3 d' i6 @; E3 T9 G& M7 Y& y& { - return HAL_ERROR;9 `7 Z0 l+ G6 U+ x1 ?' L
- }, I# p! n) J/ b3 z2 Y1 d" [( w
/ T8 @: ]# e( x+ q2 g$ q0 @, m( }- /* 对于高容量卡,获取起始块和结束块 */% |2 z' K$ q- W {8 M% k4 ~# [
- if(hsd->SdCard.CardType != CARD_SDHC_SDXC)! T& [/ C2 U. [9 X2 W9 E
- {
% ] u- c. ]# U+ P - start_add *= 512U;9 v9 C. E' L! o0 j U, E
- end_add *= 512U;
( ^* K& t$ d: b: C7 } - }5 G- [2 T! d* S9 q
- 5 x. A& L3 U' H) w
- /* 根据sd-card spec 1.0 ERASE_GROUP_START (CMD32) 和 erase_group_end(CMD33) */
9 k V5 i- M6 S- j: E - if(hsd->SdCard.CardType != CARD_SECURED)
! N. k/ N4 y8 m1 l1 ] - { R0 Q! h* q' ? \& m( |
- /* 发送CMD32 SD_ERASE_GRP_START命令带地址参数 */ f8 I5 Y' o% j, n
- errorstate = SDMMC_CmdSDEraseStartAdd(hsd->Instance, start_add);$ \! r& I- S2 P8 h6 n6 F# H
- if(errorstate != HAL_SD_ERROR_NONE)+ K2 I% e9 C2 A
- {
5 B0 m' K& e, L$ g9 t, L8 P - /* 清除所有静态标志 */" r* N8 [5 U1 K, e5 _8 l! t
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);6 P- Y% y1 k1 j$ N+ v: H2 ]
- hsd->ErrorCode |= errorstate;5 h/ f, U7 I0 `+ R3 W7 t# p
- hsd->State = HAL_SD_STATE_READY;
9 } f+ G7 ^% T- O" {4 F - return HAL_ERROR;
0 T4 M% L0 \3 ^# ]1 U - }
4 P* }- |8 y) I y - ) O' |% y, q! ]8 `2 r/ u8 ^
- /* 发送CMD33 SD_ERASE_GRP_END命令,带地址参数 */1 b4 {& A$ Q2 h. B; z
- errorstate = SDMMC_CmdSDEraseEndAdd(hsd->Instance, end_add);
/ |0 q/ m$ X( K+ S+ t2 S p# Q - if(errorstate != HAL_SD_ERROR_NONE)( T( ~7 m# G2 o. ~& q
- {
' U' K5 d3 N- ~! T- }! r - /* 清除所有静态标志 */: A5 Z, S, Q9 R* T) ~1 T0 j- ^
- __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);5 U2 [2 T+ H1 Z+ {5 ^ V; H+ L
- hsd->ErrorCode |= errorstate;& P2 W0 e" ^) {+ M( p
- hsd->State = HAL_SD_STATE_READY;
; Z) o* B. k% H5 `9 w" M6 G" V - return HAL_ERROR;
& j; ], i8 B1 Z) U - }9 f5 a3 h6 I7 y1 B/ a
- }
; K. F) B2 M, J- F1 } - " X' Z% ^* ]) s2 w3 _, Y
- /* 发送CMD38 ERASE命令 */8 C& _; i: `3 G1 q9 a }" L
- errorstate = SDMMC_CmdErase(hsd->Instance, 0UL);
4 _& J) Q( q" n8 S - if(errorstate != HAL_SD_ERROR_NONE)) H1 v7 q0 F( Z3 d. D- c" `
- {
: b" E# G6 s+ Y; n- P( W0 c - /* 清除所有静态标志 */
/ i' E' A5 g2 d( Q" C: ]0 `" \, | - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
6 [# _" G3 {9 @" C0 z - hsd->ErrorCode |= errorstate;1 u( v% |, m! }. E$ j C! |: X& \/ R; Z
- hsd->State = HAL_SD_STATE_READY;6 G E* @7 O( v7 q2 o; V1 q
- return HAL_ERROR;
% H0 v# {1 @+ t" ?* q% Q; `. } - }- ]$ N+ ]: P( T( [. Q1 J' I+ v
- 1 m! K, j( d/ r5 s; I. P; A4 ^
- hsd->State = HAL_SD_STATE_READY;
$ b# K5 \" [1 @7 L8 X* d9 [2 S - / v6 f) C8 ^) [3 K' `1 I, m
- return HAL_OK;5 i/ w8 C+ ]+ }$ V% D7 v
- }
- }, P5 h( A7 G7 Q - else
1 h# ~( b& e- b9 o; _2 y1 D - {
6 S! \6 H t: f% h) l - return HAL_BUSY;
% n) t7 z# S9 l- C& P2 g# z - }
2 d. }( O7 n; Y. W* X, G - }
复制代码 1 P8 w' J* W& i* e8 J9 [
函数描述:
0 g# h8 Y7 e3 S" d5 o/ I( [' G/ ~" O7 K0 t# V
此函数主要用于SD卡擦除。
3 P5 ]- J/ N+ \
1 V( w- y4 e" @2 E" x3 q函数参数:
7 p( I; W# B$ [; N% ]2 X/ e& P/ Z2 [6 ^/ e# l4 z- Z
第1个参数是SD_HandleTypeDef类型结构体指针变量。) Z1 D$ g: D2 M
第2个参数是擦除的起始扇区地址,地址单位是第几个扇区(512字节为一个扇区)。
% F( ~! v1 R: H! \8 U9 ^2 k 第3个参数是擦除的结束扇区地址,地址单位是第几个扇区(512字节为一个扇区)。
: _5 x& ?' k2 c. V7 d1 C2 @ 返回值,返回HAL_TIMEOUT表示超时,HAL_ERROR表示参数错误,HAL_OK表示发送成功,HAL_BUSY表示忙,正在使用中。+ X6 _3 {+ g# q& o( r: G% Z
使用举例:
$ H, q5 n6 H: D& v: ?6 z
2 Z" _+ c" b3 r# w( Y- /**! Z8 ^; j$ d$ O7 X/ r' e$ G
- * @brief Erases the specified memory area of the given SD card.: [8 T. j9 I: M' Y+ p: Y( l$ E
- * @param StartAddr: Start byte address/ P/ f: B) v7 a+ j) p
- * @param EndAddr: End byte address
9 T5 O5 o3 v/ q0 g: V - * @retval SD status% k M! [# w% N$ p: d) ~
- */
4 |% g2 K I/ ^ c! g - uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr)7 H# k {! b8 |3 w8 R
- {8 I% D+ e0 S0 o( C% d6 K
& w, q/ u- b5 W" T+ M2 \- if( HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) == HAL_OK)) d- b, L" A; J( J+ K
- {
. N: N) ^8 {/ p9 n - return MSD_OK;
7 o; k* l9 [' a: \6 x; P P2 j - }
7 q) U9 [! f* v( B - else% ~8 `; ^. X8 ^+ x6 u
- {
2 F2 S; l+ s+ ^& @/ b/ L& v - return MSD_ERROR;1 K" Z0 i6 B$ n& u8 H( p0 S
- }: |3 c, u: n" @, H, J
- }
复制代码 5 C' U: T% g( O6 U& N
87.5 总结! Z3 y: m0 x/ i' Z2 h+ M4 e
本章节就为大家讲解这么多,更多SDMMC知识可以看STM32H7的参考手册。6 L, j8 m9 ]5 ?7 T! Q! W$ j8 t
9 x1 K( H( q9 N" i
# Q$ V* z; a; F. U |