STM32读写SD卡要点

合集下载

STM32F103调试读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卡

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单片机的SD卡存储器读写模块设计

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系列微控制器来对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文件系统

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卡要点说明

智芯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放入缓冲区既可。

基于嵌入式ARM的SD卡的读写要点

基于嵌入式ARM的SD卡的读写要点

摘要SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。

本实训的作品是利用基于ARM Cotex-M3内核的嵌入式处理器STM32自带的SDIO硬件接口来驱动SD卡,并结合文件系统 FATFS R0.07C来完成一个基于嵌入式ARM的SD卡读写的作品,现实向SD 卡写入一个txt文件,并读取SD卡的文件目标并通过串口打印到PC机显示。

关键词:嵌入式;ARM;STM32;SD卡;文件系统AbstractSD Card (Secure Digital Memory Card) Chinese translation for Secure Digital Card, it is a kind of based on semiconductor flash Memory of a new generation of Memory device, it is widely used in portable devices, such as Digital cameras, personal Digital assistant (PDA) and multimedia player, etc. This training work is based on ARM Cotex - M3 kernel embedded processor STM32 own SDIO hardware interface to drive the SD card, and combined with the file system FATFS R0.07 C to complete a based on embedded ARM of the SD card, speaking, reading and writing work, reality to SD card to a TXT file, and read SD card file goals and through the serial port print to PC display.Key words:embedded;ARM;STM32; SD Card; File system目录1 前言 (1)1.1ARM应用背景 (1)1.2研究内容 (2)1.3研究成果 (3)2 STM32处理器概述 (3)2.1STM32简介 (3)2.1.1 STM32F103VET6的参数 (4)2.2内部资源 (6)2.3C ORTEX-M3内核简介 (6)2.4STM32SDIO简介 (7)2.4.1 SDIO简介 (7)2.4.2 SDIO功能特性 (8)3 SDIO的原理及实现方法 (8)3.1原理 (9)3.2SDIO适配器 (10)3.3SDIO卡识别过程 (11)3.4SDIO写数据块 (12)3.5SDIO读数据块 (13)4 FATFS文件系统 (13)4.1F A T FS文件系统简介 (13)4.2F A T FS文件系统移植 (14)4.2.1移植前工作 (14)4.2.2开始移植 (14)5 测试及结果 (15)5.1JTAG仿真器介绍 (16)5.2现象及结果 (16)6 结论 (18)致谢 (19)参考文献 (20)1 前言1.1 ARM应用背景如今,学习一种处理器的就有许多ARM内核的处理器可供使用,现在社会已步入嵌入式学习阶段。

新版STM32 HAL库SD卡读写不正常总结

