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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
1. 准备工作硬件准备
  • 开发板3 U. s$ f* O/ u5 ?) J
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):' P% b2 B- ~$ R. \) E4 a
    " L/ f' _( V! H  @" O4 \

  • Micro SD卡4 x$ ]" b- h1 p8 x: F" C8 U$ t. p
    小熊派开发板板载 Micro SD 卡槽,最大支持 32 GB,需要提前自行准备一张 Micro SD卡,如图:
    & b6 @  M3 \3 K4 O- B9 D

    2 I% R) y% p0 r! e+ F


7 n2 M9 t% q* \1 v1 {! b软件准备
  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;
    2 X- B3 v: i, }+ o8 m

    7 d$ m3 I  z6 G

+ _9 s2 l$ b& _0 k: b) k$ F- y
2.生成MDK工程" O' e, M7 J# X! `( p$ s# F
选择芯片型号

打开STM32CubeMX,打开MCU选择器:# ?" w  L" Y3 v$ P" k

搜索并选中芯片STM32L431RCT6:
0 o& H- h" L) ?9 [! X

; w6 d1 _; |9 @* Q$ k, ~
配置时钟源
  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;8 O+ l1 T. L. C8 w7 J; B7 K

    & |0 }- @  C0 u- g7 v8 K+ n  ^

这里我都使用外部时钟:

& y2 p; X. D6 C3 c. |
配置串口

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

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

接下来开始配置USART1:


8 q  n$ M5 g+ w! u. M4 o8 S# I7 U. ^配置 SDMMC 接口

知识小卡片 —— SDMMC接口

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

知识小卡片结束啦~

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

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


! [8 a5 y5 b0 @配置时钟树

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

) m3 |' Z3 h, V  `* h- d1 n8 @5 y9 I
生成工程设置


3 F! w0 @& X  X/ |. [
码生成设置7 \) t8 j$ A, r& L6 D4 ?! E5 p

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


( n8 q6 h3 x9 d$ w& C8 F

生成代码

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


' x2 m1 z- C% l. p

3. 在MDK中编写、编译、下载用户代码
$ b! x/ G& i) \- B3 V7 h5 G重定向printf( )函数
1 J2 w4 @: f1 u
读取SD卡信息并打印

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

  • 卡识别模式
  • 数据传输模式
    # E" }5 P: H1 @# U, l' q

    $ o  F, T% u' j

在系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡
3 ~$ g! W- k6 S识别模式,直到被主机识别到。

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

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

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

  1. <font color="#000000">int sdcard_status = 0;+ l2 Z$ m1 j# N. E
  2. HAL_SD_CardCIDTypeDef sdcard_cid;</font>
复制代码

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

  1. <font color="#000000">/* USER CODE BEGIN 2 */1 z* j0 {0 }0 z! q
  2. printf("Micro SD Card Test...\r\n");1 Y+ t, M; n: R9 L) R2 V8 G& g
  3. </font>
复制代码


