STM32驱动eMMC读写数据- m1 O$ ] E" q; f" A
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
7 {+ M' k7 n# e: F; }驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。4 p6 g0 ?- ~1 g0 a3 O' I5 P8 k
( {' j6 u+ W% ^6 D5 U/ D; v7 }9 D
初始化代码清单:
# z: g- U$ F, P' ?7 T$ j
( j0 S8 B3 m: d- HAL_StatusTypeDef SDMMC1_MMC_Init(void)" c$ U0 y0 b) u+ Z6 h
- {, y6 e2 d" k, L& _! i$ \) b. P
- hmmc1.Instance = SDMMC1;
/ W' i: M% |+ d - hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;0 b: G$ @% r+ D. G7 y2 X$ v
- hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
% Y' k* v( m A$ e4 q7 G - hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;5 p: N6 q+ h2 x% o) G
- hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;" d6 Z! [* d {8 u7 F9 n
- hmmc1.Init.ClockDiv = 1;
6 ^2 }) o9 R' L9 ~7 S - if (HAL_MMC_Init(&hmmc1) != HAL_OK)
1 b' J/ W8 b, w/ Z& d - {
4 K7 _7 _/ T" b+ ]3 x8 g - Error_Handler();
8 W2 P; ?" M1 c9 m, } - }9 t3 V# L% h8 b2 x' Z
- return HAL_OK;
; f. x8 M# ?% X4 C - }
复制代码
/ s- j/ _. [( Q: a4 X6 O/ |- i底层驱动代码清单:! f9 j9 j' ?+ \. p
4 v& ^; W5 }" z! e$ ^0 b- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
4 U7 n" y' i) S, G- u z - {( _1 h. _0 j4 X V% {4 P
- GPIO_InitTypeDef GPIO_InitStruct = {0};7 \, g, m8 B- v" c* M3 O! U$ P
- if(hmmc->Instance==SDMMC1)
$ `& e$ C6 G% p4 \ - {
& s. N D) f9 d/ C* s$ D0 I - /* USER CODE BEGIN SDMMC1_MspInit 0 */* j0 e* p9 H3 a6 s3 A" z
- /* Peripheral clock enable */
, }; | t6 `2 v* l) Y! v& Y: y - __HAL_RCC_SDMMC1_CLK_ENABLE();
' h$ {! U4 T% T) K& f! l; V - __HAL_RCC_GPIOC_CLK_ENABLE();
- N4 K4 ?* }" j: K; S- f5 o - __HAL_RCC_GPIOD_CLK_ENABLE();1 T- _# a4 q: T
- /**SDMMC1 GPIO Configuration 5 H7 H/ T- V+ N; D7 _) O) s
- PC8 ------> SDMMC1_D0" {3 D8 ~; m0 K5 g. y1 c/ Y$ k
- PC9 ------> SDMMC1_D1
! _; F* f+ x) `" j: b% M - PC10 ------> SDMMC1_D2
& c; v7 x" H2 p - PC11 ------> SDMMC1_D3
l. K H( M4 n/ j0 R - PB8 ------> SDMMC1_D4
' v9 s. o4 N7 i1 b" W: t/ R - PB9 ------> SDMMC1_D5# ?; r" a. b2 [" F/ {5 j. ~
- PC6 ------> SDMMC1_D6- d, ?' W; j0 i
- PC7 ------> SDMMC1_D7' w% c, Q/ K8 W$ @$ G* b
- PC12 ------> SDMMC1_CK
7 F e3 F6 B% j: y9 s) Q/ \5 P0 e - PD2 ------> SDMMC1_CMD& p2 {( \* P2 k( u6 }# q# _
- */+ u- B5 n3 P l/ F/ ~
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
/ Z4 e' y( S0 o, _ - |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;3 h4 e- Q* {. l7 W* O( l% Z6 i
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;2 X, S# U: }3 P, h( y! O3 j/ o N
- GPIO_InitStruct.Pull = GPIO_NOPULL;0 \1 s$ ]6 ~) d4 v' R$ |4 y
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;* X; s- ?# G) _* x6 R
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; Z8 J9 M* B6 O! N
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
0 | d9 l9 P6 S+ t - ! Z" Y$ k0 E, ]8 F0 J3 e
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
" Q" T% W. ^7 p% e - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
! r( G2 E9 S7 t1 c+ N2 o/ c3 P - GPIO_InitStruct.Pull = GPIO_NOPULL;
8 G0 k/ B. s/ o; ^% B# M - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;. f$ p8 u! W( F' ?% N; v* G; D" R
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;; y" }- Z t5 m1 m$ \
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);0 w( _/ d3 Z6 y8 z( I# {! g4 \
* {. ^$ S! v1 F, v8 t8 W- GPIO_InitStruct.Pin = GPIO_PIN_2;
7 W# q, G, R% j: h - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
: s& {0 m' J' j& p - GPIO_InitStruct.Pull = GPIO_NOPULL;
% s+ ]9 w- n7 _* [) X" L6 n - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
2 F, ?% N# l x5 [- P - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;# O* a+ }5 V4 Q2 H; _3 @1 E4 f5 S
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);( Q3 v2 s; V' o. v$ o/ L7 p
0 { q8 f* G/ `4 e- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
/ @* i# U5 P2 e - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断
0 E( U# ?2 X0 [3 D, B% }1 B - HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);( b9 b9 a& u9 a) |
- }
' k$ g7 R. ` l# ] - }
复制代码 " K$ T5 j/ U8 _- j Q4 R
在DMA模式下,从MMC卡的指定地址读取数据:
) \: Y u3 G8 ?9 d% {6 v9 w
7 U( z0 g- `& m b- /**1 }5 Y1 O2 Q. U: ~' u" \+ F
- * @brief 在DMA模式下,从MMC卡的指定地址读取数据1 d2 N- w% z( B, p
- * @param pData:指向将包含要传输的数据的缓冲区的指针4 w% i1 V$ N7 N; g* a
- * @param ReadAddr:要读取数据的地址; Z/ \3 l: k Z* o
- * @param NumOfBlocks:要读取的MMC块数量
$ G' C4 i! S$ C - * @retval eMMC状态
1 D+ x5 [( q2 Z+ L - */
9 {; F) U P+ Y4 @/ Y) O - uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
& [+ R, C& t, ~, z. n0 g5 P - {
3 }3 r$ S7 x, m7 Z - HAL_StatusTypeDef Status = HAL_OK;
9 A8 Q6 o( O. k5 s* s9 O - : G& J" H8 t+ }
- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)( {; \! X0 E: t, i3 U3 W8 N& G5 I
- {& p8 j0 `# H, W& t
- Status = HAL_ERROR;8 C# \( r, [$ q- T' E
- }
( L* u$ h* a" g" P; L( f - return Status;
3 y, u3 ~& A! ?4 \3 t# [ - }
复制代码
) U1 R" ~) x. V在DMA模式下,向MMC卡的指定地址写入数据:/ [( e& q+ b5 n6 z1 _4 p& m
' ]+ @& B* w' Z6 a& ~ N
- /**
- w# l* o$ k. d - * @brief 在DMA模式下,向MMC卡的指定地址写入数据* G/ _" H/ Z; c- z- ^& _8 L- [! P9 l. H- A
- * @param pData:指向将包含要传输的数据的缓冲区的指针
/ l: A9 l# d, V- H1 M3 }* C - * @param WriteAddr:要写入数据的地址
( D5 {, a# a4 ~/ A" Q - * @param NumOfBlocks:要写的MMC块的数量
6 k! L4 q; G9 i' Y- N - * @retval MMC状态
# q5 I$ Y( b" v/ Z# R& o% [& B - */
1 a$ @: b( I7 n$ Y - uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
& C6 `/ E3 U+ A+ ^. O2 F - {$ ]2 W2 f A5 o+ p. L
- HAL_StatusTypeDef Status = HAL_OK;
( v# `' V2 @: o {2 U
% _4 d" Y" b- k. Y, ^! J0 S- /* Write block(s) in DMA transfer mode */
) K4 Y* E( e6 V/ ^( M! f0 n6 ~ - if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)+ E% a) Q2 v: r
- {1 u) T# g3 |# j7 a& L7 g9 V- X
- Status = HAL_ERROR;
, u4 h2 n- L/ d' t: a0 b5 q+ C - }& M: r+ i* o, l2 z
- return Status;
0 a( w% F# D0 I% ]+ O+ q4 @ - }
复制代码
/ h% L1 Z _1 j |, D擦除eMMC卡数据:4 O, j r9 w* e" `
7 h; c" _. |( K8 M* O9 G" a- /**
4 h4 H7 d+ G9 k" O# T- j, l - * @brief 擦除eMMC卡数据9 V3 e8 S$ `* g& f1 e, p7 `
- * @param 无6 D, y) v: e" c; i
- * @retval 无/ O/ l6 h4 [, U+ O7 r5 t3 |7 ?
- */' B+ ?9 K7 u' T& ~4 g$ s7 P0 O
- void MMC_EraseTest(void); a% s# x/ W0 e* _. F/ V
- {
- ]% M8 h: M! w; R - HAL_StatusTypeDef Status = HAL_OK;8 p" ?$ ?1 T {5 G
- HAL_StatusTypeDef EraseStatus = HAL_OK;
. d h( u2 [% z - if (Status == HAL_OK)
! j6 r5 C: S6 O3 J - {! W. c* ^0 F3 X0 x
- Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));4 ?- q: o( x: Q4 N- _ _4 d
- //等待擦除完成
' c2 B5 M. i( A) p H, N9 s/ x - if(Wait_SDCARD_Ready() != HAL_OK)4 [4 N7 d1 t" t" W1 X/ w( L3 V
- {
- T* O% I6 H4 f+ {$ {5 Q0 O2 p& D - EraseStatus = HAL_ERROR;$ c4 O/ D' J1 j& M+ E5 J& b
- }
; G1 T T; j1 \. O2 u - }5 H3 F: T# l# | v6 B+ w; G3 ]; {8 I' h
- if(EraseStatus != HAL_OK)* c. t0 D8 C, b8 ` y( I: F+ T
- {
' \6 Q) t6 e2 C* K/ @( ]5 V; r - Error_Handler();6 R4 j |- D# Q7 P( ^8 B
- }
2 [- { h$ L! J1 n& H1 t - }
复制代码 7 B+ D1 l2 _3 l9 F6 m
eMMC卡等待擦除完成函数:7 G" N: _8 n# f5 [& ?
1 S4 Y$ h2 k/ {( @2 a! A2 ?% K! w
- /**
2 B3 c, x! n3 u$ j# C- o# a - * @brief eMMC卡等待擦除完成函数- t) J& M0 |; k) U. |' e
- * @param 无- V- f& I3 ]$ q+ Y! M; n
- * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败
4 ~3 D% a" f3 M1 I - */& @7 F0 w% v$ {, }2 H1 n: x) @
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)8 [& x/ H a0 I+ S' Z
- {
3 h6 H( o+ J: x5 k" C: \& H- Z - uint32_t loop = MMC_TIMEOUT;
! T5 K! S' U9 {, x - 1 X5 h9 `2 v0 H* P0 J7 u+ Z- P# ]
- /* Wait for the Erasing process is completed */
- k/ W$ ?) L U- t7 Q3 u, W - /* Verify that SD card is ready to use after the Erase */( n2 `3 ?/ ^/ `* i* e- V1 U; B. C
- while(loop > 0)/ E. L" K2 Q* k: V
- {! o% f8 c& I; @9 r: N$ `' [
- loop--;
2 ~, N" E, `# ^; B - if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)/ W( Q1 A' e I/ e: B
- {
+ C; E3 Y4 ?. d' R* Y - return HAL_OK;! _. A% L" t _! }$ j/ B! d/ q
- }
3 j" X5 U2 P$ B: p" u - }3 Q+ T" e- y; K9 x
- return HAL_ERROR;
: V# p$ y& T1 f, R3 a - }
复制代码 4 X6 A) | O1 y6 R2 R
最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
1 a$ ^% Y; Y Q; l: E$ v* N/ Z
5 c) Z% ~8 M2 j& c m; h# s. w T. ~% M1 D# a5 [3 q$ }- h# U
|