STM32G0开发笔记:SD卡模块的使用方法

来源: 电子工程世界
新闻行业新闻

使用Platformio平台的libopencm3开发框架来开发STM32G0,下面介绍SD卡模块的使用方法。


1 新建项目

在PIO主页新建项目spi_sdcard,框架选择libopencm3,开发板选择 MonkeyPi_STM32_G070RB;

新建完成后在src目录新建主程序文件main.c;

然后更改项目文件platformio.ini的烧写和调试方式:

1upload_protocol = cmsis-dap

2debug_tool = cmsis-dap

2 编写程序

2.1 加入FATFS库

从网站fatfs http://elm-chan.org/fsw/ff/00index_e.html 下载最新的源码;

工程目录lib下新建fatfs文件夹;

然后将fatfs源码的source目录下所有文件放置到工程的libfatfs目录下;

将diskio.c文件移动到src目录下,这个文件是需要我们实现的底层接口;

2.2 实现SPI接口的SD读写

在src目录下新建spi_sd.h 和 spi_sd.c 文件,现在目录结构如下:

spi_sd.h 头文件

1/**

 2 * @file spi_sd.h

 3 * @author MakerInChina (makerinchina.cn)

 4 * @brief 

 5 * @version 0.01

 6 * @date 2022-09-18

 7 * 

 8 * @copyright Copyright (c) 2022

 9 * 

10 */

11

12#ifndef _SPI_SD_HEAD_H_

13#define _SPI_SD_HEAD_H_

14

15#include 

16

17/**

18 * @brief init sd card

19 * 

20 */

21uint8_t spi_sd_init();

22

23/**

24 * @brief spi read sd

25 * 

26 * @param buff 

27 * @param sector 

28 */

29uint8_t spi_sd_read(uint8_t *buff, uint32_t sector);

30

31/**

32 * @brief spi write sd

33 * 

34 * @param buff 

35 * @param sector 

36 */

37uint8_t spi_sd_write(uint8_t *buff, uint32_t sector);

38

39#endif //!_SPI_SD_HEAD_H_

spi_sd.c 实现

1/**

  2 * @file spi_sd.c

  3 * @author MakerInChina (makerinchina.cn)

  4 * @brief 

  5 * @version 0.01

  6 * @date 2022-09-18

  7 * 

  8 * @copyright Copyright (c) 2022

  9 * 

 10 */

 11

 12#include "spi_sd.h"

 13

 14#include 3/stm32/spi.h>

 15#include 3/stm32/gpio.h>

 16

 17#define SDSPI    SPI1

 18#define SD_CS    GPIO4

 19#define SD_PORT  GPIOA

 20

 21#define spi_cs_deselect()   gpio_set(SD_PORT, SD_CS)

 22#define spi_cs_select()     gpio_clear(SD_PORT, SD_CS)

 23

 24

 25/* Definitions for MMC/SDC command */

 26#define CMD0    (0x40+0)    /* GO_IDLE_STATE */

 27#define CMD1    (0x40+1)    /* SEND_OP_COND (MMC) */

 28#define ACMD41    (0xC0+41)   /* SEND_OP_COND (SDC) */

 29#define CMD8    (0x40+8)    /* SEND_IF_COND */

 30#define CMD9    (0x40+9)    /* SEND_CSD */

 31#define CMD10    (0x40+10)   /* SEND_CID */

 32#define CMD12    (0x40+12)   /* STOP_TRANSMISSION */

 33#define ACMD13    (0xC0+13)   /* SD_STATUS (SDC) */

 34#define CMD16    (0x40+16)   /* SET_BLOCKLEN */

 35#define CMD17    (0x40+17)   /* READ_SINGLE_BLOCK */

 36#define CMD18    (0x40+18)   /* READ_MULTIPLE_BLOCK */

 37#define CMD23    (0x40+23)   /* SET_BLOCK_COUNT (MMC) */

 38#define ACMD23    (0xC0+23)   /* SET_WR_BLK_ERASE_COUNT (SDC) */

 39#define CMD24    (0x40+24)   /* WRITE_BLOCK */

 40#define CMD25    (0x40+25)   /* WRITE_MULTIPLE_BLOCK */

 41#define CMD55    (0x40+55)   /* APP_CMD */

 42#define CMD58    (0x40+58)   /* READ_OCR */

 43

 44#define CT_MMC 0x01 /* MMC ver 3 */

 45#define CT_SD1 0x02 /* SD ver 1 */

 46#define CT_SD2 0x04 /* SD ver 2 */

 47#define CT_SDC (CT_SD1|CT_SD2) /* SD */

 48#define CT_BLOCK 0x08 /* Block addressing */

 49

 50static uint8_t spi_read_write8(uint32_t spi, uint8_t tx);

 51static uint8_t wait_ready(void);

 52static uint8_t send_cmd (uint8_t cmd,uint32_t arg);

 53static void set_spi_slow();

 54static void set_spi_fast();

 55

 56/**

 57 * @brief init sd card

 58 * 

 59 */

 60uint8_t spi_sd_init()

 61{

 62    uint8_t n, cmd, ty, ocr[4];

 63    uint16_t i;

 64

 65

 66    //init with low speed

 67    // set_spi_slow();

 68

 69    spi_cs_select();

 70

 71    for (n = 10; n; n--) spi_read_write8(SDSPI,0xff);   /* 80 dummy clocks */

 72

 73    ty = 0;

 74

 75    /* Enter Idle state */

 76    ty = send_cmd(CMD0, 0);

 77

 78    // printf("  > enter idle:%d ", ty);

 79

 80    /* Initialization timeout of 1000 milliseconds */

 81    /* SDHC */

 82

 83    if(ty == 1){

 84

 85        if (send_cmd(CMD8, 0x1AA) == 1){ /* SDv2? */

 86        /* Get trailing return value of R7 response */

 87            for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);

 88            /* The card can work at VDD range of 2.7-3.6V */

 89            if (ocr[2] == 0x01 && ocr[3] == 0xAA){

 90                /* Wait for leaving idle state (ACMD41 with HCS bit) */

 91                i=0xfff;

 92                while (--i && send_cmd(ACMD41, 1UL << 30));

 93                if (i && send_cmd(CMD58, 0) == 0){

 94                /* Check CCS bit in the OCR */

 95                    for (n = 0; n < 4; n++) ocr[n] = spi_read_write8(SDSPI,0xff);

 96                    ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;

 97

 98                }

 99            }

100        }  else {    /* Not SDv2 card */

101            // if (send_cmd(ACMD41, 0) <= 1)    {   /* SDv1 or MMC? */

102            //  ty = CT_SD1; cmd = ACMD41;  /* SDv1 (ACMD41(0)) */

103            // } else {

104            //  ty = CT_MMC; cmd = CMD1;    /* MMCv3 (CMD1(0)) */

105            // }

106

107            // while (SPI_Timer_Status() && send_cmd(cmd, 0)) ;     /* Wait for end of initialization */

108            // if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0)    /* Set block length: 512 */

109            //  ty = 0;

110        }

111

112    }

