STM32驱动eMMC读写数据* Z& P0 h! e4 |- Y7 w" H% G# Y
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
: }# W( q% G( T) i3 V5 V. M0 U驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
3 e- z% `% Z8 q4 y
4 n$ w& g: }6 x% ~6 q1 R7 z, i初始化代码清单:
; k9 ^% j! L9 l! F
; M: {. r1 H0 o% w5 c. I+ ^$ v- HAL_StatusTypeDef SDMMC1_MMC_Init(void)
3 x/ z# g* s. m! z% K1 {/ S - {
& V% }. j- ]$ q' Q: ^+ r - hmmc1.Instance = SDMMC1;
5 A: U, o9 C Q" }# ^8 H - hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
! n' {+ P. w, T5 T3 C - hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;9 r6 @/ j M0 D' e; ^6 C
- hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;
9 \5 Y" Z% Z( j/ ]8 E - hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
' \4 x' X7 _+ W; b9 b - hmmc1.Init.ClockDiv = 1; ?* c* G% i( |
- if (HAL_MMC_Init(&hmmc1) != HAL_OK)2 [* o! K) O$ [ d! K- e
- {
; c* k. A/ d/ W' `, P - Error_Handler(); v3 `, H1 a# c( j! D
- }; B" A- R9 K4 e7 _4 n* k
- return HAL_OK;, b+ v m/ K @ X. Y4 c' r
- }
复制代码
; A, s6 S& ^' V/ ~: B3 Z底层驱动代码清单:
* s* s5 B7 b. ?: T
+ m: m2 {6 c$ B) I# k. }- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)) x7 L/ [, [7 r/ P
- {1 f& a6 W, |! }/ p6 ?% z
- GPIO_InitTypeDef GPIO_InitStruct = {0};
4 L# E, A) J5 [. X/ x - if(hmmc->Instance==SDMMC1)! i0 x# U! c( v) {
- {$ S3 h# r; w! k5 I1 S
- /* USER CODE BEGIN SDMMC1_MspInit 0 */
/ G- `4 b! u4 g - /* Peripheral clock enable */+ T' G7 a) m P! p
- __HAL_RCC_SDMMC1_CLK_ENABLE();
; ]+ q8 ?4 W8 z b# J% o+ k - __HAL_RCC_GPIOC_CLK_ENABLE();
" T9 f8 ]% I! x! V - __HAL_RCC_GPIOD_CLK_ENABLE();
& D. ]/ ^& j! v' t! n/ F( d - /**SDMMC1 GPIO Configuration
. m9 I) e( n" p- ` ^3 D3 A - PC8 ------> SDMMC1_D0
# V7 K2 x# ~5 X# B - PC9 ------> SDMMC1_D1 * j5 d7 G6 Y' U
- PC10 ------> SDMMC1_D2
) d% ]/ R. o; y) i! T i% B! m - PC11 ------> SDMMC1_D3
7 |7 \! B; O4 h& G - PB8 ------> SDMMC1_D4
$ I3 {$ y) {* B2 v - PB9 ------> SDMMC1_D5
( C$ N0 K; @' {& A# n9 d - PC6 ------> SDMMC1_D6
! H# z6 m' S& M n - PC7 ------> SDMMC1_D7- X8 I" W& x0 R
- PC12 ------> SDMMC1_CK
) t- n4 h# g8 ?1 Y0 W& ~ - PD2 ------> SDMMC1_CMD
( j. z! t% }) ~ b2 o( E4 V - */' }7 X6 O$ q) v1 n' I
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8 " ?, p* q. ^9 G
- |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;' p- } N2 I- m9 y: O+ \+ K
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ d% T- L5 o3 _ - GPIO_InitStruct.Pull = GPIO_NOPULL;
4 i. C, C1 G: Z+ ] - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
# v0 p% Q0 z2 g' N - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
9 J3 j: |8 O5 @) {/ w - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
! `$ ?7 x3 ~( |* `/ G - 9 p4 s3 V9 N* t3 l( J2 P+ p
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;% k; d/ C. \( a- I8 X8 S
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;, @& |7 |/ y# a5 g6 N% L) e' w5 [9 ^
- GPIO_InitStruct.Pull = GPIO_NOPULL;7 U# f5 r8 X3 K; `- |" i" o
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
" Y8 P4 J6 r- H" r9 F* O! } - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;4 K. y5 j1 ~" o: p: k; z. o
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);& s5 z" s! s, _6 F" R
- + Q4 L. s; Y' P3 i
- GPIO_InitStruct.Pin = GPIO_PIN_2;- @) M$ j. b1 R4 y. S2 w, k% z, N7 P
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
0 e- Z/ F) p) p+ J - GPIO_InitStruct.Pull = GPIO_NOPULL;5 K1 ]; d- Q. U. c, ~; \# ?
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;2 L: @0 t; M0 b- c
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;& s* D Z- z9 c( f1 u
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
3 ^) H6 L1 B$ y" P( H% n9 L* u/ |
9 a3 r* Q2 K! } B, f# b4 u- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
K; t& @/ I+ C( | - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断
" |# q& L! c2 p1 \) [ - HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);
, @ A5 q" k& {: J( j% v" t9 G( ~( s - }; z- R" V B- \
- }
复制代码
% j: I& f3 ]; q- A0 n/ f! F( _4 u6 ?在DMA模式下,从MMC卡的指定地址读取数据:
1 o) ~5 ^0 O( x' S( M' y& }( Q1 D& e T# ?: l
- /**4 ~/ M/ C! |; f- t
- * @brief 在DMA模式下,从MMC卡的指定地址读取数据5 [4 ]! H& ?/ z8 E" s4 i% j
- * @param pData:指向将包含要传输的数据的缓冲区的指针# l& _6 [6 ^, y' p7 M
- * @param ReadAddr:要读取数据的地址0 D6 s; }$ _7 W
- * @param NumOfBlocks:要读取的MMC块数量
; P3 F ] q2 {" i - * @retval eMMC状态; ?% @# ~1 q% s' a4 H3 t( r# c
- */4 |6 K; j4 a7 [ |$ s I- g% m" l: k c
- uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
; S0 ]4 A0 Q$ ~% }( k - {7 V+ {2 h; t* \' [
- HAL_StatusTypeDef Status = HAL_OK;( f: K" A, o; W% b4 m% M
- 1 _; o0 W7 x5 ]+ ]
- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK)
7 c8 U8 O: {0 r* n$ Y - {9 s0 R$ p( ?# \- y
- Status = HAL_ERROR;2 X# C7 a" Z6 @4 x( _7 y' }
- } * e" Z; y& k% b% @2 w
- return Status;
" f4 w9 n0 m: K! Y) R - }
复制代码 " j; } v+ P& D9 }8 |9 P' p: o
在DMA模式下,向MMC卡的指定地址写入数据:* O" S- I6 A# `5 o
/ U- L, `: [' R" e( ~* Q0 T7 C
- /**4 v7 X( Q5 n+ V2 H/ H
- * @brief 在DMA模式下,向MMC卡的指定地址写入数据
! o8 U- Z; c" x( a4 q - * @param pData:指向将包含要传输的数据的缓冲区的指针
; [' C+ k7 m& _1 W% l- a1 } h( _ - * @param WriteAddr:要写入数据的地址8 N- C6 U' x, u# }, n% |: E4 `7 F
- * @param NumOfBlocks:要写的MMC块的数量3 o9 H) X; z: E& ~
- * @retval MMC状态
* ]' T) S, X# ?. x5 m - */3 ^% W5 l' N2 d4 M2 y4 |
- uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
; x( z0 i1 ]1 t' b2 @# u! U - {
- k# l, g/ Y! i* u" r1 `+ a - HAL_StatusTypeDef Status = HAL_OK;# D( [, c. f# F: E5 l
- 8 ]! ]) Y! Z+ S3 v2 b. h) w5 q1 U
- /* Write block(s) in DMA transfer mode */* D P; `: N, l* `. \3 c) d0 o' O6 d
- if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)
* V* s [/ \1 g2 E; Y. x) g - {
, n. l, U+ }( J( V - Status = HAL_ERROR;
1 X7 v2 q0 n( u3 Y% K$ v - }
' I+ d) W* {. J/ o4 U4 c: M) \ - return Status; ; z) B5 u( \/ k3 D6 D3 }9 M# y
- }
复制代码
1 I% [4 R D: p& i擦除eMMC卡数据:
. W5 S- @: S. B3 _- z9 I6 N7 ^+ D# ^
- /**
1 K" k, l! s/ ] - * @brief 擦除eMMC卡数据' ?; P' M: Y5 }4 H0 @2 ]% A0 ]1 }1 T
- * @param 无
& I: f8 J. U V1 v' }8 L - * @retval 无: k$ C# a, D) ]
- */
& v$ a! _! v8 d% o5 t/ `/ l - void MMC_EraseTest(void)
2 z8 _2 O0 J1 K - {& ^/ |; p( S) x8 `3 Q7 r5 [5 m
- HAL_StatusTypeDef Status = HAL_OK;* E! [( E. r/ ^) M
- HAL_StatusTypeDef EraseStatus = HAL_OK;
4 x( _: F% E! O2 [+ \. _4 Z( j - if (Status == HAL_OK)
$ k+ s# g4 d' V1 s2 Q - {) P. i8 s- [; i+ k& g1 m. o! j! X
- Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
+ Z S! O/ {2 f& n# U5 ] - //等待擦除完成4 ]5 R m$ F! B d6 I$ o
- if(Wait_SDCARD_Ready() != HAL_OK)/ d E9 U% b5 w# {+ ~
- {; E, h. _! v ]% I
- EraseStatus = HAL_ERROR;
# q/ X- t! K5 w, w: N k( { - }
0 c0 y% ?- f8 U# S. ~ - } e; h2 G3 }' H6 ^
- if(EraseStatus != HAL_OK)
X K9 B- X7 h. C: H - { 9 \9 ?0 D+ b% }/ s4 ?3 m
- Error_Handler();
9 A: h* X. A4 r# b - }
2 a7 h2 B* {. d0 K - }
复制代码 ! H5 N2 C9 {% L: s
eMMC卡等待擦除完成函数:
- M9 @0 O3 W' c( K* I' }
$ k" t5 {, f1 y" a, n' ]3 D4 u |- /**$ x: \, }7 [& s6 h1 w
- * @brief eMMC卡等待擦除完成函数
9 J: K% z( t8 Z7 G2 J5 E! ? - * @param 无3 i7 y! G% S& H' `" T
- * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败! Q$ N6 i5 M( ~" p; R0 a7 E$ n3 Y
- */
8 b' g# Z5 b1 _ - static HAL_StatusTypeDef Wait_SDCARD_Ready(void)% P4 N8 }' `" ?
- {
" \; i* n: T, u/ D - uint32_t loop = MMC_TIMEOUT;
- Q0 }# z6 \; D, c' z; S4 ^
$ S8 r# [( X5 V! X* V4 E# Q- /* Wait for the Erasing process is completed */2 r0 G! V) C3 u/ `/ @
- /* Verify that SD card is ready to use after the Erase */; d0 D, Z9 c* J- M) |% n# Z
- while(loop > 0)* S* z9 f7 ?: G6 V$ B0 H6 b
- {+ W3 T! @5 e+ r! Q& c' p
- loop--;
& s4 M, k( w6 d. x- _9 U2 g3 g - if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)/ {8 N7 @0 X" H/ x; T+ i' k
- {
! G! L& x& Z3 C9 T2 e - return HAL_OK;" u( V+ d" Q1 T3 f; Q2 s3 \, e8 d
- }3 A- c# ~" E& s8 @: _+ @
- }; @6 J* d" H8 w% ^
- return HAL_ERROR;: } A# w, |# m3 J- ~
- }
复制代码
$ w6 I" E; s, H5 a4 z2 u% H( T! U# l% u最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。
0 ~, B3 h! I6 l# ]8 [
- e, o7 _% e8 l& r( ?
8 Z6 B0 \8 u+ m& v0 R |