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