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

发布时间:2023-08-03  

使用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;

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

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>