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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
1. 准备工作硬件准备
  • 开发板9 D/ k3 @0 t3 q# |0 a3 p/ J( h
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):' m6 V/ K' _8 Z5 Q
    . `# b) v8 t4 F5 i) ]0 a: L

  • Micro SD卡
    3 e! l/ M6 g1 b* l$ Z8 I  t  U小熊派开发板板载 Micro SD 卡槽,最大支持 32 GB,需要提前自行准备一张 Micro SD卡,如图:$ [, [+ L* _  s/ U/ v

    " R! h/ P; M0 e- r& X, [


0 N+ i7 s. {# q9 |2 ?& |软件准备
  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;
    $ q7 F$ x! W; ?, U* l* I; q

    $ J& X6 ]2 u; P1 K8 d4 i$ t
' o* n. `! {2 S8 O* F) X' s9 d
2.生成MDK工程
, o! h3 r: J0 @' T+ }# r选择芯片型号

打开STM32CubeMX,打开MCU选择器:
  }1 G6 m# {2 R

搜索并选中芯片STM32L431RCT6:" `: ?- h- w! Z9 I

6 a3 L! {4 r4 x' ^3 q7 X, n
配置时钟源
  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;
    8 E* V" u# Q& v. o) H

    ' M$ T+ [, D+ {/ Q& |  U" m

这里我都使用外部时钟:

2 A9 S1 X# M6 e& |1 [1 `1 A
配置串口

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

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

接下来开始配置USART1:


1 n1 G" L9 J% z+ x; [! ?* n! I配置 SDMMC 接口

知识小卡片 —— SDMMC接口

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

知识小卡片结束啦~

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

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


3 a% |3 s6 t, K3 G配置时钟树

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


. y% }! C; D0 d) Y2 G, C, b生成工程设置


- Q) I. J) l7 y
码生成设置9 F6 ]/ q8 I$ f; g" u% Q/ p

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

2 ?1 X6 e" G2 N$ O, S4 [' X, f

生成代码

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

/ e/ ?# G8 O, ~0 ?! o

