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