STM32驱动eMMC读写数据& j0 A/ V; \7 S' B) _- w
参照 JEDEC eMMC标准:JESD84-B51 (Revision of JESD84-B50.1, July 2014)
9 O2 F! [6 y6 H1 l! j/ M: \8 Z. d6 e驱动芯片采用stm32h7xx芯片。通过官方HAL库中stm32h7xx_hal_mmc.h文件驱动,采用8bit数据传输模式,与SD卡驱动类似。实测写入速度6-10MB/s左右。
$ g% q- o' j8 T' D/ R5 \7 i6 f5 @
9 O- W6 w/ r0 O# K+ a" N3 U初始化代码清单:
& k. L# c$ o; h/ {: Z
1 b6 R4 k1 E" G" p# H$ v" t9 h- HAL_StatusTypeDef SDMMC1_MMC_Init(void) B, T+ A o; p. P% m
- {
+ z+ `# Y @. r% p3 i8 }2 A - hmmc1.Instance = SDMMC1;
, }3 t; I1 }3 X. o" C3 m - hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;4 n1 s' _6 V) V0 _; v
- hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;, D7 O' Y/ X# _2 I; W6 h+ d
- hmmc1.Init.BusWide = SDMMC_BUS_WIDE_8B;( Q( ]) Y7 f$ ]/ u/ z9 u' a3 ^
- hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;6 g1 l4 L. D4 F; `5 U, Q5 }3 {
- hmmc1.Init.ClockDiv = 1;5 q, o$ l0 e0 x* a1 x7 z: [$ w
- if (HAL_MMC_Init(&hmmc1) != HAL_OK)
9 M. L! Y4 j3 w4 P - {( j- [ |$ l {: H$ x
- Error_Handler();. I) g; x1 M" A! A6 I, y& h+ k
- }" T1 z$ b8 V7 S1 ~; H
- return HAL_OK;
* D9 Y- q8 H5 h - }
复制代码 $ G! Y, Y" Z `* b9 ~. b( ~
底层驱动代码清单:
* m) C" _2 o6 g5 W/ T/ ]
9 w9 m; t! w% a9 O1 Y" D- void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)" l% K# s0 ?2 P# h+ K: B4 }; s+ S
- {$ y7 a4 Q3 O1 S; h
- GPIO_InitTypeDef GPIO_InitStruct = {0};
5 z5 p7 n4 I4 w h2 E - if(hmmc->Instance==SDMMC1)& Q: n1 P! ]7 I2 C& Z+ h+ ^7 U: S
- {
" f2 P) M5 ^7 _( j - /* USER CODE BEGIN SDMMC1_MspInit 0 */
+ v. Z2 Z: X( ]3 H. h W - /* Peripheral clock enable */! H( P8 E3 c0 Z& I8 n
- __HAL_RCC_SDMMC1_CLK_ENABLE();
# W% n6 i8 H4 x G7 g: O& A - __HAL_RCC_GPIOC_CLK_ENABLE();
7 o8 f; c8 }; F5 h6 e, h - __HAL_RCC_GPIOD_CLK_ENABLE();8 w+ O3 Y4 K2 W% r0 ]1 D
- /**SDMMC1 GPIO Configuration
! F0 c; H" k8 r1 A# t1 T - PC8 ------> SDMMC1_D0/ a! L6 [$ k, N" |
- PC9 ------> SDMMC1_D1 : P2 @# G4 q* V( Q4 {
- PC10 ------> SDMMC1_D2
* ~" _3 Z4 d- g0 A; U x _7 m" \& L - PC11 ------> SDMMC1_D3
0 N/ A/ v! n) S! P3 N% P, {2 _# W - PB8 ------> SDMMC1_D4 A! t6 t, y9 k" D( O2 [: N
- PB9 ------> SDMMC1_D5# [# ]( K' [5 o* D2 t
- PC6 ------> SDMMC1_D69 D) x. j* n5 q' ]" m7 w9 k9 P, m
- PC7 ------> SDMMC1_D7
0 N2 y+ d' I" Y Z5 c - PC12 ------> SDMMC1_CK
3 z0 Z+ ?2 F7 n4 ~7 N+ |. C - PD2 ------> SDMMC1_CMD& h# ~$ S( o; c( s' p8 m: Q
- */3 Y, G# Q9 A5 ?- `
- GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8
4 Q. h. [' Y- z9 P6 I+ X8 o - |GPIO_PIN_9|GPIO_PIN_6|GPIO_PIN_7;
V3 y4 ^1 n9 F - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;! y0 H: T2 x4 j" i6 D& a
- GPIO_InitStruct.Pull = GPIO_NOPULL;% Y; Y& b5 _. \; v; i8 c/ B r
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;$ C* @8 p/ M: N$ U' N
- GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
1 T" t+ D8 B* d3 N/ E; g" Q - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
8 P& Q- r) U) r- ~6 V5 A: q - " F" V: V: V1 B* M6 b" Y d
- GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
% K, v7 ~ e0 l - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
1 Z2 u7 ? `6 C ] - GPIO_InitStruct.Pull = GPIO_NOPULL;
* ^. U2 }; ]# s' k4 t# u1 n) | - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
% f; w' n* T9 E$ \2 D1 g0 c - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;0 O) ~6 `+ j( w S* |' p
- HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
( u6 W7 x5 M* j0 j* V0 F& v
. ?- F4 H. p" I- _6 O; z9 k) E- GPIO_InitStruct.Pin = GPIO_PIN_2;
; p: [' Q1 [( z - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
7 @4 V+ q9 @! K8 D8 x - GPIO_InitStruct.Pull = GPIO_NOPULL;
; M `8 u9 A y' ~8 @8 g$ z7 j - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
# k7 z# C. h' \% `( \2 v4 L - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;. P5 _# c9 g+ o
- HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);" i; |/ j3 U% q+ d! [
) K) @6 H2 o3 ~4 W! u1 C8 |, ^8 A- HAL_NVIC_SetPriority(SDMMC1_IRQn,1,1); //配置SDMMC1中断
3 e5 e8 h, X7 R# {9 x" } - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); //使能SDMMC1中断
3 c& R" p4 g9 r: V, U - HAL_NVIC_SetPriority(SysTick_IRQn, 0x0E ,0);8 @0 l6 o6 `! e |
- }
' [4 R3 K. O8 X+ z# L - }
复制代码
2 M* h& v0 _ C# f在DMA模式下,从MMC卡的指定地址读取数据:
2 f$ {# g" ]1 G/ K w
6 z+ H" u8 |4 i& ^0 z( `- /**
: x2 u; ?# y+ z w) y - * @brief 在DMA模式下,从MMC卡的指定地址读取数据( ~; j9 U( I9 k; [3 X
- * @param pData:指向将包含要传输的数据的缓冲区的指针
( M+ K, c( y: S1 {' M% q V - * @param ReadAddr:要读取数据的地址$ ?9 w4 n8 C* P+ D# h& ?" B
- * @param NumOfBlocks:要读取的MMC块数量
# _7 i$ `# Z8 b" t! f* c" W - * @retval eMMC状态
! _' u, ~) V2 B% W - */
2 B) u) g# a1 ?) B/ O$ A# X, K - uint8_t BSP_MMC_ReadBlocks_DMA(uint8_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
; I$ t, b* Y g9 Z7 _" o - {
w2 b7 s/ t r* J g - HAL_StatusTypeDef Status = HAL_OK;
% u ]6 j# |% C) W3 Y
4 h- \- x1 Z! a* s$ V# M+ S% M- if(HAL_MMC_ReadBlocks_DMA(&hmmc1, pData, ReadAddr, NumOfBlocks) != HAL_OK); G8 B9 `1 H( K: I5 g, E: o
- { G4 {2 ^/ |7 f+ |5 ~+ y
- Status = HAL_ERROR;* |& |: {0 H' M6 S$ `4 Y4 O
- }
6 ?% [% S9 m4 k4 f+ O1 G/ y9 u - return Status;
# T0 ^& D9 Y$ `$ f0 ? - }
复制代码
& @6 B; U5 `% i: ^在DMA模式下,向MMC卡的指定地址写入数据:
9 G, @# X5 C; V
; e! s/ V6 S/ s% q& J# _5 H- /**
3 \+ w. l1 \9 [! N: ] - * @brief 在DMA模式下,向MMC卡的指定地址写入数据2 W O o9 y& D
- * @param pData:指向将包含要传输的数据的缓冲区的指针
) l7 Z2 t+ n3 X+ D) q7 \( t - * @param WriteAddr:要写入数据的地址3 H# R8 I8 K# j; y% a: A
- * @param NumOfBlocks:要写的MMC块的数量
6 C z* L. }$ I- r4 M8 P( G - * @retval MMC状态2 i- i. a, U3 A
- */
7 }0 ]5 D4 y0 F5 K# Z9 o) S - uint8_t BSP_MMC_WriteBlocks_DMA(uint8_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
4 [4 o( w6 ?# x7 p+ E' S - {
# \" k p7 ]+ e7 m6 C+ O - HAL_StatusTypeDef Status = HAL_OK;- \! ^ Y# O; E3 _" s
- . t- S' Q, R" R7 C! x/ Y% S
- /* Write block(s) in DMA transfer mode */% M6 s, ]1 M% x- B
- if (HAL_MMC_WriteBlocks_DMA(&hmmc1, pData, WriteAddr, NumOfBlocks) != HAL_OK)* e4 D* T+ e1 g
- {
0 K9 ~4 X5 a. F& y4 H$ F. ^ - Status = HAL_ERROR;
: J' ]. T5 V9 U- H, r% E! m6 B - }" U1 F- {; V) T% d1 ~
- return Status;
( K# J! k; y) } O - }
复制代码 % D* l$ m' o4 a8 z0 L7 C+ ^
擦除eMMC卡数据:
" P% w' t6 F9 |/ b8 D
8 t8 Y% U& ?9 o4 h9 c* X' }- /**
/ L4 j+ x& K- ^/ H8 F; ` - * @brief 擦除eMMC卡数据
/ C' w7 S) e; b* g: S# q3 J5 j - * @param 无! d1 w0 q1 D* O
- * @retval 无
3 X; _& }! T- L8 J1 L c+ M - */
( N/ a5 ]( Z9 H& o* k3 { M - void MMC_EraseTest(void)
/ e$ U/ f- i$ e3 H" p, B$ B* h2 r - {
' x0 V; l/ F" @# y& u$ I - HAL_StatusTypeDef Status = HAL_OK;' E+ J- O2 B9 c7 |, M% F2 t7 n
- HAL_StatusTypeDef EraseStatus = HAL_OK;
4 K& H: V% v) ]8 U8 Z. R0 J - if (Status == HAL_OK)
+ J; C! ]& O% j" G- C& f8 d( l - {& n0 r, Q0 J( H1 [
- Status = HAL_MMC_Erase(&hmmc1, 0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));- C' H, V v% K# g7 A( j+ z
- //等待擦除完成5 Z0 ^1 z d/ |4 K* c
- if(Wait_SDCARD_Ready() != HAL_OK)
w" }( a5 ?, X! @7 E; ] E: Z - {# k* i/ K9 Q* `- ]1 K: w- Y9 `& {: k
- EraseStatus = HAL_ERROR;
1 J) X1 Q$ j9 \3 {$ A - }6 m: T+ m4 {$ u! g
- }
* J l5 ~# a3 F' R' |' U& @ - if(EraseStatus != HAL_OK)
* U8 }) j, S% o" d+ a6 D" V% g9 i - { * V! u( g; ^0 t' X3 o
- Error_Handler();
" n- B7 C3 b6 y0 r; i% x. V0 W - }- |9 f$ t6 B1 s2 p1 I1 T4 o* s
- }
复制代码 ; I9 [! D- v' p/ L$ U
eMMC卡等待擦除完成函数:
& Y) ]! H3 ~% r6 k( L' ?' B( T1 x1 _6 ]8 Z, I
- /**: f1 ~5 t% `% ^2 e( x1 ]7 h% m
- * @brief eMMC卡等待擦除完成函数8 Q/ m, z$ G, R/ l7 j
- * @param 无1 Q5 F/ d$ ?, |
- * @retval HAL_OK:擦除成功;HAL_ERROR:擦除失败# k& {& M6 h- m3 y, k' Q* W
- */) l7 |8 ^/ I: B& x' T4 a
- static HAL_StatusTypeDef Wait_SDCARD_Ready(void)
* F' N. p4 L/ r- y, h# I - {
% J/ e% `# D5 U I. L' a - uint32_t loop = MMC_TIMEOUT;) d$ D7 b' c. }, _$ {
: P" N" i& z+ k: W7 k. h5 E- /* Wait for the Erasing process is completed */5 s% W! A* |* I1 h
- /* Verify that SD card is ready to use after the Erase */
* }' q% m7 t8 t8 n/ C/ s( V - while(loop > 0)" S+ u! l8 j Y( g0 m1 v
- {4 K/ r3 S+ t4 b+ m" }! R/ X; R
- loop--;2 [% n& \4 z# _; B: i# @
- if(HAL_MMC_GetCardState(&hmmc1) == HAL_MMC_CARD_TRANSFER)/ i' h/ _4 q5 ^$ M1 y0 N) _
- {
# h4 M: t2 h$ U$ ^: f - return HAL_OK;
. Y0 [9 @0 C4 n2 r - }8 F, U! \0 a! c: o# l1 G9 N
- }
/ A4 {7 ^$ ]9 u! u/ @ - return HAL_ERROR;
, z% k; W" p, _9 {; F: v+ t# Z' a - }
复制代码
1 J* T6 n6 A- n% b' y7 x最近移植的eMMC卡的驱动程序,分享出来希望对各位开发者有所帮助。还移植了FATFS文件系统到eMMC驱动程序中,之后整理好再分享。; {# q7 l& h4 D
' K( t( z; F/ y9 V2 i3 ?
, |, Z" X" O: ?4 I
|