1 T6 k/ W) H; [: I

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */; B7 n/ n# t1 @3 B3 m: u8 g
sdcard_status = HAL_SD_GetCardState(&hsd1);' S, t5 u* X5 H6 Q0 b1 p2 V
if(sdcard_status == HAL_SD_CARD_TRANSFER)3 ]! r( G6 R+ J! E% Y- v/ x3 v& x# d
{3 R# l4 O- ^% {
printf(“SD card init ok!\r\n\r\n”);

  1. <font color="#000000"><span class="token comment">//打印SD卡基本信息</span>
    & h: `9 ?; Y4 Q9 N* E1 S
  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>1 v' v& A! a% M9 }& @
  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>
    # m0 f8 ?3 S! ^0 |; f; @6 W. X% f
  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>
    9 ?4 L* K; G) f4 o; I
  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>
    / u5 ^( z$ T8 Z# C) Q* h
  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>
    6 @: o4 s+ T9 Z

  7. 6 I* d3 k4 \3 Q$ q: \' \; |
  8. <span class="token comment">//读取并打印SD卡的CID信息</span>
    . z9 \# m( I# y/ D) H9 Y9 v6 m
  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>
    9 @- B* p$ O7 E  e# ^
  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>
复制代码


+ P  \8 z1 @% m! L. ~: M# G

}
0 `! O, p' R, W5 m! O+ Zelse* @% V& `* k: c6 W1 r8 m! i) f
{' A( Q5 N  D' P
printf(“SD card init fail!\r\n” );
( {4 {7 J- R/ b% I6 u2 N7 [return 0;4 \* H( {) k; }* q+ H; g
}/ _% F5 j% ^  B
/* USER CODE END 2 */

- J) M3 h2 W4 W  ?" `5 x

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

, i) n) {7 a6 f1 q

擦除SD卡块数据

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

  1. /* 擦除SD卡块 */
      R6 L4 |. I% Q, c3 [1 P; Z3 l( T
  2. printf("------------------- Block Erase -------------------------------\r\n");
    7 t$ d9 u  `7 ?) H, ?% b" c
  3. sdcard_status = HAL_SD_Erase(&hsd1, 0, 512);0 I! E4 {: t2 [, g9 p3 U, P/ f$ X+ S% d
  4. if (sdcard_status == 0)
    7 t0 R) ~) _3 g+ _, ~
  5. {
    1 w# ~# B' G# b/ g  d" j( d
  6.     printf("Erase block ok\r\n");6 |+ m5 O' ~# F! S% M. {, @
  7. }
      w- P) _7 k; h9 F' n2 h! h
  8. else' r: m# v8 `/ L. \
  9. {
    9 ]0 V. G2 d. c( n- O
  10.     printf("Erase block fail\r\n");
    4 P6 ?, L5 U$ R4 q/ x# I
  11. }
    & L$ W8 l1 V; H5 z4 }
复制代码
' U' f( c3 Y7 {' M3 o2 _9 n
读取SD卡块数据
  1. /* Private user code ---------------------------------------------------------*/
    $ F% y! m  e4 K" n6 W' o3 y5 k
  2. /* USER CODE BEGIN 0 */2 m) ]9 n' j5 d$ J7 b" ~
  3. uint8_t read_buf[512];
    * g. x9 R+ N6 m# ]' |
  4. /* USER CODE END 0 */8 G+ l3 ~5 x: q+ }* n2 b
复制代码
7 M$ ~) {- P& w3 q! `

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

  1. /* 读取未操作之前的数据 */! N! P* G2 L+ ~! K8 @: \7 C
  2. printf("------------------- Read SD card block data Test ------------------\r\n");
    0 _% I& n2 I7 ~& }" C9 R) o
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);3 @, I) I: e! w, f) R  S
  4. if(sdcard_status == 0)! b, `) c: Y% M6 B3 k- x7 {* B
  5. { ; D; B# y% M. d" h
  6.     printf("Read block data ok \r\n" );
    / c9 Y% \4 Q! ?- z9 P# P3 D( s$ W
  7.     for(i = 0; i < 512; i++)5 t1 X# {+ [: L3 W+ D
  8.     {3 {) S+ i4 [7 x' A
  9.         printf("0x%02x ", read_buf[i]);" p' Z$ r( `* V6 u3 F! @8 j' ^
  10.         if((i+1)%16 == 0)  ~" |) I: O$ m3 p3 }% ^
  11.         {
    8 z5 J6 ?5 G1 C$ M; `: B2 _
  12.             printf("\r\n");
    ! s, K7 S4 z  G. B2 M, q2 Q1 V
  13.         }. H4 D2 ~+ B8 U: {
  14.     }* I. b7 ]! F! h% w' d
  15. }
    0 b  ?7 u& F, e  y
  16. else
    ) ?: s* P5 u, G: {0 ~" v! ]/ C# `
  17. {
    # C$ ~4 w% p' j: E1 Z
  18.     printf("Read block data fail!\r\n " );  I% _/ |) d0 p, x' N1 F3 f3 \
  19. }# g% v, g/ K6 l  O
复制代码

' `/ p; B4 Y/ Q  g  d向SD卡块写入数据

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

  1. uint8_t write_buf[512];4 {  b5 @( W* ~4 p2 l: Q
复制代码
, ?8 G( I' y# w  }, c/ |  K

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

  1. /* 填充缓冲区数据 */8 R$ t6 P6 A2 h+ {* Q
  2. for(i = 0; i < 512; i++)
    . i" b9 W! r  N* T
  3. {- N' x. E2 N8 D2 r
  4.     write_buf[i] = i % 256;
    . x2 |; J( X( c  @' V+ q
  5. }# X& h! |; a. U3 e! G6 L
复制代码

. L8 Y0 N# L. P

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

  1. /* 向SD卡块写入数据 */
    : V# R: w$ u/ H3 l8 ^
  2. printf("------------------- Write SD card block data Test ------------------\r\n");9 i. d! B) _' _, P. U( k( r' L
  3. sdcard_status = HAL_SD_WriteBlocks(&hsd1,(uint8_t *)write_buf,0,1,0xffff);
    + U3 H& Z. Q2 I6 Q. B( m
  4. if(sdcard_status == 0)& C8 D9 Z) i( U
  5. { # x6 {6 d3 H% m% F
  6.     printf("Write block data ok \r\n" );& j% Q+ \" L4 p4 L# w$ d
  7. }
    $ b* L& O* h; l) r" p- T
  8. else
    , a' o- G- `& H! f
  9. {
    8 R) l  s8 [* Z: J( k/ z$ Q
  10.     printf("Write block data fail!\r\n " );
    ' C4 o; n3 V9 @8 C! ?8 C: |( o
  11. }
    # Q: t1 V" u' ~7 f  b# L. X
复制代码
5 N! f$ R6 u2 z# p& j

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

  1. /* 读取操作之后的数据 */3 g. R& q2 R8 [# X8 b# A" O+ `* U: w
  2. printf("------------------- Read SD card block data after Write ------------------\r\n");
    + a" e6 Y7 a! e: ^4 Z: _0 [8 {- ?# x0 ^
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);1 _  Z7 ~/ P) H2 ]" Y6 ~* {/ \
  4. if(sdcard_status == 0)! A( g+ X# V* L4 \
  5. { * d* d6 n+ z0 p6 n' a6 O) L6 P9 q) i3 _
  6.     printf("Read block data ok \r\n" );
    ; @' q, x; S6 K- N' C# K: A
  7.     for(i = 0; i < 512; i++)+ l/ S% _$ `2 i8 ?7 f  C# O
  8.     {
    8 u. a9 ?  a7 W. x8 s/ c8 @+ r2 Y
  9.         printf("0x%02x ", read_buf[i]);9 d4 _( [% [; U3 a, q
  10.         if((i+1)%16 == 0)) z& D' I: h& Y0 [2 p
  11.         {
    1 ^, l0 f4 m; k1 q6 Z3 V3 x
  12.             printf("\r\n");
    1 Z2 H) p  Z" W3 [" Y
  13.         }
    , `8 G3 y3 p2 A; {  ^2 W' _& Q7 V
  14.     }
    ! G0 O% L3 u5 p: K
  15. }* ]0 l  l. `0 L
复制代码

$ M/ r$ f6 H3 Q; y% h, O: H5 v/ L7 O

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

" B6 p( j3 Y& A0 k4 M

3 W) P4 h. c- {, t5 x* l' t


, N8 v" J# d6 i# H( Q6 p' ?


2 {% y* J) K) L6 Q2 b+ z& O3 ?; o
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版