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

STM32G0开发笔记-Platformio+libopencm3-SPI接口SD卡使用

[复制链接]
STMCU小助手 发布时间:2023-2-22 17:41
使用Platformio平台的libopencm3开发框架来开发STM32G0,下面介绍SD卡模块的使用方法。
( u; J& n6 {4 H0 ~- ?" t
1 新建项目
  • 在PIO主页新建项目spi_sdcard,框架选择libopencm3,开发板选择 MonkeyPi_STM32_G070RB;
  • 新建完成后在src目录新建主程序文件main.c;
  • 然后更改项目文件platformio.ini的烧写和调试方式:
    # Y9 s5 \. y$ C; u6 m; B& e
  1. 1upload_protocol = cmsis-dap
    3 x9 `& V  [1 r4 M% e
  2. 2debug_tool = cmsis-dap
复制代码
4 y: R  y- J7 w$ ^+ \9 c

/ x: I5 [9 \  J/ y4 f" ]. \
2 编写程序2.1 加入FATFS库
  • 工程目录lib下新建fatfs文件夹;
  • 然后将fatfs源码的source目录下所有文件放置到工程的lib\fatfs目录下;
  • 将diskio.c文件移动到src目录下,这个文件是需要我们实现的底层接口;

    ! Z0 [4 R7 E9 K! w% V
2.2 实现SPI接口的SD读写
在src目录下新建spi_sd.h 和 spi_sd.c 文件,现在目录结构如下:

# v0 L, C) A1 X3 Z- f/ G* Y( e! Y0 C5 v
微信图片_20230222174036.png
0 P  y: S% \7 }
# o& m+ W$ e0 W8 `* X5 v. m
  • spi_sd.h 头文件
    . h1 A4 m/ D  }3 g5 i" K5 R) M
  1. 1/**$ k) l6 l/ D/ h  m
  2. 2 * @file spi_sd.h9 ~, r, \; X. ^' U+ v5 j
  3. 3 * @author MakerInChina (makerinchina.cn)
    / G  ~, h' e8 y4 N+ E+ ^, ^
  4. 4 * @brief
    + W) g1 O" _: `% H9 D
  5. 5 * @version 0.01
    7 O: {0 h2 x' _6 K
  6. 6 * @date 2022-09-18& Z# U; s# h' ?' y
  7. 7 * 2 L9 ~3 S5 Q9 b
  8. 8 * @copyright Copyright (c) 2022; J' H3 @& |# A5 b
  9. 9 * 8 K3 a; [  A+ A& c" u: f# R: l/ s; [
  10. 10 */
    ' ^1 l( ^" A* A9 _8 U! g- }% s
  11. 11
    0 M* a5 o6 k( M' z/ `" f& U
  12. 12#ifndef _SPI_SD_HEAD_H_8 M; d. }/ A6 {; l2 v# o+ j- p
  13. 13#define _SPI_SD_HEAD_H_
    * H6 _% ^2 w4 e4 s2 W1 B
  14. 14$ \- Z  p9 ~1 W. l2 p5 W
  15. 15#include <stdint.h>; u4 `+ r% k- J; B4 u; N
  16. 16* d0 F6 L+ K$ m$ P3 A2 b
  17. 17/**% x/ z2 _1 w. K
  18. 18 * @brief init sd card+ a2 W+ J) ?- y, u  J/ e% T
  19. 19 *
    - `% A, S( _) i
  20. 20 */1 {# X5 G3 Z& v& K6 A" g- ]
  21. 21uint8_t spi_sd_init();, ]+ U  L4 a% Y) i: m  L0 e
  22. 22. _9 I6 V% M# ]" g5 B
  23. 23/**
    ) H/ A* C7 w+ L3 {
  24. 24 * @brief spi read sd5 c) v; ]4 J' V- `9 Q2 J0 P
  25. 25 *
    - s* Y( m, N. i9 T% m# H0 ^+ z
  26. 26 * @param buff 3 D/ a, }$ G. F* m6 V, R4 n! t
  27. 27 * @param sector % b+ z+ E; q& M( a! u
  28. 28 */6 Q6 S$ n* E  `; h- y3 d
  29. 29uint8_t spi_sd_read(uint8_t *buff, uint32_t sector);$ t( T0 Z8 o9 W# W4 @4 p
  30. 30
    & O& e% t4 B. ?9 G. S8 u
  31. 31/**
    + ^/ k$ {: k; g7 U; d
  32. 32 * @brief spi write sd
    + o! I! \. Y; Q/ R  p
  33. 33 *
    0 [( ~7 J' _+ `- c% J) r* ?/ O
  34. 34 * @param buff 4 U! K$ l" M7 D0 R- _7 Z" G" f
  35. 35 * @param sector 3 N8 I" j8 F* R
  36. 36 */
    4 I  q" }6 U( o* T* i1 O- g
  37. 37uint8_t spi_sd_write(uint8_t *buff, uint32_t sector);: L$ G; ?) J) I# ~
  38. 38! p* E0 r8 `* I
  39. 39#endif //!_SPI_SD_HEAD_H_
复制代码

9 c, j, ?/ F9 O6 @" T5 h
! s- m) t1 P6 _
  • spi_sd.c 实现
    - T6 `, R, U- N6 K( e0 e* e6 N
  1.   1/**
    ) E: x" X3 r% D% n, u2 Z6 k
  2.   2 * @file spi_sd.c
    + K( }' Q' s# K7 f2 O
  3.   3 * @author MakerInChina (makerinchina.cn)
    6 |# J1 o$ _4 A% f9 H
  4.   4 * @brief
    1 v0 S6 e% }: p7 _/ m$ y
  5.   5 * @version 0.011 }7 @0 d9 ]% \+ H; V) H: K
  6.   6 * @date 2022-09-18
    ; @2 p- w: F: R7 }
  7.   7 * 5 d! ?6 N/ |, ]. t! X( n  @
  8.   8 * @copyright Copyright (c) 20228 o0 ^5 B4 ^% J9 D, H. p
  9.   9 *
    ( W) b( U0 i" u" x
  10. 10 */
    1 J( j- ?9 h# A
  11. 117 X: y. O% K1 c4 L2 v. N" {) b
  12. 12#include "spi_sd.h"4 d9 K: r  H! Y* Q; g
  13. 13* u9 w, n8 R" o8 n8 I
  14. 14#include <libopencm3/stm32/spi.h>
    8 J  b: }1 T4 ?# Z9 c/ z
  15. 15#include <libopencm3/stm32/gpio.h>
    , F( E& Z, T. W9 J' S9 g0 v
  16. 16
    $ B) g0 b, w) G6 }: m# N* Y4 K
  17. 17#define SDSPI    SPI17 Y% r4 E/ t( n$ \: v% F. L
  18. 18#define SD_CS    GPIO4
    + K: I- H  C4 z) I
  19. 19#define SD_PORT  GPIOA
    ( u4 I; h* _( U3 P& O; ^
  20. 20' ^& m6 N9 A' j4 a
  21. 21#define spi_cs_deselect()   gpio_set(SD_PORT, SD_CS)1 J$ V/ J% t3 d7 I' E
  22. 22#define spi_cs_select()     gpio_clear(SD_PORT, SD_CS)1 U/ w$ r5 r$ `6 B7 \/ R
  23. 23! t% [* K$ w1 x) ]' D* U
  24. 24
    2 F& j7 ]7 ^" E- W; @6 f
  25. 25/* Definitions for MMC/SDC command */2 R* Y% y$ \7 \9 J; u, Z7 N$ g
  26. 26#define CMD0    (0x40+0)    /* GO_IDLE_STATE */
    0 }' s7 \& W! c  _' w, p- J3 ?
  27. 27#define CMD1    (0x40+1)    /* SEND_OP_COND (MMC) */
    * \+ J) }0 F) k! x
  28. 28#define ACMD41    (0xC0+41)   /* SEND_OP_COND (SDC) */9 ~1 G) N) a0 t& S& F
  29. 29#define CMD8    (0x40+8)    /* SEND_IF_COND */
    0 i0 e$ B! [; g  @
  30. 30#define CMD9    (0x40+9)    /* SEND_CSD */& G7 r- z0 x; G  p6 G. h
  31. 31#define CMD10    (0x40+10)   /* SEND_CID */$ l( h" N- E- w* Y0 j0 ^0 d
  32. 32#define CMD12    (0x40+12)   /* STOP_TRANSMISSION */
    + a% x+ `! q4 A- K; D  u* z
  33. 33#define ACMD13    (0xC0+13)   /* SD_STATUS (SDC) */6 U: p# F( z5 G# j1 f# v# d3 w1 d; O
  34. 34#define CMD16    (0x40+16)   /* SET_BLOCKLEN */! S" w! _9 I3 w0 Y$ o
  35. 35#define CMD17    (0x40+17)   /* READ_SINGLE_BLOCK */
    7 K0 p7 s- \+ a  H5 d; z
  36. 36#define CMD18    (0x40+18)   /* READ_MULTIPLE_BLOCK */
    6 N) a" G5 _2 b. b+ u4 e
  37. 37#define CMD23    (0x40+23)   /* SET_BLOCK_COUNT (MMC) */( J/ l$ P. D. _5 F& E0 E
  38. 38#define ACMD23    (0xC0+23)   /* SET_WR_BLK_ERASE_COUNT (SDC) */
    6 r1 b! ?  D% D& m5 g) d$ Y, _
  39. 39#define CMD24    (0x40+24)   /* WRITE_BLOCK */
    ) f6 P" G) |  N5 n; \
  40. 40#define CMD25    (0x40+25)   /* WRITE_MULTIPLE_BLOCK */( H& Y/ U3 o# \  j8 `; g
  41. 41#define CMD55    (0x40+55)   /* APP_CMD */
    ' L- b' Y- \# w9 R: p% v5 F7 g" W$ t
  42. 42#define CMD58    (0x40+58)   /* READ_OCR */5 u9 {/ t4 J' }* p# ~
  43. 433 G0 P8 P) S) a2 I5 q8 k
  44. 44#define CT_MMC 0x01 /* MMC ver 3 */' Z4 q0 w9 t* e' U$ e
  45. 45#define CT_SD1 0x02 /* SD ver 1 */
    7 h7 d! z: z- ^
  46. 46#define CT_SD2 0x04 /* SD ver 2 */- x4 l8 R" p' A; q
  47. 47#define CT_SDC (CT_SD1|CT_SD2) /* SD */6 p, G. v4 C" j
  48. 48#define CT_BLOCK 0x08 /* Block addressing */
    / v# k* A) d3 E$ R5 L7 y
  49. 49. }, r+ y8 m* r) w' V: i
  50. 50static uint8_t spi_read_write8(uint32_t spi, uint8_t tx);
    6 V/ B" T& u0 B
  51. 51static uint8_t wait_ready(void);  N" s4 C( ]9 `% O
  52. 52static uint8_t send_cmd (uint8_t cmd,uint32_t arg);" v) |1 E9 N: Z! \1 A( ~* ?
  53. 53static void set_spi_slow();
    ( ?: u, _9 p. E) _
  54. 54static void set_spi_fast();
    3 c# }3 S: \0 }. N0 @# _; \+ z
  55. 55
    ! f4 h  A5 }; R# @
  56. 56/**5 @' G" C8 R' o
  57. 57 * @brief init sd card
    + G. o$ I8 j- `3 h) a$ f! P
  58. 58 *
    6 L* m( M) s9 G! b  j: H
  59. 59 */* l' o5 d, e$ f1 |: S! w
  60. 60uint8_t spi_sd_init()
    2 H6 v7 n8 A3 d. U
  61. 61{5 [9 Q+ Q. P8 G9 T
  62. 62    uint8_t n, cmd, ty, ocr[4];
    # O5 ^" \7 ?8 ]3 c* v0 b
  63. 63    uint16_t i;6 n4 W8 C* J/ y! v4 M5 Y
  64. 640 b$ a( d. u* t, t- j9 F$ e1 |
  65. 652 Y6 `" m% t, x+ t  X3 S
  66. 66    //init with low speed
    " q; A! A1 J( [' K) g
  67. 67    // set_spi_slow();2 d3 w) \2 X* f+ `6 g, n
  68. 68+ O* a6 E& B, s
  69. 69    spi_cs_select();6 k1 a- c. I, W5 }' C. F" j6 m
  70. 70) ^8 A9 T9 I& G9 Y( s; }% p
  71. 71    for (n = 10; n; n--) spi_read_write8(SDSPI,0xff);   /* 80 dummy clocks */: z2 Z* O3 [" i8 ?9 [, y
  72. 72
    * o1 e# C0 i. h' s& X' c+ r7 d
  73. 73    ty = 0;3 E) K% ~: x( _2 M5 \# X
  74. 74
    7 t' r8 i# ?4 B6 t0 A* y
  75. 75    /* Enter Idle state */
      f* @" d- d* z( X. j3 [
  76. 76    ty = send_cmd(CMD0, 0);7 r4 K3 g1 _. W4 B3 f
  77. 777 R! \/ s6 ~' H1 ^" Y* ^$ O
  78. 78    // printf("  > enter idle:%d\n", ty);# x9 j  ~- Z) X+ K1 q$ u0 h
  79. 798 O* u: {, ^7 f2 h
  80. 80    /* Initialization timeout of 1000 milliseconds */( O, p+ B% t# A& F0 f0 P8 I
  81. 81    /* SDHC */
    2 z+ V$ N# T4 a% p0 O' P. \8 \
  82. 82
    5 ?) ?: ]7 k! J  {2 `6 z
  83. 83    if(ty == 1){& H) d# k- b: r* [, |
  84. 840 `) ~: Y8 G% c0 K
  85. 85        if (send_cmd(CMD8, 0x1AA) == 1){ /* SDv2? */
    7 L3 Y" t  ^: {- F! Y  ~
  86. 86        /* Get trailing return value of R7 response */" I" _2 ~6 C; R# {: A8 |
  87. 87            for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);" {8 |' O5 w- f; v1 B: {, B
  88. 88            /* The card can work at VDD range of 2.7-3.6V */+ p0 B- N7 `% ~( b
  89. 89            if (ocr[2] == 0x01 && ocr[3] == 0xAA){# z  C# R* t6 E1 G, t. k! S
  90. 90                /* Wait for leaving idle state (ACMD41 with HCS bit) */2 l" F& h5 f# c/ U7 J8 R7 ~  [+ A
  91. 91                i=0xfff;
    * ~$ v& k, A0 ^+ m2 y1 H7 ~
  92. 92                while (--i && send_cmd(ACMD41, 1UL << 30));
      `& A  W4 @% D  S, c& e
  93. 93                if (i && send_cmd(CMD58, 0) == 0){
    % y2 r* t4 o# N9 g9 \
  94. 94                /* Check CCS bit in the OCR */8 V) D% s8 h2 t- ~+ ~
  95. 95                    for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);7 l; m( d3 P# M! N
  96. 96                    ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;4 p- f  k9 l7 B& N) K: S
  97. 97
    / G( M- |+ z3 p) B- @1 k
  98. 98                }5 B0 M: v3 |) y# e7 Z
  99. 99            }
    , h4 A# a. N" x5 N5 `
  100. 100        }  else {    /* Not SDv2 card */6 F5 {6 I2 U# ~  ^7 {% Z' F8 V
  101. 101            // if (send_cmd(ACMD41, 0) <= 1)    {   /* SDv1 or MMC? */
    0 v9 k! T8 f+ J
  102. 102            //  ty = CT_SD1; cmd = ACMD41;  /* SDv1 (ACMD41(0)) */4 I- v  w; |2 ~) Z# s7 y2 L" }; e
  103. 103            // } else {; F- `: n6 W* ]3 F) }: h
  104. 104            //  ty = CT_MMC; cmd = CMD1;    /* MMCv3 (CMD1(0)) */
    ( D, q+ f- m& Q' U; s
  105. 105            // }
    : ~  G8 @" \$ W* M0 \; }
  106. 106
    , _( X/ W0 y. l# D
  107. 107            // while (SPI_Timer_Status() && send_cmd(cmd, 0)) ;     /* Wait for end of initialization */
    , n9 \" R8 q1 z6 A# @
  108. 108            // if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0)    /* Set block length: 512 */
    ( M/ q" d2 ^& k# H7 _
  109. 109            //  ty = 0;2 R3 o7 L; p. @5 a; o
  110. 110        }
    : }$ Z" R( r1 c5 @+ `: h
  111. 111" f; ~0 [4 g$ ?
  112. 112    }
    2 Q" i. f: p9 l7 O/ c0 O  O" H$ s
  113. 113    //CardType = ty;
    % N1 N9 P9 `0 N( u
  114. 114. C, w+ ?' }) Q3 D7 r4 G! P
  115. 1150 z, }. [/ ~( c9 Z: S  s3 w. s
  116. 116    spi_cs_deselect();; e2 [! F! h6 ^; h+ y- l
  117. 117    spi_read_write8(SDSPI,0xff);/ s& o& ~4 t$ k/ q$ u9 f8 F, Y7 ~
  118. 118    while (SPI_SR(SDSPI) & SPI_SR_BSY);- p1 B% V6 V$ B' U5 L- O5 Z
  119. 119
    1 E9 e7 @, S! O# `4 n" R' _
  120. 120    set_spi_fast();
    ( N+ c; u: K" k: X6 Z1 s) ^( t9 E
  121. 121
    " r# O* {. a4 M( M' }" w1 T
  122. 122    return ty;
    1 Z% ~9 Z# X' ~0 c( p- Z
  123. 123}
      J) u! \% s' ^  j" ~/ k: u6 M
  124. 124
    : \( N( ?% y  r: k
  125. 125/**# C' \& L  y. g9 W7 O/ q* H- G! \
  126. 126 * @brief spi read sd
    3 H3 F0 {( I! J& s" T
  127. 127 *
    1 [! F! g2 v' X: R6 a1 o( ?7 \
  128. 128 * @param buff
    , E* m5 t5 t# m1 U7 d
  129. 129 * @param sector , C  t( t# a8 g7 k( s1 M  q2 R
  130. 130 */1 ?( g7 y) _! ^$ A# ?, r
  131. 131uint8_t spi_sd_read(uint8_t *buff, uint32_t sector); b+ v% N2 Z4 `! Y6 t, `
  132. 132{
    3 N# J1 k" Y7 S9 h
  133. 133    uint8_t result;( h" Z# x7 l# i0 Z
  134. 134    uint16_t cnt=0xffff;0 Y0 _6 w' A4 k; B* C
  135. 135    spi_cs_select();   
    # a# B8 i/ H# w) E! o
  136. 136    result=send_cmd(CMD17, sector); //CMD17 даташит стр 50 и 960 i7 v4 L0 {) m( @
  137. 137    if (result){spi_cs_deselect(); return 5;} //Выйти, если результат не 0x00
    . Y: Z7 [  \6 t/ W
  138. 138
    9 {3 U/ U; ~7 [' P. U  D  D
  139. 139    spi_read_write8(SDSPI,0xff);
    " W, `5 I  ?6 _: K* c
  140. 140    cnt=0;
    . R2 T5 d, m. P3 M6 m) i
  141. 141    do result=spi_read_write8(SDSPI,0xff); while ((result!=0xFE)&&--cnt);
    8 G9 e1 B0 d  M) X( \- e
  142. 142    if(!cnt){spi_cs_deselect(); return 5;}
    - s6 J- O; Q5 H3 [7 m  ^
  143. 143
    - O1 W# P1 P+ q; L* @3 ]" Y
  144. 144    for (cnt=0;cnt<512;cnt++) *buff++=spi_read_write8(SDSPI,0xff); 8 X6 |4 v% N% G( K
  145. 145" N. q  E8 d7 m( E
  146. 146    spi_read_write8(SDSPI,0xff);
    + Y' a9 D6 c7 y3 N3 \4 J
  147. 147    spi_read_write8(SDSPI,0xff);2 \" m7 Q0 W/ _: F# x
  148. 148    spi_cs_deselect();  w+ [/ v6 Y- `: J' F5 F0 z% ~! _
  149. 149    spi_read_write8(SDSPI,0xff);
    8 y7 {( B  j5 e' s
  150. 150, N) z- H$ u4 d- D6 C. [
  151. 151    return 0;
    + G% L+ q) f+ N& I* t
  152. 152}4 z9 S. x% l- q$ _+ @& j- q6 p
  153. 153! T$ A4 W# }  a
  154. 154/**
    ; H0 n" V! O7 N
  155. 155 * @brief spi write sd
    , y- N& i  c. }
  156. 156 *
    ; y, U  Y8 r! X2 u( W
  157. 157 * @param buff
    & b; m$ J/ _5 A9 U5 Q6 x- J6 Z
  158. 158 * @param sector   R. s& f" u$ c1 _# j; Z
  159. 159 */) H- g. b/ n) ~: H9 |# j# w/ L
  160. 160uint8_t spi_sd_write(uint8_t *buff, uint32_t sector)
    6 S, u  h! u( o( u! J# j3 `
  161. 161{( {$ U! A! O9 @
  162. 162    uint8_t result;
    4 P2 E1 ~! N9 R: O
  163. 163    uint16_t cnt=0xffff;$ O2 g6 W7 G) B0 J% f
  164. 164    spi_cs_select();9 Q- W1 @3 Q) E' L% Q) ^1 b
  165. 165    result=send_cmd(CMD24,sector); //CMD24
    * l/ V& r7 y2 f
  166. 166    if(result){spi_cs_deselect(); return 6;} //
    9 ]* X* d4 V0 S3 j( d
  167. 167    spi_read_write8(SDSPI,0xff);
    ' Z1 L' t% n* G- t+ t- A8 r
  168. 168    spi_read_write8(SDSPI,0xfe);//1 T$ S& B( j! a/ U2 M+ k+ l  G
  169. 169    for (cnt=0;cnt<512;cnt++) spi_read_write8(SDSPI,buff[cnt]); //Данные
    # ?9 S0 `' U4 P4 J7 v  A
  170. 170    spi_read_write8(SDSPI,0xff);7 M! d" v: o7 T0 X) r
  171. 171    spi_read_write8(SDSPI,0xff);
    # q! R5 l; F% Q; _6 Z& Q+ _, R6 X% [
  172. 172    result=spi_read_write8(SDSPI,0xff);
    - F; g7 X7 O! T$ r0 X
  173. 173    //result=wait_ready();
    ( ]/ s4 K6 a% e0 ]. }
  174. 174    if((result&0x05)!=0x05){spi_cs_deselect(); return 6;}
    ( \' A7 n7 p6 |
  175. 175    //spi_read_write8(SDSPI,0xff);6 A, ^1 I- T9 Z1 i4 B" Y9 ]' }
  176. 176    while (SPI_SR(SDSPI) & SPI_SR_BSY);
    : k- x" x) i/ J& z" w) J4 u
  177. 177    //( j% q5 I/ f9 @4 j5 k" `
  178. 178    spi_cs_deselect();; S$ V- _' \7 p2 f9 l
  179. 179    spi_read_write8(SDSPI,0xff);) B9 e' y5 s2 k
  180. 180    return 0;
    ) S& R5 e/ N* V
  181. 181}8 s+ {1 X" b1 d$ `4 f  v- A& b
  182. 182
    4 j) @2 l/ S! |) l+ A7 h% R0 g% N
  183. 183
    9 E# K2 E# ]) W9 J  }3 k2 h
  184. 184static void set_spi_slow()0 u5 e* Q$ k! {, s8 t1 W
  185. 185{
    : X1 B! B& b4 M, k5 S
  186. 186    // spi_disable(SDSPI);# H6 Z! o, J0 o6 e2 ~3 C  }0 i
  187. 187    spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_128);
    4 f# z1 J3 e: I
  188. 188    // spi_enable(SDSPI);
    ' e  d9 z/ \1 R: B- x  Y
  189. 189}( q" j% j  z( q
  190. 190
    8 @* y  N) v" N8 ^: {. R% j2 A
  191. 191static void set_spi_fast()
    1 H/ T; q" ]! {' U# ^' g# o" F
  192. 192{
    8 @6 O" N4 e2 x$ d
  193. 193    // spi_disable(SDSPI);
    : G& }* |8 V8 K0 P( U
  194. 194    spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_8);
    2 D# c8 m# F6 w) ^! f7 r
  195. 195    // spi_enable(SDSPI);% Y: z2 V7 p6 m. G. p" v2 c' c0 V3 \! _' x
  196. 196}
    1 L! \. S3 X" W- i
  197. 197* m# b# S- f+ S$ p& K/ x  K; ^
  198. 198static uint8_t spi_read_write8(uint32_t spi, uint8_t tx)' R3 Q. l) P! L, K; [' d
  199. 199{4 C' w* B, H7 G6 k; d8 F0 u
  200. 200    spi_send8(spi, tx);7 j7 `4 {  c1 N2 g3 j; O! _3 ]
  201. 201    return spi_read8(spi);
    # R+ b9 _/ P5 G9 g' O# L
  202. 202}
    ( R  H  t; {' @5 U% E
  203. 203
    6 _8 L; k9 \4 E3 c( O
  204. 204static uint8_t wait_ready(void)
    5 e1 k" T  P2 @  J9 b  N2 f
  205. 205{0 y% Q, [) r, A5 c% Z7 M
  206. 206    uint8_t res;
    ( m8 e- n2 q/ }- R  W
  207. 207    uint16_t cnt=0xffff;
    5 c- }5 s# F1 R. T
  208. 208    spi_read_write8(SDSPI, 0xff);/ M, ^$ u! ?5 }3 j- o
  209. 209    do res = spi_read_write8(SDSPI, 0xff); while ((res!=0xFF)&& --cnt );- X! a4 z( ?6 o
  210. 210    return res;  y$ Q# p1 g6 W% \+ J- T& j1 h% U
  211. 211}
    / E7 f  l' W+ i) d3 o, h0 d  l
  212. 212
    ) \+ r2 M6 d7 j2 o
  213. 213static uint8_t send_cmd (uint8_t cmd,uint32_t arg)
    * m# v* D+ X% v$ \0 a
  214. 214{0 V0 H7 O) J! R$ M
  215. 215    uint8_t n, res;
    0 A8 |- ]6 ?4 ^. r
  216. 216
    7 M8 k% A% Z  D. F# R" E8 @
  217. 217    /* ACMD<n> is the command sequence of CMD55-CMD<n> */
    " J6 E% [! y5 i+ Y4 V
  218. 218    if (cmd & 0x80){
    ( [2 r  o4 F$ [& O7 G" C( f& D
  219. 219        cmd &= 0x7F;" t9 I0 ^8 F& R# Z( w+ I
  220. 220        res = send_cmd(CMD55, 0);* Q0 d! a7 w, N( u. N
  221. 221        if (res > 1) return res;
    6 O1 p- @5 |( S
  222. 222    }* W9 c3 N/ b0 t$ c1 \* p. _: H, v# [
  223. 223/ n6 I2 M5 E* J' K! D; t' \4 y
  224. 224    if (wait_ready()!=0xFF) return 0xFF;
    5 D% K+ z4 X0 n# ^
  225. 225    /* Send command packet */, z% Q2 Y0 l7 f# _6 k; l
  226. 226    spi_read_write8(SDSPI, cmd);                    /* Start + Command index */. x: w$ k5 ~# w( k
  227. 227    spi_read_write8(SDSPI,(uint8_t)(arg >> 24));    /* Argument[31..24] */; C7 s6 Q% Z9 |8 v
  228. 228    spi_read_write8(SDSPI,(uint8_t)(arg >> 16));    /* Argument[23..16] */! ^- Y+ M4 K  m- o% E
  229. 229    spi_read_write8(SDSPI,(uint8_t)(arg >> 8)); /* Argument[15..8] */- _7 t# ^/ K. Y- h* q% U
  230. 230    spi_read_write8(SDSPI,(uint8_t)arg);            /* Argument[7..0] */# P! C( B2 ^/ J- M+ Y4 h  S
  231. 231    n = 0x01;                               /* Dummy CRC + Stop */
    3 c' G7 i3 f+ s% h
  232. 232    if (cmd == CMD0) n = 0x95;              /* Valid CRC for CMD0(0) */8 Z$ k" @7 A  I
  233. 233    if (cmd == CMD8) n = 0x87;              /* Valid CRC for CMD8(0x1AA) */
    $ v4 d- v4 f9 x, J
  234. 234    spi_read_write8(SDSPI,n);+ j3 S' b6 A3 W2 R8 \, z% j5 R' L) o
  235. 235    /* Receive command response */' _# ?# \5 b  T# h# o& O! u$ _+ ~  P' p
  236. 236    if (cmd == CMD12) spi_read_write8(SDSPI,0xff);  / b- p+ s' u7 ^% }) @- _
  237. 237    /* Skip a stuff byte when stop reading */
    ( }% {) c- @! I) S* I
  238. 238    /* Wait for a valid response in timeout of 10 attempts */
    ! W5 o$ [5 c$ q2 d4 q6 h6 K
  239. 239    n = 10;
    $ C" @7 N/ p2 E) y
  240. 240    do res=spi_read_write8(SDSPI,0xff); while ((res & 0x80) && --n);
    ; I* {  l, [$ m
  241. 241( S* i5 f$ s4 T& d
  242. 242    while (SPI_SR(SDSPI) & SPI_SR_BSY); //wait if busy
    3 o% Y8 _, b8 X" n8 l3 N
  243. 243
    ' I7 p. R4 B, f! i' X+ U3 ~
  244. 244    return res;                    /* Return with the response value */
    # |. {8 l6 ?) ^2 O+ B4 {
  245. 245}
复制代码
& |! Y! ^! x4 f! X* \2 h/ r+ U/ `
: {" I/ Y+ r# z
注:这里初始化部分只写了SDv2的判断;

" b) P8 L5 s/ ~! O% y* m" b
  • diskio.c 调用 spi_sd的读写接口:
    4 A6 m) J% z; H  K" |
  1. 1/*-----------------------------------------------------------------------*/. Y3 z9 v/ T# S7 F" @. X3 d
  2. 2/* Read Sector(s)                                                        */
    # C( ~" I+ g$ E/ v. Z# O! B) v1 ?
  3. 3/*-----------------------------------------------------------------------*/0 n1 z# ]" V7 F
  4. 4
    ! c) X8 ?+ z  e0 ?, K$ G
  5. 5DRESULT disk_read (
    1 y3 J4 k, D) H! q9 ?' F$ L
  6. 6    BYTE pdrv,      /* Physical drive nmuber to identify the drive */$ l2 W' w2 M) ]6 A" i+ V
  7. 7    BYTE *buff,     /* Data buffer to store read data */2 [* }  A0 e% F
  8. 8    LBA_t sector,   /* Start sector in LBA */
    5 Q, O' N. f% X6 P: f
  9. 9    UINT count      /* Number of sectors to read */
    / a8 B7 `" d1 v* r& B
  10. 10)+ a4 L* }" x5 {9 u' r( z; I
  11. 11{
    : \) r& D* h7 x
  12. 12    while(count){2 f( ~4 O" X* b- {! ~/ c0 K
  13. 13        if (spi_sd_read(buff,sector)) return RES_ERROR;/ s3 h! z7 P: K2 g
  14. 14        --count;$ M) e6 p+ C3 u: H
  15. 15        ++sector;) j! g6 f0 x' D& x7 a. i+ W
  16. 16        buff+=512;( u4 n" U3 s* _/ x( G+ ], |
  17. 17    }* F; |4 v2 |7 h5 }1 K
  18. 18    return RES_OK;$ }+ Z9 \4 o! H) N
  19. 19}
    0 p  \+ N; ?6 N9 {
  20. 20
    ! b" @$ r; A# B! p1 |
  21. 21: A  ]. m  `( T$ y, x  P" K+ F
  22. 22
    # }/ A6 H6 c! f  `
  23. 23/*-----------------------------------------------------------------------*/
    2 T0 g2 E. k, n- \5 m- p' Y5 `: l
  24. 24/* Write Sector(s)                                                       */6 V. h& Y7 n6 R5 M: J6 t
  25. 25/*-----------------------------------------------------------------------*/* J" ~) }# s0 O& }2 M1 `3 a3 N5 u/ e
  26. 26
    - m$ g4 C4 a5 G6 y1 i
  27. 27#if FF_FS_READONLY == 0- C6 Q: O# Y( S( \& b- [/ x
  28. 28
    + k+ Q3 _, U7 k4 B  x# h! ~
  29. 29DRESULT disk_write (4 Z7 i) v* R' {+ E8 B
  30. 30    BYTE pdrv,          /* Physical drive nmuber to identify the drive */5 r$ H* z# ^$ Y# g3 O( j; |! D0 q
  31. 31    const BYTE *buff,   /* Data to be written */5 u; W; X5 E2 X$ j
  32. 32    LBA_t sector,       /* Start sector in LBA */
    , L5 D  d+ ~+ D. U
  33. 33    UINT count          /* Number of sectors to write */, O2 P& E7 u% T& e7 Z8 U  @
  34. 34)) M$ ~" q' q- j( H) v) `
  35. 35{; Z8 F) y; N3 u# h3 z
  36. 36    while(count){
    $ {( [8 d: }/ j+ G6 G
  37. 37        if(spi_sd_write(buff,sector)) return RES_ERROR;
    , L: K/ W/ K- x) a9 B5 j! X0 ]
  38. 38        --count;, o& _* u# u$ j9 Y4 l/ W8 d0 {, N
  39. 39        ++sector;8 }( N9 [9 X) k7 J
  40. 40        buff+=512;2 y" R1 x; h% n2 X+ N- i
  41. 41    }
    ' O. G; z4 \/ w/ |1 z3 t" x
  42. 42    return RES_OK;0 H1 D+ E2 ]- w& [
  43. 43}
复制代码

7 F( T% F; }! K$ X0 J9 }/ ?5 ]
* J6 Q  v. D) Z9 e
2.3 SPI接口配置
  1. 1static void spi1_init(void){
    # J8 Y# l5 l4 h/ @5 g
  2. 2    //spi1 - display# T* q$ z9 u& A1 J0 b* k: }2 V
  3. 3    /* Enable SPI1 Periph and gpio clocks */7 r$ F+ m, X  ?
  4. 4    rcc_periph_clock_enable(RCC_SPI1);
    ' Q0 L; t/ I: S) k3 y/ P, f
  5. 5    rcc_periph_clock_enable(RCC_GPIOA);% m* Q$ z4 w$ F* G  I2 ^5 D
  6. 6
    8 q+ r6 R3 @- l1 [6 X2 S
  7. 7    /* Configure GPIOs:
    2 m# d! W) [, m. m) V
  8. 8     *
    ! S: i9 ?7 a9 z% V) d, X7 @/ x
  9. 9     * SCK=PA5
    , A) e& t1 `% g( j
  10. 10     * MOSI=PA7
    - k7 [3 V5 N& v
  11. 11     * MISO=PA6$ y- G. ~% w9 M0 t3 C0 P
  12. 12     * ' k- j8 Q0 X8 G, U  f
  13. 13     * for SD card& i2 z) G* v+ i5 T9 k
  14. 14     * SDCS PA4
    ) a3 g) ?  p9 S$ Z+ k# h
  15. 15     */
    8 E! e" x! Z% B* [, b1 n; [
  16. 16
    8 M, O+ d- g# c+ g  D
  17. 17    //MOSI & SCK & MISO
    5 t. I8 U. \2 {8 T1 B' q
  18. 18    gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,GPIO5|GPIO7|GPIO6);6 Q7 G+ J6 t$ j6 |4 ]! m  X3 X
  19. 19    gpio_set_af(GPIOA,GPIO_AF0,GPIO5|GPIO7|GPIO6);
    ( K. a9 ~1 a: o
  20. 20    gpio_set_output_options(GPIOA, GPIO_OTYPE_PP,GPIO_OSPEED_LOW,GPIO5|GPIO7|GPIO6);
    6 ~# U( r& P% j3 T/ C. J
  21. 219 Q9 B$ S' X3 ?7 Y3 W9 n* b3 Z7 O# u
  22. 22    //SDCS + b  c% l" I- [7 b8 e+ ^7 W" q
  23. 23    gpio_mode_setup(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO4);( L! s* D& |) j, J0 Q  o8 _
  24. 240 r: Q/ ~8 p/ s" ?1 P: ~* w! T
  25. 25    gpio_set(GPIOA,GPIO4);( G2 \( m8 S6 P5 B6 f# }
  26. 26' s3 j, s) A  z; y2 x; A0 c- \
  27. 27  /* Reset SPI, SPI_CR1 register cleared, SPI is disabled */
    * I- H, K; v- o' F9 w" N
  28. 28    spi_reset(SPI1);
    5 g+ V% E' k  ~+ G& S, M
  29. 29
    ' R2 h9 O1 x3 y+ A, V+ U( K
  30. 30  /* Set up SPI in Master mode with:; B7 b( x( t" _! [$ J" H3 r
  31. 31   * Clock baud rate* n( R# D; F# N7 W5 L
  32. 32   * Clock polarity
    7 |0 X4 M. X6 Q! l9 `# S
  33. 33   * Clock phase- u8 D4 g' P' z8 y4 q4 ?
  34. 34   * Frame format MSB9 v+ v3 C- E0 @6 T9 j
  35. 35   */
    ( \5 `: [  e3 ?/ b! H. t. ^
  36. 36    spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_128,
    7 n5 k! g& d! n4 N
  37. 37                    SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,4 a; G9 j% a0 n3 @* r# |7 o
  38. 38                    SPI_CR1_CPHA_CLK_TRANSITION_1,
    & u8 ?+ c; D. n$ ~! a! C
  39. 39                    SPI_CR1_MSBFIRST);2 l( U5 L5 o; i( U  O$ m
  40. 40
    * G( f/ G, B  d, q5 Q
  41. 41    spi_set_data_size(SPI1,SPI_CR2_DS_8BIT);: }0 M- f1 c0 p8 a+ h& h
  42. 42    spi_set_full_duplex_mode(SPI1);3 G5 Y' m. [1 m/ k# @6 m
  43. 439 Y2 B' W! ?' N
  44. 44    spi_fifo_reception_threshold_8bit(SPI1);) y1 M" O2 P9 I" ]
  45. 452 S: O: B. X9 m- D6 r5 M
  46. 46    SPI_CR2(SPI1) |= SPI_CR2_NSSP; //NSSP, ?? clock continus1 ~4 m+ O  G! r; }, o- J
  47. 47    // spi_set_unidirectional_mode(SPI1);
    4 |  }6 I7 m% n7 D" b. k. @* w: J/ ~4 I+ n
  48. 48    // SPI_CR2(SPI1) &= (~SPI_CR2_FRF_TI_MODE); //motorala mode8 \1 l/ n. j% @  r7 R
  49. 49    // SPI_CR2(SPI1) |= SPI_CR2_FRF_TI_MODE;
    : f$ _& i0 w' q+ e% S  c
  50. 50
    ) y1 ]  N: K$ V+ O! f  z7 A9 O8 I
  51. 51  /*
    8 Q  L' t& V4 o% Q, \
  52. 52   * Set NSS management to software.
    $ ?0 ~2 Q: C, D2 @
  53. 53   *
    " Y1 {  a6 c: u! T. |
  54. 54   * Note:. U6 F+ {' o5 m$ s) O; v: Z
  55. 55   * Setting nss high is very important, even if we are controlling
    ; A. E1 Q" D1 E# t. F; A1 g, N8 S) x
  56. 56   * the GPIO$ c; Q, v( ]6 ?4 U; H) ?3 k
  57. 57   * ourselves this bit needs to be at least set to 1, otherwise the spi
    4 X* h% u" ^3 h- B
  58. 58   * peripheral will not send any data out.7 o* V& y  _# M+ \1 ?% ]" t( ?
  59. 59   */( [5 ?. Y6 \3 C% j/ V
  60. 60    spi_enable_software_slave_management(SPI1);! Z- O8 a; x3 p) f* r
  61. 61    spi_set_nss_high(SPI1);
    7 m, C! s6 ~. i# u
  62. 62
    * X1 e" I, k" f& D! y. D
  63. 63  /* Enable SPI1 periph. */
    / A8 x" w. v& z) n* X( t
  64. 64    spi_enable(SPI1);" W3 r" a) G2 A5 E
  65. 656 n& I. `$ t4 t$ a/ e7 K- T' j
  66. 66}
复制代码
, R% _" ^3 ^$ a4 v* r
- N# j) P( j& O6 I
2.4 SD卡读写测试
5 c; r  G: k: _2 g4 N! t$ ]+ ]
  1. 1printf(" init spi.\n");$ D! p; S+ N( j
  2. 2  x8 B% S, b% r( o
  3. 3//spi
    # J* X" i+ M1 H5 ~$ P+ ^2 `
  4. 4spi1_init();- t( G8 n4 R7 P: f- C  n
  5. 5
    / q, t: n# S0 J9 ~
  6. 6//sd3 h5 I3 G6 p; c" H7 s% v  s' X
  7. 7uint8_t sd_type = spi_sd_init();
    - n1 C4 _- K! U+ H
  8. 85 U( r  h) c% s  R6 i
  9. 9//sdv2: 0x08|0x04 . 0x0c1 w- `7 Y' e3 O6 J3 T, v
  10. 10// printf(" sd_type: %x\n", sd_type);, D0 W( a) g& f
  11. 11
    ) q& V/ S3 J, x; L" ^) d8 F
  12. 12FATFS fs;/ \8 B, m0 s! q9 d9 \
  13. 13FRESULT res;
    % B- n5 B' i5 z$ q! P
  14. 14res = f_mount(&fs, "", 0);/ ?: c# z4 u8 _! i1 M  h4 Q
  15. 15if(res != FR_OK) {& o- R. ]) z% U% |+ ?0 M( W- M
  16. 16    printf("mount fs failed, res = %d\r\n", res);
    5 t) F- l# p4 e2 c
  17. 17    return -1;
    / V' p' S7 P) R% E+ h7 g
  18. 18}else{7 T$ V( Z$ n4 P" p$ j( n2 s7 F5 Q6 l, Z
  19. 19    printf(" mount fs OK.\n");
    ( n' p! F5 K  n
  20. 20}# u) E5 _1 ^6 Z0 \0 P/ r
  21. 21" n/ G3 b$ H4 S/ H
  22. 22FIL fd;
    5 F( b! a  S' `; e2 x0 O# V8 w
  23. 23
    3 [6 @# v; _$ Q) S3 L' O5 K8 b
  24. 24res = f_open(&fd, "test.txt", FA_CREATE_ALWAYS|FA_WRITE);
    . e* U; g0 b/ R" D$ A6 @" ~" q
  25. 25if(res != FR_OK){
    & w- M* g8 Q  e5 ~* I
  26. 26    printf("open file failed: %d\n", res);1 j6 T! x( w9 h" f
  27. 27}else{
    / s9 R6 L: P2 p5 ^
  28. 28    printf("open file OK.\n");* \. M3 ~. s5 X* A7 p$ E
  29. 29}8 Y/ @. o% B/ ]
  30. 30, b+ O' R$ B4 R8 O
  31. 31char *buff = "test data to write to fs\n";
    7 g" D( ^, S6 ?+ ]) b6 y0 y
  32. 32uint32_t len = 0;
    ' o* T2 q$ U; c. k: A
  33. 33res = f_write(&fd,buff, strlen(buff),&len);/ P9 r6 j7 S' E! E, n0 f
  34. 34if(res != FR_OK){) `6 l0 h0 P, i. ~
  35. 35    printf(" write file failed.\n");# ]* V$ T3 b  I( F& f; T9 q, ~
  36. 36}else{* X9 R; c* ?$ @6 R( e" k
  37. 37    printf(" write file OK, write size %d .\n", len);% e! z5 G3 d3 h. i" p
  38. 38}6 p# X2 a" |3 G* K( ?
  39. 39
    : N' e3 v# L1 P: C+ Y  K
  40. 40res = f_close(&fd);
    6 [, N  Y1 c0 g3 m5 @
  41. 41if(res != FR_OK){
    % c5 h" _! l+ K/ D, R, X
  42. 42    printf(" close fs failed.\n");
    % w7 `5 h! r' \% I7 v
  43. 43}else{
    / Z( J* o# B4 A! E$ Q9 H, k
  44. 44    printf(" close fs OK.\n");& h: T! V/ W! h$ M4 ~4 ]6 k! H
  45. 45}8 @+ \% s( V0 ^
  46. 46/ x9 b9 d2 {$ J( m$ _8 p
  47. 47res = f_unmount("");4 C: w- s9 g& f- D
  48. 48if(res != FR_OK) {5 T2 U8 T; `0 ]7 e. F3 ]% ]
  49. 49    printf("Unmount fs failed, res = %d\r\n", res);1 b( K1 p% k8 K  E# U
  50. 50    return -1;
    3 O% G) _2 s' b  M& L. t
  51. 51}else{
    - m% ^7 s- ~3 T5 x0 O* ?
  52. 52    printf("Unmound fs OK.\n");+ l0 _8 [/ l( b7 Y- r
  53. 53}
复制代码
* A" S; q; L0 g/ M; ~, U
0 X7 I; f* j( d7 I7 s: A( i% G
main中测试SD卡挂载、读写;
3 i: e0 F1 A/ ~, v' D5 V( s
3 硬件连接
硬件引脚按如下方式连接到SPI1

( }  C( _  q# ~$ _6 ^$ B
微信图片_20230222174026.png

1 y& Z; Y- R  e* t. Y4 U! b8 V+ r5 i  ]7 x2 ]

! c7 y5 s& d3 ?8 E# z2 }5 j: S4 烧写测试
将程序烧写到开发板后,打开串口,可以看到测试成功,卡中写入文件在电脑显示正确:
; ?* K6 R1 x' q, T  N, H- f
微信图片_20230222174024.png

8 J$ M$ D4 \# q
转载自:MakerInChina.cn
: w4 {# \# ^: i& Q4 _

0 j2 v5 ^( t- o) U8 O
赞 收藏 评论0 发布时间:2023-2-22 17:41

举报

0个回答

所属标签

相似技术帖

官网相关资源

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