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