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

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

[复制链接]
STMCU小助手 发布时间:2021-12-15 11:00
1. 准备工作硬件准备
  • 开发板; E3 X% N! [- V& |5 S
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):5 f. V$ O& W# g  a: O, y( T, g8 o. ?# L
    5 X7 y& g( J5 O2 }$ c

  • Micro SD卡
    8 r2 }8 \! F, X+ W/ O' J小熊派开发板板载 Micro SD 卡槽,最大支持 32 GB,需要提前自行准备一张 Micro SD卡,如图:1 N) c1 C9 h3 A
    % M1 k. k) I& E& q1 A1 F& A


- {! z& {9 b+ B$ ]1 v6 x9 ^6 a* p. F软件准备
  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility;
    # h: n. ?# ?8 ~

    : h1 _! }5 x/ Y  A
9 E3 ~  K3 I, _* c) H! S
2.生成MDK工程! H7 q* F; A) z+ r7 s
选择芯片型号

打开STM32CubeMX,打开MCU选择器:# O+ s* Z) `0 E0 X* T. ~

搜索并选中芯片STM32L431RCT6:* w* t( Z- r6 m* z/ i" Y! @% x1 I

6 `! U0 q* ~: e! P8 T/ f
配置时钟源
  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;
    - a% K0 G/ T6 ]  j- J
    ! |: ?. I5 x2 K5 i, |0 q

这里我都使用外部时钟:


% D- T/ K0 q1 ?- `配置串口

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

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

接下来开始配置USART1:


" Y9 p) U3 _1 Y4 Q* c配置 SDMMC 接口

知识小卡片 —— SDMMC接口

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

知识小卡片结束啦~

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

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


* ?! S" y" ^! y. N配置时钟树

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

0 G0 [# l% V3 s! Y4 X
生成工程设置

3 L! x) a8 b3 T
码生成设置0 ?" M8 q2 U+ [

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

7 }5 m+ d+ C' q  y. g2 k

生成代码

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

8 S' W* o. @$ S

3. 在MDK中编写、编译、下载用户代码! f! q5 |8 ~& t& G
重定向printf( )函数
  K7 A8 W. Y4 x4 J6 `* ~4 u2 O* A1 v
读取SD卡信息并打印

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

  • 卡识别模式
  • 数据传输模式  q6 s# \3 G: A6 k4 a
    4 r& j. D+ N, _

在系统复位后,主机处于卡识别模式,寻找总线上可用的 SD卡设备;同时,SD 卡也处于卡& D& J1 G# r( z& U: u& Y' s
识别模式,直到被主机识别到。

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

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

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

  1. <font color="#000000">int sdcard_status = 0;
    - M. X+ k& g: B9 K6 g# R- g
  2. HAL_SD_CardCIDTypeDef sdcard_cid;</font>
复制代码

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

  1. <font color="#000000">/* USER CODE BEGIN 2 */
    ! L* `! c; o; X" K- x: h
  2. printf("Micro SD Card Test...\r\n");
    9 w& c- u5 t: B
  3. </font>
复制代码


  r  W) C# |& b9 p