3. 在MDK中编写、编译、下载用户代码4 H, |! X0 {1 @( t" |( P. q+ R% Y
重定向printf( )函数
5 t; Y6 q! L& g% O, K6 a  A( h6 K8 x6 K
读取SD卡信息并打印

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

  • 卡识别模式
  • 数据传输模式
    6 m- [8 L1 ^; o5 O! y/ L
    , |( I3 S- V8 N

在系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡5 F& j7 n- \) k* s3 T6 ^  F
识别模式,直到被主机识别到。

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

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

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

  1. <font color="#000000">int sdcard_status = 0;
    / |. z/ b8 p% h7 X* n' z
  2. HAL_SD_CardCIDTypeDef sdcard_cid;</font>
复制代码

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

  1. <font color="#000000">/* USER CODE BEGIN 2 */
    ) Q3 i* n; m5 U+ W
  2. printf("Micro SD Card Test...\r\n");
    6 S" a. U6 r( |: Q$ z' j, z
  3. </font>
复制代码

* \# E8 [4 a0 {' U3 N

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */
* P$ |5 n% Z5 L7 D. H- B& isdcard_status = HAL_SD_GetCardState(&hsd1);" _8 v* l  b& E! `6 t
if(sdcard_status == HAL_SD_CARD_TRANSFER)
8 B* q8 o7 E0 \6 H{
0 U" i0 S2 f, p9 b0 j' A0 qprintf(“SD card init ok!\r\n\r\n”);

  1. <font color="#000000"><span class="token comment">//打印SD卡基本信息</span>
    & D) b9 G% @0 @$ _& v4 L, ~' g
  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>7 m0 A' A, ?, c' l! D
  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>( [, r8 g  L! u7 V( j  Z
  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>8 a: V1 r% h: r, }
  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>8 W7 j( |% q0 S
  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>
    . z! q$ x, r1 v% N  t" V
  7. * U+ ]. c' [, ^0 G
  8. <span class="token comment">//读取并打印SD卡的CID信息</span>
    , @- U" L4 @2 k3 x% 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>
    5 z$ [! n2 M  g, l) C4 D" O. X
  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>
复制代码


( O4 w3 A4 |* ]9 o

}
  t2 t: W, K1 n. e% Qelse  M8 k3 G) u2 j' z4 T
{
& ?3 \. e! {& ^# Sprintf(“SD card init fail!\r\n” );9 ^3 @3 ?8 ?; _6 D  U
return 0;6 g- l- F0 f8 @. H7 X( \$ p, \" p
}% q' Z. ]! E" D3 U, J
/* USER CODE END 2 */


6 A( B- V/ y9 E  E! ]: A/ a

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


  T; g* d& g4 l' m4 T) `

擦除SD卡块数据

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

  1. /* 擦除SD卡块 */
    5 l5 f* x% u7 R2 a9 m4 B; u
  2. printf("------------------- Block Erase -------------------------------\r\n");) u! m- ?' Y: I" A
  3. sdcard_status = HAL_SD_Erase(&hsd1, 0, 512);
    1 ~) h2 W; |1 V" \# }
  4. if (sdcard_status == 0)' `% D+ u- y. Z6 T* h7 I' p
  5. {
    / X/ A; M/ O- s( \" A
  6.     printf("Erase block ok\r\n");
    " Q0 d  v: w! K, h3 @/ i) x& Q
  7. }; n2 R& U0 F  E& l0 \
  8. else' q# m, c. d& c4 d, B5 Z
  9. {
    1 i9 y0 C- O- X
  10.     printf("Erase block fail\r\n");
    / K' R6 ?4 i) r$ V6 x9 ^9 [' X
  11. }
    ) M* Y5 {  v5 Y# X
复制代码
( N8 r% \2 v/ E
读取SD卡块数据
  1. /* Private user code ---------------------------------------------------------*/4 l# e+ V7 C& P( ]
  2. /* USER CODE BEGIN 0 */) K* S! R3 U7 d) [) M3 I( N
  3. uint8_t read_buf[512];" D% F6 {  E4 a5 ~* d
  4. /* USER CODE END 0 */* i- ]+ u/ U! D* g  t2 m
复制代码
: P# c! b2 `, N' J1 c! L; @; b

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

  1. /* 读取未操作之前的数据 */% ]) I" @# O+ x4 T9 H' K% b  T% A
  2. printf("------------------- Read SD card block data Test ------------------\r\n");% y7 E4 ~# ?" e& e
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);7 z/ r3 N; G8 V
  4. if(sdcard_status == 0)/ i6 o: B% U% z
  5. {
    / _; B  v( Y+ R+ H
  6.     printf("Read block data ok \r\n" );
    * W' [6 l) j! r/ y2 B! E
  7.     for(i = 0; i < 512; i++)
    ! j- K. @+ k& Y# ~
  8.     {
    1 {$ D7 \3 J% x; D# u* K" d2 N4 J
  9.         printf("0x%02x ", read_buf[i]);
    + v( ^7 w0 o# N( p0 p: X
  10.         if((i+1)%16 == 0)+ y; g6 ?/ {1 ^
  11.         {) F. e8 z- @( O! S: F# W* V1 b
  12.             printf("\r\n");
    # a0 e" {' V3 M
  13.         }! O2 N( E# x. H4 n% _
  14.     }
    / G" _+ ~% d! x9 n' z
  15. }, s3 M: {0 {- ]0 E5 r: r: @
  16. else2 s& E2 G- I$ a. y+ W8 q
  17. {. w" b1 l/ w* ]0 ]
  18.     printf("Read block data fail!\r\n " );8 c! Y7 H0 L5 E' _- a% T3 F
  19. }
    $ m2 h+ E1 q6 F6 [( F  l% G
复制代码

  a) |8 O! N6 @向SD卡块写入数据

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

  1. uint8_t write_buf[512];
    , I: R% `1 G3 v2 H2 G
复制代码

( S$ s+ T1 O! \" |  H! j# {

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

  1. /* 填充缓冲区数据 */
    / s; J9 S/ ~) h. }
  2. for(i = 0; i < 512; i++)
    7 a$ }: ~( p) n& m& q" \$ ?& ]
  3. {% g0 b" P( D" N; J6 v
  4.     write_buf[i] = i % 256;
    ' ^3 ?7 y9 V$ l$ l0 j& j
  5. }
    0 O+ F, o1 F; Z& c/ k6 R& B4 i
复制代码
. F2 u( K, ]. j; C

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

  1. /* 向SD卡块写入数据 */
    0 ~, u! q  O& p0 R$ I
  2. printf("------------------- Write SD card block data Test ------------------\r\n");
    7 W3 E5 j" v; u
  3. sdcard_status = HAL_SD_WriteBlocks(&hsd1,(uint8_t *)write_buf,0,1,0xffff);: Q1 O: `' e! `; O& N7 i8 _+ ]1 g
  4. if(sdcard_status == 0). ]+ l/ u: Z! ]- Q, W) q+ Z
  5. {
    / U+ Z9 \$ k/ K4 `, r
  6.     printf("Write block data ok \r\n" );
    % F6 o( a+ O2 K+ h9 P" B" A
  7. }9 t( l3 {# ^+ m* w# ?# \# Z: l
  8. else
      i6 {$ Z7 w& e, c4 j
  9. {; X: @9 U/ ?7 ?8 s  \
  10.     printf("Write block data fail!\r\n " );
    6 y, b$ }' S" |/ L6 ?- h7 z. U4 o
  11. }
    9 u( V5 M7 b$ I: o; i% D& p
复制代码

* W$ e4 L( L* V4 t- C  \3 C

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

  1. /* 读取操作之后的数据 */9 h6 W# F  i% o6 J& S4 b
  2. printf("------------------- Read SD card block data after Write ------------------\r\n");+ z0 G& F. r4 [6 [; h
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);' P; d/ f3 r" y) [5 y1 T
  4. if(sdcard_status == 0)
    . L3 N& y0 n' C  e# W* f1 k
  5. {
    & k( z4 Y) G8 \) }0 P% A
  6.     printf("Read block data ok \r\n" );
    . J# v- ?& |9 V1 s. O1 z; \+ F8 i
  7.     for(i = 0; i < 512; i++)
    ) D( ^- g  k& h) P  ~9 j& |
  8.     {; y% |: j5 n- f7 M8 ~( k8 V; S) q, ~
  9.         printf("0x%02x ", read_buf[i]);
    1 ~/ G3 f; p$ b0 j9 M) O, y
  10.         if((i+1)%16 == 0)
    5 u, C+ Y& w+ q
  11.         {- R9 G9 g* Q1 o/ C5 ^* v( |
  12.             printf("\r\n");+ F- c- e: k9 R% i
  13.         }
    & C% R( Q1 z& H. |% C1 N, r
  14.     }/ ?% C5 p6 C* J
  15. }
    6 W' i" T6 Z; _$ |, f
复制代码

5 y  p7 `5 Z' O: O* u4 K

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

1 x: A* J3 x, i

8 H% e+ p. u5 e& ?

4 C( r- Q/ o7 W9 H. Y& U3 r* y


" D% m; I# a6 j$ p  W# a2 C" x2 D# \7 o( A2 S7 H! [
收藏 评论0 发布时间:2021-12-15 11:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版