STM32驱动eMMC读写数据% q/ i. r# W2 c4 r+ ~
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
# v: z, B- q) Y; n& {. o% R) j7 [" X驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
, T3 S# I/ Q7 ?* E8 l5 G: y4 V- P+ ]$ ]( P
初始化代码清单:. g, z1 B, c, s6 m3 g
5 x! I8 ]% Z" y$ w1 z$ b( J
- HAL_StatusTypeDef SDMMC1_MMC_Init(void)
' O: E6 T- L6 ^) b. n, U4 `! V - {
) d( ~2 n3 Z* i% b! X; z - hmmc1.Instance = SDMMC1;1 O& {" U" c; S9 [) d
- hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
9 h! g3 B4 a2 P' G- Y1 y - hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
# u) |! J0 V+ G; d" R - hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
; j: h* U6 q* E+ Z" C7 C - hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
! |2 Q) W# s* c) t$ l, R- c/ R$ Z - hmmc1.Init.ClockDiv = 1;1 D+ b, R9 Z( Z3 `! s7 r
- if (HAL_MMC_Init(&hmmc1) != HAL_OK)
( z& `. `8 g6 M; _$ S* `2 ~ - {9 j* P: P. S$ |* ^2 N/ W: {
- Error_Handler();1 _9 x4 a0 U: b; a' T% P
- }. ]% l8 ^! H; B/ i/ U8 D8 _) h' R
- return HAL_OK;
/ s4 `7 w% r a4 t( u9 `, t6 [; s! g - }
复制代码 + ]7 c [: G E. p% J
底层驱动代码清单:& H( I* l1 L5 K5 o
9 j$ @% K3 y3 B5 O. J4 _: X2 z9 G0 @- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)0 A/ R, E( }( H2 {- U3 k
- {% M) ~, _& G& v, i# W
- GPIO_InitTypeDef GPIO_InitStruct = {0};/ i5 x: o% _# D1 b8 V% M
- if(hmmc->Instance==SDMMC1)6 i2 F( R8 j8 j, \
- {; h- {6 m& E& n3 _0 S4 C6 y5 j
- /* USER CODE BEGIN SDMMC1_MspInit 0 */
5 u P3 N$ U7 |1 a0 d& ^ } - /* Peripheral clock enable */
% m) K7 O9 o4 W - __HAL_RCC_SDMMC1_CLK_ENABLE();
, n5 d5 ]- s( w3 O9 J - __HAL_RCC_GPIOC_CLK_ENABLE();
4 c6 X3 r8 c/ W' q i - __HAL_RCC_GPIOD_CLK_ENABLE();
4 r$ k2 l) ]( m6 z. Y5 y - /**SDMMC1 GPIO Configuration
2 M- L/ j- Z7 G* z+ d - PC8 ------> SDMMC1_D0
' N7 n/ p+ V; ` - PC9 ------> SDMMC1_D1 2 N% [0 w' |: T( g
- PC10 ------> SDMMC1_D21 z) | [ Q3 G6 i# a. Q
- PC11 ------> SDMMC1_D3
4 C9 ^9 ~/ C5 D% n - PB8 ------> SDMMC1_D4; r4 X. s5 I# l1 T0 o0 G
- PB9 ------> SDMMC1_D5
1 f8 r, l5 P. B P6 B, Y9 I - PC6 ------> SDMMC1_D6
& n& d+ [4 ^+ Q+ R Q - PC7 ------> SDMMC1_D7
7 o/ \9 [4 \% o5 j& c0 g- n% K+ x - PC12 ------> SDMMC1_CK8 ~& h" R- ?2 ^& u0 z/ w% ?
- PD2 ------> SDMMC1_CMD
6 K0 J R2 r. H9 \& C# l* O8 K - */' Q( S8 G( s8 W% H' k. \
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
/ ?: Z3 g8 v' l - |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
! y4 ^6 l) O9 V$ O9 D. U - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
. v1 F L/ y4 q& O5 l - GPIO_InitStruct.Pull = GPIO_NOPULL;
; K1 {- v! g# \2 |/ ? - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;7 Q) W4 P% e, ]& u+ [* \* {9 Q
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
6 I/ p, }, W# o! Q9 D) F - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);% F3 y; Z5 K- j) w
& C+ a5 ~. T# c/ H4 Q1 F5 {- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;; n. G( b K' _
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;! H# Q" T. t6 s- d5 ?, J9 a0 X% z
- GPIO_InitStruct.Pull = GPIO_NOPULL;& Q( Z' j% l) e$ u2 W
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
/ s. T" i2 @( b# j' J; t; m* `, B - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;$ j/ \# s4 z$ f* L
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
: }& ]# O1 R" g. r% @2 }6 C9 H - / s0 \+ _7 ] ?1 s( T; F
- GPIO_InitStruct.Pin = GPIO_PIN_2; X# x) P+ G; K* G7 j7 ]% l( j9 W
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
0 \; R4 Z8 Y% g" Z Q% l - GPIO_InitStruct.Pull = GPIO_NOPULL;1 p2 ?; z6 B' J* D P4 \7 s
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;+ r# k) l! b1 Y: `$ V$ a9 ]3 b
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
8 @) p8 o4 h" R% [8 W- j( @: N! G* I, l - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);5 i1 k' e7 z9 J) A( Y1 \; A6 | y
6 u+ p8 S( T: X& h7 B, L4 ~- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
% @ P. X9 {& R/ Z/ c; K - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断 @3 p! e: [6 [5 M
- HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);7 L4 {3 ]# l% {- d
- }/ b- a/ y/ z/ B9 E
- }
复制代码
+ _" Q! R2 o, x0 Z在DMA模式下,从MMC卡的指定地址读取数据:
, H* Q g# e P% Z$ L
- Q8 L- l# z8 g. u8 A+ B- B- /**$ N% a' K+ y% X+ V
- * @brief 在DMA模式下,从MMC卡的指定地址读取数据0 n+ ?5 g) I( p. `
- * @param pData:指向将包含要传输的数据的缓冲区的指针6 s! ?6 @/ Z; i7 ]; B& Q: P/ m& B
- * @param ReadAddr:要读取数据的地址! V8 d" N6 k; {6 t
- * @param NumOfBlocks:要读取的MMC块数量! S. Z$ P5 f' Z
- * @retval eMMC状态
5 S" O2 Y7 w; ?+ F; {1 w - */
$ Y) `! m! b+ [9 Y, W/ L* J - uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
+ x" T+ t A* V6 T$ \, ] - {6 c: y! d$ Y p9 E) ]3 b% E( W
- HAL_StatusTypeDef Status = HAL_OK;- }9 q1 R6 A$ Y" s
- B2 Y$ r: {+ `
- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
% N6 a9 i$ W6 ]4 ~8 D8 R - {
9 i: a4 G a9 Q I( u+ v+ p; r - Status = HAL_ERROR;
6 M, P o% Z- P- o9 U* }$ H8 B - }
+ x- o! @( l! _$ C3 }8 |! H" q - return Status; # S+ \' I5 a8 c0 S% n( a, r9 E% F
- }
复制代码 % H, [3 `4 e2 J: e& {
在DMA模式下,向MMC卡的指定地址写入数据:2 V# z$ w" |0 v+ U c) D% _% G
3 q$ p, e# k1 p" m0 ?+ O* z. d
- /**8 P7 D, u% W1 u! l6 H( Z H6 C& t
- * @brief 在DMA模式下,向MMC卡的指定地址写入数据
0 r* s2 H }; {+ }% ^ - * @param pData:指向将包含要传输的数据的缓冲区的指针; r6 Y7 a3 @$ I# W7 x1 i1 e$ ]
- * @param WriteAddr:要写入数据的地址
( s4 b ~- a# t ~6 c - * @param NumOfBlocks:要写的MMC块的数量
9 e2 i, ^0 {; e3 d, _ - * @retval MMC状态
5 \/ ^: M# a* s3 k" r- P& ?% E9 }' K - */4 R* T; Q3 ~& C6 F, u
- uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
3 C* W: a3 [ P, _; \3 y2 U - {
' n& p- y9 ?1 `7 c5 b. Q7 z3 [ - HAL_StatusTypeDef Status = HAL_OK;$ R$ Q! y7 i! Z3 s% C( T( ~
+ p0 @% o) i0 ?% Z- /* Write block(s) in DMA transfer mode */3 C% B, b. _$ `8 C6 q9 j' S" [
- if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)( I& }) G0 z) P/ }; m. i. R: B8 y
- {9 d9 s6 J/ j& `6 L$ U8 T
- Status = HAL_ERROR;/ @; y2 r+ H& T4 Q4 B1 e
- }! r$ R$ M) B; I0 T- V
- return Status;
& Y+ r# v9 E' I; T! G4 e - }
复制代码
! [1 ?4 v) ]* m! r3 C3 [擦除eMMC卡数据:
: J: _9 f' |! v! m$ A- R4 W: d/ d* t. W+ O+ W# l
- /*** Z, c: G* I/ f N; S
- * @brief 擦除eMMC卡数据
) \2 [$ I0 [( t6 S( D* p - * @param 无6 O. q# `! }4 e
- * @retval 无
$ O" u9 g9 E: s3 ~: g" z% M - */3 r8 w5 y" K; m2 `- D; `
- void MMC_EraseTest(void)
3 d8 @1 n* v* H+ O: I2 n+ d, w+ { - {3 g2 w8 I/ Q3 w4 M- q" c
- HAL_StatusTypeDef Status = HAL_OK;
' J: x2 a9 c1 a; N. v - HAL_StatusTypeDef EraseStatus = HAL_OK;
k3 w6 |( {9 x& s$ r - if (Status == HAL_OK). p& c9 f5 i& D
- {1 l2 a) v& g5 `' _: A
- Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));* X" F9 _2 j9 B: t9 F& [* }
- //等待擦除完成0 g4 Z6 q, q' x9 [% R4 E
- if(Wait_SDCARD_Ready() != HAL_OK)& X$ R& i2 f/ j& _( \
- {/ O" {# s" G/ e
- EraseStatus = HAL_ERROR;
8 n, L' E' t* E( y4 E) x - }
) E( I0 j1 A& ~ - }+ d9 T5 ]# q, i+ a) F, }
- if(EraseStatus != HAL_OK)* Y- R+ V, k* b- b' L9 c* G0 a8 p3 X
- {
; i% }2 D# L5 U) x" a) z# Q - Error_Handler();
- o8 D9 S Y/ o - }3 L$ D8 Y; |* x7 M3 k/ w9 @
- }
复制代码
% Q$ v& S. a0 F0 |: \& oeMMC卡等待擦除完成函数:
4 [) D0 |# }, _9 Q
T/ S* ^' s0 x1 w- /**8 N3 C3 C$ v5 r" v
- * @brief eMMC卡等待擦除完成函数
% U' t7 e- b7 h; O4 [! e/ } - * @param 无: t1 Z7 c3 A# K$ z, L! G' p$ Z+ }
- * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败4 [( q w }; B" C" l% [+ g
- */2 X* g& J5 X4 G
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
5 c3 F S0 J7 r - {
+ c6 x# Z; I0 S# b1 K- S - uint32_t loop = MMC_TIMEOUT;5 N( O2 X' j" r* d* w
0 J: Q2 F( Y2 H9 v# [% z" a5 F- /* Wait for the Erasing process is completed */( R3 s( U" r' a. X$ h
- /* Verify that SD card is ready to use after the Erase */
) y; d' E, E1 I4 u - while(loop > 0); j) j8 P$ v l, C* x
- {
W- G2 ~: C8 [1 t- T6 O$ Z - loop--;; m6 `7 k4 P/ V) V
- if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)" g+ I" s0 x* q; X4 b, y f
- {( S. N7 U: K+ w# a d$ u
- return HAL_OK;
3 w7 z! U2 l6 Q6 Y5 [$ ^3 B2 C - }) |% {' O* M! q6 y& F; Y8 K
- }- ^6 e) X1 M% J6 X1 a& v
- return HAL_ERROR;
* I( d7 T) k% A# J3 l" {- Q - }
复制代码 + c4 ]3 \" i4 s
最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
+ ]0 K; W1 r2 e& ^5 T4 C+ g
" B* X* ]8 U# p8 l P( |- \" B4 z
|