STM32驱动eMMC读写数据
9 O; `7 _7 ]9 v) Y: c参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014) j( i: p% w) c0 z0 O7 H
驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。) t. F Q1 a" u* V6 `* U
0 E$ l/ m$ B, g: D5 b
初始化代码清单:3 [5 k8 H# Y7 O4 i% c7 Z
6 K% I }2 J; P( k9 m3 `# H- W" Z# U4 K
- HAL_StatusTypeDef SDMMC1_MMC_Init(void): b9 F) R& h( L7 _
- {
' _, U: y8 q: t - hmmc1.Instance = SDMMC1;; }6 ~2 h! V2 l( g* [% ?
- hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;% v2 @. R# w- ^
- hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
4 u- b5 }3 U7 c7 y8 @% M - hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
T7 a# w# {8 U( ?. j" @ - hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
% ?0 s" U7 S: c' t2 h: T' v - hmmc1.Init.ClockDiv = 1;
, D( }! V# m( W+ U3 B - if (HAL_MMC_Init(&hmmc1) != HAL_OK)
( d8 O% o t9 W. J - {
, M T3 I3 P4 E - Error_Handler();0 s5 E2 E& B' N+ n, z$ s
- }
) J7 ]0 \, Y; d; c! g" V- ^$ n - return HAL_OK;& b1 B9 B. J/ j2 ?/ \) ]* a/ o
- }
复制代码 7 S% C2 [4 C" @9 |- A' A
底层驱动代码清单:
7 H; E& X8 w$ M- }4 n! j8 D, m) r: |& D0 b' w. G* c
- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
9 }6 W. f. W. F - {+ b7 p' G; u$ s4 W r- D0 T7 N
- GPIO_InitTypeDef GPIO_InitStruct = {0};
" F) R% s, W5 o1 Z3 |$ j - if(hmmc->Instance==SDMMC1)1 j9 M8 o) p2 }9 h) h6 p8 S+ X
- {
7 h- @. r5 R2 s - /* USER CODE BEGIN SDMMC1_MspInit 0 */: Q, M5 D( r" c
- /* Peripheral clock enable */
1 Q k" v, W+ H. ^- h: T7 @; b - __HAL_RCC_SDMMC1_CLK_ENABLE();! S$ U1 [4 m# T" A
- __HAL_RCC_GPIOC_CLK_ENABLE();1 t, b! }- B$ h& W! U
- __HAL_RCC_GPIOD_CLK_ENABLE();( w9 E8 n& K, {% B
- /**SDMMC1 GPIO Configuration
. b4 }$ W7 ?7 s J) u5 g s - PC8 ------> SDMMC1_D0
+ v [2 {& C8 x2 O0 Q4 h, c/ H6 b - PC9 ------> SDMMC1_D1 1 G7 g( C* G4 \5 w, k
- PC10 ------> SDMMC1_D2
! B+ E& d+ I) x: P - PC11 ------> SDMMC1_D3
) ^7 D; I: ^0 {. N0 g# g - PB8 ------> SDMMC1_D4
. F# T/ E3 j$ j# ~: _ - PB9 ------> SDMMC1_D5
0 l7 i: g, V- W; o* G - PC6 ------> SDMMC1_D6
* B! D7 g3 M: B. m - PC7 ------> SDMMC1_D7
0 P% N, {( S/ l - PC12 ------> SDMMC1_CK+ ]: S9 ]" N+ X3 Y% [
- PD2 ------> SDMMC1_CMD2 [ j. T d8 }
- */7 O1 I! J+ X0 ~. X4 O% ]
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8 + ^0 \2 A( {3 C9 h, f4 w" r3 s
- |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
6 L% j: p/ _! |: e1 m - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
6 J& i- }/ g- l. P2 G - GPIO_InitStruct.Pull = GPIO_NOPULL;
) z0 |( z4 m0 P2 H, r* F r4 x, u - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
# j- ~- Q* ~& Z1 p7 H/ k, m6 v! M - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
( B8 b7 j( B2 W4 p( }/ g0 e! k) q - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
- w1 O& X' ~0 e6 g" f1 L7 e - 4 Y7 K, F6 X( D! i# ^9 I
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
$ t% m' K9 h4 L# f% d N4 o& @ - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
* `) g8 s5 C; y7 T - GPIO_InitStruct.Pull = GPIO_NOPULL;7 l+ q2 x- J- I! R) ]/ z
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;" S, e- O* A% Q" u9 l0 o
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;/ i; w5 q" d( [; h# j0 P; O( [
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
% p, T. y! D% [% l7 m! J - / q7 e; G! m( Y
- GPIO_InitStruct.Pin = GPIO_PIN_2;) [$ W0 K2 H, H7 Q
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
) w" S- L4 w( B0 \ F - GPIO_InitStruct.Pull = GPIO_NOPULL;
9 L+ a2 F, t0 }, I1 Z5 J - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
* `2 q' l9 t: x, X! L - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
7 E! h( L) I8 E6 T% ^0 L4 I3 c& v' c - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);# t* s& n2 x$ F. m
$ f, V; P( x: _ G+ ?- [3 \( X; z- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断 r2 B9 I0 F% ^0 [7 c$ c" P! [: @
- HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断( X' ~8 u8 I. F
- HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);
0 F! v3 m- z; L0 _3 n - }' _# }, p+ K* ~& j
- }
复制代码 ! W$ q, S' {6 P" B- |
在DMA模式下,从MMC卡的指定地址读取数据:5 x5 u2 d) j. @6 n/ b
0 G3 ]0 Q% B M$ |
- /**
7 J$ x# D1 K# u z/ _) E' Z - * @brief 在DMA模式下,从MMC卡的指定地址读取数据
2 o$ z1 J. K; K' S - * @param pData:指向将包含要传输的数据的缓冲区的指针" w+ r' A8 J, |1 s3 g2 A+ u1 U
- * @param ReadAddr:要读取数据的地址
, B! |* K+ j/ i, i - * @param NumOfBlocks:要读取的MMC块数量
8 Q$ k/ [; ^- [ - * @retval eMMC状态
& p3 E5 t6 e) k/ ?# n6 R - */
u4 ]9 {5 {! h' W+ T# F - uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)1 v0 c6 X5 e: O$ Q9 f I, i$ X9 l
- {: x! Q/ n5 F/ r0 ?! I
- HAL_StatusTypeDef Status = HAL_OK;
# g' _ W [7 n+ o3 U( v( @ - / h; a% K3 }1 N J% p/ O: i" Y
- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
. x" ?+ x, E6 D- E6 L; ? - {
5 D& \# K0 A9 v( s l' }. S; d - Status = HAL_ERROR;; g! c F! K3 t1 G, C
- } 0 l l( C0 f- i9 c, t& N
- return Status;
; P2 V" Z7 t* G! M6 V4 P% I1 m' n6 n - }
复制代码 5 w2 U& ~1 e) V S4 S8 V
在DMA模式下,向MMC卡的指定地址写入数据:
7 r0 A; o; M8 l& L4 K
8 p% w4 B7 v, O \7 k% M- /**
0 L4 }, F7 n/ l7 K {% @, f" z$ D - * @brief 在DMA模式下,向MMC卡的指定地址写入数据
: }3 i' i3 I1 f1 }5 U5 a | - * @param pData:指向将包含要传输的数据的缓冲区的指针7 X/ h; Z, o7 h2 [ H
- * @param WriteAddr:要写入数据的地址
; }" j, g) [. B; Q( m - * @param NumOfBlocks:要写的MMC块的数量
9 ]: I# _* F6 O5 ? - * @retval MMC状态3 S( {+ Q a) d: N5 ~
- */& A1 x# s: z9 a8 z2 r% ^" d: c
- uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)9 F- f% G& Q7 g- H' d9 `) n; w. l
- {7 p8 E& G, A/ L' \- J3 ]
- HAL_StatusTypeDef Status = HAL_OK;; q5 e5 ?& j: U# H6 \
- 7 b- g' q! i y4 L# {
- /* Write block(s) in DMA transfer mode */3 A f6 K: O& _0 Q6 ]# t6 M: ]
- if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)$ V; b3 `0 D% ^! m+ f
- {
" ? ?1 I. f: z3 [0 ~) ~ - Status = HAL_ERROR;5 u/ O* M' M+ E/ {3 ?2 P8 R
- }) _. C9 y1 c& X6 ?9 p4 L
- return Status; 0 o% P6 K, q9 l: z; c1 \
- }
复制代码 $ R* S/ ^& s+ k3 e
擦除eMMC卡数据:
& ]% a' V% I3 `; u4 j! D; N) L! k( f7 c
- /**
0 G. V5 u6 V. A. h - * @brief 擦除eMMC卡数据
8 l+ c0 q) Y1 `4 E! F - * @param 无+ S* x( @; [+ T* d. R0 Q
- * @retval 无1 ?" ^8 h5 n* C, \
- */6 D5 |- ` @, `1 B, o8 U9 u& @
- void MMC_EraseTest(void)
/ K# f* G, O8 ^+ R5 ~% X - {
3 q+ o4 W7 @& p - HAL_StatusTypeDef Status = HAL_OK;
$ s" G: O/ Z; Z& \ - HAL_StatusTypeDef EraseStatus = HAL_OK;2 d1 w- z3 s- _: g6 ~4 a# u
- if (Status == HAL_OK)
$ u: @0 f s# G0 s1 U* r - {
" T! C/ \/ S: N* R - Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
. M& ?; n8 w1 {& X% t1 `% k - //等待擦除完成
( H" B3 z2 U. \9 x8 f8 h5 e( l - if(Wait_SDCARD_Ready() != HAL_OK)0 h' l J1 F4 M' y- \3 I4 r1 `
- {! p4 n% O( i% e( i) a# p, J
- EraseStatus = HAL_ERROR;) t' M& W* K# }, Z9 U
- }9 I& Z: n2 {; O" A. r' K
- }& x4 U0 ~' K1 Q# ~3 ~9 |; N! Q
- if(EraseStatus != HAL_OK) v: V+ N+ `+ Q7 J" g
- {
& ` D- D% o# B, t/ N) M+ O1 Y - Error_Handler();
/ m4 f5 Y h# f: b9 v! w L5 |" P - }
+ f! J; u! i3 W4 A8 v - }
复制代码
8 f" N% J3 V- C* c' X* reMMC卡等待擦除完成函数:
4 l; M2 |* B1 X* K K* e: `0 P4 Y7 w" l: c0 B; R
- /**
) y* D9 P, [% y2 i% r - * @brief eMMC卡等待擦除完成函数
, Q9 P! f( N/ }6 @ - * @param 无5 v- ?! \) ]- t X8 T* y- C
- * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败
; L7 d3 l p9 q& u5 W - */; X6 b, D/ `/ j( u. P9 m- n
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
! D& u: W B- q0 Z4 Y) I; I - {6 P, ]8 i/ S9 W& T" Y6 x3 [5 P
- uint32_t loop = MMC_TIMEOUT;
% s5 Y3 X4 M% m( I3 }3 g
9 a" ?3 }' P' ~$ v- /* Wait for the Erasing process is completed */' K3 j/ v9 X3 _: p
- /* Verify that SD card is ready to use after the Erase */- r. O" R; W0 @, P! V
- while(loop > 0)$ X& L' \6 ]" E8 N& S) J
- {! x% G, u' O6 S8 S T/ r% ^; X
- loop--;
; t3 t# z- A* a; \ - if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER) H' C" e/ }4 Y# T. A
- {8 J/ e. E. }/ [: F% Q1 J$ F
- return HAL_OK;
! h. i+ v5 R& k' x. M6 q# h& a - }% C; }" R6 ?) n. _
- }
. o3 r8 u" L$ U$ o! Z4 s, P - return HAL_ERROR;: I- D+ f' J, v5 g+ p
- }
复制代码
" b9 k' X) J, D' c( g最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
4 T( \8 q- i( y* E5 V$ K! E: V& @7 Y7 _3 f/ Q% Z
! t a% B" X. A- d1 e
|