|
使用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
- 1upload_protocol = cmsis-dap
3 x9 `& V [1 r4 M% e - 2debug_tool = cmsis-dap
复制代码 4 y: R y- J7 w$ ^+ \9 c
/ x: I5 [9 \ J/ y4 f" ]. \2 编写程序2.1 加入FATFS库2.2 实现SPI接口的SD读写在src目录下新建spi_sd.h 和 spi_sd.c 文件,现在目录结构如下:
# v0 L, C) A1 X3 Z- f/ G* Y( e! Y0 C5 v 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/**$ k) l6 l/ D/ h m
- 2 * @file spi_sd.h9 ~, r, \; X. ^' U+ v5 j
- 3 * @author MakerInChina (makerinchina.cn)
/ G ~, h' e8 y4 N+ E+ ^, ^ - 4 * @brief
+ W) g1 O" _: `% H9 D - 5 * @version 0.01
7 O: {0 h2 x' _6 K - 6 * @date 2022-09-18& Z# U; s# h' ?' y
- 7 * 2 L9 ~3 S5 Q9 b
- 8 * @copyright Copyright (c) 2022; J' H3 @& |# A5 b
- 9 * 8 K3 a; [ A+ A& c" u: f# R: l/ s; [
- 10 */
' ^1 l( ^" A* A9 _8 U! g- }% s - 11
0 M* a5 o6 k( M' z/ `" f& U - 12#ifndef _SPI_SD_HEAD_H_8 M; d. }/ A6 {; l2 v# o+ j- p
- 13#define _SPI_SD_HEAD_H_
* H6 _% ^2 w4 e4 s2 W1 B - 14$ \- Z p9 ~1 W. l2 p5 W
- 15#include <stdint.h>; u4 `+ r% k- J; B4 u; N
- 16* d0 F6 L+ K$ m$ P3 A2 b
- 17/**% x/ z2 _1 w. K
- 18 * @brief init sd card+ a2 W+ J) ?- y, u J/ e% T
- 19 *
- `% A, S( _) i - 20 */1 {# X5 G3 Z& v& K6 A" g- ]
- 21uint8_t spi_sd_init();, ]+ U L4 a% Y) i: m L0 e
- 22. _9 I6 V% M# ]" g5 B
- 23/**
) H/ A* C7 w+ L3 { - 24 * @brief spi read sd5 c) v; ]4 J' V- `9 Q2 J0 P
- 25 *
- s* Y( m, N. i9 T% m# H0 ^+ z - 26 * @param buff 3 D/ a, }$ G. F* m6 V, R4 n! t
- 27 * @param sector % b+ z+ E; q& M( a! u
- 28 */6 Q6 S$ n* E `; h- y3 d
- 29uint8_t spi_sd_read(uint8_t *buff, uint32_t sector);$ t( T0 Z8 o9 W# W4 @4 p
- 30
& O& e% t4 B. ?9 G. S8 u - 31/**
+ ^/ k$ {: k; g7 U; d - 32 * @brief spi write sd
+ o! I! \. Y; Q/ R p - 33 *
0 [( ~7 J' _+ `- c% J) r* ?/ O - 34 * @param buff 4 U! K$ l" M7 D0 R- _7 Z" G" f
- 35 * @param sector 3 N8 I" j8 F* R
- 36 */
4 I q" }6 U( o* T* i1 O- g - 37uint8_t spi_sd_write(uint8_t *buff, uint32_t sector);: L$ G; ?) J) I# ~
- 38! p* E0 r8 `* I
- 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/**
) E: x" X3 r% D% n, u2 Z6 k - 2 * @file spi_sd.c
+ K( }' Q' s# K7 f2 O - 3 * @author MakerInChina (makerinchina.cn)
6 |# J1 o$ _4 A% f9 H - 4 * @brief
1 v0 S6 e% }: p7 _/ m$ y - 5 * @version 0.011 }7 @0 d9 ]% \+ H; V) H: K
- 6 * @date 2022-09-18
; @2 p- w: F: R7 } - 7 * 5 d! ?6 N/ |, ]. t! X( n @
- 8 * @copyright Copyright (c) 20228 o0 ^5 B4 ^% J9 D, H. p
- 9 *
( W) b( U0 i" u" x - 10 */
1 J( j- ?9 h# A - 117 X: y. O% K1 c4 L2 v. N" {) b
- 12#include "spi_sd.h"4 d9 K: r H! Y* Q; g
- 13* u9 w, n8 R" o8 n8 I
- 14#include <libopencm3/stm32/spi.h>
8 J b: }1 T4 ?# Z9 c/ z - 15#include <libopencm3/stm32/gpio.h>
, F( E& Z, T. W9 J' S9 g0 v - 16
$ B) g0 b, w) G6 }: m# N* Y4 K - 17#define SDSPI SPI17 Y% r4 E/ t( n$ \: v% F. L
- 18#define SD_CS GPIO4
+ K: I- H C4 z) I - 19#define SD_PORT GPIOA
( u4 I; h* _( U3 P& O; ^ - 20' ^& m6 N9 A' j4 a
- 21#define spi_cs_deselect() gpio_set(SD_PORT, SD_CS)1 J$ V/ J% t3 d7 I' E
- 22#define spi_cs_select() gpio_clear(SD_PORT, SD_CS)1 U/ w$ r5 r$ `6 B7 \/ R
- 23! t% [* K$ w1 x) ]' D* U
- 24
2 F& j7 ]7 ^" E- W; @6 f - 25/* Definitions for MMC/SDC command */2 R* Y% y$ \7 \9 J; u, Z7 N$ g
- 26#define CMD0 (0x40+0) /* GO_IDLE_STATE */
0 }' s7 \& W! c _' w, p- J3 ? - 27#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
* \+ J) }0 F) k! x - 28#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */9 ~1 G) N) a0 t& S& F
- 29#define CMD8 (0x40+8) /* SEND_IF_COND */
0 i0 e$ B! [; g @ - 30#define CMD9 (0x40+9) /* SEND_CSD */& G7 r- z0 x; G p6 G. h
- 31#define CMD10 (0x40+10) /* SEND_CID */$ l( h" N- E- w* Y0 j0 ^0 d
- 32#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
+ a% x+ `! q4 A- K; D u* z - 33#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */6 U: p# F( z5 G# j1 f# v# d3 w1 d; O
- 34#define CMD16 (0x40+16) /* SET_BLOCKLEN */! S" w! _9 I3 w0 Y$ o
- 35#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
7 K0 p7 s- \+ a H5 d; z - 36#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
6 N) a" G5 _2 b. b+ u4 e - 37#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */( J/ l$ P. D. _5 F& E0 E
- 38#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
6 r1 b! ? D% D& m5 g) d$ Y, _ - 39#define CMD24 (0x40+24) /* WRITE_BLOCK */
) f6 P" G) | N5 n; \ - 40#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */( H& Y/ U3 o# \ j8 `; g
- 41#define CMD55 (0x40+55) /* APP_CMD */
' L- b' Y- \# w9 R: p% v5 F7 g" W$ t - 42#define CMD58 (0x40+58) /* READ_OCR */5 u9 {/ t4 J' }* p# ~
- 433 G0 P8 P) S) a2 I5 q8 k
- 44#define CT_MMC 0x01 /* MMC ver 3 */' Z4 q0 w9 t* e' U$ e
- 45#define CT_SD1 0x02 /* SD ver 1 */
7 h7 d! z: z- ^ - 46#define CT_SD2 0x04 /* SD ver 2 */- x4 l8 R" p' A; q
- 47#define CT_SDC (CT_SD1|CT_SD2) /* SD */6 p, G. v4 C" j
- 48#define CT_BLOCK 0x08 /* Block addressing */
/ v# k* A) d3 E$ R5 L7 y - 49. }, r+ y8 m* r) w' V: i
- 50static uint8_t spi_read_write8(uint32_t spi, uint8_t tx);
6 V/ B" T& u0 B - 51static uint8_t wait_ready(void); N" s4 C( ]9 `% O
- 52static uint8_t send_cmd (uint8_t cmd,uint32_t arg);" v) |1 E9 N: Z! \1 A( ~* ?
- 53static void set_spi_slow();
( ?: u, _9 p. E) _ - 54static void set_spi_fast();
3 c# }3 S: \0 }. N0 @# _; \+ z - 55
! f4 h A5 }; R# @ - 56/**5 @' G" C8 R' o
- 57 * @brief init sd card
+ G. o$ I8 j- `3 h) a$ f! P - 58 *
6 L* m( M) s9 G! b j: H - 59 */* l' o5 d, e$ f1 |: S! w
- 60uint8_t spi_sd_init()
2 H6 v7 n8 A3 d. U - 61{5 [9 Q+ Q. P8 G9 T
- 62 uint8_t n, cmd, ty, ocr[4];
# O5 ^" \7 ?8 ]3 c* v0 b - 63 uint16_t i;6 n4 W8 C* J/ y! v4 M5 Y
- 640 b$ a( d. u* t, t- j9 F$ e1 |
- 652 Y6 `" m% t, x+ t X3 S
- 66 //init with low speed
" q; A! A1 J( [' K) g - 67 // set_spi_slow();2 d3 w) \2 X* f+ `6 g, n
- 68+ O* a6 E& B, s
- 69 spi_cs_select();6 k1 a- c. I, W5 }' C. F" j6 m
- 70) ^8 A9 T9 I& G9 Y( s; }% p
- 71 for (n = 10; n; n--) spi_read_write8(SDSPI,0xff); /* 80 dummy clocks */: z2 Z* O3 [" i8 ?9 [, y
- 72
* o1 e# C0 i. h' s& X' c+ r7 d - 73 ty = 0;3 E) K% ~: x( _2 M5 \# X
- 74
7 t' r8 i# ?4 B6 t0 A* y - 75 /* Enter Idle state */
f* @" d- d* z( X. j3 [ - 76 ty = send_cmd(CMD0, 0);7 r4 K3 g1 _. W4 B3 f
- 777 R! \/ s6 ~' H1 ^" Y* ^$ O
- 78 // printf(" > enter idle:%d\n", ty);# x9 j ~- Z) X+ K1 q$ u0 h
- 798 O* u: {, ^7 f2 h
- 80 /* Initialization timeout of 1000 milliseconds */( O, p+ B% t# A& F0 f0 P8 I
- 81 /* SDHC */
2 z+ V$ N# T4 a% p0 O' P. \8 \ - 82
5 ?) ?: ]7 k! J {2 `6 z - 83 if(ty == 1){& H) d# k- b: r* [, |
- 840 `) ~: Y8 G% c0 K
- 85 if (send_cmd(CMD8, 0x1AA) == 1){ /* SDv2? */
7 L3 Y" t ^: {- F! Y ~ - 86 /* Get trailing return value of R7 response */" I" _2 ~6 C; R# {: A8 |
- 87 for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);" {8 |' O5 w- f; v1 B: {, B
- 88 /* The card can work at VDD range of 2.7-3.6V */+ p0 B- N7 `% ~( b
- 89 if (ocr[2] == 0x01 && ocr[3] == 0xAA){# z C# R* t6 E1 G, t. k! S
- 90 /* Wait for leaving idle state (ACMD41 with HCS bit) */2 l" F& h5 f# c/ U7 J8 R7 ~ [+ A
- 91 i=0xfff;
* ~$ v& k, A0 ^+ m2 y1 H7 ~ - 92 while (--i && send_cmd(ACMD41, 1UL << 30));
`& A W4 @% D S, c& e - 93 if (i && send_cmd(CMD58, 0) == 0){
% y2 r* t4 o# N9 g9 \ - 94 /* Check CCS bit in the OCR */8 V) D% s8 h2 t- ~+ ~
- 95 for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);7 l; m( d3 P# M! N
- 96 ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;4 p- f k9 l7 B& N) K: S
- 97
/ G( M- |+ z3 p) B- @1 k - 98 }5 B0 M: v3 |) y# e7 Z
- 99 }
, h4 A# a. N" x5 N5 ` - 100 } else { /* Not SDv2 card */6 F5 {6 I2 U# ~ ^7 {% Z' F8 V
- 101 // if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */
0 v9 k! T8 f+ J - 102 // ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */4 I- v w; |2 ~) Z# s7 y2 L" }; e
- 103 // } else {; F- `: n6 W* ]3 F) }: h
- 104 // ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
( D, q+ f- m& Q' U; s - 105 // }
: ~ G8 @" \$ W* M0 \; } - 106
, _( X/ W0 y. l# D - 107 // while (SPI_Timer_Status() && send_cmd(cmd, 0)) ; /* Wait for end of initialization */
, n9 \" R8 q1 z6 A# @ - 108 // if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */
( M/ q" d2 ^& k# H7 _ - 109 // ty = 0;2 R3 o7 L; p. @5 a; o
- 110 }
: }$ Z" R( r1 c5 @+ `: h - 111" f; ~0 [4 g$ ?
- 112 }
2 Q" i. f: p9 l7 O/ c0 O O" H$ s - 113 //CardType = ty;
% N1 N9 P9 `0 N( u - 114. C, w+ ?' }) Q3 D7 r4 G! P
- 1150 z, }. [/ ~( c9 Z: S s3 w. s
- 116 spi_cs_deselect();; e2 [! F! h6 ^; h+ y- l
- 117 spi_read_write8(SDSPI,0xff);/ s& o& ~4 t$ k/ q$ u9 f8 F, Y7 ~
- 118 while (SPI_SR(SDSPI) & SPI_SR_BSY);- p1 B% V6 V$ B' U5 L- O5 Z
- 119
1 E9 e7 @, S! O# `4 n" R' _ - 120 set_spi_fast();
( N+ c; u: K" k: X6 Z1 s) ^( t9 E - 121
" r# O* {. a4 M( M' }" w1 T - 122 return ty;
1 Z% ~9 Z# X' ~0 c( p- Z - 123}
J) u! \% s' ^ j" ~/ k: u6 M - 124
: \( N( ?% y r: k - 125/**# C' \& L y. g9 W7 O/ q* H- G! \
- 126 * @brief spi read sd
3 H3 F0 {( I! J& s" T - 127 *
1 [! F! g2 v' X: R6 a1 o( ?7 \ - 128 * @param buff
, E* m5 t5 t# m1 U7 d - 129 * @param sector , C t( t# a8 g7 k( s1 M q2 R
- 130 */1 ?( g7 y) _! ^$ A# ?, r
- 131uint8_t spi_sd_read(uint8_t *buff, uint32_t sector); b+ v% N2 Z4 `! Y6 t, `
- 132{
3 N# J1 k" Y7 S9 h - 133 uint8_t result;( h" Z# x7 l# i0 Z
- 134 uint16_t cnt=0xffff;0 Y0 _6 w' A4 k; B* C
- 135 spi_cs_select();
# a# B8 i/ H# w) E! o - 136 result=send_cmd(CMD17, sector); //CMD17 даташит стр 50 и 960 i7 v4 L0 {) m( @
- 137 if (result){spi_cs_deselect(); return 5;} //Выйти, если результат не 0x00
. Y: Z7 [ \6 t/ W - 138
9 {3 U/ U; ~7 [' P. U D D - 139 spi_read_write8(SDSPI,0xff);
" W, `5 I ?6 _: K* c - 140 cnt=0;
. R2 T5 d, m. P3 M6 m) i - 141 do result=spi_read_write8(SDSPI,0xff); while ((result!=0xFE)&&--cnt);
8 G9 e1 B0 d M) X( \- e - 142 if(!cnt){spi_cs_deselect(); return 5;}
- s6 J- O; Q5 H3 [7 m ^ - 143
- O1 W# P1 P+ q; L* @3 ]" Y - 144 for (cnt=0;cnt<512;cnt++) *buff++=spi_read_write8(SDSPI,0xff); 8 X6 |4 v% N% G( K
- 145" N. q E8 d7 m( E
- 146 spi_read_write8(SDSPI,0xff);
+ Y' a9 D6 c7 y3 N3 \4 J - 147 spi_read_write8(SDSPI,0xff);2 \" m7 Q0 W/ _: F# x
- 148 spi_cs_deselect(); w+ [/ v6 Y- `: J' F5 F0 z% ~! _
- 149 spi_read_write8(SDSPI,0xff);
8 y7 {( B j5 e' s - 150, N) z- H$ u4 d- D6 C. [
- 151 return 0;
+ G% L+ q) f+ N& I* t - 152}4 z9 S. x% l- q$ _+ @& j- q6 p
- 153! T$ A4 W# } a
- 154/**
; H0 n" V! O7 N - 155 * @brief spi write sd
, y- N& i c. } - 156 *
; y, U Y8 r! X2 u( W - 157 * @param buff
& b; m$ J/ _5 A9 U5 Q6 x- J6 Z - 158 * @param sector R. s& f" u$ c1 _# j; Z
- 159 */) H- g. b/ n) ~: H9 |# j# w/ L
- 160uint8_t spi_sd_write(uint8_t *buff, uint32_t sector)
6 S, u h! u( o( u! J# j3 ` - 161{( {$ U! A! O9 @
- 162 uint8_t result;
4 P2 E1 ~! N9 R: O - 163 uint16_t cnt=0xffff;$ O2 g6 W7 G) B0 J% f
- 164 spi_cs_select();9 Q- W1 @3 Q) E' L% Q) ^1 b
- 165 result=send_cmd(CMD24,sector); //CMD24
* l/ V& r7 y2 f - 166 if(result){spi_cs_deselect(); return 6;} //
9 ]* X* d4 V0 S3 j( d - 167 spi_read_write8(SDSPI,0xff);
' Z1 L' t% n* G- t+ t- A8 r - 168 spi_read_write8(SDSPI,0xfe);//1 T$ S& B( j! a/ U2 M+ k+ l G
- 169 for (cnt=0;cnt<512;cnt++) spi_read_write8(SDSPI,buff[cnt]); //Данные
# ?9 S0 `' U4 P4 J7 v A - 170 spi_read_write8(SDSPI,0xff);7 M! d" v: o7 T0 X) r
- 171 spi_read_write8(SDSPI,0xff);
# q! R5 l; F% Q; _6 Z& Q+ _, R6 X% [ - 172 result=spi_read_write8(SDSPI,0xff);
- F; g7 X7 O! T$ r0 X - 173 //result=wait_ready();
( ]/ s4 K6 a% e0 ]. } - 174 if((result&0x05)!=0x05){spi_cs_deselect(); return 6;}
( \' A7 n7 p6 | - 175 //spi_read_write8(SDSPI,0xff);6 A, ^1 I- T9 Z1 i4 B" Y9 ]' }
- 176 while (SPI_SR(SDSPI) & SPI_SR_BSY);
: k- x" x) i/ J& z" w) J4 u - 177 //( j% q5 I/ f9 @4 j5 k" `
- 178 spi_cs_deselect();; S$ V- _' \7 p2 f9 l
- 179 spi_read_write8(SDSPI,0xff);) B9 e' y5 s2 k
- 180 return 0;
) S& R5 e/ N* V - 181}8 s+ {1 X" b1 d$ `4 f v- A& b
- 182
4 j) @2 l/ S! |) l+ A7 h% R0 g% N - 183
9 E# K2 E# ]) W9 J }3 k2 h - 184static void set_spi_slow()0 u5 e* Q$ k! {, s8 t1 W
- 185{
: X1 B! B& b4 M, k5 S - 186 // spi_disable(SDSPI);# H6 Z! o, J0 o6 e2 ~3 C }0 i
- 187 spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_128);
4 f# z1 J3 e: I - 188 // spi_enable(SDSPI);
' e d9 z/ \1 R: B- x Y - 189}( q" j% j z( q
- 190
8 @* y N) v" N8 ^: {. R% j2 A - 191static void set_spi_fast()
1 H/ T; q" ]! {' U# ^' g# o" F - 192{
8 @6 O" N4 e2 x$ d - 193 // spi_disable(SDSPI);
: G& }* |8 V8 K0 P( U - 194 spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_8);
2 D# c8 m# F6 w) ^! f7 r - 195 // spi_enable(SDSPI);% Y: z2 V7 p6 m. G. p" v2 c' c0 V3 \! _' x
- 196}
1 L! \. S3 X" W- i - 197* m# b# S- f+ S$ p& K/ x K; ^
- 198static uint8_t spi_read_write8(uint32_t spi, uint8_t tx)' R3 Q. l) P! L, K; [' d
- 199{4 C' w* B, H7 G6 k; d8 F0 u
- 200 spi_send8(spi, tx);7 j7 `4 { c1 N2 g3 j; O! _3 ]
- 201 return spi_read8(spi);
# R+ b9 _/ P5 G9 g' O# L - 202}
( R H t; {' @5 U% E - 203
6 _8 L; k9 \4 E3 c( O - 204static uint8_t wait_ready(void)
5 e1 k" T P2 @ J9 b N2 f - 205{0 y% Q, [) r, A5 c% Z7 M
- 206 uint8_t res;
( m8 e- n2 q/ }- R W - 207 uint16_t cnt=0xffff;
5 c- }5 s# F1 R. T - 208 spi_read_write8(SDSPI, 0xff);/ M, ^$ u! ?5 }3 j- o
- 209 do res = spi_read_write8(SDSPI, 0xff); while ((res!=0xFF)&& --cnt );- X! a4 z( ?6 o
- 210 return res; y$ Q# p1 g6 W% \+ J- T& j1 h% U
- 211}
/ E7 f l' W+ i) d3 o, h0 d l - 212
) \+ r2 M6 d7 j2 o - 213static uint8_t send_cmd (uint8_t cmd,uint32_t arg)
* m# v* D+ X% v$ \0 a - 214{0 V0 H7 O) J! R$ M
- 215 uint8_t n, res;
0 A8 |- ]6 ?4 ^. r - 216
7 M8 k% A% Z D. F# R" E8 @ - 217 /* ACMD<n> is the command sequence of CMD55-CMD<n> */
" J6 E% [! y5 i+ Y4 V - 218 if (cmd & 0x80){
( [2 r o4 F$ [& O7 G" C( f& D - 219 cmd &= 0x7F;" t9 I0 ^8 F& R# Z( w+ I
- 220 res = send_cmd(CMD55, 0);* Q0 d! a7 w, N( u. N
- 221 if (res > 1) return res;
6 O1 p- @5 |( S - 222 }* W9 c3 N/ b0 t$ c1 \* p. _: H, v# [
- 223/ n6 I2 M5 E* J' K! D; t' \4 y
- 224 if (wait_ready()!=0xFF) return 0xFF;
5 D% K+ z4 X0 n# ^ - 225 /* Send command packet */, z% Q2 Y0 l7 f# _6 k; l
- 226 spi_read_write8(SDSPI, cmd); /* Start + Command index */. x: w$ k5 ~# w( k
- 227 spi_read_write8(SDSPI,(uint8_t)(arg >> 24)); /* Argument[31..24] */; C7 s6 Q% Z9 |8 v
- 228 spi_read_write8(SDSPI,(uint8_t)(arg >> 16)); /* Argument[23..16] */! ^- Y+ M4 K m- o% E
- 229 spi_read_write8(SDSPI,(uint8_t)(arg >> 8)); /* Argument[15..8] */- _7 t# ^/ K. Y- h* q% U
- 230 spi_read_write8(SDSPI,(uint8_t)arg); /* Argument[7..0] */# P! C( B2 ^/ J- M+ Y4 h S
- 231 n = 0x01; /* Dummy CRC + Stop */
3 c' G7 i3 f+ s% h - 232 if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */8 Z$ k" @7 A I
- 233 if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
$ v4 d- v4 f9 x, J - 234 spi_read_write8(SDSPI,n);+ j3 S' b6 A3 W2 R8 \, z% j5 R' L) o
- 235 /* Receive command response */' _# ?# \5 b T# h# o& O! u$ _+ ~ P' p
- 236 if (cmd == CMD12) spi_read_write8(SDSPI,0xff); / b- p+ s' u7 ^% }) @- _
- 237 /* Skip a stuff byte when stop reading */
( }% {) c- @! I) S* I - 238 /* Wait for a valid response in timeout of 10 attempts */
! W5 o$ [5 c$ q2 d4 q6 h6 K - 239 n = 10;
$ C" @7 N/ p2 E) y - 240 do res=spi_read_write8(SDSPI,0xff); while ((res & 0x80) && --n);
; I* { l, [$ m - 241( S* i5 f$ s4 T& d
- 242 while (SPI_SR(SDSPI) & SPI_SR_BSY); //wait if busy
3 o% Y8 _, b8 X" n8 l3 N - 243
' I7 p. R4 B, f! i' X+ U3 ~ - 244 return res; /* Return with the response value */
# |. {8 l6 ?) ^2 O+ B4 { - 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/*-----------------------------------------------------------------------*/. Y3 z9 v/ T# S7 F" @. X3 d
- 2/* Read Sector(s) */
# C( ~" I+ g$ E/ v. Z# O! B) v1 ? - 3/*-----------------------------------------------------------------------*/0 n1 z# ]" V7 F
- 4
! c) X8 ?+ z e0 ?, K$ G - 5DRESULT disk_read (
1 y3 J4 k, D) H! q9 ?' F$ L - 6 BYTE pdrv, /* Physical drive nmuber to identify the drive */$ l2 W' w2 M) ]6 A" i+ V
- 7 BYTE *buff, /* Data buffer to store read data */2 [* } A0 e% F
- 8 LBA_t sector, /* Start sector in LBA */
5 Q, O' N. f% X6 P: f - 9 UINT count /* Number of sectors to read */
/ a8 B7 `" d1 v* r& B - 10)+ a4 L* }" x5 {9 u' r( z; I
- 11{
: \) r& D* h7 x - 12 while(count){2 f( ~4 O" X* b- {! ~/ c0 K
- 13 if (spi_sd_read(buff,sector)) return RES_ERROR;/ s3 h! z7 P: K2 g
- 14 --count;$ M) e6 p+ C3 u: H
- 15 ++sector;) j! g6 f0 x' D& x7 a. i+ W
- 16 buff+=512;( u4 n" U3 s* _/ x( G+ ], |
- 17 }* F; |4 v2 |7 h5 }1 K
- 18 return RES_OK;$ }+ Z9 \4 o! H) N
- 19}
0 p \+ N; ?6 N9 { - 20
! b" @$ r; A# B! p1 | - 21: A ]. m `( T$ y, x P" K+ F
- 22
# }/ A6 H6 c! f ` - 23/*-----------------------------------------------------------------------*/
2 T0 g2 E. k, n- \5 m- p' Y5 `: l - 24/* Write Sector(s) */6 V. h& Y7 n6 R5 M: J6 t
- 25/*-----------------------------------------------------------------------*/* J" ~) }# s0 O& }2 M1 `3 a3 N5 u/ e
- 26
- m$ g4 C4 a5 G6 y1 i - 27#if FF_FS_READONLY == 0- C6 Q: O# Y( S( \& b- [/ x
- 28
+ k+ Q3 _, U7 k4 B x# h! ~ - 29DRESULT disk_write (4 Z7 i) v* R' {+ E8 B
- 30 BYTE pdrv, /* Physical drive nmuber to identify the drive */5 r$ H* z# ^$ Y# g3 O( j; |! D0 q
- 31 const BYTE *buff, /* Data to be written */5 u; W; X5 E2 X$ j
- 32 LBA_t sector, /* Start sector in LBA */
, L5 D d+ ~+ D. U - 33 UINT count /* Number of sectors to write */, O2 P& E7 u% T& e7 Z8 U @
- 34)) M$ ~" q' q- j( H) v) `
- 35{; Z8 F) y; N3 u# h3 z
- 36 while(count){
$ {( [8 d: }/ j+ G6 G - 37 if(spi_sd_write(buff,sector)) return RES_ERROR;
, L: K/ W/ K- x) a9 B5 j! X0 ] - 38 --count;, o& _* u# u$ j9 Y4 l/ W8 d0 {, N
- 39 ++sector;8 }( N9 [9 X) k7 J
- 40 buff+=512;2 y" R1 x; h% n2 X+ N- i
- 41 }
' O. G; z4 \/ w/ |1 z3 t" x - 42 return RES_OK;0 H1 D+ E2 ]- w& [
- 43}
复制代码
7 F( T% F; }! K$ X0 J9 }/ ?5 ]
* J6 Q v. D) Z9 e2.3 SPI接口配置 - 1static void spi1_init(void){
# J8 Y# l5 l4 h/ @5 g - 2 //spi1 - display# T* q$ z9 u& A1 J0 b* k: }2 V
- 3 /* Enable SPI1 Periph and gpio clocks */7 r$ F+ m, X ?
- 4 rcc_periph_clock_enable(RCC_SPI1);
' Q0 L; t/ I: S) k3 y/ P, f - 5 rcc_periph_clock_enable(RCC_GPIOA);% m* Q$ z4 w$ F* G I2 ^5 D
- 6
8 q+ r6 R3 @- l1 [6 X2 S - 7 /* Configure GPIOs:
2 m# d! W) [, m. m) V - 8 *
! S: i9 ?7 a9 z% V) d, X7 @/ x - 9 * SCK=PA5
, A) e& t1 `% g( j - 10 * MOSI=PA7
- k7 [3 V5 N& v - 11 * MISO=PA6$ y- G. ~% w9 M0 t3 C0 P
- 12 * ' k- j8 Q0 X8 G, U f
- 13 * for SD card& i2 z) G* v+ i5 T9 k
- 14 * SDCS PA4
) a3 g) ? p9 S$ Z+ k# h - 15 */
8 E! e" x! Z% B* [, b1 n; [ - 16
8 M, O+ d- g# c+ g D - 17 //MOSI & SCK & MISO
5 t. I8 U. \2 {8 T1 B' q - 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 gpio_set_af(GPIOA,GPIO_AF0,GPIO5|GPIO7|GPIO6);
( K. a9 ~1 a: o - 20 gpio_set_output_options(GPIOA, GPIO_OTYPE_PP,GPIO_OSPEED_LOW,GPIO5|GPIO7|GPIO6);
6 ~# U( r& P% j3 T/ C. J - 219 Q9 B$ S' X3 ?7 Y3 W9 n* b3 Z7 O# u
- 22 //SDCS + b c% l" I- [7 b8 e+ ^7 W" q
- 23 gpio_mode_setup(GPIOA,GPIO_MODE_OUTPUT,GPIO_PUPD_NONE,GPIO4);( L! s* D& |) j, J0 Q o8 _
- 240 r: Q/ ~8 p/ s" ?1 P: ~* w! T
- 25 gpio_set(GPIOA,GPIO4);( G2 \( m8 S6 P5 B6 f# }
- 26' s3 j, s) A z; y2 x; A0 c- \
- 27 /* Reset SPI, SPI_CR1 register cleared, SPI is disabled */
* I- H, K; v- o' F9 w" N - 28 spi_reset(SPI1);
5 g+ V% E' k ~+ G& S, M - 29
' R2 h9 O1 x3 y+ A, V+ U( K - 30 /* Set up SPI in Master mode with:; B7 b( x( t" _! [$ J" H3 r
- 31 * Clock baud rate* n( R# D; F# N7 W5 L
- 32 * Clock polarity
7 |0 X4 M. X6 Q! l9 `# S - 33 * Clock phase- u8 D4 g' P' z8 y4 q4 ?
- 34 * Frame format MSB9 v+ v3 C- E0 @6 T9 j
- 35 */
( \5 `: [ e3 ?/ b! H. t. ^ - 36 spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_128,
7 n5 k! g& d! n4 N - 37 SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,4 a; G9 j% a0 n3 @* r# |7 o
- 38 SPI_CR1_CPHA_CLK_TRANSITION_1,
& u8 ?+ c; D. n$ ~! a! C - 39 SPI_CR1_MSBFIRST);2 l( U5 L5 o; i( U O$ m
- 40
* G( f/ G, B d, q5 Q - 41 spi_set_data_size(SPI1,SPI_CR2_DS_8BIT);: }0 M- f1 c0 p8 a+ h& h
- 42 spi_set_full_duplex_mode(SPI1);3 G5 Y' m. [1 m/ k# @6 m
- 439 Y2 B' W! ?' N
- 44 spi_fifo_reception_threshold_8bit(SPI1);) y1 M" O2 P9 I" ]
- 452 S: O: B. X9 m- D6 r5 M
- 46 SPI_CR2(SPI1) |= SPI_CR2_NSSP; //NSSP, ?? clock continus1 ~4 m+ O G! r; }, o- J
- 47 // spi_set_unidirectional_mode(SPI1);
4 | }6 I7 m% n7 D" b. k. @* w: J/ ~4 I+ n - 48 // SPI_CR2(SPI1) &= (~SPI_CR2_FRF_TI_MODE); //motorala mode8 \1 l/ n. j% @ r7 R
- 49 // SPI_CR2(SPI1) |= SPI_CR2_FRF_TI_MODE;
: f$ _& i0 w' q+ e% S c - 50
) y1 ] N: K$ V+ O! f z7 A9 O8 I - 51 /*
8 Q L' t& V4 o% Q, \ - 52 * Set NSS management to software.
$ ?0 ~2 Q: C, D2 @ - 53 *
" Y1 { a6 c: u! T. | - 54 * Note:. U6 F+ {' o5 m$ s) O; v: Z
- 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 * the GPIO$ c; Q, v( ]6 ?4 U; H) ?3 k
- 57 * ourselves this bit needs to be at least set to 1, otherwise the spi
4 X* h% u" ^3 h- B - 58 * peripheral will not send any data out.7 o* V& y _# M+ \1 ?% ]" t( ?
- 59 */( [5 ?. Y6 \3 C% j/ V
- 60 spi_enable_software_slave_management(SPI1);! Z- O8 a; x3 p) f* r
- 61 spi_set_nss_high(SPI1);
7 m, C! s6 ~. i# u - 62
* X1 e" I, k" f& D! y. D - 63 /* Enable SPI1 periph. */
/ A8 x" w. v& z) n* X( t - 64 spi_enable(SPI1);" W3 r" a) G2 A5 E
- 656 n& I. `$ t4 t$ a/ e7 K- T' j
- 66}
复制代码 , R% _" ^3 ^$ a4 v* r
- N# j) P( j& O6 I
2.4 SD卡读写测试
5 c; r G: k: _2 g4 N! t$ ]+ ]- 1printf(" init spi.\n");$ D! p; S+ N( j
- 2 x8 B% S, b% r( o
- 3//spi
# J* X" i+ M1 H5 ~$ P+ ^2 ` - 4spi1_init();- t( G8 n4 R7 P: f- C n
- 5
/ q, t: n# S0 J9 ~ - 6//sd3 h5 I3 G6 p; c" H7 s% v s' X
- 7uint8_t sd_type = spi_sd_init();
- n1 C4 _- K! U+ H - 85 U( r h) c% s R6 i
- 9//sdv2: 0x08|0x04 . 0x0c1 w- `7 Y' e3 O6 J3 T, v
- 10// printf(" sd_type: %x\n", sd_type);, D0 W( a) g& f
- 11
) q& V/ S3 J, x; L" ^) d8 F - 12FATFS fs;/ \8 B, m0 s! q9 d9 \
- 13FRESULT res;
% B- n5 B' i5 z$ q! P - 14res = f_mount(&fs, "", 0);/ ?: c# z4 u8 _! i1 M h4 Q
- 15if(res != FR_OK) {& o- R. ]) z% U% |+ ?0 M( W- M
- 16 printf("mount fs failed, res = %d\r\n", res);
5 t) F- l# p4 e2 c - 17 return -1;
/ V' p' S7 P) R% E+ h7 g - 18}else{7 T$ V( Z$ n4 P" p$ j( n2 s7 F5 Q6 l, Z
- 19 printf(" mount fs OK.\n");
( n' p! F5 K n - 20}# u) E5 _1 ^6 Z0 \0 P/ r
- 21" n/ G3 b$ H4 S/ H
- 22FIL fd;
5 F( b! a S' `; e2 x0 O# V8 w - 23
3 [6 @# v; _$ Q) S3 L' O5 K8 b - 24res = f_open(&fd, "test.txt", FA_CREATE_ALWAYS|FA_WRITE);
. e* U; g0 b/ R" D$ A6 @" ~" q - 25if(res != FR_OK){
& w- M* g8 Q e5 ~* I - 26 printf("open file failed: %d\n", res);1 j6 T! x( w9 h" f
- 27}else{
/ s9 R6 L: P2 p5 ^ - 28 printf("open file OK.\n");* \. M3 ~. s5 X* A7 p$ E
- 29}8 Y/ @. o% B/ ]
- 30, b+ O' R$ B4 R8 O
- 31char *buff = "test data to write to fs\n";
7 g" D( ^, S6 ?+ ]) b6 y0 y - 32uint32_t len = 0;
' o* T2 q$ U; c. k: A - 33res = f_write(&fd,buff, strlen(buff),&len);/ P9 r6 j7 S' E! E, n0 f
- 34if(res != FR_OK){) `6 l0 h0 P, i. ~
- 35 printf(" write file failed.\n");# ]* V$ T3 b I( F& f; T9 q, ~
- 36}else{* X9 R; c* ?$ @6 R( e" k
- 37 printf(" write file OK, write size %d .\n", len);% e! z5 G3 d3 h. i" p
- 38}6 p# X2 a" |3 G* K( ?
- 39
: N' e3 v# L1 P: C+ Y K - 40res = f_close(&fd);
6 [, N Y1 c0 g3 m5 @ - 41if(res != FR_OK){
% c5 h" _! l+ K/ D, R, X - 42 printf(" close fs failed.\n");
% w7 `5 h! r' \% I7 v - 43}else{
/ Z( J* o# B4 A! E$ Q9 H, k - 44 printf(" close fs OK.\n");& h: T! V/ W! h$ M4 ~4 ]6 k! H
- 45}8 @+ \% s( V0 ^
- 46/ x9 b9 d2 {$ J( m$ _8 p
- 47res = f_unmount("");4 C: w- s9 g& f- D
- 48if(res != FR_OK) {5 T2 U8 T; `0 ]7 e. F3 ]% ]
- 49 printf("Unmount fs failed, res = %d\r\n", res);1 b( K1 p% k8 K E# U
- 50 return -1;
3 O% G) _2 s' b M& L. t - 51}else{
- m% ^7 s- ~3 T5 x0 O* ? - 52 printf("Unmound fs OK.\n");+ l0 _8 [/ l( b7 Y- r
- 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
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
8 J$ M$ D4 \# q: w4 {# \# ^: i& Q4 _
0 j2 v5 ^( t- o) U8 O |