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