你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 HAL库配置SDMMC(转载,软件版本STM32Cube_FW_F7_V1.14.0, en.stm32cubemx (5.0.0))

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
1. 准备工作硬件准备
  • 开发板" S& ~3 H0 t  q: L
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):
    5 m+ p5 \( m, Y' T
    3 x3 {, L) ^1 Q# O9 m$ i

  • Micro SD卡6 W. C' k( q* x" h$ f
    小熊派开发板板载 Micro SD 卡槽,最大支持 32 GB,需要提前自行准备一张 Micro SD卡,如图:6 T( u% ]1 \  E  o  y% E% b+ K0 {
    3 t% ^  |6 h5 G8 `8 P

: E* y- _- z! @! t! w
软件准备
  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;
    # j) y. R2 E' S9 h1 I# L8 X
    # `; D  f& ^- B$ s3 X2 H

( W" K/ D: u0 ^$ c! H6 L! N
2.生成MDK工程: y/ u4 t# f  k5 i# P
选择芯片型号

打开STM32CubeMX,打开MCU选择器:; g5 ]. d1 g5 K1 ]% M

搜索并选中芯片STM32L431RCT6:
9 g3 _9 y% m+ {0 |# ~/ j$ ~+ z

' p* Y4 q7 V3 T5 v
配置时钟源
  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;
    ; `6 m$ v; N7 Y' ]
    % U2 \3 |8 L* i2 p; l3 V! ]. }, |0 E

这里我都使用外部时钟:


# q& e- Q0 r; ~4 y. S: i配置串口

小熊派开发板板载ST-Link并且虚拟了一个串口,原理图如下:

这里我将开关拨到AT-MCU模式,使PC的串口与USART1之间连接。

接下来开始配置USART1:


4 ]( V' u. P% S; ^% h0 E配置 SDMMC 接口

知识小卡片 —— SDMMC接口

SDMMC接口的全称叫SD/SDIO MMC card host interface,SD/SDIO MMC 卡 主机接口,通俗的来说,就是这个接口支持SD卡,支持SDIO设备,支持MMC卡。

知识小卡片结束啦~

首先查看小熊派开发板的原理图:

然后根据原理图配置 SDMMC 接口:


+ y# J3 I4 m" p8 ?6 u3 R% w# l1 [配置时钟树

STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可:

9 A& y" `: l3 u; x7 z. ]4 }* t4 b
生成工程设置

7 |* t( f) t0 _
码生成设置
9 x5 x" t, Y( |. g

最后设置生成独立的初始化文件:


4 s5 Q2 M" |1 N, g  b  U& B1 F

生成代码

点击GENERATE CODE即可生成MDK-V5工程:


7 A# Y( X4 t& Q1 K

3. 在MDK中编写、编译、下载用户代码' v0 T5 o& g9 X
重定向printf( )函数7 T( J) g& d9 ~& [: B' M
读取SD卡信息并打印

SD 卡系统(包括主机和 SD 卡)定义了两种操作模式:

  • 卡识别模式
  • 数据传输模式
    ) A* \4 Z; J9 R+ B
    0 V, g, \' ^( C6 I1 H

