STM32驱动eMMC读写数据5 r) Q( T4 j3 m/ |9 p
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
1 A8 K- Y* F7 U% G, V驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。- Z2 j* u& H7 t8 E( t* ~4 Z
$ z5 ~+ {( W! E) Y4 H1 l; M
初始化代码清单:
% |* o( M' q& ~8 R2 j3 a) c( E8 m$ U$ Q5 a
- HAL_StatusTypeDef SDMMC1_MMC_Init(void)* x+ `. G- ^: ?- F* j O0 |
- {& a, Y* T5 v- U3 W0 K
- hmmc1.Instance = SDMMC1; p8 _3 y, Y# v( y% H/ y6 |
- hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;& ^) g6 [- p. r& m0 k I7 K( G
- hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;6 [' V, a; H) M9 g: z
- hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;" }. W8 y8 o( \0 f
- hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
' V5 U# E% W3 y" ^8 ]& X7 S) P2 { - hmmc1.Init.ClockDiv = 1;
) ^( w# z7 A- ~( {- A/ [' j4 u - if (HAL_MMC_Init(&hmmc1) != HAL_OK)* t# F1 a1 u% Z' u
- {
9 w8 d' R; q( V/ C - Error_Handler();
9 ]$ p1 Y; V. I. h4 f' ~0 i9 u - }7 o) e( [* w% G$ w. d7 U
- return HAL_OK;
5 Z; n; s h1 x* x" G9 ]& g - }
复制代码
9 g3 v$ _1 {$ |, ^3 z. c底层驱动代码清单:
8 s* H' s B( j& L6 `3 V1 p6 s% W/ C) o3 n: q( P# w
- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)6 ^* u' ]. Y! n0 h) }, L ^7 H
- { T7 D. R+ ^$ G4 H
- GPIO_InitTypeDef GPIO_InitStruct = {0};
1 F* E9 ^. f% H7 M: g - if(hmmc->Instance==SDMMC1)3 m4 s( D$ V8 i+ R1 Y4 u6 \- P; w
- {- U0 K7 U. U ?& P5 D- B
- /* USER CODE BEGIN SDMMC1_MspInit 0 */
" P* B* x, v) i$ S0 h8 ? - /* Peripheral clock enable */
6 o% X$ R+ d0 U' p- G+ I1 } - __HAL_RCC_SDMMC1_CLK_ENABLE();4 ^0 V, \, z/ D& N" D
- __HAL_RCC_GPIOC_CLK_ENABLE();( _9 o/ j0 K, m% E4 g
- __HAL_RCC_GPIOD_CLK_ENABLE();
2 H+ I8 H+ X9 k - /**SDMMC1 GPIO Configuration
( Q! J, n2 L# k- @ - PC8 ------> SDMMC1_D0 y0 j0 G$ d; S2 y, }$ d
- PC9 ------> SDMMC1_D1
/ K7 K8 w% ^2 R( a+ F - PC10 ------> SDMMC1_D2
" K- B" _' P" I+ f& I7 E - PC11 ------> SDMMC1_D3
' Z! `; x# R9 Y, k! K. n" N. R - PB8 ------> SDMMC1_D4
( w* {6 P9 y4 Z) I" L& z! j9 a - PB9 ------> SDMMC1_D5
% M0 ^) N& p: q/ o+ n( O - PC6 ------> SDMMC1_D6" W" `$ c4 q2 v: {/ d! U& Z$ E
- PC7 ------> SDMMC1_D7
* c0 ?, u( {! s) i+ ^0 `# N' l7 M - PC12 ------> SDMMC1_CK: _+ h* s7 x0 l9 S J# _" m5 z
- PD2 ------> SDMMC1_CMD
4 D7 r% ], b$ T M# K* z( u - */6 T# l- b# L' E6 i( Z. t) U
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
x! Y+ L5 K5 M. a7 _; z9 { - |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
6 \1 {1 Y# e6 s - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;, \# b* b( o) ?7 i$ y. q
- GPIO_InitStruct.Pull = GPIO_NOPULL; u# B# x5 K1 B+ v
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
. |. S( g/ c% i' S% d9 n - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;0 r: @: | j9 F5 w8 m; N8 x o
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
* |* ^$ y4 d/ Z* [: Z7 A
' s& V, V1 `$ r4 w/ R- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
1 T; [' h* W$ \5 R6 U3 Q - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;" g3 k2 a3 W- I& a3 ]+ |3 O+ z
- GPIO_InitStruct.Pull = GPIO_NOPULL;" {7 W' V8 C4 q& i3 ^; \. E+ w6 \7 b
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
4 ]6 K3 e' S4 _ k' [2 q( ] - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
" n6 t, G* w8 O- [. u - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
% {7 ~5 r; e \ f! M$ A
7 W; D5 D( t3 s' F# t6 y! @6 d- GPIO_InitStruct.Pin = GPIO_PIN_2;
0 Y' Z3 b7 }1 v9 J% Y% L - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;! d/ }6 t, K0 S5 n
- GPIO_InitStruct.Pull = GPIO_NOPULL;
' ]% Q3 m" I m - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
F# B* D, d* K2 E - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
3 O0 e' [# P6 ^6 f2 v - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
, G2 g3 H4 s3 n0 P! c - 5 o. r# U9 ?( j: _& a" G
- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
- m/ W. s7 h; A9 g2 ? - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断" l3 F, R/ Z8 T# V9 b
- HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);* ^6 N# P! h; X& N' P
- }, U6 G" P- U& g2 B
- }
复制代码
' Z. ?* T; @4 d! @1 x$ @7 A% b! d在DMA模式下,从MMC卡的指定地址读取数据:
3 z# ?( E4 ]4 }2 Q0 A: O7 v8 V& i/ S- o+ x9 O
- /**. C3 C( }8 o& A0 [ c! b$ e) P
- * @brief 在DMA模式下,从MMC卡的指定地址读取数据
2 m& B" e5 M) Z/ u - * @param pData:指向将包含要传输的数据的缓冲区的指针; L5 ^0 I0 S3 R
- * @param ReadAddr:要读取数据的地址
`3 D9 h, \2 \% K - * @param NumOfBlocks:要读取的MMC块数量- L$ w: d k3 {4 C0 K, g' u# c
- * @retval eMMC状态+ ~2 x3 n/ l* P- g
- */
* T. a# k0 z& p4 B - uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
6 L8 v- {# A. b1 n, e - {' `4 {4 j( n# x; S+ W
- HAL_StatusTypeDef Status = HAL_OK;! D% {* F- ~ `, g
+ w# u2 s9 H5 Z- o& U& E- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)6 S5 Z9 b# D1 g }6 t3 W
- {
5 N2 |9 g' m+ C/ g) L: R$ y - Status = HAL_ERROR;, w" Z& [7 T! e! Z. D' F: k5 t
- } " `' i, ^5 ]) ~, B
- return Status;
" c- m7 ^! O" g: p) p2 K& b - }
复制代码
0 \! m+ p* \& t在DMA模式下,向MMC卡的指定地址写入数据:
/ x; R8 p! \8 E5 c8 d; N V; |3 n& H; s+ M+ s( D S# q
- /**
9 l# R' N0 b2 r+ G+ w. S# ~ - * @brief 在DMA模式下,向MMC卡的指定地址写入数据
1 F5 F. M" \$ V1 v2 m- h- y, x- \& q- U - * @param pData:指向将包含要传输的数据的缓冲区的指针
- w- X% E# e) x7 V# U - * @param WriteAddr:要写入数据的地址( i# L% k0 s+ @8 ^, H) P0 s3 v! F
- * @param NumOfBlocks:要写的MMC块的数量4 Q7 S9 q% P% F! w9 |% A
- * @retval MMC状态
5 O( `/ b1 i# ^8 G6 k$ A, X - */( { G8 L: F9 s9 m( }# S9 g1 L
- uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
^- J0 Q7 y8 D9 E6 M$ t3 {0 V - {
, o3 D6 \ w! ~1 Q" i' K - HAL_StatusTypeDef Status = HAL_OK;3 C* h. i) [, p% @4 I
- ; C+ r# g9 v2 I' P, C
- /* Write block(s) in DMA transfer mode */
, Z6 I' Z% ? R& B7 l - if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)# |+ b9 R. |6 V: u2 ?* J8 L
- {: L8 J2 D0 c* Y& c) p1 F5 w
- Status = HAL_ERROR;
5 _- z' f9 o# m& Y; a - }( h, C X$ a p$ ^4 n6 I
- return Status; 1 ~& {8 q! ~2 n+ U
- }
复制代码 0 ]. d& Y0 R3 R
擦除eMMC卡数据:
. F( s# [. _: C5 @% i. R; O% ?3 ^" y. x% B7 p
- /**! r1 U9 T: y- u8 t4 ]! |9 G7 D
- * @brief 擦除eMMC卡数据+ ]6 l( R& c, R: S, z
- * @param 无
" A( F1 }6 S( O5 {, `8 }; p - * @retval 无
7 S+ w* g! @$ M0 f - */
7 D" b% G# s* N# \ - void MMC_EraseTest(void)/ E: h; f# x5 J, m3 L0 ~
- {) o& Q7 G. _! L/ X# T' C
- HAL_StatusTypeDef Status = HAL_OK;! \9 ^; U4 Z* r" D
- HAL_StatusTypeDef EraseStatus = HAL_OK;4 u( M) z- G! C H$ Y% [5 Q6 V
- if (Status == HAL_OK)
+ h! E F1 N) ` - {6 @5 p! j$ w3 W* A0 H% `
- Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));2 K7 t9 O6 t& i/ N2 }8 g
- //等待擦除完成
9 z3 j9 d) M* v6 c4 s' q - if(Wait_SDCARD_Ready() != HAL_OK)6 W8 Y% e! R/ e0 W# ^
- {
3 n5 h N' j9 S - EraseStatus = HAL_ERROR; w- D# c2 n P
- }" A2 f; F; d( ]% G* g' z
- }
: _$ @+ J$ ^3 p- F% c - if(EraseStatus != HAL_OK)
! c e, e$ b5 k - {
! i, J$ B% o o - Error_Handler();! f. S- f' q6 {$ U* e# M5 \# e+ i
- }9 g3 W4 x2 X z2 [
- }
复制代码 * J' S" g7 Y0 i. i7 n# _
eMMC卡等待擦除完成函数:
0 D: A/ p3 C! ^9 E) e9 f' y
: Z$ Y. n* r6 Y* `" Y% {- /**& p( h6 l; f: i/ {9 t
- * @brief eMMC卡等待擦除完成函数# R8 A2 i) L3 d0 O# n: _
- * @param 无
: @2 Z% P8 {( F, h' s - * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败! s6 q! x1 N( }8 n7 I% n; K
- */$ |1 U5 K/ j' Q x0 R) C. D
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)6 x0 h3 s: Q# D1 _( M
- {. Z8 k% X' F9 w5 Z) E5 t
- uint32_t loop = MMC_TIMEOUT;$ z; ?( @6 { f+ x1 I. [
: H) U) r; u W; s* @& m+ r5 x. ~& t- /* Wait for the Erasing process is completed */
$ D0 T9 b2 u: l% W9 c- W - /* Verify that SD card is ready to use after the Erase */
. i6 M' @" ]+ Q5 s - while(loop > 0)& `* q+ A* c4 ?8 v0 o. h7 a
- {: M& N3 z+ X2 S- e9 d
- loop--;$ q5 |: D5 |2 b; }8 d3 D/ ?
- if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)
; A( _; U& R( T- }1 y& f - {; y# U2 L2 q% y! g. \7 z F
- return HAL_OK;
& |) W+ J. j" Z - }
+ d& B' \" S" w1 s: S- Q- o - }
! Y0 }# k+ X1 d) A - return HAL_ERROR;
2 Q, m' e1 w- k2 U - }
复制代码
2 P2 L" m0 C' |: m9 z/ i5 a8 q" h最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。: s% d" f0 s8 r `+ u. H
; k$ I& {8 {$ |8 x, M' Y
/ Z9 M: S. x S3 ~" g$ h Z |