113    //CardType = ty;

114

115

116    spi_cs_deselect();

117    spi_read_write8(SDSPI,0xff);

118    while (SPI_SR(SDSPI) & SPI_SR_BSY);

119

120    set_spi_fast();

121

122    return ty;

123}

124

125/**

126 * @brief spi read sd

127 * 

128 * @param buff 

129 * @param sector 

130 */

131uint8_t spi_sd_read(uint8_t *buff, uint32_t sector)

132{

133    uint8_t result;

134    uint16_t cnt=0xffff;

135    spi_cs_select();    

136    result=send_cmd(CMD17, sector); //CMD17 даташит стр 50 и 96

137    if (result){spi_cs_deselect(); return 5;} //Выйти, если результат не 0x00

138

139    spi_read_write8(SDSPI,0xff);

140    cnt=0;

141    do result=spi_read_write8(SDSPI,0xff); while ((result!=0xFE)&&--cnt);

142    if(!cnt){spi_cs_deselect(); return 5;}

143

144    for (cnt=0;cnt<512;cnt++) *buff++=spi_read_write8(SDSPI,0xff); 

145

146    spi_read_write8(SDSPI,0xff); 

147    spi_read_write8(SDSPI,0xff);

148    spi_cs_deselect();

149    spi_read_write8(SDSPI,0xff);

150

151    return 0;

152}

153

154/**

155 * @brief spi write sd

156 * 

157 * @param buff 

158 * @param sector 

159 */

160uint8_t spi_sd_write(uint8_t *buff, uint32_t sector)

161{

162    uint8_t result;

163    uint16_t cnt=0xffff;

164    spi_cs_select();

165    result=send_cmd(CMD24,sector); //CMD24 

166    if(result){spi_cs_deselect(); return 6;} //

167    spi_read_write8(SDSPI,0xff);

168    spi_read_write8(SDSPI,0xfe);//

169    for (cnt=0;cnt<512;cnt++) spi_read_write8(SDSPI,buff[cnt]); //Данные

170    spi_read_write8(SDSPI,0xff);

171    spi_read_write8(SDSPI,0xff);

172    result=spi_read_write8(SDSPI,0xff);

173    //result=wait_ready();

174    if((result&0x05)!=0x05){spi_cs_deselect(); return 6;} 

175    //spi_read_write8(SDSPI,0xff);

176    while (SPI_SR(SDSPI) & SPI_SR_BSY);

177    //

178    spi_cs_deselect();

179    spi_read_write8(SDSPI,0xff);

180    return 0;

181}

182

183

184static void set_spi_slow()

185{

186    // spi_disable(SDSPI);

187    spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_128);

188    // spi_enable(SDSPI);

189}

190

191static void set_spi_fast()

192{

193    // spi_disable(SDSPI);

194    spi_set_baudrate_prescaler(SDSPI,SPI_CR1_BAUDRATE_FPCLK_DIV_8);

195    // spi_enable(SDSPI);

196}

197

198static uint8_t spi_read_write8(uint32_t spi, uint8_t tx)

199{

200    spi_send8(spi, tx);

201    return spi_read8(spi);

202}

203

204static uint8_t wait_ready(void)

205{

206    uint8_t res;

207    uint16_t cnt=0xffff;

208    spi_read_write8(SDSPI, 0xff);

209    do res = spi_read_write8(SDSPI, 0xff); while ((res!=0xFF)&& --cnt );

210    return res;

211}

212

213static uint8_t send_cmd (uint8_t cmd,uint32_t arg)

214{

215    uint8_t n, res;

文章来源于: 电子工程世界原文链接

本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。