在系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡; `+ R% L" k. v6 o3 c5 y9 U; M
识别模式,直到被主机识别到。

使用STM32CubeMX初始化的工程中会自动生成 SDMMC 初始化函数,向 SD 卡发送命令,当 SD 卡接收到命令后, SD 卡就会进入数据传输模式,而主机在总线上所有卡被识别后也进入数据传输模式。

所以在操作之前,需要先检查 SD 卡是否处于数据传输模式并且处于数据传输状态:

在main函数中首先定义一个变量用于存储 SD 卡状态:

  1. <font color="#000000">int sdcard_status = 0;! I' z: O) u0 h* @7 k. j& u  g5 j
  2. HAL_SD_CardCIDTypeDef sdcard_cid;</font>
复制代码

然后在while(1)之前编写如下读取信息代码:

  1. <font color="#000000">/* USER CODE BEGIN 2 */
    ( S3 g7 }% W. N3 [* t, }. ^4 M
  2. printf("Micro SD Card Test...\r\n");
    # ~  x4 a5 |" @, G% c
  3. </font>
复制代码


# @2 n7 `0 l6 w5 Y0 \2 s2 |

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */7 X* q, Z, t: \0 }
sdcard_status = HAL_SD_GetCardState(&hsd1);
3 e3 e( _/ I  c7 w+ fif(sdcard_status == HAL_SD_CARD_TRANSFER): [" R5 ~2 h3 w
{/ Y$ e$ C# z  x9 A8 a! k
printf(“SD card init ok!\r\n\r\n”);

  1. <font color="#000000"><span class="token comment">//打印SD卡基本信息</span>" }- G0 K( [& }* i
  2. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"SD card information!\r\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    $ T4 U4 ~+ Z2 A
  3. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"CardCapacity: %llu\r\n"</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">long</span> <span class="token keyword">long</span><span class="token punctuation">)</span>hsd1<span class="token punctuation">.</span>SdCard<span class="token punctuation">.</span>BlockSize<span class="token operator">*</span>hsd1<span class="token punctuation">.</span>SdCard<span class="token punctuation">.</span>BlockNbr<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    0 u$ D6 S7 {! D, i6 K3 _
  4. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"CardBlockSize: %d \r\n"</span><span class="token punctuation">,</span>hsd1<span class="token punctuation">.</span>SdCard<span class="token punctuation">.</span>BlockSize<span class="token punctuation">)</span><span class="token punctuation">;</span>7 G* |( C! U. h! f
  5. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"RCA: %d \r\n"</span><span class="token punctuation">,</span>hsd1<span class="token punctuation">.</span>SdCard<span class="token punctuation">.</span>RelCardAdd<span class="token punctuation">)</span><span class="token punctuation">;</span>* Q) ?% s) ~6 W/ O: ~3 I, w
  6. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"CardType: %d \r\n"</span><span class="token punctuation">,</span>hsd1<span class="token punctuation">.</span>SdCard<span class="token punctuation">.</span>CardType<span class="token punctuation">)</span><span class="token punctuation">;</span>
    5 P* d9 t' V7 j

  7. ! o8 V" O. J! Z0 G4 b/ i
  8. <span class="token comment">//读取并打印SD卡的CID信息</span>
    & x+ x' Z7 D0 D  T8 p* ^9 q3 b
  9. <span class="token function">HAL_SD_GetCardCID</span><span class="token punctuation">(</span><span class="token operator">&</span>hsd1<span class="token punctuation">,</span><span class="token operator">&</span>sdcard_cid<span class="token punctuation">)</span><span class="token punctuation">;</span>
    * N7 @# r) b" {' s; R1 K* B! o
  10. <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"ManufacturerID: %d \r\n"</span><span class="token punctuation">,</span>sdcard_cid<span class="token punctuation">.</span>ManufacturerID<span class="token punctuation">)</span><span class="token punctuation">;</span></font>
复制代码

( V7 o0 O7 c: i9 |) O9 W

}
" k$ f+ Y' E9 R5 qelse
* o: K  [& H8 z4 G9 O0 c; c9 T! J{! E" O% `4 U# g/ v
printf(“SD card init fail!\r\n” );
  L# \/ b1 t4 k' m1 k, Lreturn 0;
5 @& j) t6 k/ c$ E) Y% J}
% h* u, Q0 y: u/* USER CODE END 2 */


" S( \# R  F' G) t# P: ^

编译下载后串口助手输出结果如下:

6 S# u8 k# M+ O1 C

擦除SD卡块数据

为了验证实验的正确性或,先擦除数据:

  1. /* 擦除SD卡块 */0 w5 r7 y8 O3 J% A
  2. printf("------------------- Block Erase -------------------------------\r\n");1 S! x0 M# H* Z4 @  Z9 M! ~
  3. sdcard_status = HAL_SD_Erase(&hsd1, 0, 512);
    1 W6 _, [" t! Y2 e9 N0 m
  4. if (sdcard_status == 0)7 e# p! s* u" N
  5. {0 w/ p3 A2 ?* ~2 e% ^! Q% t6 ~; C
  6.     printf("Erase block ok\r\n");! }7 q& M5 W" b3 a' m) x
  7. }/ w0 \; E1 h) M% ^- G
  8. else# j& J2 W% i# X1 K/ x
  9. {
    / J- u2 \$ j% z; r
  10.     printf("Erase block fail\r\n");) A4 N! W! E9 k
  11. }- c3 V0 i% ]1 ~$ m. {* E. q0 {, D7 N
复制代码

# J  u" V2 @6 t' U1 R读取SD卡块数据
  1. /* Private user code ---------------------------------------------------------*/1 i0 L6 }  N! J8 j" p# ^9 H
  2. /* USER CODE BEGIN 0 */5 x; T& ~+ |! v% P# ?: l, e
  3. uint8_t read_buf[512];
    6 e' j2 m# U8 _, S+ n' W! j
  4. /* USER CODE END 0 */4 x+ M0 W4 U- f* ]5 Z2 L6 d
复制代码

1 Q: M! h. t1 ]