新版STM32 HAL库SD卡读写不正常总结
官方给的驱动未使用DMA,读写不正常表现: 单个字节循环写文件,有时候写到1KB就出错,有时候能写到400KB,测试写到1MB,但多次测试没有一次能写完成。 自己移值的驱动使用DMA,因为没有参考,所以移植的也有问题。
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) {
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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端口输出。

注意:在SPI模式下,CS/MOSI/MISO/CLK都需要加10~100K左右的上拉电阻。

SD卡要进入SPI模式很简单,就是在SD卡收到复位命令(CMD0)时,CS为有效电平(低电平)则SPI模式被启用。

不过在发送CMD0之前,要发送>74个时钟,这是因为SD卡内部有个供电电压上升时间,大概为64个CLK,剩下的10个CLK用于SD卡同步,之后才能开始CMD0的操作,在卡初始化的时候,CLK时钟最大不能超过400Khz!。

ALENTEK MiniSTM32开发板使用的是SPI模式来读写SD卡,下面我们就重点介绍一下SD卡在SPI模式下的相关操作。

首先介绍SPI模式下几个重要的操作命令,如下表所示:命令参数回应描述CMD0(0X00)NONE R1复位SD卡CMD9(0X09)NONE R1读取卡特定数据寄存器CMD10(0X0A)NONE R1读取卡标志数据寄存器CMD16(0X10)块大小R1设置块大小(字节数)CMD17(0X11)地址R1读取一个块的数据CMD24(0X18)地址R1写入一个块的数据CMD41(0X29)NONE R1引用命令的前命令CMD55(0X37)NONE R1开始卡的初始化CMD59(0X3B)仅最后一位有效R1设置CRC开启(1)或关闭(0)表3.20.1.2 SPI模式下SD卡部分操作指令其中R1的回应格式如下表所示:表3.20.1.3 SD卡R1回应格式接着我们看看SD卡的初始化,SD卡的典型初始化过程如下:1、初始化与SD卡连接的硬件条件(MCU的SPI配置,IO口配置);2、上电延时(>74个CLK);3、复位卡(CMD0);4、激活卡,内部初始化并获取卡类型(CMD1(用于MMC卡)、CMD55、CMD41);5.、查询OCR,获取供电状况(CMD58);6、是否使用CRC(CMD59);7、设置读写块数据长度(CMD16);8、读取CSD,获取存储卡的其他信息(CMD9);9、发送8CLK后,禁止片选;这样我们就完成了对SD卡的初始化,这里面我们一般设置读写块数据长度为512个字节,并禁止使用CRC。

在完成了初始化之后,就可以开始读写数据了。

SD卡读取数据,这里通过CMD17来实现,具体过程如下:1、发送CMD17;2、接收卡响应R1;3、接收数据起始令牌0XFE;4、接收数据;5、接收2个字节的CRC,如果没有开启CRC,这两个字节在读取后可以丢掉。

6、8CLK之后禁止片选;以上就是一个典型的读取SD卡数据过程,SD卡的写于读数据差不多,写数据通过CMD24来实现,具体过程如下:1、发送CMD24;2、接收卡响应R1;3、发送写数据起始令牌0XFE;4、发送数据;5、发送2字节的伪CRC;6、8CLK之后禁止片选;以上就是一个典型的写SD卡过程。

关于SD卡的介绍,我们就介绍到这里,更详细的介绍请参考SD卡的参考资料。

3.20.2 硬件设计本节实验功能简介:开机的时候先初始化SD卡,如果SD卡初始化完成,则读取扇区0的数据,然后通过串口打印到电脑上。

如果没初始化通过,则在LCD上提示初始化失败。

同样用DS0来指示程序正在运行。

所要用到的硬件资源如下:1)STM32F103RBT6。

2)DS0(外部LED0)。

3)串口1。

4)TFTLCD液晶模块。

5)SD卡。

前面四部分,在之前的实例已经介绍过了,这里我们介绍一下SD卡在开发板上的连接方式,SD卡与MCU的连接原理图如下:图3.20.2.1 SD卡与STM32连接电路图3.20.3 软件设计打开上一节的工程,首先在HARDW ARE文件夹下新建一个SD的文件夹。

然后新建一个MMC_SD.C和MMC_SD.H的文件保存在SD文件夹下,并将这个文件夹加入头文件包含路径。

