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