然后在之前读取信息的代码之后添加读取数据的代码:

  1. /* 读取未操作之前的数据 */
    7 y: e. W/ f$ M" f$ h
  2. printf("------------------- Read SD card block data Test ------------------\r\n");
    % b. K5 x8 l5 O" x
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);
    7 D0 }' P* V4 j0 m/ A9 k9 ]
  4. if(sdcard_status == 0): y# O1 U! n4 I! \- e/ r
  5. {
    . k+ i. R5 U, w. y) o/ c# Z7 q
  6.     printf("Read block data ok \r\n" );
    ! y( p" y" \6 N) n
  7.     for(i = 0; i < 512; i++)# B. i: K! u6 C& M, V: B9 C
  8.     {: W3 i6 K" `* d/ B, y* d
  9.         printf("0x%02x ", read_buf[i]);% |9 m- b- l, ]0 R1 [
  10.         if((i+1)%16 == 0)
    * X/ ]6 H) `" c4 J  F8 [1 |
  11.         {5 K; w) W, o  Q4 M  S6 i
  12.             printf("\r\n");1 `+ s( v, {4 d, a: t! h/ X
  13.         }
    $ S5 j+ F3 P" J$ q1 Y
  14.     }
    $ J* Y4 \' F; y, r3 i4 T
  15. }
    7 g- X* V4 P: `! L8 N
  16. else* N) Z* q+ {* e5 E9 y4 Q6 g$ x2 v/ }
  17. {' H! x6 k% e; V/ P9 G1 f& x( F9 S
  18.     printf("Read block data fail!\r\n " );
    % L2 J* ^/ ^. v0 \0 `" T
  19. }9 N! ~0 _6 X6 Y; Q9 r* j9 Y% b
复制代码
! f" Z' A' R$ x. c6 c* r2 N2 H
向SD卡块写入数据

同样的,开辟一个全局缓冲区,用于存放即将要写入SD卡的数据:

  1. uint8_t write_buf[512];. I0 W; }  {3 L1 W! M" ~3 L
复制代码
' |7 U) t& ~6 h1 W" x

然后在之前读取数据的代码之后添加的代码,将缓冲区的数据赋初值:

  1. /* 填充缓冲区数据 */4 L. G; z: z. O# P+ [7 {
  2. for(i = 0; i < 512; i++)
    ( g7 y! D$ Z9 x1 U1 |/ x+ K( P
  3. {3 c1 |; E& T! k1 y' ]
  4.     write_buf[i] = i % 256;  L0 H6 w/ T3 q; C5 |% `1 e; \5 j
  5. }* z, d5 l; m% }$ `+ ?
复制代码
5 O6 _2 A9 T8 T. k& N

然后继续添加代码,将该缓冲区数据写入SD卡:

  1. /* 向SD卡块写入数据 */# o( l! s8 G7 Y  ^! J- {
  2. printf("------------------- Write SD card block data Test ------------------\r\n");
    4 S- o0 k3 v8 D, ~" |8 X
  3. sdcard_status = HAL_SD_WriteBlocks(&hsd1,(uint8_t *)write_buf,0,1,0xffff);2 H  {  F9 ?. `% d1 F
  4. if(sdcard_status == 0)
    + S0 z5 \7 p) i
  5. {
    / C. F' v% d0 u& j2 A  Q
  6.     printf("Write block data ok \r\n" );8 M/ ~# e3 x" K2 C3 H
  7. }) ~) D/ n1 _3 n5 h% }( {
  8. else" o$ h& Y& v( \, {% z
  9. {
    * w, \- |4 d2 i& ?$ m
  10.     printf("Write block data fail!\r\n " );, x& g' e1 g7 J6 [' x! x
  11. }  Z# w/ Z" P* S) |" N/ M' h
复制代码
5 O4 q+ T* q1 p; k- o6 E

添加完之后,为了检查数据是否正常写入,再将数据读出:

  1. /* 读取操作之后的数据 */$ P" j) m5 b) X. X- k, g  d$ F
  2. printf("------------------- Read SD card block data after Write ------------------\r\n");
    " \9 i: M( {5 ]0 k
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);! ], @" A' G' e' g6 L7 o
  4. if(sdcard_status == 0)2 }) j2 f# H$ e
  5. { ! c. l, Y2 g8 A: g5 ?$ x
  6.     printf("Read block data ok \r\n" );
    8 b; Y* {8 F) B. Z  D9 U7 ]5 a- x
  7.     for(i = 0; i < 512; i++)
    : N4 e7 g4 K  r$ w0 m2 `
  8.     {
    $ {3 s- K; ~! T6 @& M
  9.         printf("0x%02x ", read_buf[i]);' j) D8 H3 h' s" f2 w+ i, ^! q! f
  10.         if((i+1)%16 == 0)
    8 K# _- S! }, C% ^" h1 J
  11.         {
    * L7 ]6 \2 c" q. k# d5 c0 l3 W
  12.             printf("\r\n");
    , Y  M& U1 a, _7 n- p, k
  13.         }
    % e) Z. Q+ L; _7 B
  14.     }. z0 Y9 u3 ^" n% N, N
  15. }" H1 v* ]' H: _0 g
复制代码
8 J3 `7 R& @6 I+ H  ~1 M

将程序编译下载,最终的实验结果如下:

% p) D0 H# A) X. A

- J' {4 H* w/ y8 i, D$ j4 m: g

6 E1 g2 n# r/ w


/ y+ }8 p* M( ~" D4 y+ i
- G2 l5 L0 B6 r
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版