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