/* 检测SD卡是否正常(处于数据传输模式的传输状态) */
- \& v  v/ ?6 l# r) D4 l/ vsdcard_status = HAL_SD_GetCardState(&hsd1);
: K! O/ D& [* c  |) Bif(sdcard_status == HAL_SD_CARD_TRANSFER)
' Z% t, u; s! V: Y6 Y1 \3 ?" {{
- Z6 b; Q! @' K/ x4 lprintf(“SD card init ok!\r\n\r\n”);

  1. <font color="#000000"><span class="token comment">//打印SD卡基本信息</span>
      S$ U& M) X+ M; V9 s8 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>
    % A( g5 j# e/ |) `# c
  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>
    & j  f: U- }- o  ?% ~, }$ 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>
    6 v. T/ b: l4 W1 ~8 K3 E
  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>6 G, X" A% V% T( L2 I
  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>
    ) @! I. x$ M/ J/ g' K, D( w$ Y- W
  7. 7 I% g" {+ {2 p  `
  8. <span class="token comment">//读取并打印SD卡的CID信息</span>& t2 t6 @/ D  X9 B& L% _' a
  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>
    . G# Q$ M- J( Y
  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 {1 ~4 F- g- e

}4 j" n% M5 P2 r8 \( B* o" x
else5 |0 s7 B8 p. Z$ D( {( f8 L
{
" ], W! g' X, Vprintf(“SD card init fail!\r\n” );  W" j0 @  {) P' T! t
return 0;* i  U% A1 A( h+ ~
}
  i% d/ B3 ~0 |4 s$ o/* USER CODE END 2 */

) ^9 r9 q: ^0 ~6 {( P6 o

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

9 W0 l* ^7 H+ f. w8 x

擦除SD卡块数据

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

  1. /* 擦除SD卡块 */
    & k% f* k) z8 x) }: J/ T
  2. printf("------------------- Block Erase -------------------------------\r\n");+ C3 N! [; K7 K1 D
  3. sdcard_status = HAL_SD_Erase(&hsd1, 0, 512);
    . P( S$ p! A; {! m
  4. if (sdcard_status == 0)
    3 j6 z7 G2 w0 U: j# D2 _7 p3 q* v
  5. {
    - V& f* I. O9 O& @
  6.     printf("Erase block ok\r\n");
    , K2 g* g) x7 g) E0 Q( D6 h
  7. }, v# B( e* n8 b4 c% ?! x
  8. else
    9 y/ {! [; l4 P& F
  9. {
    8 M+ M: V1 Z3 S/ D
  10.     printf("Erase block fail\r\n");8 A6 O! Y  T2 |7 L% p
  11. }
    % i1 _, Y8 \1 p
复制代码

! I- R0 a0 j% h# [读取SD卡块数据
  1. /* Private user code ---------------------------------------------------------*/% f% ]7 a# |! ~1 A- U! q5 v/ D
  2. /* USER CODE BEGIN 0 */5 J! T% ~' |. z* Q& j+ b. U- v7 o' P
  3. uint8_t read_buf[512];
    0 B& q* \; \1 Q8 X
  4. /* USER CODE END 0 */3 ^* a7 ~( Q3 w" u+ \9 i, o7 E; n
复制代码

) `" t1 h% |" ]( {1 u

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

  1. /* 读取未操作之前的数据 */; j1 W- w7 l) a
  2. printf("------------------- Read SD card block data Test ------------------\r\n");
    8 c2 b8 X) g/ S; Y5 n: E' L  y
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);
    1 \) P$ p' y" D
  4. if(sdcard_status == 0)
    ( a( `* C* @0 M  r1 N) C( w  T
  5. {
    ) I  t9 G" F7 x4 x' o
  6.     printf("Read block data ok \r\n" );
    $ a/ a; q9 W! n3 E; t% Q% {
  7.     for(i = 0; i < 512; i++), c: @* j& ?( C1 J' y! }! A
  8.     {
    % q$ T; v% m* y$ h; ~! k
  9.         printf("0x%02x ", read_buf[i]);/ y* F6 i/ h7 o, m+ ]: |0 R$ C5 h
  10.         if((i+1)%16 == 0)
      y& ]0 n2 }& w3 t% s
  11.         {$ s+ F7 b6 Q+ Q& J. q* D
  12.             printf("\r\n");0 v7 X- u$ T( X: k. F
  13.         }
    + V. l- V9 y7 K
  14.     }
    0 J! ^  o+ g7 |( ~
  15. }" ?& f, k- R4 X  Y9 {$ x0 x
  16. else
    # a& M& |- W: S( ]2 ^9 |( z
  17. {  k, m0 L8 v* g' S2 T4 r
  18.     printf("Read block data fail!\r\n " );
    - y: L9 G8 ^$ M
  19. }
    1 W8 {% m' X& d" W, M1 s8 k! ]
复制代码
! x+ n3 O) L- V& O" n) C
向SD卡块写入数据

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

  1. uint8_t write_buf[512];
    # i1 o/ u- r9 `- N
复制代码
4 X7 o5 G) x6 v7 I9 G! k+ Y

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

  1. /* 填充缓冲区数据 *// H$ G+ R2 S# X0 Q$ ^" [- J1 m
  2. for(i = 0; i < 512; i++)
    & D/ V5 ~3 t( u/ O( n" y% s* ^
  3. {
    + B: S; Z( E! q
  4.     write_buf[i] = i % 256;4 ]: M( l9 g" n$ R" ^
  5. }0 [# s. `5 f: D6 R+ _# O! w0 ^7 R
复制代码

! z$ ?+ a( V" f  y1 f2 \2 N9 q7 k

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

  1. /* 向SD卡块写入数据 */
    9 i' ^9 u% U1 a7 G$ x6 ^
  2. printf("------------------- Write SD card block data Test ------------------\r\n");
    9 K# B- S/ `/ i2 w6 i
  3. sdcard_status = HAL_SD_WriteBlocks(&hsd1,(uint8_t *)write_buf,0,1,0xffff);, P' S9 i7 H. P" A7 L# C: |3 X  N
  4. if(sdcard_status == 0)
    % |' `6 ]# z& H& R# D
  5. {
    / w# R( A( h1 G' W3 u& @& v
  6.     printf("Write block data ok \r\n" );
    % f, F2 W1 {9 n7 M1 l' R/ f$ J2 d
  7. }
    , _! @8 h! `0 K" u* V5 L9 P
  8. else
    ! y2 ^+ |. t( j: A* I# U% Q& I) N5 W
  9. {2 `, V6 V) I& o1 o' o
  10.     printf("Write block data fail!\r\n " );* r1 D+ c8 Q$ a$ X3 C
  11. }
    6 u3 E0 H3 Z+ \9 J' b5 e" Q
复制代码

( a) _+ h. {' n2 ~

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

  1. /* 读取操作之后的数据 */
    # u+ ~+ I9 e8 e- ^( x* G
  2. printf("------------------- Read SD card block data after Write ------------------\r\n");- b3 {  T" w* j# K: V  m# I' s
  3. sdcard_status = HAL_SD_ReadBlocks(&hsd1,(uint8_t *)read_buf,0,1,0xffff);
    , Y1 Y' m" @3 A* m  I, r
  4. if(sdcard_status == 0)% F, t5 K: [; M
  5. {
    9 C3 |4 m, n# ?$ r0 p
  6.     printf("Read block data ok \r\n" );
    ( m$ |3 `, Q: r' M" B) w
  7.     for(i = 0; i < 512; i++). e2 s* f) Z$ r! l% G
  8.     {
    ( S) V" W6 s3 w: K" O, j% X
  9.         printf("0x%02x ", read_buf[i]);7 I" P" b/ }/ ?1 a6 M' B* x
  10.         if((i+1)%16 == 0)
    * s# c% K* S+ a$ Q- [
  11.         {
    # o: h) N2 Z. K4 [8 v
  12.             printf("\r\n");: b" u% ?2 m5 r+ L
  13.         }
    1 e" W( @, |( X* h) \! z$ u
  14.     }
    . d  F0 ~% z0 J7 G
  15. }
    * ^  t! S7 j6 D) l# m9 _0 A
复制代码
5 i) C7 f6 _& i: |5 ^5 h

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

- |$ T) Y  R& e2 Q

, l0 F3 ]9 N& w/ U  C& b, |

: _/ A$ [' S$ p7 v* N( w


/ z+ j3 T( n, b9 B" j# B% V# w
8 }: ^. L' [7 X0 t& o, n
收藏 评论0 发布时间:2021-12-15 11:00

举报

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