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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
1. 准备工作硬件准备
  • 开发板  t  T4 F. C" \7 m5 N& J. T6 \* H
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):4 E+ o) R5 f6 N% T5 a
    9 P5 u% H$ {" m% R0 k! v

  • Micro SD卡
    1 g4 X. s, g* E" `, X" z! `# ^& F小熊派开发板板载 Micro SD 卡槽,最大支持 32 GB,需要提前自行准备一张 Micro SD卡,如图:/ J" f+ ]& r: B$ q+ Z

    2 V! L* Q) }8 p$ ?


) m, A6 r3 s7 R' Y$ }2 a软件准备
  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;
    / H. [& Y' j* G& V! m0 ~0 |9 `) W' X/ K

    ) J! d6 S' }8 R/ r8 G
8 u- S* M3 `' A# j) J( C
2.生成MDK工程
2 _7 ^6 ~6 ]" `# ?选择芯片型号

打开STM32CubeMX,打开MCU选择器:- {" h4 S* K/ ^# R  T

搜索并选中芯片STM32L431RCT6:4 H, u$ g) e  U6 v


3 b2 ?; I) g6 ]8 M配置时钟源
  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;+ }0 }1 \' k( P$ S6 v8 S0 S& C
    3 A. S& K) i2 e3 r2 {

这里我都使用外部时钟:


( R2 Q3 E9 }' b' M0 I配置串口

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

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

接下来开始配置USART1:

0 e" \! J1 A  l; ~8 g
配置 SDMMC 接口

知识小卡片 —— SDMMC接口

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

知识小卡片结束啦~

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

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


$ h$ W/ j% J, _: q配置时钟树

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


- A% @* ]% s8 `& f0 K7 y( ^2 P6 b3 A生成工程设置


; j  V3 K5 }/ I  F0 s3 u0 ]- b+ H
码生成设置; o4 c9 X. X9 d- m' T* J

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

; U& X1 g: y+ J

生成代码

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


5 q, V  Y: ?% F# n

3. 在MDK中编写、编译、下载用户代码
- K( u* x. n) l2 V& Q重定向printf( )函数
2 U% \/ u0 T( }, J. ]
读取SD卡信息并打印

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

  • 卡识别模式
  • 数据传输模式
    ; ?7 \( E, r3 e/ f5 x9 {

    + [# P1 b( U' }/ h4 C3 |& O. S

在系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡/ L, U) p( p4 J' e# L4 f
识别模式,直到被主机识别到。

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

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

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

  1. <font color="#000000">int sdcard_status = 0;- ^* Y8 X( s7 b
  2. HAL_SD_CardCIDTypeDef sdcard_cid;</font>
复制代码

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

  1. <font color="#000000">/* USER CODE BEGIN 2 */
    : P: c) R( I6 P2 f  u
  2. printf("Micro SD Card Test...\r\n");
    * X; G# R' ^! c) |) p
  3. </font>
复制代码

5 J7 f) R; Y6 C5 |; S- r

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */
! G) L$ ~) G  F* usdcard_status = HAL_SD_GetCardState(&hsd1);) q1 D, j( X3 B$ ~) X- p& z
if(sdcard_status == HAL_SD_CARD_TRANSFER)& D" l6 L  G/ {5 r4 R
{
1 v0 I) T3 q, _printf(“SD card init ok!\r\n\r\n”);

  1. <font color="#000000"><span class="token comment">//打印SD卡基本信息</span>+ t7 E, K! ^- r# l( X- P
  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>
    % c# Y# s3 }4 A5 i. Q) Z
  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>1 W* S1 S9 Z  [6 Y9 b, I; `# r- v
  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>
    % k) q. ]6 D; D# v+ m/ Y
  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>
    , A$ Y) G( D: G2 \! {* i& X3 K( `1 d
  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>
    ( x) I  t- |+ t2 v5 ]% s# z

  7. 1 N) b: k8 b6 d) _$ [. ^: H; T4 W  Q& x
  8. <span class="token comment">//读取并打印SD卡的CID信息</span>) m; }$ w3 N% K* f) {; u3 Y7 X
  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>, W( G# w$ h) ^$ ^! n
  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>
复制代码

1 X! |; ]) ?' j4 e+ d, y! [# G/ m

}
/ N6 J9 d& ]& q* I# Q& [else
. I' Z  P7 Y$ o4 E{% d( I; F/ T. Z. \6 A, O
printf(“SD card init fail!\r\n” );& T  I% R# M2 Y% `* b
return 0;; V% l  O. E6 ~# \
}
# D( V+ c( l) E/* USER CODE END 2 */


* a# s( e$ X& g3 U! g

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

1 l3 c4 }/ ]3 k+ p# N! Q2 h. ^7 r

擦除SD卡块数据

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

  1. /* 擦除SD卡块 */
    ' `& K0 l$ G6 e: X- _% v/ G
  2. printf("------------------- Block Erase -------------------------------\r\n");
    3 B6 M4 N) r- u0 }) `3 Y/ {# s2 M
  3. sdcard_status = HAL_SD_Erase(&hsd1, 0, 512);
    0 v, }6 j8 W1 V$ C6 {! r
  4. if (sdcard_status == 0)% \$ N7 m+ A  p; w+ U. n
  5. {
      ]7 J% c: l* c* O* N9 [
  6.     printf("Erase block ok\r\n");
    & U. Y8 ^6 q  j
  7. }
    5 \  v# t7 u1 q& w: h% i2 K
  8. else
    ) j1 f  J: T8 \* {. c0 ^" g" J
  9. {1 c0 w; G7 @. _- i6 @
  10.     printf("Erase block fail\r\n");
    ; a: ], E, r2 s- C7 E2 {- t+ X
  11. }+ a5 g) j: Q( _: I' z2 B+ w/ n
复制代码

/ u* G0 w0 v1 D" P读取SD卡块数据
  1. /* Private user code ---------------------------------------------------------*/
    & ^$ M! R' X/ {7 g
  2. /* USER CODE BEGIN 0 */
    ! I6 Q' \: u/ V& z9 ?- s( k
  3. uint8_t read_buf[512];
    4 Y6 u; ~' \+ P) t$ N3 I! D, P
  4. /* USER CODE END 0 */
    ; t+ Z" `8 y# t7 F/ l, Y& c