打开MMC_SD.C文件,输入如下代码:#include "sys.h"#include "mmc_sd.h"#include "spi.h"#include "usart.h"#include "delay.h"u8SD_Type=0;//SD卡的类型//Mini STM32开发板//SD卡驱动//正点原子@ALIENTEK//2010/5/13//增加了一些延时,实测可以支持TF卡(1G/2G),金士顿2G,4G 16G SD卡//2010/6/24//加入了u8 SD_GetResponse(u8 Response)函数//修改了u8 SD_WaitDataReady(void)函数//增加了USB读卡器支持的u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead);//和u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);两个函数//等待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);//设置到低速模式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卡,再修改为MMCSD_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);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);}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命令,读CSDif(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);//如果不是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;}/////////////////下面2个函数为USB读写所需要的///////////////////////////定义SD卡的块大小#define BLOCK_SIZE 512//写入MSD/SD数据//pBuffer:数据存放区//ReadAddr:写入的首地址//NumByteToRead:要写入的字节数//返回值:0,写入完成//其他,写入失败u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite) {u32 i,NbrOfBlock = 0, Offset = 0;u32 sector;u8 r1;NbrOfBlock = NumByteToWrite / BLOCK_SIZE;//得到要写入的块的数目SD_CS=0;while (NbrOfBlock--)//写入一个扇区{sector=WriteAddr+Offset;if(SD_Type==SD_TYPE_V2HC)sector>>=9;//执行与普通操作相反的操作} r1=SD_SendCommand_NoDeassert(CMD24,sector,0xff);//写命令if(r1){SD_CS=1;return 1;//应答不正确,直接返回}SPIx_ReadWriteByte(0xFE);//放起始令牌0xFE//放一个sector的数据for(i=0;i<512;i++)SPIx_ReadWriteByte(*pBuffer++);//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);if(SD_WaitDataReady())//等待SD卡数据写入完成{SD_CS=1;return 2;}Offset += 512;//写入完成,片选置1SD_CS=1;SPIx_ReadWriteByte(0xff); return 0;}//读取MSD/SD数据//pBuffer:数据存放区//ReadAddr:读取的首地址//NumByteToRead:要读出的字节数//返回值:0,读出完成//其他,读出失败u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead){u32 NbrOfBlock=0,Offset=0;u32 sector=0;u8 r1=0;NbrOfBlock=NumByteToRead/BLOCK_SIZE;SD_CS=0;while (NbrOfBlock --){sector=ReadAddr+Offset;if(SD_Type==SD_TYPE_V2HC)sector>>=9;//执行与普通操作相反的操作r1=SD_SendCommand_NoDeassert(CMD17,sector,0xff);//读命令} if(r1)//命令发送错误{SD_CS=1;return r1;}r1=SD_ReceiveData(pBuffer,512,RELEASE); if(r1)//读数错误{SD_CS=1;return r1;}pBuffer+=512;Offset+=512;} SD_CS=1;SPIx_ReadWriteByte(0xff); 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_HIGH);//如果不是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_HIGH);//设置为高速模式//如果不是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_HIGH);//设置为高速模式if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是sector地址,将其转换成byte地址SDHC,给定的是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;//读出剩余字节此部分代码我们在本节主要用到的就是SD卡初始化函数SD_Init和SD卡读取函数SD_ReadSingleBlock,通过前面的介绍,相信大家不难理解,这里我们就不多说了,接下来保存MMC_SD.C文件,并加入到HARDW ARE组下,然后打开MMC_SD.H,在该文件里面输入如下代码:#ifndef _MMC_SD_H_#define _MMC_SD_H_#include <stm32f10x_lib.h>//Mini STM32开发板//SD卡驱动//正点原子@ALIENTEK//2010/6/13//SD传输数据结束后是否释放总线宏定义#define NO_RELEASE0#define RELEASE 1// SD卡类型定义#define SD_TYPE_MMC0#define SD_TYPE_V1 1#define SD_TYPE_V2 2#define SD_TYPE_V2HC4// SD卡指令表#define CMD00//卡复位#define CMD1 1#define CMD99//命令9 ,读CSD数据#define CMD1010//命令10,读CID数据#define CMD1212//命令12,停止数据传输#define CMD1616//命令16,设置SectorSize 应返回0x00#define CMD1717//命令17,读sector#define CMD1818//命令18,读Multi sector#define ACMD2323//命令23,设置多sector写入前预先擦除N个block #define CMD2424//命令24,写sector#define CMD2525//命令25,写Multi sector#define ACMD4141//命令41,应返回0x00#define CMD5555//命令55,应返回0x01#define CMD5858//命令58,读OCR信息#define CMD5959//命令59,使能/禁止CRC,应返回0x00//数据写入回应字意义#define MSD_DATA_OK0x05#define MSD_DATA_CRC_ERROR0x0B#define MSD_DATA_WRITE_ERROR0x0D#define MSD_DATA_OTHER_ERROR0xFF//SD卡回应标记字#define MSD_RESPONSE_NO_ERROR0x00#define MSD_IN_IDLE_STATE0x01#define MSD_ERASE_RESET0x02#define MSD_ILLEGAL_COMMAND0x04#define MSD_COM_CRC_ERROR0x08#define MSD_ERASE_SEQUENCE_ERROR0x10#define MSD_ADDRESS_ERROR0x20#define MSD_PARAMETER_ERROR0x40#define MSD_RESPONSE_FAILURE0xFF//这部分应根据具体的连线来修改!//Mini STM32使用的是PA3作为SD卡的CS脚.#define SD_CS PAout(3) //SD卡片选引脚extern u8SD_Type;//SD卡的类型//函数申明区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 intoffset,unsigned int bytes);//读取一byte#endif该部分代码主要是一些命令的宏定义以及函数声明,在这里我们设定了SD卡的CS管脚为PA3。

相关文档
最新文档