STM32的SD卡读取
STM32F103调试读SD卡经验总结
WL板子EK-STM32F103调试读S D卡经验总结一开始碰到的问题:发送CMD0能执行返回01,CMD1超时没响应。
查到原因:模板程序控制SD供电逻辑反了。
#if 0#define MSD_POWER_ON() GPIO_ResetBits(GPIOD, GPIO_Pi n_10)#define MSD_POWER_OFF() GPIO_SetBits(GPIOD, GPIO_Pin_10)#else#define MSD_POWER_ON() GPIO_SetBits(GPIOD, GPIO_Pin_10)#define MSD_POWER_OFF() GPIO_ResetBits(GPIOD, GPIO_Pin_10)#endif第二个问题:单步执行CMD0,CMD1,有响应,直接运行没响应。
查到原因,上电时间少于1ms,SD卡内部复位没准备好,初始化前加廷时1ms./* delay 1ms*/delay(5000);/* MSD chip select low */MSD_CS_LOW();/* Send CMD0 (GO_IDLE_STATE) to put MSD in SPI m ode */MSD_SendCmd(MSD_GO_IDLE_STATE, 0, 0x95);第三个问题:有时执行还是没有响应。
原因,SD卡初始化SPI时钟要在100kHz到400kHz之间,更改SPI速率为180kHz.第四个问题:读SD卡CSD寄存器没返回数据。
原因:供电不足,平时只有2.9V,SPI通迅时,出现瞬间低于2.7V现像。
短接直接供3.3V,如附图。
继续其它试验。
出处:kimfufree[最后修改于2008-09-03 19:58]。
STM32读写SD卡
3.20SD卡实验很多单片机系统都需要大容量存储设备,以存储数据。
目前常用的有U盘,FLASH芯片,SD卡等。
他们各有优点,综合比较,最适合单片机系统的莫过于SD卡了,它不仅容量可以做到很大(32Gb以上),而且支持SPI接口,方便移动,有几种体积的尺寸可供选择(标准的SD 卡尺寸,以及TF卡尺寸),能满足不同应用的要求。
只需要4个IO口,就可以外扩一个最大达32GB以上的外部存储器,容量选择尺度很大,更换也很方便,而且方便移动,编程也比较简单,是单片机大容量外部存储器的首选。
ALIENTKE MiniSTM3开发板就带有SD卡接口,利用STM32自带的SPI接口,最大通信速度可达18Mbps,每秒可传输数据2M字节以上,对于一般应用足够了。
本节将向大家介绍,如何在ALIENTEK MiniSTM32开发板上读取SD卡。
本节分为如下几个部分:3.20.1 SD卡简介3.20.2 硬件设计3.20.3 软件设计3.20.4 下载与测试3.20.1 SD卡简介SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。
SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。
大小犹如一张邮票的SD记忆卡,重量只有2克,但却拥有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性。
SD卡一般支持2种操作模式:1,SD卡模式;2,SPI模式;主机可以选择以上任意一种模式同SD卡通信,SD卡模式允许4线的高速数据传输。
SPI模式允许简单的通过SPI接口来和SD卡通信,这种模式同SD卡模式相比就是丧失了速度。
SD卡的引脚排序如下图所示:图3.20.1.1 SD卡引脚排序图SD卡引脚功能描述如下表所示:表3.20.1.1 SD卡引脚功能表SD卡只能使用3.3V的IO电平,所以,MCU一定要能够支持3.3V的IO端口输出。
STM32+SDIO+FATFS文件系统直读SD卡
STM32+SDIO+FATFS文件系统直读SD卡STM32+SDIO+FATFS文件系统直读SD卡网上关于小型嵌入式的文件系统有好多~当然要数FATFS 很是出名一来小巧,二来免费。
当然了国产的振南的znFAT 一样开源好用而且极其的省资源~!非常适合51单片。
更重要的是国语的支持,呵呵!这次在STM32上为SD卡移植文件系统还是非常简单顺利的,这多亏了ST 官方提供的驱动,而我自己不用动手编写SD卡的命令省了很多时间而且官方做的驱动虽然效率一般但是极其严谨我很是佩服。
FATFS的官方网站是znFAT的官方网站是SD卡可以用SPI驱动也可以直接用SDIO 驱动STM32 256KB FLASH 以上的片子全部都有SDIO,我们当然要用高速快捷的SDIO 方式了!至于 SDIO 又有 1位 4位 8 位的之分我想不来8位SDIO 是怎么回事?SD卡上最多只能接4位嘛~网上有人说4位的SDIO 不好用多半是固件版本太老的缘故了。
呵呵这里还是要靠库~STM32真适合懒人用。
网上关于的FATFS 的文章很多不过都太老旧,很多东西已经不适用了。
我建议阁下到官方去下载最新的版本目前是最新是R0.08b,使用最新的版本好处是很多网上很多要改来改去的地方只要你使用了新版本那就是完全可以规避的。
另外STM32 的SDIO驱动也一定要用最新的,老版本问题很多不少人的失败就在这。
我这次用的是V3.3的库没有任何改动就可以了,现在最新的好像在3.4以上了。
好了说说移植ffconf.h是配置的头文件简单的修改宏就可以了,英文注释的很完全而且网上也有翻译我不多说了自己看主要在这里进行功能裁剪写写我的配置。
#define _FS_TINY 0 /* 0:Normal or 1:Tiny 完整的FATFS 精简版的是Tiny */#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only 能读能写*/#define _FS_MINIMIZE 1 /* 0 to 3 简单的裁剪f_mkdir, f_chmod..这些功能没法用的*//* The _FS_MINIMIZE option defines minimization level to remove some functions.// 0: Full function./ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename/ are removed./ 2: f_opendir and f_readdir are removed in addition to 1./ 3: f_lseek is removed in addition to 2. */#define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable是否使用字符串文件接口 *//* To enable string functions, set _USE_STRFUNC to 1 or 2. */#define _USE_MKFS 0 /* 0:Disable or 1:Enable 制作文件系统我在PC上一般已经格式化好了*//* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */#define _USE_FORWARD 0 /* 0:Disable or 1:Enable 发文件流?*//* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable 搜索*//* To enable fast seek feature, set _USE_FASTSEEK to 1. */#define _CODE_PAGE 1 / /1 - ASCII only (Valid for non LFN cfg.)#define _USE_LFN 0 /* 0 to 3 */#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) 这些都是长文件名或是汉字文件支持很费资源所以不开启这些*/#define _FS_SHARE 0 /* 0:Disable or >=1:Enable 不使用相对路径*/#define _FS_SHARE 0 /* 0:Disable or >=1:Enable 文件共享多任务的操作系统会用到的*/#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable 这些是啥用?同步什么呢?默认就好了*/#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */integer.h主要定义了文件的类型若是最新的可以不用修改。
STM32单片机的SD卡存储器读写模块设计
S T M 32单片机的S D卡存储器读写模块设计*汤才刚,刘京京,沈瑞东(上海舜华新能源系统有限公司,上海201806)*基金项目:上海市科学技术委员会科研计划项目(19D Z 1206100)㊂摘要:为了满足氢气加气机在使用过程中大量数据的存储要求,设计了一种利用S D 卡来扩展存储的电路模块㊂在兼顾稳定性与读写速度的基础上,利用S TM 32单片机与S D 卡存储器件的接口技术,把S D 卡的读写以及F a t F S 文件系统的读取写入移植到此单片机上㊂在读写的过程中,使用W i n d o w s 中通用的文件系统使最终存储在S D 卡的数据可以直接被P C 机读取,使开发利用有更好的扩展性,取得了良好的效果㊂硬件设计方面利用单片机的S P I 接口,只需要4个I /O 口再加上几个上拉电阻就可实现与S D 卡的接口电路,软件设计方面利用I A R 嵌入式集成开发环境和移植S TM 32库函数,并使用开源的F a t F S 文件系统模块源代码实现单片机S D 卡的读写编程㊂关键词:S TM 32单片机;S P I 接口;S D 卡;F a t F S 文件系统中图分类号:T P 274 文献标识码:AD e s i gn o f S D C a r d R e a d -w r i t e M o d u l e B a s e d o n S T M 32T a n g C a i g a n g ,L i u J i n g j i n g ,S h e n R u i d o n g(S h a n g h a i S u n w i s e E n e r g y S y s t e m s C o .,L t d .,S h a n gh a i 201806,C h i n a )A b s t r a c t :I n o r d e r t o m e e t t h e l a r g e d a t a s t o r a g e r e q u i r e m e n t s o f t h e h y d r o g e n d i s pe n s e r i n u s e ,a c i r c u i t m o d u l e t h a t u s e s S D c a r d t o e x -p a n d s t o r a g e i s d e s i g n e d .B a s e d o n t h e b a l a n c e b e t w e e n s t a b i l i t y a n d r e a d i n g a n d w r i t i n g s p e e d ,t h e i n t e rf a c e t e c h n o l og y of S TM 32m i c r o -c o n t r o l l e r a n d S D c a r d s t o r ag e d e v i c e a r e u s e d t o t r a n s p l a n t S D c a r d r e a d a n d w r i t e a n d F a t F S f i l e s ys t e m r e a d a n d w r i t e t o t h i s m i c r o -c o n t r o l l e r .I n t h e p r o c e s s o f r e a d a n d w r i t e ,t h e g e n e r a l f i l e s y s t e m i n W i n d o w s i s u s e d ,s o t h a t t h e d a t a f i n a l l y st o r e d i n t h e S D c a r d c a n b e d i r e c t l y r e a d b y t h e P C ,t h e d e v e l o p m e n t a n d u t i l i z a t i o n h a v e b e t t e r s c a l a b i l i t y a n d a c h i e v e d g o o d r e s u l t s .T h e h a r d w a r e d e s i gn u s e s t h e S P I i n t e r f a c e o f t h e s i n g l e -c h i p m i c r o c o m p u t e r ,o n l y f o u r I /O p o r t s a n d a f e w p u l l -u p r e s i s t o r s c a n b e u s e d t o a c h i e v e t h e i n t e r f a c e c i r c u i t w i t h t h e S D c a r d .T h e s o f t w a r e d e s i g n u s e s t h e I A R e m b e d d e d i n t e g r a t e d d e v e l o p m e n t e n v i r o n m e n t a n d t r a n s p l a n t a t i o n o f S TM 32l i b r a r y f u n c t i o n s ,a n d u s e t h e s o u r c e c o d e o f t h e o p e n s o u r c e F a t F S f i l e s y s t e m m o d u l e t o r e a l i z e t h e p r o g r a mm i n g of t h e r e a d a n d w r i t e o f t h e S D c a r d o f t h e s i ng l e chi p m i c r o c o m pu t e r .K e y wo r d s :S TM 32m i c r o c o n t r o l l e r ;S P I i n t e r f a c e ;S D c a r d ;F a t F S f i l e s y s t e m 引 言在氢气加气机使用过程中,经常需要存储大量的数据,并且要求在P C 机上查看数据㊂由于受单片机自身硬件的限制,为了实现大容量数据的存储,必须要通过单片机的外部扩展来实现,现在通常使用的方法是在单片机外部扩展大容量E E P R OM 或F L A S H 芯片来实现㊂这种方法有两个缺点:①外部电路连接复杂,通用性差,对于不同的系统需要采用不同的电路;②存储的数据读取非常不便,需要通过单片机系统发给P C 机来实现㊂综合比较后发现,最适合单片机系统的莫过于S D 卡了,不仅容量大(32G B 以上),而且支持S P I 方式,方便移动,能满足不同应用的要求㊂只需要几个I /O 口就可以外扩一个最大达32G B 以上的外部存储器,容量选择范围很大,更换也很方便,而且方便移动,编程也简单,是单片机大容量外部存储器的首选[1]㊂为了方便管理S D 卡中的文件㊁高效地读写数据,需要在S D 卡中装载文件系统㊂因F a t F S 文件系统源码开源,资源占用少,兼容性好,使用范围较广,本设计利用S TM 32自带的S P I 接口与S D 卡连接通信,电路非常简单且易于实现,并成功实现了在S D 卡中建立F a t F S 文件系统,使S TM 32单片机能够对S D 卡中的文件进行读写等操作㊂1 系统结构设计S D 卡一般支持2种模式:S D 模式和S P I 模式㊂主机可以选择任意一种模式与S D 卡通信,S D 模式允许4线的高速数据传输,S P I 模式允许简单地通过S P I 接口与S D 卡通信,这种模式较S D 模式速度慢,不过利用S T M 32片内集成的S P I 接口,最大通信速度可达18M b ps ,每秒可传输数据2M B 以上,对于单片机系统一般的应用足够了[2]㊂本设计的S D 卡接口电路硬件设计主要由以S TM 32F 103V C T 6为核心的处理器㊁电源和S D 卡及连接器组成㊂系统整体结构如图1所示㊂图1 系统整体结构2 硬件电路设计2.1 S T M 32单片机简介本设计使用的主控制芯片为S TM 32F 103V C T 6单片机,主要实现S P I 模块功能,控制S D 卡的读写㊂该单片机是S T 公司推出的基于A R M C o r t e x M 3内核的高性能的微处理器芯片,该单片机功能强大,处理速度快㊂在软件开发上应用I A R E m b e d d e d W o r k b e n c h f o r A R M 嵌入式集成开发平台进行产品研发,使得整个产品的研发周期大大缩短并使整个程序移植性强,方便易懂㊂S TM 32F 103V C T 6单片机工作主频最高可达72MH z ,封装形式为L Q F P 100,内置256K B F L A S H 和48K B R AM ,包含10个定时器㊁2个12位的A D C ㊁5个异步通信串行口U S A R T ㊁3个同步通信串行口S P I ㊁2个I 2C接口㊁80个I /O 口等[4-5]㊂2.2 S D 卡接口电路设计本设计中使用S TM 32F 103V C T 6单片机P B 12㊁P B 13㊁P B 14㊁P B 15这4个I /O 口所组成的片内集成S P I 2接口与S D 卡进行通信,单片机为主设备,S D 卡为从设备㊂所对应的信号线分别为S D _C S 为片选控制端;S D _S C K 为主设备时钟输出端口,与S D 卡时钟输入端口相连;S D _M I S O 为主设备输入端口,与S D 卡数据输出端口相连;S D _MO S I 为主设备输出端口,与S D 卡数据输入端口相连㊂这4根信号线必须接上拉电阻[3],连接电路图如图2所示㊂3 软件设计3.1 F a t F S 文件系统应用F a t F S 是一个开源的㊁为小型嵌入式系统设计的通用F A T 文件系统模块,支持F A T 12㊁F A T 16与F A T 32,支持多种存储媒介,有独立的缓冲区,可对多个文件进行读图2 S D 卡与S T M 32连接电路图写,可裁剪的文件系统㊂F a t F S 的编写遵循A N S I C ,并且完全与磁盘I /O 层分开㊂因此,它独立(不依赖)于硬件架构,可以被嵌入到低成本的微控制器中(如A V R ㊁8051㊁P I C ㊁A R M ㊁Z 80㊁68K 等),而不需要做任何修改㊂F a t F S 文件系统在嵌入式软件开发中的应用图如图3所示,应用图3 F a t F S 文件系统应用图层使用F a t F S 提供的A P I 函数与F a t F S 模块通信,F a t F S 模块使用F a t F S 提供的底层存储介质接口函数对存储设备进行配置,只有这样才能正常使用F a t F S 文件系统[4]㊂3.2 程序流程图主程序总体设计思路:系统上电后单片机内部进行复位,接着对系统时钟㊁G P I O 口㊁S D 卡接口硬件进行配置㊂G P I O 口初始化时需要使能S P I 2时钟,否则无法开启单片机的S P I 模式㊂接下来配置F a t F S 底层存储介质接口函数,将S D 驱动有关的操作放在文件系统中,再调用A P I 接口函数,将S D 卡写入数据或读取S D 卡的数据,最后在P C机上对数据进行验证[5]㊂主程序设计流程如图4所示㊂3.3 S D 卡S P I 模式下的命令S P I 模式下S D 卡和单片机的通信采用发送应答机制㊂首先主机端(单片机)发送命令c o mm a n d ,S D 卡应答r e s po n s e ㊂S D 卡的命令格式如下:字节1字节2~5字节6765 031 07 1001c o mm a n d命令参数C R C1S D 卡的指令由6个字节组成,字节1的最高2位固图4 程序流程图定为01,低6位为命令号,比如C M D 17,为10001即16进制0x 11,完整的C M D 17,第一个字节为01010001,即0x 11+0x 40;字节2~5位为命令参数,有些命令没有参数;字节6的高7位为C R C 值,最低位固定为1㊂S D 卡的命令总共有12类,下面是几个重要的命令,如表1所列㊂表1 S D 卡部分操作指令命 令参 数回 应描 述C MD 0(0x 00)N O NE R 1复位S D 卡C MD 8(0x 08)V H S +C h e c kP a t t e r nR 7发送接口状态命令C M D 9(0x 09)N O N E R 1读取卡特定数据寄存器C M D 10(0x 0A )N O N E R 1读取卡标志数据寄存器C M D 16(0x 10)按大小R 1设置块大小(字节数)C M D 17(0x 11)地址R 1读取一个块的数据C M D 24(0x 18)地址R 1写入一个块的数据C M D 41(0x 29)N O N E R 3发送给主机容量支持信息和激活卡初始化过程C M D 55(0x 37)N O N E R 1告诉S D 卡,下一个是特定应用命令C MD 58(0x 3A )N O N ER 3读取O C R 寄存器单片机每发送一条命令,S D 卡都会给出一个应答,以告知主机该命令的执行情况,或者返回主机需要获取的数据㊂S P I 模式下,S D 卡针对不同的命令,应答可以是R 1~R 7,其中R 1的应答最多,其格式如下:B I T 7B I T 6B I T 5B I T 4B I T 3B I T 2B I T 1B I T 00参数错误地址错误连续擦除错误命令C R C 错误非法命令擦除错误I D L E状态3.4 S D 卡初始化对S D 卡进行初始化操作,是S D 卡进行正常数据读写的前提㊂S D 卡接入后,默认进入S D 模式,等待电压稳定需上电延时250m s 即等待至少74个时钟周期㊂将时钟周期频率设置为100~400k H z ,拉低片选信号C S,发送C M D 0㊂如果收到应答信号01H ,则表示S D 卡进入S P I 模式[6]㊂S D 卡的初始化过程如下:①初始化与S D 卡连接的硬件配置(C P U 的S P I 配置,I /O 口配置);②上电延时(大于74个C L K );③复位卡(C M D 0),进入I D L E 状态;④发送C M D 8,检查是否支持2.0协议;⑤根据不同协议检查S D 卡并判断卡类型(命令包括C M D 1㊁C M D 55㊁C M D 41和C MD 58等);⑥取消片选,发送8个C L K 后,结束初始化㊂这样就完成了对S D 卡的初始化,注意末尾发送的8个C L K 是提供S D 卡额外的时钟,完成某些操作㊂通过S D 卡初始化可以知道S D 卡的类型(V 1㊁V 2㊁V 2H C 或MM C ),在完成初始化之后,就可以开始读写数据了㊂3.5 S D 卡读写操作S D 卡的数据读写以块为单位,一个块的最大长度为512字节,在初始化中进行设置㊂单片机发送C M D 17或C MD 18进行S D 卡的单个块或多个块的读操作;单片机发送C M D 24或C M D 25进行S D 卡的单个块或多个块的写操作㊂下面以读写单个块为例,介绍具体操作过程,读写多个块的过程与此类似,命令为C M D 18和C M D 25㊂读S D 卡单个块数据,具体过程如下:①发送C M D 17;②接收卡响应R 1;③接收数据起始令牌0x F E ;④接收数据;⑤接收2个字节的C R C ,如果不使用C R C ,这两个字节在读取后可以丢掉;⑥禁止片选之后,发8个C L K ㊂写S D 卡单个块数据,具体过程如下:①发送C M D 24;②接收卡响应R 1;③发送写数据起始令牌0x F E ;④发送数据;⑤发送2字节的伪C R C ;⑥禁止片选之后,发8个C L K[7]㊂S D 卡数据的读写基本单位是块,如需大数据量的读写操作,可以有两种方法实现:单块的多次读写和多块读写的命令㊂在速度要求不高的场合可以使用单块的多次读写,在高速的数据读写场合,必须使用多块读写的命令,效率比单块的多次读写高很多㊂3.6 F a t F S 文件系统模块移植在S TM 32程序工程中需要新建两个文件夹,F a t F S用于存放F a t F S 源文件,U s e r 文件夹下S P I _S D _D r i v e r .c 文件用于存放S P I 的底层驱动文件,这个文件是S D 卡初始化和读写相关的函数㊂这些函数是在d i s k i o .c 文件中的5个函数所调用的:函数d i s k _i n i t i a l i z e ,S D 卡的初始化,调用底层的S D _I n i t ()函数;函数d i s k _s t a t u s ,获取S D卡的状态,这里可以不用管;函数d i s k _r e a d ,从S D 卡中读取数据,含读S D 卡单块数据函数和多块数据函数;函数d i s k _w r i t e ,将数据写入S D 卡,含写S D 卡单块数据函数和多块数据函数,若该文件系统为只读文件系统则不用实现该函数,含写单块函数和多块函数;函数d i s k _i o c t l ,获取S D 卡文件系统相关信息[8]㊂4 S D 卡文件读写实现F a t F S 底层存储介质接口函数已修改完成,下一步就需要使用A P I 函数实现文件的读写[9]㊂具体实现代码如下:u n s i g n e d c h a r T x F i l e B u f f e r []="F a t F S S ys t e m t e s t i s O K !\r \n ";r e s =f _m o u n t (&f s ,"0:",1);/*创建一个工作区,调用初始化函数*/i f (r e s !=F R _O K )p r i n t f ("m o u n t E R R O R \n \t ");e l s ep r i n t f ("m o u n t S U C C E S S \n \t ");r e s =f _o p e n (&F i l e S ys t e m D s t ,"0:/D e m o 1.t x t ",F A _C R E A T E _A L WA Y S |F A _WR I T E );/*在刚刚开辟的工作区的盘符0下打开一个名为D e m o 1.t x t 的文件,没有则创建文件*/i f (r e s ==F R _O K ){ p r i n t f ("F i l e O pe n S U C C E S S !\n \t "); r e s=f _w r i t e (&F i l e S y s t e m D s t ,T x F i l e B u f f e r ,s i z e o f (T x F i l e -B u f f e r ),&b w );/*将缓冲区的数组变量T x F i l e B u f f e r 的内容写到刚刚打开的D e m o 1.t x t 文件中*/ i f (r e s ) p r i n t f ("F i l e W r i t e E R R O R !\n \t "); e l s ep r i n t f ("F i l e W r i t e S U C C E S S !\n \t "); f _c l o s e (&F i l e S ys t e m D s t );/*关闭文件*/}e l s e if (r e s ==F R _E X I S T )p r i n t f ("F i l e i s a l r e a d y ex i s t \n ");e l s ep r i n t f ("D o n 't k n o w t h e e r r o r !\r \n ");以上代码实现的功能是在S D 卡中新建一个文件名为D e m o 1.t x t 的文本文件,将数据缓冲区T x F i l e B u f f e r 中的内容写入这个文件中㊂r e s =f _o p e n (&F i l e S ys t e m D s t ,"0:/D e m o 1.t x t ",F A _O P E N _E X I S T I N G |F A _R E A D );i f (r e s ) p r i n t f ("F i l e O pe n E R R O R !\n \t ");e l s ep r i n t f ("F i l e O pe n S U C C E S S !\n \t ");b r =1;f o r (i =0;i <512;i ++) F i l e R x B u f f e r [i ]=0;r e s=f _r e a d (&F i l e S y s t e m D s t ,F i l e R x B u f f e r ,s i z e o f (F i l e R x -B u f f e r ),&b r);i f (r e s) p r i n t f ("F i l e R e a d E R R O R !\n \t ");e l s ep r i n t f ("F i l e R e a d S U C C E S S !\n \t ");pr i n t f ("\r \n %s ",F i l e R x B u f f e r );f _c l o s e (&F i l e S ys t e m D s t );以上代码实现的功能是读取S D 卡中文件名为D e m -o 1.t x t 的文本文件,将读取到的数据放在数据缓冲区F i l -e R x B u f f e r 中㊂5 数据读写验证把S TM 32单片机写过数据的S D 卡插入P C 的S D 卡插槽查看数据,与单片机写入的数据一致,P C 机端数据如图5所示㊂图5 P C 机端数据单片机读取S D 卡的数据放在数据缓冲区F i l e R x -B u f f e r 中,通过I A R 平台查看缓冲区数据如图6所示,其数据与文本文件中的数据一致[10]㊂图6 缓冲区数据结 语该设计以S TM 32微处理器为控制核心,根据F a t F S文件系统规范成功实现了基于S D 卡的一系列操作(如创建㊁删除㊁读写等),经测试,该系统稳定可靠,并已成功应用于氢气加气机样机的数据存储系统中㊂该系统硬件电路简单,软件的可移植性强,非常适用于高速㊁大容量的数据存储场合㊂它支持热插拔及数据写保护功能,能正确读写S a n D i s k ㊁K i n g s t o n ㊁S AM S U N G 等厂商多种容量的S D 卡,最高读写速度可达1M B /s,可满足小型嵌入式系统的应用需求,具有较高的应用价值㊂参考文献[1]S T M i c r o e l e c t r o n i c s .S TM 32F 10x x x i na p pl i c a t i o n p r o -g r a mm i n g u s i n g t h e S P I [E B /O L ].[202006].h t t p://w w w.s t .c o m.[2]刘波文.A RM C o r t e x M 3应用开发实例详解[M ].北京:电子工业出版社,2011.电子科技大学,2018.[8]唐思超.R I S C V 处理器的C 语言启动代码设计方法[J ].单片机与嵌入式系统应用,2020(4):1417.[9]谷涛.轻松学C #[M ].北京:电子工业出版社,2013:1324.[10]缑文博.基于A V R 单片机的电动汽车蓄电池监测系统的设计[J ].电子世界,2020(7):198.[11]高淑婷.基于A V R 单片机的汽车空调控制系统设计[J ].机械装备研发,2020(11):130.[12]刘晓,陈广凯,赵汉青,等.一种基于单片机串口通信的数据缓存处理方法[J ].信息通信,2020(4):103104.[13]陈旭辉,杨红云.U S B 接口的虚拟多串口通信设备设计[J ].单片机与嵌入式系统应用,2020(4):1821.[14]黄才权,毕增军,张辉.Z Y N Q 的超低时延视频编解码系统设计[J ].单片机与嵌入式系统应用,2020(2):2730.王君(工程师),主要研究方向为预警装备保障㊂(责任编辑:薛士然 收稿日期:2020-07-07) [3]史胜伟,潘冀宁,孙慧洋.基于S TM 32的M i c r o S D 卡F a t 文件系统快速实现[J ].通讯世界,2016(17):8183.[4]李鸿征.高性能M i c r o S D 卡读写器的设计与开发[J ].焦作大学学报,2017,31(4):6972.[5]颜秋男,胡毅.S TM 32F 103V B 的S D 卡在应用编程设计[J ].单片机与嵌入式系统应用,2012(2):3638,46.[6]李敏,侯亚玲,刘颖.基于S D 卡的F A T 32文件系统设计与实现[J ].物联网技术,2017,7(7):9698,102.[7]王坤,丁红胜.基于S TM 32的图像编码与采集系统[J ].电子设计工程,2018,26(5):179183.[8]徐涛,陈赫,卢少微,等.基于S TM 32的碳纳米纸传感器信号采集系统设计[J ].仪表技术与传感器,2019(9).[9]孙海英,朱晔,罗春,等.基于S TM 32控制器的设备运行时间自动统计装置设计[J ].电子测试,2020(2):2021.[10]梁菲惜.基于S TM 32和D G U S 液晶屏的随机键盘设计[J ].电子制作,2019(1):1011.汤才刚(工程师),主要研究方向为单片机与嵌入式系统应用㊂(责任编辑:薛士然 收稿日期:2020-06-28)X i l i n x 为5G 无线电大规模部署推出突破性Z y n q RF S o C D F E 赛灵思公司(X i l i n x ,I n c .)宣布推出Z y n q RF S o C D F E ,这是一类全新的具有突破性意义的自适应无线电平台,旨在满足不断演进的5G N R 无线应用标准㊂Z y n q RF S o C D F E 将硬化的数字前端(D F E )模块与灵活应变的可编程逻辑相结合,为涵盖低㊁中㊁高频段频谱的广泛用例打造了高性能㊁低功耗且经济高效的5G N R 无线电解决方案㊂Z y n q RF S o C D F E 在采用硬化模块的A S I C 的成本效益与可编程和自适应S o C 的灵活性㊁可扩展性及上市时间优势之间,实现了最佳的技术平衡㊂5G 无线电所需的解决方案,不仅要满足广泛部署所提出的带宽㊁功耗和成本挑战,还必须适应三大关键5G 用例:增强型移动宽带(e M B B )㊁大规模机器类通信(mM T C )以及超可靠低时延通信(U R L L C )㊂此外,解决方案必须能够随不断演进的5G 标准进行扩展,如O p e n R A N (O R A N )㊁全新的颠覆性5G 商业模式㊂Z y n q R F S o C D F E 集成了针对5G N R 性能与节电要求而硬化的D F E 应用专用模块,同时还提供了结合可编程自适应逻辑的灵活性,从而为日益发展的5G 3G P P 和O R A N 无线电架构提供了面向未来的解决方案㊂赛灵思执行副总裁兼有线与无线业务部总经理L i a m M a d d e n 表示: 为满足5G 的特殊需求,赛灵思史上首次推出这样一款硬化应用专用I P 多于自适应逻辑的无线电平台㊂随着5G 相关市场需求日益演进,集成式R F 解决方案也需不断适应未来标准㊂Z y n q RF S o C D F E 在灵活应变能力与固定功能I P 之间提供了最佳平衡㊂ 与上一代产品相比,Z y n q RF S o C D F E 将单位功耗性能提升高达两倍,并且能够从小蜂窝扩展至大规模M I MO (mM I MO )宏蜂窝㊂该解决方案是一款独特的直接R F 采样平台,能够在所有F R 1频带和新兴频带(最高可达7.125GH z)内实现载波聚合/共享㊁多模式㊁多频带400MH z 瞬时带宽㊂当用作毫米波中频收发器时,Z y n q R F S o C D F E 可提供高达1600MH z 的瞬时带宽㊂Z y n q RF S o C D F E 的架构支持客户绕过或定制硬化的I P 模块㊂例如,客户既可以利用支持现有和新兴G a N P a s 的赛灵思经现场验证的D P D ,也可以插入其自有的独特D P D I P ㊂A B I R e s e a r c h 5G 高级研究总监D i m i t r i s M a v r a k i s 表示: 随着5G 商业部署和新用例持续演进,对于整个供应链而言,如何为供应商提供灵活的组件以创建具有成本效益㊁适应性强且面向未来的设备十分关键㊂尤其是O pe n R A N ,其在这方面的要求更高,灵活的设计对其成功至关重要㊂Z y n q R F S o C D F E 实现了硬化和自适应可编程逻辑之间的平衡,是一款兼具通常A S I C 才具有的成本优势以及F P G A 才拥有的设计灵活性和定制化优势的独特产品㊂。
基于stm32f103对sd卡底层的基本操作方法
基于stm32f103对sd卡底层的基本操作方法基于STM32F103的SD卡底层操作方法是指通过STM32F103系列微控制器来对SD卡进行读写操作的一组基本方法。
本文将详细介绍如何配置STM32F103的SPI接口和相关寄存器,以及如何使用SPI接口与SD卡进行通信和文件操作。
一、硬件连接首先,需要连接STM32F103与SD卡之间的硬件接口。
STM32F103的SPI接口包括四根引脚,分别是NSS(片选信号)、SCK(时钟信号)、MISO(数据输入信号)和MOSI(数据输出信号)。
通常,可以将SD卡的NSS引脚连接到STM32F103的任一GPIO引脚上作为片选信号,并通过软件控制片选信号的高低电平来选择SD卡进行读写操作。
此外,还需要将SD卡的SCK、MISO和MOSI引脚分别连接到STM32F103的SPI接口的SCK、MISO和MOSI引脚上。
为了方便起见,可以直接使用STM32F1的SPI中的SPI1进行配置。
二、SPI接口配置在STM32F103中,SPI接口由SPI1、SPI2和SPI3三个外设实现,其中SPI1位于APB2总线上,SPI2和SPI3位于APB1总线上。
在本文中,我们将使用SPI1进行SD卡的底层操作。
首先,需要在CubeMX中将SPI1的NSS、SCK、MISO和MOSI引脚分别配置为GPIO输出、SPI时钟、SPI数据输入和SPI数据输出功能。
然后,需要配置SPI1的时钟分频系数、数据位数、传输模式等参数。
SPI1的时钟分频系数由BDIV和BR两个参数决定,其中BDIV位于SPI1->CR1寄存器的位6-7位,用于设定SPI1主频的1/2、1/4、1/8还是1/16,BR位于SPI1->CR1寄存器的位3-5位,用于设定SPI1的分频系数。
根据SD卡的时钟特性,一般选择SPI1的分频系数为sclk/32,其中sclk为主控芯片时钟。
在SPI接口配置完成之后,需要打开SPI1外设时钟使能,并设置SPI1的工作模式、数据位数等参数。
STM32笔记(六)SD卡的读写和FatFS文件系统
STM32笔记(六)SD卡的读写和FatFS文件系统因为要用,学习了一下SPI操作SD卡,同时移植了一个免费开源的FAT文件系统:FatFS。
感觉挺好,在单片机上实现了读写文件的操作,接下来就可以解释我的G代码咯!我的SD卡底层操作参考了网上几种常见的代码,但又对其结构做了一定的优化,至少看起来用起来比较方便。
既可以作为文件系统的diskio使用,也可以直接使用底层函数,把SD卡作为一块flash读写。
FatFs文件系统体积蛮小,6-7K足矣,对于128Kflash的STM32来说很合适,代价不大。
同时可移植性很高,最少只需要4个函数修改既可以实现文件系统的移植。
相关文件系统的介绍请看这里。
这里给一套比较完整的参考资料,包括fatfs文件系统的原版资料、几个重要的手册和网上下载的代码。
/bbs/bbs_content.jsp?bbs_sn=3210864&bbs_page_no=1&bbs_id=3020 下面是我的代码:其中底层的SPI总线对SD卡的操作在SPI_SD_driver.c/h中,而FATFS的移植文件diskio.c中对磁盘的操作函数中将调用底层的操作函数。
下面是一些底层操作函数:u8 SPI_ReadWriteByte(u8 TxData); //SPI总线读写一个字节u8 SD_WaitReady(void); //等待SD卡就绪u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令,不断线u8 SD_Init(void); //SD卡初始化u8 SD_ReceiveData(u8 *data, u16 len, u8 release); //SD卡读数据u8 SD_GetCID(u8 *cid_data); //读SD卡CIDu8 SD_GetCSD(u8 *csd_data); //读SD卡CSDu32 SD_GetCapacity(void); //取SD卡容量u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sectoru8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //写一个sectoru8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sectoru8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count); //写多个sector这是diskio.c中的一段代码,在disk初始化中,我们调用了SPI_SD_driver.c中的SD卡初始化函数。
智芯STM32开发板SD卡资料SD卡要点说明
SD 卡 要 点 说 明
Written by pasyong
SD卡有两个可选的通信协议:SD模式和SPI模式。
为了电路的简化,选用SPI模式。
模式选择;SD卡默认为SD模式,要进入SPI模式时,要遵守如下操作。
当SD卡接收RESTE命令(CMD0)时,拉低CS即可。
命令CMD0就是0,CMD16就是16,其它以此类推。
SPI命令格式如下,由6个字节构成,高位在前。
SPI模式下Command从CMD0到CMD63。
Command Argument为附加命令,有些CMD命令有,有些无,CRC为校验字节。
下图是SPI模式下的命令分类表。
SPI命令分为11个组,各个组是多个命令的集合,每个组中的命令有相似的功能。
这里介绍三个常用命令。
CMD0,CMD1,CMD16
CMD0 为复位,CMD1为激活初始化,CMD16设置一个读写块的长度。
有些命令发送出去后会有返回值,表示的是错误码。
比如CMD0,CMD1返回值是R1格式的。
一个字节长,0,7位是0,其它位表示错误码。
SD卡初始化
在上电后,主机启动SCK及在CMD线上发送74个高电平的信号,接着发送CMD0进入SPI 模式,然后发送CMD1激活初始化进程。
读扇区:SD卡允许以块数据进行读写,在这里我们用CMD16命令设定每读写的块为512字节,正好是一个扇区。
设置好后用CMD17读块命令读取512放入缓冲区既可。
新版STM32 HAL库SD卡读写不正常总结
2个版本的SD卡驱动改动较大, 看一下对比 V1.14.0 uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks) uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumOfBlocks)
V1.15.0 uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,(uint32_t)(sector),count) == MSD_OK) {
while( BSP_SD_RxOK()==0 || BSP_SD_GetCardState()!=MSD_OK ) //读写完成的判断需要同时同时满足 {
sd_tx_ok = 1; } void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) {
stm32f103c8t6 tf卡简单的读写函数
stm32f103c8t6 tf卡简单的读写函数STM32F103C8T6是一款常用的微控制器,它内部集成了SDIO接口,可以方便地与TF卡进行数据读写。
在本文中,我将介绍一些简单的读写函数,以帮助您在STM32F103C8T6上使用TF卡。
下面是相关内容:一、TF卡介绍TF卡(T-Flash卡)是一种袖珍型存储卡,广泛应用于移动设备中。
它的体积小、价格低廉,并且容量可扩展。
在STM32F103C8T6上使用TF卡,可以实现大量数据存储,方便后续的读写操作。
二、初始化函数在使用TF卡之前,我们需要进行初始化操作。
以下是一个简单的TF卡初始化函数示例:```c#include "stm32f10x.h"void TF_Card_Init(){// 初始化SPI接口RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;// 更多SPI参数配置,如速率、时钟极性等// ...SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);// 等待TF卡初始化完成while(TF_Card_SendCommand(CMD0, 0) != 0x01);}```该函数使用了STM32F10x库,通过SPI1接口与TF卡进行通信。
在实际使用中,您需要根据TF卡的具体规格进行参数的设置和修改。
三、读取函数TF卡的读取操作可以通过发送命令和读取数据实现。
基于STM32F407平台实现FATFS读写大容量(128G)SD卡的心得
基于STM32F407平台实现FATFS读写大容量(128G)SD卡的心得本人是沈阳大学的一名小白,之前,无论是STM32,还是FATFS,都是小白一个,甚至不理解那是什么东西,但是据说这种技术目前为止好像是读写大容量卡挺费劲,只能64G,就到头了,但是最近接到一个任务就是做一个数据记录仪而且要把这个东西做成128G 的。
废话不多说,直接来把。
首先你要知道FATFS 是一个文件管理系统,看他的手册,分为应用层,底层驱动等等,但是对于我们嵌入式开发者来说,移植他,我们需要的是修改底层驱动!应用他给出的API 实现自己的任务。
修改底层驱动!应用他给出的API 实现自己的任务。
修改底层驱动!应用他给出的API 实现自己的任务。
1、修改底层驱动官网下载,需注意他的版本,如果你做32G ,64G, OK 那你下载哪个版本都可以,建议下载低版本,如0.10 版本左右的都可以。
如果你想做大容量卡,那一定要移植0.12 之后的版本,现在我写这篇文章的时候,最新版是0.13a,所以我就简单说一下0.13a。
0.13a 的底层驱动,也就是你下载下来的有一个diskio.c 的文件,你打开。
正常的移植,是在这里写或者修改底层驱动,底层驱动是什么呢,例如我这次用的是SDIO 操作读写SD 卡的,大家都知道,SDIO 操作SD 卡有两种方式,一个是SPI,一个是SDIO。
那我要写的就是这两种中的一个了。
我用的是SDIO,因为这种速度块。
继续说,当你打开0.13a 的diskio.c 的时候,你会发现这帮人TMD 写的很随意,这里如果你是个大手你可以自己写好你的底层驱动(就是刚才我说的那个如何通过SDIO 操作SD 卡),如果嫌费劲,直接拿你开发板给出的例程里的diskio.c(每个嵌入式开发者手里都会有开发板吧?!)因为它给出这个一定是调好的!。
基于STM32的几种读SD卡方式的速度探究
F I F O  ̄
C MD7 命令 选择 卡 , 配置 D MA2 , 发送 C MD 2 4 ( 开始 写数据 ) , 查 询D MA 通 道的使 能状 态 寄存器 , 确认 没 有通 道仍 处于 使 能状 态 。 配 置D MA2 的具 体步 骤如 下 :
1 ) 使  ̄D MA2 控 制器 并 清 除所有 的 中断 标志 位 。
特性 , 如 今越 来越 多 的芯 片集 成 了这种 通信 协 议 。
1 . 3 S D1 0
S D 卡 读取 操作 后 , 先 发送一 个起 始数 据 命令 , 接 着发 送 固定数 量 的数据 , 最 后 是2 个 字节 的C RC 校验 。 2 3 S D 卡的 文件存 储
1 . 硬 件设 计
1 . 1 ST M 3 2 F 1 0 3 Z E T6
2 . 1 . 2将S D 卡初 始 化 为S D I O 模 式 首先 上 电( p o we r - o n ) , 然后发出C MD 0, 再接着发送C MD8, 有 应 答
S T M3 2 F 1 0 3 z E T 6 基于 高 性 能3 2 位 RI S C 的AR M C o r t e x - M3 核, 其最 高 工 作频 率为 7 2 MHz 。 片上 集 成了高 速 存储 器 ,
须 与 计 算机 的文 件 系 统 兼容 。 目前 常用 的文 件 系 统 主 要 有 w i n d o WS 下 的
F A T3 2 , NT F S , L u x 下的E XT 2 , E XT 3 等。
2 4 D M A 的配置
一
S T M3 2 F 1 0 x 系列 MCU支持D MA功 能 , 可 以直接 将数 据从 一 个地 址 空 间
【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(六)-FatFs使用的思路介绍
f_open打开/创建⽂件f_close关闭⽂件f_read读取⽂件f_write写⼊⽂件f_lseek移动读/写指针,扩展⼤⼩f_truncate 截断⽂件f_sync 刷新缓存数据f_forward 转移⽂件数据到⼀个数据流f_expand 为⽂件分配⼀个连续的块f_gets 读取⼀个字符串(string )f_putc写⼊⼀个字符(character )f_puts写⼊⼀个字符串(string )f_printf写⼊⼀个格式化字符串f_tell获取当前读/写指针f_eof⽂件结束测试f_size获取长度f_error测试错误f_opendir 打开⼀个⽬录f_closedir 关闭⼀个已打开的⽬录f_readdir 读取⽬录f_findfirst 打开⼀个⽬录并读取匹配的第⼀个项⽬f_findnext 查找下⼀个匹配的项⽬【STM32】使⽤SDIO 进⾏SD 卡读写,包含⽂件管理FatFs (六)-FatFs 使⽤的思路介绍本篇要来介绍⽂件管理FatFs官⽅的⽹站是:这是⼀个⽇本⼈写的,除了⽂件管理以外,还有其他的,例如解码JPEG 、红外遥控等在官⽹链接内,最下⽅有个Return ,点击后就可以看到相关的开源库以下开始正题(本⽂⾥提到的媒介,其实就是设备了,我不想改图了...)打开官⽅⽹站,页⾯简单明了,就分为4个区块(以下图⽚为FatFs 官⽹上截取的图⽚)第⼀区块、介绍及特性(Features ):FatFs 是⽂件管理系统,可⽤于SD 卡、硬盘(ATA )、RTC 时钟,FTL 和etc 不清楚是什么,另外,也可以⽤于Flash 或是EEPROM第⼆区块、应⽤接⼝(Application Interface ):FatFs 提供了接⼝,使得我们的应⽤可以和它交互。
官⽹左侧为⼀些接⼝的介绍,分四个部分第⼀部分:File Access (⽂件存取)第⼆部分:Directory Access (⽬录访问)f_stat 检查⽂件或⼦⽬录是否存在f_unlink 删除⽂件或⼦⽬录f_rename 重命名/移动⽂件或⼦⽬录f_chmod 更改⽂件或⼦⽬录的属性f_utime更改⽂件或⼦⽬录的时间戳f_mkdir创建⼦⽬录f_chdir 更改当前⽬录f_chdive 更改当前驱动f_getcwd 检索当前⽬录和驱动f_mount注册/注销⼀个⼯作区(挂起与否)f_mkfs在逻辑驱动上创建⼀个FAT 卷f_fdisk 在物理驱动上创建分区f_getfree 获取卷上的可⽤空间f_getlabel 获取卷标f_setlabel 设置卷标f_setcp设置活动代码页disk_status获取设备状态disk_initialize 初始化设备disk_read读取数据disk_write写⼊数据disk_ioctl控制设备相关功能get_fattime 获取当前时间第三部分:File and Dirextor Management (⽂件和⽬录管理)第四部分:Volume Management and System Configuration (卷管理和系统配置)第三区块、媒介访问接⼝(Media Access Interface ):你想管理的存储设备,必须要和FatFs 链接。
STM32下SD卡的读取
STM32下SD卡的读取⼀、SD卡模块介绍1.1 什么是SD卡SD存储卡是⼀种基于半导体快闪记忆器的新⼀代记忆设备,由于它体积⼩、数据传输速度快、可热插拔等优良的特性,被⼴泛地于便携式装置上使⽤,例如数码相机、平板电脑和多媒体播放器等。
控制器对 SD 卡进⾏读写通信操作⼀般有两种通信接⼝可选,⼀种是 SPI 接⼝,另外⼀种是 SDIO 接⼝。
1.2 SD卡的物理结构⼀张SD卡包括有存储单元、存储单元接⼝、电源检测、卡及接⼝控制器和接⼝驱动器5 个部分。
存储单元是存储数据部件,存储单元通过存储单元接⼝与卡控制单元进⾏数据传输;电源检测单元保证SD卡⼯作在合适的电压下,如出现掉电或上状态时,它会使控制单元和存储单元接⼝复位;卡及接⼝控制单元控制SD卡的运⾏状态,它包括有8个寄存器;接⼝驱动器控制 SD 卡引脚的输⼊输出。
⼆、项⽬代码已挂载在Github上烧录程序成功后:主要函数代码分析:int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_FATFS_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1); //enable uart printf(" mian \r\n");Get_SDCard_Capacity(); //得到使⽤内存并选择格式化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){WritetoSD(WriteBuffer,sizeof(WriteBuffer));HAL_Delay(500);WriteBuffer[0] = WriteBuffer[0] +0;WriteBuffer[1] = WriteBuffer[1] +1;write_cnt ++;while(write_cnt > 10){printf(" while \r\n");HAL_Delay(500);}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}void WritetoSD(BYTE write_buff[],uint8_t bufSize){FATFS fs;FIL file;uint8_t res=0;UINT Bw;res = SD_init(); //SD卡初始化if(res == 1){printf("SD卡初始化失败! \r\n");}else{printf("SD卡初始化成功! \r\n");}res=f_mount(&fs,"0:",1); //挂载// if(test_sd == 0) //⽤于测试格式化if(res == FR_NO_FILESYSTEM) //没有⽂件系统,格式化{// test_sd =1; //⽤于测试格式化printf("没有⽂件系统! \r\n");res = f_mkfs("", 0, 0); //格式化sd卡if(res == FR_OK){printf("格式化成功! \r\n");res = f_mount(NULL,"0:",1); //格式化后先取消挂载res = f_mount(&fs,"0:",1); //重新挂载if(res == FR_OK){printf("SD卡已经成功挂载,可以进进⾏⽂件写⼊测试!\r\n");}}else{printf("格式化失败! \r\n");}}else if(res == FR_OK){printf("挂载成功! \r\n");}else{printf("挂载失败! \r\n");}res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);if((res & FR_DENIED) == FR_DENIED){printf("卡存储已满,写⼊失败!\r\n");}f_lseek(&file, f_size(&file));//确保写词写⼊不会覆盖之前的数据if(res == FR_OK){printf("打开成功/创建⽂件成功! \r\n");res = f_write(&file,write_buff,bufSize,&Bw); //写数据到SD卡if(res == FR_OK){printf("⽂件写⼊成功! \r\n");}else{printf("⽂件写⼊失败! \r\n");}}else{printf("打开⽂件失败!\r\n");}f_close(&file); //关闭⽂件f_mount(NULL,"0:",1); //取消挂载}程序⾸先进⾏相关初始化,完成后输出mian,之后进⾏SD卡格式化,成功后进⼊循环,进⼊SD卡读写函数,先后进⾏SD卡的初始化,挂载,创⽂件,写⼊,写⼊超过10次,输出while三、相关引脚的配置CS -> PB0SCK -> PA5MISO -> PA6MOSI -> PA7四、实验结果SD卡中⽣成⼀个新的hello.txt⽂件内容如下更改写⼊内容写⼊结果如下:五、⼼得体会在初始化过程中确保SD格式化成FAT⽂件模式,确保单⽚机的供电和SD卡模块的供电最好是5V,不然可能带不动SD卡驱动导致实验失败。
stm32SPI模式读写SD卡
stm32SPI模式读写SD卡SPI模式读写SD卡SD卡初始化过程:1. 初始化STM32的SPI接口使用低速模式2. 延时至少74clock3. 发送CMD0,需要返回0x01,进入Idle状态4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态5. 设置读写block大小为512byte5. 把STM32的SPI设置为高速模式读一个block块的过程1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x002. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes写一个block块的过程1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x002. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes/******************************************************************* ************* Function Name : SD_MMC_SPI_Init* Description : SD_MMC_SPI_Init* Input : None* Output : None* Return : zero init success, non-zero init error************************************************************************ *******/u8 SD_MMC_SPI_Init(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIO clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_SD_MMC_SPI_CS, ENABLE);/* Configure SPI1 pins: SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* Configure SD_MMC_SPI_CS */GPIO_InitStructure.GPIO_Pin = SD_MMC_SPI_CS_Pin_CS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(SD_MMC_SPI_CS, &GPIO_InitStructure);///////////////////////////////////////////////////////////////////////////////* initialize SPI with lowest frequency */SD_MMC_Low_Speed();/* card needs 74 cycles minimum to start up */for(u8 i = 0; i < 10; ++i) {/* wait 8 clock cycles */ SD_MMC_ReadWrite_Byte(0x00); } /* address card */ SD_MMC_SPI_SELECT();/* reset card */u8 response;for(u16 i = 0; ; ++i){response = SD_MMC_Send_Command(CMD_GO_IDLE_STATE ,0 );if( response == 0x01 ) break;if(i == 0x1ff) {SD_MMC_SPI_DESELECT(); return 1;}}/* wait for card to get ready */ for(u16 i = 0; ; ++i) {response = SD_MMC_Send_Command(CMD_SEND_OP_COND, 0);if(!(response & (1 << R1_IDLE_STATE)))break;if(i == 0x7fff) {SD_MMC_SPI_DESELECT(); return 1;}}/* set block size to 512 bytes */if(SD_MMC_Send_Command(CMD_SET_BLOCKLEN, 512)) {SD_MMC_SPI_DESELECT();return 1;}/* deaddress card */SD_MMC_SPI_DESELECT();/* switch to highest SPI frequency possible */ SD_MMC_High_Speed();return 0;//////////////////////////////////////////////////////////////////// //////////}/******************************************************************* ************* Function Name : SD_MMC_Read_Single_Block * Description :SD_MMC_Read_Single_Block * Input : sector number and buffer data point * Output : None* Return : zero success, non-zero error************************************************************************ *******/u8 SD_MMC_Read_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 Retry = 0;//读命令 send read commandResponse =SD_MMC_Send_Command(CMD_READ_SINGLE_BLOCK, sector<<9); if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();// start byte 0xfewhile(SD_MMC_ReadWrite_Byte(0xff) != 0xfe) {if(++Retry > 0xfffe){SD_MMC_SPI_DESELECT();return 1; //timeout}}for(i = 0; i < 512; ++i) {//读512个数据*buffer++ = SD_MMC_ReadWrite_Byte(0xff); }SD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_ReadWrite_Byte(0xff); //伪crcSD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff); // extra 8 CLKreturn 0;}/******************************************************************* ************* Function Name : SD_MMC_Write_Single_Block* Description : SD_MMC_Write_Single_Block * Input : sector number and buffer data point* Output : None* Return : zero success, non-zero error.************************************************************************ *******/u8 SD_MMC_Write_Single_Block(u32 sector, u8* buffer) {u8 Response;u16 i;u16 retry=0;//写命令 send write commandResponse =SD_MMC_Send_Command(CMD_WRITE_SINGLE_BLOCK, sector<<9);if(Response != 0x00)return Response;SD_MMC_SPI_SELECT();SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);SD_MMC_ReadWrite_Byte(0xff);//发开始符 start byte 0xfeSD_MMC_ReadWrite_Byte(0xfe);//送512字节数据 send 512 bytes datafor(i=0; i<512; i++){SD_MMC_ReadWrite_Byte(*buffer++);}SD_MMC_ReadWrite_Byte(0xff); //dummy crc SD_MMC_ReadWrite_Byte(0xff); //dummy crcResponse = SD_MMC_ReadWrite_Byte(0xff);//等待是否成功 judge if it successfulif( (Response&0x1f) != 0x05){SD_MMC_SPI_DESELECT();return Response;}//等待操作完 wait no busywhile(SD_MMC_ReadWrite_Byte(0xff) != 0x00) {if(retry++ > 0xfffe){SD_MMC_SPI_DESELECT();return 1;}}SD_MMC_SPI_DESELECT();SD_MMC_ReadWrite_Byte(0xff);// extra 8 CLKreturn 0;}if( SD_MMC_SPI_Init() ==1)printf(" _SD_MMC Initialization ERROR\r\n"); else{printf(" _SD_MMC Initialization OK\r\n"); //memset(buffer,0,512); //读取一个扇区的内容这里读的是0扇区SD_MMC_Read_Single_Block( 0 , buffer );Uart1_PutString( buffer , 512 );}。
52- STM32F4 STM32 通过网口 读取 SD卡 TF卡 文件 内容
一、功能说明本例程的功能当在浏览器中输入预先设置好的静态IP:192.168.0.120时,控制网页界面将打开,可以分别控制STM32F4 Discovery板子上四颗不同颜色的LED灯,可以触发、打开、关闭共3种控制功能,点击对应功能时,除了LED状态改变之外,还会打开存储在TF中的wwwindex.html文件,同时串口会打印一些列的提示。
二、软件修改本例程软件层面无需修改,如果fatfs要支持长文件名,并且支持中文,需要参考例程说明《29-fatfs 011a版本长文件名支持U盘TF SD卡基于STM32F4单片机》配置。
三、硬件连接将串口连接到4PIN的串口座,网线连接到路由器,TF中放入对应的“wwwindex.html”文件。
需要注意的是,如果路由器的网关的192.168.1.1,则IP需要改为192.168.1.120,确保前三段IP地址和网关一致。
关于例程的其他信息如有问题,请发我QQ邮件:3199212692@例程对象:STM32F407单片机,fatfs R0.11a版本项目的工程文件在百度云盘上:/s/1qYgr2LAQuevoice扩展板资料在百度云盘上:/s/1eSBedbW例程中的开发套件在我的个人网店上:https:///shop/view_shop.htm?tracelog=twddp&user_number_id=29 52611999GitHub关于STM32F4 Discovery的开源工程GitHub开源工程介绍链接:/2014/05/all-stm32f429-libraries-at-one-place/GitHub开源工程文件链接:https:///MaJerle/stm32f429。
stm32f103c8t6 tf卡简单的读写函数
文章标题:探索STM32F103C8T6与TF卡的简单读写函数在嵌入式系统开发中,TF卡的读写功能一直是一个不可或缺的部分。
而对于如何在STM32F103C8T6芯片上实现简单的TF卡读写函数,也是我们经常需要探讨的一个问题。
在本文中,我们将会从简单到复杂地讨论如何在STM32F103C8T6芯片上实现TF卡的读写功能,以便读者能更深入地理解这一过程。
1. TF卡简介在开始讨论TF卡的读写函数之前,我们先简要介绍一下TF卡的基本知识。
TF卡,全称TransFlash卡,又称MicroSD卡,是一种常见的存储卡,常用于嵌入式系统、手机、相机等设备中。
TF卡具有体积小、读写速度快、存储容量大等优点,因此在嵌入式系统中得到广泛应用。
2. STM32F103C8T6与TF卡的连接在实现TF卡读写功能之前,首先需要将TF卡与STM32F103C8T6芯片进行连接。
一般来说,TF卡的连接方式是通过SPI接口进行。
SPI接口是一种串行外设接口,可以实现与外部设备的高速数据传输。
通过SPI接口连接TF卡,可以在STM32F103C8T6芯片上实现对TF卡的读写操作。
3. TF卡读写函数的实现在STM32F103C8T6芯片上实现TF卡的读写函数,一般需要以下几个步骤:初始化SPI接口、初始化TF卡、读取TF卡数据、写入TF卡数据。
需要初始化SPI接口,设置好SPI的时钟频率、数据传输格式等参数。
通过初始化TF卡,可以对TF卡进行一些基本的设置,比如设置TF卡的工作模式、文件系统类型等。
接下来,可以通过读取TF 卡数据和写入TF卡数据函数,实现对TF卡的读写操作。
4. 个人观点和总结通过深入地探讨STM32F103C8T6与TF卡的简单读写函数,我对于嵌入式系统中TF卡的应用有了更深入的理解。
在实际应用中,我们需要根据具体的需求和硬件评台来选择合适的读写函数,并且需要注意好数据的正确读取和写入,以保证系统的稳定性和可靠性。
STM32的SPI1引脚重映射后读写SD卡
STM32的SPI1引脚重映射后读写SD卡初次使用STM32有些不太明白,此次调试经验奉献出来与大家分享!系统:STM32 + SD + FATFSSTM32与SD卡的连接如下定义,PB口#define SD_SCK GPIO_Pin_3#define SD_MISO GPIO_Pin_4#define SD_MOSI GPIO_Pin_5#define SD_CS GPIO_Pin_7我想使用SPI1并重映射引脚使用时注意的事项如下:1.使能PB0时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);2.使能AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);3.使能SPI1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 , ENABLE);4.禁用JTAG时钟复用 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENA BLE);5.SPI1引脚重映射 GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);接着初始化GPIO和SPI1即可,如:void SpiOpen(void){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;/* Configure SPI1 pins: SCKand MOSI */GPIO_InitStructure.GPIO_Pin = SD_MOSI|SD_SCK|SD_MISO;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PB7 pin: CS pin */GPIO_InitStructure.GPIO_Pin = SD_CS;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,SD_CS);/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullD uplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePres caler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);/* SPI1 enable */SPI_Cmd(SPI1, ENABLE);}可是这一切完成的时候结果却与想象的不同,无法在SD卡内创建文件,找一个晚上没有结果不得已采用另一种方法:软件模拟SPI测试了一下,结果另人出呼意料,一次搞定,没有任何问题,但为了效率还是希望使用硬SPI口,于是从引脚重映射上寻找原因又费了一晚上无果第三个晚上:经过无数次的改动 + 测试终于OK了,问题出在哪里了呢?原来SD卡的初始时钟不一定是<400KHz就行ST标准库初始化系统时APB2时钟为72MHz,经过256分频波特率约等于 280KHz (SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePre scaler_256;)对于我测试用的SD卡这个速度仍太快,于是降APB2时钟进行测试,OK!RCC_PCLK2Config(RCC_HCLK_Div4); //72/4=18MHz仅仅是一行代码,这就是初学代价!,哈哈.另外要说明的是,在MISO引脚上加了一个22k上接电阻.代码://#define USE_SOFT_SPI#ifdef USE_SOFT_SPIBYTE g_SPISpeedFlag=0;static void delay_bus(void){unsigned int i=100;if(g_SPISpeedFlag) //高速模式 < 25MHzi=10;while(--i) //低速模式 < 400KHz__nop();}void SpiOpen(void){//IO初始化用结构体GPIO_InitTypeDef GPIO_InitStructure;//输出引脚初始化GPIO_InitStructure.GPIO_Pin=SD_SCK|SD_CS|SD_MOSI; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure);//输入引脚配置GPIO_InitStructure.GPIO_Pin=SD_MISO;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//GPIO_ Mode_IN_FLOATING ;GPIO_Init(GPIOB, &GPIO_InitStructure);//设置端口初始电平GPIO_SetBits(GPIOB,SD_CS);GPIO_SetBits(GPIOB,SD_SCK);g_SPISpeedFlag=0;}void SpiClose(void){GPIO_SetBits(GPIOB,SD_CS);GPIO_SetBits(GPIOB,SD_SCK);Stat &= ~STA_NOINIT;}void SPI_SetHeighSpeed(void){g_SPISpeedFlag=1;}BYTE SPI_ReadWriteByte(BYTE outgoing){uint32_t i;uint8_t ret=0;delay_bus();for(i=0;i<8;i++){ret<<=1;if(outgoing &0x80) //主设备锁存数据GPIO_SetBits(GPIOB,SD_MOSI);elseGPIO_ResetBits(GPIOB,SD_MOSI);GPIO_ResetBits(GPIOB,SD_SCK); //产生第一个时钟沿,让从设备也在此时锁存数据delay_bus();if(GPIO_ReadInputDataBit(GPIOB,SD_MISO)) //主设备采样ret|=1;GPIO_SetBits(GPIOB,SD_SCK); //产生第二个时钟沿,让从设备也在此时采样delay_bus();outgoing<<=1;}return ret;}#else //硬件SPI 使用SPI1引脚重映射void SpiOpen(void){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);/* Configure SPI1 pins: SCKand MOSI */GPIO_InitStructure.GPIO_Pin = SD_MOSI|SD_SCK|SD_MISO;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PB7 pin: CS pin */GPIO_InitStructure.GPIO_Pin = SD_CS;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,SD_CS);/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullD uplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePres caler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);/* SPI1 enable */SPI_Cmd(SPI1, ENABLE);}void SpiClose(void){SPI_Cmd(SPI1, DISABLE);Stat &= ~STA_NOINIT;}void SPI_SetHeighSpeed(void){SPI_InitTypeDef SPI_InitStructure;/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullD uplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePres caler_4;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI1, &SPI_InitStructure);SPI_Cmd(SPI1, ENABLE);}BYTE SPI_ReadWriteByte(BYTE outgoing){/* Loop while DR register in not emplty */while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RE SET);/* Send byte through the SPI1 peripheral */SPI_I2S_SendData(SPI1, outgoing);/* Wait to receive a byte */while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == R ESET);/* Return the byte read from the SPI bus */return SPI_I2S_ReceiveData(SPI1);}#endif。
SD卡的初始化和读写程序
/****************************************************************************** *****SPI模式读写SD卡SD卡初始化过程:1. 初始化STM32的SPI接口使用低速模式2. 延时至少74clock3. 发送CMD0,需要返回0x01,进入Idle状态4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态5. 设置读写block大小为512byte5. 把STM32的SPI设置为高速模式读一个block块的过程1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x002. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes写一个block块的过程1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x002. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes-----------------------------------------------------------------------------* ----------------------------------------------* | STM32F10x | MSD Pin |* ----------------------------------------------* | PE.3 | ChipSelect 1 |* | PA.7 / MOSI | DataIn 2 |* | | GND 3 (0 V) |* | | VDD 4 (3.3 V) |* | PA.5 / SCLK | Clock 5 |* | | GND 6 (0 V) |* | PA.6 / MISO | DataOut 7 |* -----------------------------------------------******************************************************************************* ****//* Includes ------------------------------------------------------------------*///#include "stm32f10x_lib.h"#include "stm32f10x.h"#include "hardwareinit.h"/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define sd_cs_1 GPIO_SetBits(GPIOB,GPIO_Pin_12)#define sd_cs_0 GPIO_ResetBits(GPIOB,GPIO_Pin_12)#define sd_check GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15)/* Select MSD Card: ChipSelect pin low *///#define MSD_CS_LOW() GPIO_ResetBits(GPIOE, GPIO_Pin_3)/* Deselect MSD Card: ChipSelect pin high *///#define MSD_CS_HIGH() GPIO_SetBits(GPIOE, GPIO_Pin_3)//SD传输数据结束后是否释放总线宏定义#define NO_RELEASE 0#define RELEASE 1// SD卡类型定义#define SD_TYPE_MMC 0#define SD_TYPE_V1 1#define SD_TYPE_V2 2#define SD_TYPE_V2HC 4// SD卡指令表#define CMD0 0 //卡复位#define CMD1 1#define CMD9 9 //命令9 ,读CSD数据#define CMD10 10 //命令10,读CID数据#define CMD12 12 //命令12,停止数据传输#define CMD16 16 //命令16,设置SectorSize 应返回0x00#define CMD17 17 //命令17,读sector#define CMD18 18 //命令18,读Multi sector#define ACMD23 23 //命令23,设置多sector写入前预先擦除N个block #define CMD24 24 //命令24,写sector#define CMD25 25 //命令25,写Multi sector#define ACMD41 41 //命令41,应返回0x00#define CMD55 55 //命令55,应返回0x01#define CMD58 58 //命令58,读OCR信息#define CMD59 59 //命令59,使能/禁止CRC,应返回0x00//数据写入回应字意义#define MSD_DATA_OK 0x05#define MSD_DATA_CRC_ERROR 0x0B#define MSD_DATA_WRITE_ERROR 0x0D#define MSD_DATA_OTHER_ERROR 0xFF//SD卡回应标记字#define MSD_RESPONSE_NO_ERROR 0x00#define MSD_IN_IDLE_STA TE 0x01#define MSD_ERASE_RESET 0x02#define MSD_ILLEGAL_COMMAND 0x04#define MSD_COM_CRC_ERROR 0x08#define MSD_ERASE_SEQUENCE_ERROR 0x10#define MSD_ADDRESS_ERROR 0x20#define MSD_PARAMETER_ERROR 0x40#define MSD_RESPONSE_FAILURE 0xFF#define Dummy_Byte 0xA5 //0xff/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*///u8 Dummy_Byte = 0xa5; //0xff;u8 SD_Type; //SD卡的类型u8 buf[512];/* Private function prototypes -----------------------------------------------*//* Private functions ---------------------------------------------------------*/FlagStatus sd_insert_check(void);u8 SD_WaitReady(void); //等待SD卡就绪u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);u8 SD_Init(void); //SD卡初始化u8 SD_Idle_Sta(void); //设置SD卡到挂起模式u8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据u8 SD_GetCID(u8 *cid_data); //读SD卡CIDu8 SD_GetCSD(u8 *csd_data); //读SD卡CSDu32 SD_GetCapacity(void); //取SD卡容量//USB 读卡器SD卡操作函数//u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);//u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead);u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sectoru8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //写一个sectoru8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sectoru8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count);//写多个sectoru8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes);//读取一byte//--------------------------------spi speed setting-------------------------/****************************************************************************** ** Function Name : SPI_Config* Description : Initializes the SPI1 and CS pins.* Input : None* Output : None* Return : None******************************************************************************* /void SPI_Config(u16 BaudRatePrescaler){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;/* GPIOA and GPIOC Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);/* SPI1 Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/* Configure SPI2 pins: SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PE3 pin: CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = BaudRatePrescaler;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);/* SPI1 enable */SPI_Cmd(SPI2, ENABLE);}void spi_high_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//SPI_BaudRatePrescaler_256;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_4);}void spi_low_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI_BaudRatePrescaler_4;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_256);}//---------------sd_insert_check---------------------------FlagStatus sd_insert_check(void){FlagStatus card_exist_state;if(!sd_check){card_exist_state = SET;}else{card_exist_state = RESET;}return card_exist_state;}//-------------------------------------------------------------------------/****************************************************************************** ** Function Name : SPI_FLASH_SendByte* Description : Sends a byte through the SPI interface and return the byte* received from the SPI bus.* Input : byte : byte to send.* Output : None* Return : The value of the received byte.******************************************************************************* /u8 SPIx_ReadWriteByte(u8 byte){/* Loop while DR register in not emplty */while ((SPI2->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);SPI2->DR = byte;/* Wait to receive a byte */while((SPI2->SR &SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);return SPI2->DR;}//u8 SPIx_ReadWriteByte(u8 byte)//{/* Loop while DR register in not emplty *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //((SPIx->SR & SPI_I2S_FLAG) != (uint16_t)RESET)/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);/* Wait to receive a byte *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);//}/****************************************************************************** ** Function Name : SPI_FLASH_ReadByte* Description : Reads a byte from the SPI Flash.* This function must be used only if the Start_Read_Sequence* function has been previously called.* Input : None* Output : None* Return : Byte Read from the SPI Flash.******************************************************************************* /u8 SPI_ReadByte(void){return (SPIx_ReadWriteByte(Dummy_Byte));}//-----------------------------------------------------------------------------------------------------------------------------------//等待SD卡回应//Response:要得到的回应值//返回值:0,成功得到了该回应值// 其他,得到回应值失败u8 SD_GetResponse(u8 Response){u16 Count=0xFFF;//等待次数while ((SPIx_ReadWriteByte(0XFF)!=Response)&&Count) Count--;//等待得到准确的回应if (Count==0){return MSD_RESPONSE_FAILURE;//得到回应失败}else{return MSD_RESPONSE_NO_ERROR;//正确回应}}//------------------------------------------------------------------------//等待SD卡写入完成//返回值:0,成功;// 其他,错误代码;u8 SD_WaitDataReady(void){u8 r1=MSD_DATA_OTHER_ERROR;u32 retry;retry=0;do{r1=SPIx_ReadWriteByte(0xFF)&0X1F; //读到回应if(retry==0xfffe)return 1;retry++;switch (r1){case MSD_DATA_OK: //数据接收正确了r1=MSD_DATA_OK;break;case MSD_DATA_CRC_ERROR: //CRC校验错误return MSD_DATA_CRC_ERROR;case MSD_DATA_WRITE_ERROR: //数据写入错误return MSD_DATA_WRITE_ERROR;default: //未知错误r1=MSD_DATA_OTHER_ERROR;break;}}while(r1==MSD_DATA_OTHER_ERROR); //数据错误时一直等待retry=0;while(SPIx_ReadWriteByte(0XFF)==0) //读到数据为0,则数据还未写完成{retry++;//delay_us(10); //SD卡写等待需要较长的时间if(retry>=0XFFFFFFFE)return 0XFF; //等待失败了};return 0; //成功了}//-----------------------------------------------------------------//向SD卡发送一个命令//输入: u8 cmd 命令// u32 arg 命令参数// u8 crc crc校验值//返回值:SD卡返回的响应u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc){u8 r1;u8 Retry=0;sd_cs_1;SPIx_ReadWriteByte(0xff); //高速写命令延时SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//片选端置低,选中SD卡sd_cs_0;//发送SPIx_ReadWriteByte(cmd | 0x40); //分别写入命令SPIx_ReadWriteByte(arg >> 24);SPIx_ReadWriteByte(arg >> 16);SPIx_ReadWriteByte(arg >> 8);SPIx_ReadWriteByte(arg);SPIx_ReadWriteByte(crc);//等待响应,或超时退出while((r1=SPIx_ReadWriteByte(0xFF))==0xFF){Retry++;if(Retry>200)break;}//关闭片选sd_cs_1;//在总线上额外增加8个时钟,让SD卡完成剩下的工作SPIx_ReadWriteByte(0xFF);//返回状态值return r1;}//-----------------------------------------------------------//向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)//输入:u8 cmd 命令// u32 arg 命令参数// u8 crc crc校验值//返回值:SD卡返回的响应u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc){u8 Retry=0;u8 r1;SPIx_ReadWriteByte(0xff);//高速写命令延时SPIx_ReadWriteByte(0xff);sd_cs_0;//片选端置低,选中SD卡//发送SPIx_ReadWriteByte(cmd | 0x40); //分别写入命令SPIx_ReadWriteByte(arg >> 24);SPIx_ReadWriteByte(arg >> 16);SPIx_ReadWriteByte(arg >> 8);SPIx_ReadWriteByte(arg);SPIx_ReadWriteByte(crc);//等待响应,或超时退出while((r1=SPIx_ReadWriteByte(0xFF))==0xFF){Retry++;if(Retry>200)break;}//返回响应值return r1;}//------------------------------------------------------------//把SD卡设置到挂起模式//返回值:0,成功设置// 1,设置失败u8 SD_Idle_Sta(void){u16 i;u8 retry;for(i=0;i<0xf00;i++); //纯延时,等待SD卡上电完成//先产生>74个脉冲,让SD卡自己初始化完成for(i=0;i<10;i++)SPIx_ReadWriteByte(0xFF);//-----------------SD卡复位到idle开始-----------------//循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态//超时则直接退出retry = 0;do{//发送CMD0,让SD卡进入IDLE状态i = SD_SendCommand(CMD0, 0, 0x95);retry++;}while((i!=0x01)&&(retry<200));//跳出循环后,检查原因:初始化成功?or 重试超时?if(retry==200)return 1; //失败return 0; //成功}//---------------------------------------------------------------//初始化SD卡//如果成功返回,则会自动设置SPI速度为18Mhz//返回值:0:NO_ERR// 1:TIME_OUT// 99:NO_CARDu8 SD_Init(void){u8 r1; // 存放SD卡的返回值u16 retry; // 用来进行超时计数u8 buff[6];/*//设置硬件上与SD卡相关联的控制引脚输出//避免NRF24L01/W25X16等的影响RCC->APB2ENR|=1<<2; //PORTA时钟使能GPIOA->CRL&=0XFFF000FF;GPIOA->CRL|=0X00033300;//PA2.3.4 推挽GPIOA->ODR|=0X7<<2; //PA2.3.4上拉SPIx_Init();SPIx_SetSpeed(SPI_SPEED_256);//设置到低速模式*/spi_low_speed();sd_cs_1;if(SD_Idle_Sta()) return 1;//超时返回1 设置到idle 模式失败//-----------------SD卡复位到idle结束-----------------//获取卡片的SD版本信息sd_cs_0;r1 = SD_SendCommand_NoDeassert(8, 0x1aa,0x87);//如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化if(r1 == 0x05){//设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC SD_Type = SD_TYPE_V1;//如果是V1.0卡,CMD8指令后没有后续数据//片选置高,结束本次命令sd_cs_1;//多发8个CLK,让SD结束后续操作SPIx_ReadWriteByte(0xFF);//-----------------SD卡、MMC卡初始化开始-----------------//发卡初始化指令CMD55+ACMD41// 如果有应答,说明是SD卡,且初始化完成// 没有回应,说明是MMC卡,额外进行相应初始化retry = 0;do{//先发CMD55,应返回0x01;否则出错r1 = SD_SendCommand(CMD55, 0, 0);if(r1 == 0XFF)return r1;//只要不是0xff,就接着发送//得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次r1 = SD_SendCommand(ACMD41, 0, 0);retry++;}while((r1!=0x00) && (retry<400));// 判断是超时还是得到正确回应// 若有回应:是SD卡;没有回应:是MMC卡//----------MMC卡额外初始化操作开始------------if(retry==400){retry = 0;//发送MMC卡初始化命令(没有测试)do{r1 = SD_SendCommand(1,0,0);retry++;}while((r1!=0x00)&& (retry<400));if(retry==400)return 1; //MMC卡初始化超时//写入卡类型SD_Type = SD_TYPE_MMC;}//----------MMC卡额外初始化操作结束------------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();SPIx_ReadWriteByte(0xFF);//禁止CRC校验r1 = SD_SendCommand(CMD59, 0, 0x95);if(r1 != 0x00)return r1; //命令错误,返回r1//设置Sector Sizer1 = SD_SendCommand(CMD16, 512, 0x95);if(r1 != 0x00)return r1;//命令错误,返回r1//-----------------SD卡、MMC卡初始化结束-----------------}//SD卡为V1.0版本的初始化结束//下面是V2.0卡的初始化//其中需要读取OCR数据,判断是SD2.0还是SD2.0HC卡else if(r1 == 0x01){//V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令buff[0] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[1] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[2] = SPIx_ReadWriteByte(0xFF); //should be 0x01buff[3] = SPIx_ReadWriteByte(0xFF); //should be 0xAAsd_cs_1;SPIx_ReadWriteByte(0xFF);//the next 8 clocks//判断该卡是否支持2.7V-3.6V的电压范围//if(buff[2]==0x01 && buff[3]==0xAA) //不判断,让其支持的卡更多{retry = 0;//发卡初始化指令CMD55+ACMD41do{r1 = SD_SendCommand(CMD55, 0, 0);if(r1!=0x01)return r1;r1 = SD_SendCommand(ACMD41, 0x40000000, 0);if(retry>200)return r1; //超时则返回r1状态}while(r1!=0);//初始化指令发送完成,接下来获取OCR信息//-----------鉴别SD2.0卡版本开始-----------r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);if(r1!=0x00){sd_cs_1;//释放SD片选信号return r1; //如果命令没有返回正确应答,直接退出,返回应答}//读OCR指令发出后,紧接着是4字节的OCR信息buff[0] = SPIx_ReadWriteByte(0xFF);buff[1] = SPIx_ReadWriteByte(0xFF);buff[2] = SPIx_ReadWriteByte(0xFF);buff[3] = SPIx_ReadWriteByte(0xFF);//OCR接收完成,片选置高sd_cs_1;SPIx_ReadWriteByte(0xFF);//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC //如果CCS=1:SDHC CCS=0:SD2.0if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC; //检查CCSelse SD_Type = SD_TYPE_V2;//-----------鉴别SD2.0卡版本结束-----------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();}}return r1;}//---------------------------------------------------------------------//从SD卡中读回指定长度的数据,放置在给定位置//输入: u8 *data(存放读回数据的内存>len)// u16 len(数据长度)// u8 release(传输完成后是否释放总线CS置高0:不释放1:释放)//返回值:0:NO_ERR// other:错误信息u8 SD_ReceiveData(u8 *data, u16 len, u8 release){// 启动一次传输sd_cs_0;if(SD_GetResponse(0xFE)) //等待SD卡发回数据起始令牌0xFE {sd_cs_1;return 1;}while(len--)//开始接收数据{*data=SPIx_ReadWriteByte(0xFF);data++;}//下面是2个伪CRC(dummy CRC)SPIx_ReadWriteByte(0xFF);SPIx_ReadWriteByte(0xFF);if(release==RELEASE)//按需释放总线,将CS置高{sd_cs_1;//传输结束SPIx_ReadWriteByte(0xFF);}return 0;}//-----------------------------------------------------------------//获取SD卡的CID信息,包括制造商信息//输入: u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCID(u8 *cid_data){u8 r1;//发CMD10命令,读CIDr1 = SD_SendCommand(CMD10,0,0xFF);if(r1 != 0x00)return r1; //没返回正确应答,则退出,报SD_ReceiveData(cid_data,16,RELEASE);//接收16个字节的return 0;}//-------------------------------------------------------------------//获取SD卡的CSD信息,包括容量和速度信息//输入:u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCSD(u8 *csd_data){u8 r1;r1=SD_SendCommand(CMD9,0,0xFF);//发CMD9命令,读CSD if(r1)return r1; //没返回正确应答,则退出,报错SD_ReceiveData(csd_data, 16, RELEASE);//接收16个字节的数据return 0;}//------------------------------------------------------------------------ //获取SD卡的容量(字节)//返回值:0:取容量出错// 其他:SD卡的容量(字节)u32 SD_GetCapacity(void){u8 csd[16];u32 Capacity;u8 r1;u16 i;u16 temp;//取CSD信息,如果期间出错,返回0if(SD_GetCSD(csd)!=0) return 0;//如果为SDHC卡,按照下面方式计算if((csd[0]&0xC0)==0x40){Capacity=((u32)csd[8])<<8;Capacity+=(u32)csd[9]+1;Capacity = (Capacity)*1024;//得到扇区数Capacity*=512;//得到字节数}else{i = csd[6]&0x03;i<<=8;i += csd[7];i<<=2;i += ((csd[8]&0xc0)>>6);//C_SIZE_MULTr1 = csd[9]&0x03;r1<<=1;r1 += ((csd[10]&0x80)>>7);r1+=2;//BLOCKNRtemp = 1;while(r1){temp*=2;r1--;}Capacity = ((u32)(i+1))*((u32)temp);// READ_BL_LENi = csd[5]&0x0f;//BLOCK_LENtemp = 1;while(i){temp*=2;i--;}//The final resultCapacity *= (u32)temp;//字节为单位}return (u32)Capacity;}//--------------------------------------------------------------------//读SD卡的一个block//输入:u32 sector 取地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}/*u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}*///----------------------------------------------------------------------//写入SD卡的一个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_WriteSingleBlock(u32 sector, const u8 *data){u8 r1;u16 i;u16 retry;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD24, sector, 0x00);if(r1 != 0x00){return r1; //应答不正确,直接返回}//开始准备数据传输sd_cs_0;//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//放起始令牌0xFESPIx_ReadWriteByte(0xFE);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1;return r1;}//等待操作完成retry = 0;while(!SPIx_ReadWriteByte(0xff)){retry++;if(retry>0xfffe) //如果长时间写入没有完成,报错退出{sd_cs_1;return 1; //写入超时返回1}}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return 0;}//-------------------------------------------------------------------//读SD卡的多个block(实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 连续读count个block//返回值:0:成功// other:失败u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count) {u8 r1;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式//如果不是SDHC,将sector地址转成byte地址if(SD_Type!=SD_TYPE_V2HC)sector = sector<<9;//SD_WaitDataReady();//发读多块命令r1 = SD_SendCommand(CMD18, sector, 0);//读命令if(r1 != 0x00)return r1;do//开始接收数据{if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)break;buffer += 512;} while(--count);//全部传输完毕,发送停止命令SD_SendCommand(CMD12, 0, 0);//释放总线sd_cs_1;SPIx_ReadWriteByte(0xFF);if(count != 0)return count; //如果没有传完,返回剩余个数else return 0;}//------------------------------------------------------------------------//写入SD卡的N个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 写入的block数目//返回值:0:成功// other:失败u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count){u8 r1;u16 i;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type != SD_TYPE_MMC) r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除r1 = SD_SendCommand(CMD25, sector, 0x00);//发多块写入指令if(r1 != 0x00)return r1; //应答不正确,直接返回sd_cs_0;//开始准备数据传输SPIx_ReadWriteByte(0xff);//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);//--------下面是N个sector写入的循环部分do{//放起始令牌0xFC 表明是多块写入SPIx_ReadWriteByte(0xFC);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1; //如果应答为报错,则带错误代码直接退出return r1;}//等待SD卡写入完成if(SD_WaitDataReady()==1){sd_cs_1; //等待SD卡写入完成超时,直接退出报错return 1;}}while(--count);//本sector数据传输完成//发结束传输令牌0xFDr1 = SPIx_ReadWriteByte(0xFD);if(r1==0x00){count = 0xfe;}if(SD_WaitDataReady()) //等待准备好{sd_cs_1;return 1;}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return count; //返回count值,如果写完则count=0,否则count=1 }//-----------------------------------------------------------------------------//在指定扇区,从offset开始读出bytes个字节//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buf 数据存储地址(大小<=512byte)// u16 offset 在扇区里面的偏移量// u16 bytes 要读出的字节数//返回值:0:成功// other:失败u8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes){u8 r1;u16 i=0;r1=SD_SendCommand(CMD17,address<<9,0);//发送读扇区命令if(r1)return r1; //应答不正确,直接返回sd_cs_0;//选中SD卡if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE{sd_cs_1; //关闭SD卡return 1;//读取失败}for(i=0;i<offset;i++)SPIx_ReadWriteByte(0xff);//跳过offset位for(;i<offset+bytes;i++)*buf++=SPIx_ReadWriteByte(0xff);//读取有用数据for(;i<512;i++) SPIx_ReadWriteByte(0xff); //读出剩余字节SPIx_ReadWriteByte(0xff);//发送伪CRC码SPIx_ReadWriteByte(0xff);sd_cs_1;//关闭SD卡return 0;}。
(整理)stm32Fatfs读写SD卡.
stm32 Fatfs 读写SD卡读写SD是嵌入式系统中一个比较基础的功能,在很多应用中都可以用得上SD 卡。
折腾了几天,总算移植成功了最新版Fatfs(Fatfs R0.09),成功读写SD卡下文件。
FatFs (/fsw/ff/00index_e.html)是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。
FatFs 的编写遵循ANSI C,因此不依赖于硬件平台。
它可以嵌入到便宜的微控制器中,如8051, PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。
1. SD卡/TF卡硬件接口SD卡有两种操作接口,SDIO和SPI。
使用SDIO口的速度比较快,SPI的速度比较慢。
SD卡引脚描述如下: SD卡SPI接法如下:我使用的是正点原子的开发板,所以采用的是SPI接口的模式。
TF卡SDIO 模式和SPI模式引脚定义:可以发现Micro SD卡只有8个引脚是因为比SD卡少了一个Vss。
使用TF转SD的卡套套在Micro SD卡上,这样一来大小就和SD卡一样大,这时候卡套上的9个引脚就和SD卡一样了,你可以完全当做SD卡来操作。
2. SD卡底层驱动SD卡的操作比较复杂,需要多看看一些文档。
这里附上SD底层驱动代码,代码说明详见注释Sd卡SPi操作底层代码: sdcard.c sdcard.h3. Fatfs 移植FatFs 软件包中相关文件:ffconf.h FatFs 模块配置文件ff.h FatFs 和应用模块公用的包含文件ff.c FatFs 模块diskio.h FatFs and disk I/O 模块公用的包含文件integer.h 数据类型定义option 可选的外部功能diskio.c FatFs 与disk I/O 模块接口层文件(不属于FatFs 需要由用户提供)FatFs 配置,文件系统的配置项都在ffconf.h 文件之中:(1) _FS_TINY :这个选项在R0.07 版本之中开始出现,在之前的版本都是以独立的文件出现,现在通过一个宏来修改使用起来更方便;(2) _FS_MINIMIZE、_FS_READONLY、_USE_STRFUNC、_USE_MKFS、_USE_FORWARD 这些宏是用来对文件系统进行裁剪(3) _CODE_PAGE :本选项用于设置语言码的类型(4) _USE_LFN :取值为0~3,主要用于长文件名的支持及缓冲区的动态分配:0:不支持长文件名;1:支持长文件名存储的静态分配,一般是存储在BSS 段;2:支持长文件名存储的动态分配,存储在栈上;3:支持长文件名存储的动态分配,存储在堆上。
基于STM32F407平台实现FATFS读写大容量SD卡的心得
基于STM32F407平台实现FATFS读写大容量SD卡的心得在基于STM32F407平台实现FATFS读写大容量(128G)SD卡的过程中,我积累了一些心得和经验。
下面我将简要介绍一下这些经验。
首先,在使用FATFS文件系统之前,我们需要确保已经正确初始化了SD卡的硬件和配置。
这包括对GPIO、SPI或SDIO等外设进行初始化,并设置正确的时钟源和参数。
对于不同的硬件配置,可能会有所不同,因此需要仔细查看STM32F407的相关文档和资料。
其次,在FATFS文件系统的使用中,我们需要了解和掌握以下几个核心概念和操作:1. 初始化文件系统和 Mount 卷标:在开始进行 SD 卡的读写之前,我们需要使用 f_mount 函数初始化文件系统,并使用 f_mount 函数挂载指定的卷标。
卷标可以是 0 到 9 之间的一个整数,用于表示 SD 卡上的不同分区或逻辑盘符。
2. 打开文件和读写操作:在进行文件读写之前,我们需要使用f_open 函数打开指定的文件,并返回一个文件指针。
然后可以使用f_read 和 f_write 函数进行读写操作。
读操作可以使用 f_read 函数读取指定长度的数据到缓冲区中,写操作可以使用 f_write 函数从缓冲区中写入指定长度的数据到文件中。
对于大容量的SD卡,我们可能需要提前进行一些准备工作,以确保能够正确读写数据:1. 使用 f_mkfs 函数进行格式化:在首次使用 SD 卡之前,我们可能需要对其进行格式化。
可以使用 f_mkfs 函数来完成格式化操作,指定分区号和扇区大小等参数。
2.适当分割文件:为了提高读写性能和避免内存溢出,我们可以将大的文件分割为多个小文件进行读写。
这可以通过调整缓冲区大小和每次读取或写入的数据长度来实现。
3.合理规划缓冲区内存:在进行SD卡读写时,我们需要使用一些缓冲区来暂存读取或写入的数据。
在选择缓冲区大小时,需要考虑到STM32F407的内存限制和其他功能的内存占用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
连载】【ALIENTEK 战舰STM32开发板】STM32开发指南--第四十四章SD卡实验2013-04-04 23:07第四十四章 SD卡实验很多单片机系统都需要大容量存储设备,以存储数据。
目前常用的有U盘,FLASH芯片,SD卡等。
他们各有优点,综合比较,最适合单片机系统的莫过于SD卡了,它不仅容量可以做到很大(32Gb以上),而且支持SPI接口,方便移动,并且有几种体积的尺寸可供选择(标准的SD卡尺寸,以及TF卡尺寸等),能满足不同应用的要求。
只需要4个IO口即可外扩一个最大达32GB以上的外部存储器,容量从几十M到几十G 选择尺度很大,更换也很方便,编程也简单,是单片机大容量外部存储器的首选。
ALIENTKE 战舰STM32开发板自带了标准的SD卡接口,可使用STM32自带的SPI/S DIO接口驱动(通过跳线帽选择驱动方式),本章我们使用SPI驱动,最高通信速度可达18Mbps,每秒可传输数据2M字节以上,对于一般应用足够了。
在本章中,我们将向大家介绍,如何在ALIENTEK战舰STM32开发板上实现SD卡的读取。
本章分为如下几个部分:44.1 SD卡简介44.2 硬件设计44.3 软件设计44.4 下载验证44.1 SD卡简介SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,它是在MMC的基础上发展而来,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。
SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。
大小犹如一张邮票的SD记忆卡,重量只有2克,但却拥有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性。
按容量分类,可以将SD卡分为3类:SD卡、SDHC卡、SDXC卡。
如表44.1.1所示:容量命名简称0~2G Standard Capacity SD Memory Card SDSC或SD2G~32G High Capacity SD Memory Card SDHC32G~2T Extended Capacity SD Memory Card SDXC表44.1.1 SD卡按容量分类SD卡和SDHC卡协议基本兼容,但是SDXC卡,同这两者区别就比较大了,本章我们讨论的主要是SD/SDHC卡(简称SD卡)。
SD卡一般支持2种操作模式:1,SD卡模式(通过SDIO通信);2,SPI模式;主机可以选择以上任意一种模式同SD卡通信,SD卡模式允许4线的高速数据传输。
SPI 模式允许简单的通过SPI接口来和SD卡通信,这种模式同SD卡模式相比就是丧失了速度。
SD卡的引脚排序如下图44.1.1所示:图44.1.1 SD卡引脚排序图SD卡引脚功能描述如表45.1.2所示:表45.1.2 SD卡引脚功能表SD卡只能使用3.3V的IO电平,所以,MCU一定要能够支持3.3V的IO端口输出。
注意:在SPI模式下,CS/MOSI/MISO/CLK都需要加10~100K左右的上拉电阻。
SD卡有5个寄存器,如表45.1.3所示:名称宽度描述CID 128 卡标识寄存器RCA 16 相对卡地址(Relative card address)寄存器:本地系统中卡的地址,动态变化,在主机初始化的时候确定*SPI模式中没有CSD 128 卡描述数据:卡操作条件相关的信息数据SCR 64 SD配置寄存器:SD卡特定信息数据OCR 32 操作条件寄存器表45.1.3 SD卡相关寄存器关于这些寄存器的详细描述,请参考光盘相关SD卡资料。
我们在这里就不描述了。
接下来,我们看看SD卡的命令格式,如表45.1.4所示:字节1 字节2--5 字节67 6 5 0 31 0 7 1 00 1 command 命令参数CRC 1表45.1.4 SD卡命令格式SD卡的指令由6个字节组成,字节1的最高2位固定为01,低6位为命令号(比如CM D16,为10000即16进制的0X10,完整的CMD16,第一个字节为01010000,即0 X10+0X40)。
字节2~5为命令参数,有些命令是没有参数的。
字节6的高七位为CRC值,最低位恒定为1。
SD卡的命令总共有12类,分为Class0~Class11,本章,我们仅介绍几个比较重要的命令,如表45.1.5所示:命令参数回应描述CMD0(0X00)NONE R1 复位SD卡CMD8(0X08) VHS+Check patternR7 发送接口状态命令CMD9(0X09)NONE R1 读取卡特定数据寄存器CMD10(0X0A)NONE R1 读取卡标志数据寄存器CMD16(0X10)块大小R1 设置块大小(字节数)CMD17(0X11)地址R1 读取一个块的数据CMD24(0X18)地址R1 写入一个块的数据CMD41(0X29) NONE R3发送给主机容量支持信息和激活卡初始化过程CMD55(0X37)NONE R1 告诉SD卡,下一个是特定应用命令CMD58(0X3A)NONE R3 读取OCR寄存器表45.1.5 SD卡部分命令上表中,大部分的命令是初始化的时候用的。
表中的R1、R3和R7等是SD卡的回应,SD卡和单片机的通信采用发送应答机制,如图45.1.2所示:图45.1.2 SD卡命令传输过程每发送一个命令,SD卡都会给出一个应答,以告知主机该命令的执行情况,或者返回主机需要获取的数据。
SPI模式下,SD卡针对不同的命令,应答可以使R1~R7,R1的应答,各位描述如表45.1.6所示:R1响应格式位7 6 5 4 3 2 1含义开始位始终为0参数错误地址错误擦除序列错误CRC错误非法命令擦除复位表45.1.6 R1响应各位描述R2~R7的响应,我们就不介绍了,请的大家参考SD卡2.0协议。
接下来,我们看看SD卡初始化过程。
因为我们使用的是SPI模式,所以先得让SD卡进入SPI模式。
方法如下:在SD卡收到复位命令(CMD0)时,CS为有效电平(低电平)则SPI模式被启用。
不过在发送CMD0之前,要发送>74个时钟,这是因为SD卡内部有个供电电压上升时间,大概为64个CLK,剩下的10个CLK用于SD卡同步,之后才能开始CMD0的操作,在卡初始化的时候,CLK时钟最大不能超过400Khz!。
接着我们看看SD卡的初始化,SD卡的典型初始化过程如下:1、初始化与SD卡连接的硬件条件(MCU的SPI配置,IO口配置);2、上电延时(>74个CLK);3、复位卡(CMD0),进入IDLE状态;4、发送CMD8,检查是否支持2.0协议;5、根据不同协议检查SD卡(命令包括:CMD55、CMD41、CMD58和CMD1等);6、取消片选,发多8个CLK,结束初始化这样我们就完成了对SD卡的初始化,注意末尾发送的8个CLK是提供SD卡额外的时钟,完成某些操作。
通过SD卡初始化,我们可以知道SD卡的类型(V1、V2、V2HC或者M MC),在完成了初始化之后,就可以开始读写数据了。
SD卡读取数据,这里通过CMD17来实现,具体过程如下:1、发送CMD17;2、接收卡响应R1;3、接收数据起始令牌0XFE;4、接收数据;5、接收2个字节的CRC,如果不使用CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,发多8个CLK;以上就是一个典型的读取SD卡数据过程,SD卡的写于读数据差不多,写数据通过CMD2 4来实现,具体过程如下:1、发送CMD24;2、接收卡响应R1;3、发送写数据起始令牌0XFE;4、发送数据;5、发送2字节的伪CRC;6、禁止片选之后,发多8个CLK;以上就是一个典型的写SD卡过程。
关于SD卡的介绍,我们就介绍到这里,更详细的介绍请参考光盘SD卡的参考资料(SD卡2.0协议)。
44.2 硬件设计本章实验功能简介:开机的时候先初始化SD卡,如果SD卡初始化完成,则提示LCD初始化成功。
按下KEY0,读取SD卡扇区0的数据,然后通过串口发送到电脑。
如果没初始化通过,则在LCD上提示初始化失败。
同样用DS0来指示程序正在运行。
本实验用到的硬件资源有:1)指示灯DS02) KEY0按键3)串口4) TFTLCD模块5) SD卡前面四部分,在之前的实例已经介绍过了,这里我们介绍一下战舰STM32开发板板载的S D卡接口和STM32的连接关系,如图44.2.1所示:图44.2.1 SD卡接口与STM32连接原理图我们用跳线帽将P10的SD_DT3、SD_CMD、SD_SCK、SD_DT0分别同P12的SD_CS、SPI2_MOSI、SPI2_SCK、SPI2_MISO连接起来,即实现SD卡的SPI模式连接。
硬件连接示意图如图44.2.2所示:图44.2.2 SD卡SPI方式硬件连接示意图将图中所示的4处,用跳线帽短接,接口实现SD卡与STM32的SPI连接。
最后,你还得自备一个SD卡,将其插入板子下面的SD卡接口。
44.3 软件设计打开上一章的工程,首先在HARDWARE文件夹下新建一个SD的文件夹。
然后新建一个MMC_SD.C和MMC_SD.H的文件保存在SD文件夹下,并将这个文件夹加入头文件包含路径。
打开MMC_SD.C文件,在该文件里面,我们输入与SD卡相关的操作代码,这里由于篇幅限制,我们不贴出所有代码,仅介绍两个最重要的函数,第一个是SD_Initialize函数,该函数源码如下://初始化SD卡u8 SD_Initialize(void){u8 r1; // 存放SD卡的返回值u16 retry; // 用来进行超时计数u8 buf[4];u16 i;SD_SPI_Init(); //初始化IOSD_SPI_SpeedLow(); //设置到低速模式for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲retry=20;do{r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态}while((r1!=0X01) && retry--);SD_Type=0;//默认无卡if(r1==0X01){if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0{for(i=0;i<4;i++)buf=SD_SPI_ReadWriteByte(0XFF);//得到R7相应值if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V{retry=0XFFFE;do{SD_SendCmd(CMD55,0,0X01); //发送CMD55r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41}while(r1&&retry--);if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2. 0卡版本开始{for(i=0;i<4;i++)buf=SD_SPI_ReadWriteByte(0XF F);//得到OCR值if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //检查CCSelse SD_Type=SD_TYPE_V2;}}}else//SD V1.x/ MMC V3{SD_SendCmd(CMD55,0,0X01); //发送CMD55r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41if(r1<=1){SD_Type=SD_TYPE_V1;retry=0XFFFE;do //等待退出IDLE模式{SD_SendCmd(CMD55,0,0X01); //发送CMD55r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41}while(r1&&retry--);}else//MMC卡不支持CMD55+CMD41识别{SD_Type=SD_TYPE_MMC;//MMC V3retry=0XFFFE;do //等待退出IDLE模式{r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1}while(r1&&retry--);}if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type= SD_TYPE_ERR;//错误的卡}}SD_DisSelect();//取消片选SD_SPI_SpeedHigh();//高速if(SD_Type)return 0;else if(r1)return r1;return 0xaa;//其他错误}该函数先设置与SD相关的IO口及SPI初始化,然后发送CMD0,进入IDLE状态,并设置SD卡为SPI模式通信,然后判断SD卡类型,完成SD卡的初始化,注意该函数调用的SD_SPI_Init等函数,实际是对SPI2的相关函数进行了一层封装,方便移植。