复制代码

5 N+ o1 U* N) Q+ G9 W. z

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

  1. /* 读取未操作之前的数据 */# t$ [7 x1 u/ l) }
  2. printf("------------------- Read SD card block data Test ------------------\r\n");
    6 A* e( E9 h5 w) c9 Y' a& z
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);
    6 y, u1 `  J2 z& ?9 L, [
  4. if(sdcard_status == 0)& ]2 S: T+ x+ ^  d
  5. { * l, w# B% l& x6 Y
  6.     printf("Read block data ok \r\n" );/ m: }6 G: W" M
  7.     for(i = 0; i < 512; i++)" q4 K  g% V5 Q5 i; l$ q1 J0 y
  8.     {
    3 Y2 ^& N9 ?( _$ a
  9.         printf("0x%02x ", read_buf[i]);. H9 ~1 g! T, I% L$ Z
  10.         if((i+1)%16 == 0)
    1 X) _3 {+ w5 W) Z' j7 w
  11.         {
    ( {3 a6 U0 K, k
  12.             printf("\r\n");* ^- Q1 Q' b' H; o' W: S- p
  13.         }9 V4 R8 j6 l4 G8 u: Q- \
  14.     }5 K/ n+ q/ {4 v' T
  15. }
    2 @- I# {+ @* |) O5 W0 Q9 a: A6 m
  16. else/ o6 a2 M+ e1 A* t# W
  17. {
    . i2 K! G1 ^# ]2 y( C2 B; i, N
  18.     printf("Read block data fail!\r\n " );+ q4 E6 j' T' O7 Z! ?* N- T# {
  19. }
    6 s& _! b5 X- J# \* {' ~% q& a7 N
复制代码
( L7 u( t% D$ S4 f4 A
向SD卡块写入数据

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

  1. uint8_t write_buf[512];
    . ]6 C& O' D1 u$ j, d
复制代码

1 d! F% `# E9 u) S

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

  1. /* 填充缓冲区数据 */4 I1 J9 M/ d& n6 Z# B
  2. for(i = 0; i < 512; i++)( S& T5 D' f! y8 y
  3. {
    7 R& {8 u; t% a
  4.     write_buf[i] = i % 256;( l, _2 `+ j' R( u" _
  5. }
    5 e9 k9 f6 N7 K" s% \/ `
复制代码

' d5 |! A4 q) A" @) p

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

  1. /* 向SD卡块写入数据 */8 p0 h3 ]( C" [6 F! ^8 v* b
  2. printf("------------------- Write SD card block data Test ------------------\r\n");. `& a$ R1 Z( T- U; M
  3. sdcard_status = HAL_SD_WriteBlocks(&hsd1,(uint8_t *)write_buf,0,1,0xffff);
    8 l2 u* l' T- m6 @, m  c5 A
  4. if(sdcard_status == 0)
    1 c5 t$ e/ C" P  {# I; e
  5. { 7 N: z1 Y; C9 X+ J. x9 Q
  6.     printf("Write block data ok \r\n" );1 f+ R) c/ a& b5 C
  7. }* e) w. x2 a$ B; s: ]; D0 c
  8. else
    , u$ d7 W1 c; [5 s
  9. {
    5 D. Z0 t, @$ a, `
  10.     printf("Write block data fail!\r\n " );
    * Z, y4 ^! r9 Y* M; W4 z
  11. }
    - S0 a! r3 |7 A$ R
复制代码
, {. D  s& H+ o( i& h

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

  1. /* 读取操作之后的数据 */. N6 I3 L- I4 h/ T8 @9 T2 y3 I
  2. printf("------------------- Read SD card block data after Write ------------------\r\n");
    ' `) D3 [- [, w2 ]1 V8 S
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);5 i, ?1 L% e2 W* H" ]" z
  4. if(sdcard_status == 0)4 r4 H0 h2 R9 ]" E, v# @
  5. {
    3 h1 D7 i% M: l9 K- e5 b
  6.     printf("Read block data ok \r\n" );
    ( Z" S! w  K4 C) o
  7.     for(i = 0; i < 512; i++)! G8 w  n5 F$ y
  8.     {
    5 u5 G$ K$ t- i. u. w
  9.         printf("0x%02x ", read_buf[i]);
    * _- @' f- `' [' H: }( F
  10.         if((i+1)%16 == 0)
      m8 M6 T- F; d8 Y. K6 u' I
  11.         {
    1 L+ }! d0 Q9 c- C5 d+ ?" Q
  12.             printf("\r\n");
    ; }  ^3 }: C+ R5 l  X
  13.         }
    6 R6 m3 q' ?; E8 q
  14.     }
    7 X. d7 a) e# v
  15. }
    2 O8 |' u  i% j( T4 K
复制代码
3 A: a" [! u6 t+ X) P/ E" q  o

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


5 s  a/ c" r+ n& e- k5 w8 t

# k$ u8 @, M6 ^6 L  g& T+ p7 ?


# j! v1 V4 O0 P6 R- z$ @- O


" n2 L( L2 A# X8 {* K% e% w: C* R7 Y
4 g4 n. [& b0 ]8 O
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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