STM32驱动eMMC读写数据
: p6 V' t5 H8 P- w; E参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
& l! { J/ b) k" |6 ]/ t驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
- ~3 S6 P$ k: I8 [
6 t' q' S# H2 R4 W0 z: K初始化代码清单:& p* S( _$ i6 r" s( K
z+ T) f' _3 c ?- HAL_StatusTypeDef SDMMC1_MMC_Init(void)
' S6 z- _0 O1 h* _1 x# l4 ? - {) i/ F4 {$ I: l" z+ X
- hmmc1.Instance = SDMMC1;
$ R/ Y; f$ ? ~% m/ t, X - hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
1 C# w5 e; q6 E+ ]" R) L2 s& C9 T# W - hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
. Z: K4 Z( `' e( Q - hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
! k H8 n4 Z# g) Q - hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
2 }" {4 \% J; ]& v B$ L5 s' _ - hmmc1.Init.ClockDiv = 1;6 [0 m' |2 O: Q% w) ]
- if (HAL_MMC_Init(&hmmc1) != HAL_OK)9 t" l7 }$ H# h5 l) \& ^" u
- {, r7 D9 I4 c3 \5 i8 c
- Error_Handler();4 f4 p! e* f9 a# [0 d
- }% H4 v: Y; ?& `: q
- return HAL_OK;3 O! j- @4 t. k0 F
- }
复制代码
1 d3 A; B9 B3 |5 U; g底层驱动代码清单:
- r* x; B2 c- v, d7 i( {+ l+ y y0 w6 S6 J
- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
$ W% G, H2 R# D7 H+ [ - {
# _! _5 k7 g: k - GPIO_InitTypeDef GPIO_InitStruct = {0};
, j; y( R# i+ t& ]* J7 D, [ - if(hmmc->Instance==SDMMC1)
' X2 D0 P# b' C( F: j - {
! U, Z6 Y* B" m7 b5 ]! v" A) g w9 [ - /* USER CODE BEGIN SDMMC1_MspInit 0 */
- a6 l' O; v& W. _3 _3 d! m8 T( M - /* Peripheral clock enable */
; I) J8 J- G5 T/ \1 p% D - __HAL_RCC_SDMMC1_CLK_ENABLE();
0 ?% x2 J8 ~$ {( `/ m( O - __HAL_RCC_GPIOC_CLK_ENABLE();/ u% X0 T- {/ Q+ r8 H' X0 `2 K
- __HAL_RCC_GPIOD_CLK_ENABLE();: x$ u; y1 c- D& f
- /**SDMMC1 GPIO Configuration
$ x5 T- e7 e' A. l - PC8 ------> SDMMC1_D04 \# Q' W, g- K/ M9 Q, @! [9 \) e( J
- PC9 ------> SDMMC1_D1 ! f" s( a4 I$ n4 f6 }
- PC10 ------> SDMMC1_D20 j; @9 W2 A2 V$ c7 T& G
- PC11 ------> SDMMC1_D3
; J; ^0 b# V% n - PB8 ------> SDMMC1_D4
2 C7 R' l6 O% d: Z& N - PB9 ------> SDMMC1_D58 F: p4 n( C2 x/ G& h8 _+ w' `. ^3 G
- PC6 ------> SDMMC1_D6
1 t! V# e% D( p- _; G* ~ - PC7 ------> SDMMC1_D7* V% V. y+ b9 l! m
- PC12 ------> SDMMC1_CK+ U/ ?' ?5 B% V- a
- PD2 ------> SDMMC1_CMD
9 _& K" c. w$ H/ n3 a% O - */
$ O8 b6 d: }+ u, ~. [; ? - GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8 , d1 F/ k! ^# p
- |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
3 m8 f0 u6 g2 A g* L2 h0 g$ Y - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
) W1 Q5 c9 t- u) s - GPIO_InitStruct.Pull = GPIO_NOPULL;
; I. r, H0 [+ O9 P5 L3 t - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;( E+ y$ s& X) k$ \0 A4 c `9 G
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
0 {7 [% w( w3 q+ F; { - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
K, H1 T W5 s
/ A; p. m% \: e/ A2 n$ i. Q4 w- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;( [& |$ y: F* p% b5 B6 [
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
- Y3 |2 Z' V W4 u1 U; T( ^ - GPIO_InitStruct.Pull = GPIO_NOPULL;
4 ^8 s9 z. v/ @- \ - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
# R, s \6 O6 v& `: w% W - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;7 t" p: l- D3 j4 [* l! \
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
1 R5 a9 A% D2 G4 _ - 1 t! V) m* F! i& b. L; n! r7 p1 K
- GPIO_InitStruct.Pin = GPIO_PIN_2;
" J) c3 s2 w, u. {+ e" O2 ~ - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;1 \# P G+ j5 c R' p* [
- GPIO_InitStruct.Pull = GPIO_NOPULL;; {3 ]+ [. f M3 Z
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;9 K* w9 h4 H [: d, h7 B' o
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;: v& d/ ]0 `1 _1 |) o
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
; {8 [5 R* n0 X" Q) d - 8 ~. V5 F# m& H. X6 V& {/ H
- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
* f) q, r( b/ N, x - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断" G5 N- _6 a% V; v# `. I
- HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);6 T$ F2 w0 u* K1 ^) P
- }, P- l8 c& H9 i5 U6 v# G
- }
复制代码 : ~4 j, A$ x" ]
在DMA模式下,从MMC卡的指定地址读取数据:
2 s6 \/ E: k" x3 [. J
8 p y% r' s: t9 s: @1 [- /**
/ J a" K# a; e2 [/ ]1 t t( Y - * @brief 在DMA模式下,从MMC卡的指定地址读取数据8 `( x% ? x1 O1 F0 l6 @
- * @param pData:指向将包含要传输的数据的缓冲区的指针, ~+ @9 U6 ~6 @4 _
- * @param ReadAddr:要读取数据的地址( q, q& \/ I, ^1 q' V+ V j2 o
- * @param NumOfBlocks:要读取的MMC块数量
' |( B+ L7 T( S, a) @" c1 i; R - * @retval eMMC状态% ^; i [" p# w0 i8 J' r( P
- */ w4 U1 \+ t1 D
- uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)" g) k5 r# t! v4 l
- {9 Z! K6 m1 Z) E) {
- HAL_StatusTypeDef Status = HAL_OK;; y" B% l) E2 G! W1 G4 i* `$ N
/ ? {" m r) E, w }, `- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
_. @" r% W) u ^/ c7 H, G - {/ m& D# }3 p2 |# d& W
- Status = HAL_ERROR;2 }' z, N3 n. ?; d/ B- z M
- }
" b t$ z2 z; d! M - return Status; ' V' d3 c, L; T
- }
复制代码
; d6 e0 Y6 f- d7 p8 d在DMA模式下,向MMC卡的指定地址写入数据:
: u1 [, t4 d! [" i" ^! b
* l8 O' ?; R# ^$ J- /**+ F# Y0 [' o1 v8 [# |5 R
- * @brief 在DMA模式下,向MMC卡的指定地址写入数据
9 }8 t) y9 |- {3 S' O' z - * @param pData:指向将包含要传输的数据的缓冲区的指针
" b6 u" G+ h1 c& C$ I' N& p3 d - * @param WriteAddr:要写入数据的地址- l% m, G! c, ?# N8 ~9 \
- * @param NumOfBlocks:要写的MMC块的数量
# e( v1 E# j% j4 A! `+ H - * @retval MMC状态( i. n) K5 O& ~" x0 r& m: t
- */
$ F1 ]# O* v$ n7 ]" [+ v5 a" j - uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)9 ?; v7 v/ d, M5 z
- {+ y) [. t I7 ?
- HAL_StatusTypeDef Status = HAL_OK;% l" j4 j" u( i; Q! C: N1 V
- 9 e$ E; }' {& t9 O/ J7 }
- /* Write block(s) in DMA transfer mode */2 Y* A; R8 a/ ]/ K
- if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)( l) f4 Y2 D: p3 _
- {- b6 D- E, c6 f5 }0 N
- Status = HAL_ERROR;! w4 ~( F$ c- E4 Z$ H% m
- }
2 ~% V7 S2 N# o: F: H8 \ - return Status;
2 ]5 r! ]" C$ V8 z% u; D4 R/ v - }
复制代码
0 d" H! }1 o" x% d擦除eMMC卡数据:$ c4 L, T! x3 W4 I4 r0 Q/ W" ?
# v [1 x2 K1 z" x& W- /**3 g2 I# a$ U/ G3 V
- * @brief 擦除eMMC卡数据" w$ X+ q& ]% k! u3 f9 v. `+ r
- * @param 无
5 n. w/ n. w. k9 }' O - * @retval 无
! t! E( j( a' m/ s0 Q: d - */
5 ^8 F; v! F$ t9 A# T - void MMC_EraseTest(void)
! u# D% l+ h- b" \- q7 t - {( t$ H1 ?/ B# _* i) M# h3 ]" _
- HAL_StatusTypeDef Status = HAL_OK;( Q( d# |( Y7 K8 U2 {+ g' V
- HAL_StatusTypeDef EraseStatus = HAL_OK;
# Y2 }3 i) D4 W/ O( M5 ^4 g. E1 j - if (Status == HAL_OK)& ?$ s4 v) D& ~% \/ L/ Z
- {
8 W% @4 Q# \0 f; O3 P( n; h - Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
- P# B! y7 B% ` - //等待擦除完成
! b) n/ z7 R( m4 N - if(Wait_SDCARD_Ready() != HAL_OK)
1 S8 y* q4 {) p5 y( [6 b3 ]2 n - { D# t8 a/ F6 e# V! H; |
- EraseStatus = HAL_ERROR;
5 v5 A& s& N4 e% F% E - }8 m7 K# T7 ?. R& l
- }+ U: \ n+ q- E8 V
- if(EraseStatus != HAL_OK)7 I) A0 D+ d# M+ K4 H
- { * ]3 o' Y9 K$ }& ~
- Error_Handler();
4 y4 e) ?& e6 w, l$ {3 g0 E - }7 Z- A- L8 @* U( N4 z/ ]
- }
复制代码
# o7 N; a' J5 Z7 y, W* ]9 feMMC卡等待擦除完成函数:% Y% T4 b4 H& O8 B2 m+ x' {0 ]
3 L& A& Z0 w3 q( R2 G. D- /**
. A4 t2 F a- C: ]& ~& @ - * @brief eMMC卡等待擦除完成函数. b8 F- h$ A" L F' o# e
- * @param 无
% ] _; a1 r% e+ E, e - * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败* q5 U# K# b/ R2 C" L, Q
- */' S1 f1 o; ]/ C9 g( c" C8 B/ d8 p
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
' {) Z+ ?6 p1 L, S2 w } - {$ E0 a( @' F( p- E# o! E3 j2 R1 F
- uint32_t loop = MMC_TIMEOUT;# S% b" Y# t3 `
- 3 E% G- B5 \1 p) t# o
- /* Wait for the Erasing process is completed *// D' n% p" I5 F3 h' O( d/ C, Z
- /* Verify that SD card is ready to use after the Erase */
* p! k# Y) Q& a3 N - while(loop > 0)
! I3 l( P$ _- S& c$ E- Q/ u+ o - {0 c4 H/ ]7 d! o9 n& N/ k1 z
- loop--;& ?( E2 u/ {+ Y! d
- if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER). ], M$ a& }" g
- {3 z2 @$ i0 o: v* ?- @4 U+ b! p) \
- return HAL_OK;
0 Y- |1 E, ^+ z! J& i9 L: h4 u3 k - }* T! o& C* ^9 `* ?# z' N: M
- }' `3 D3 n0 E7 h. R8 w) A% S. y) T
- return HAL_ERROR;
! q% b+ Z0 s+ A3 n5 j! [ - }
复制代码
% y9 V* X f$ P* u7 u5 O最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
9 p) f1 A2 k! G7 |$ b
- n* y/ Q7 }4 o9 r& I
+ B N* a3 g8 o& ~$ v |