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