万利EK-stm32创建SD卡文件系统(一)SD卡读写
万利的板子上创建SD卡文件系统 (一)---SD卡读写
之前在AVR上做过SD和FAT文件系统,万利的EK-STM32F板子上有SD接口,正好可以做一个基于SD的FAT文件系统,打算要做成支持FAT32和FAT16,通过串口与PC连接,可以显示SD卡中的文件信息,也可以把文件读出来,例如,把指定文件名的txt文件通过串口显示到PC。
我是去年过年以前决定开始做MP3,由于一直用AVR,所以自然就选用那个流传最广的方案——AVR+SD+VS1003,自己做了PCB,最后终于做成了,主要参考www.ourdev.cn上波仔的MEGA8版本的MP3(感谢波仔),其间花了大量时间学习SD卡读写和FAT文件系统的知识,现在正好用上。
昨天晚上本来想用KEIL的SD卡工程,但是一直不成功,于是装到以前在AVR上的代码上来。我用的是Keil3.22,这个版本比较新,可以从Keil的中文网站上下载,最大的好处就是使用方便,已经开始支持J-Link2了,万利的板子可以用Keil调试了,当然老版本的Keil可以先生成hex再用串口烧写到STM32。
EK-STM32F板子上使用的是SPI1访问SD卡,还有一个SD卡的Power和CS线,另外一个PA2接到了SD卡插入检测,大家可以不理会,(万利不专业,原理图上没有画出来,板子背面写了)。
软件: Keil3.22工程
硬件:
SD STM32
SCK- PA5
MISO — PA6
MOSI — PA7
POWER—PD10
CS -PD9
具体的可以参考原理图,这个光盘里有,万利网站上有。
SPI和GPIO的初始化如下。
void SPI_Config(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/* GPIOA and GPIOD Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
/* SPI1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* Configure SPI1 pins: SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PD9 pin: CS pin,PD10 : SD Power*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* 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 = SPI_BaudRatePrescaler_128;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* SPI1 enable */
SPI_Cmd(SPI1, ENABLE);
}
定义两个宏,分别是SD卡选中和不选中
#define SPI_CS_Assert() GPIO_ResetBits(GPIOD, GPIO_Pin_9)
/* Deselect MSD Card: ChipSelect pin high */
#define SPI_CS_Deassert() GPIO_SetBits(GPIOD, GPIO_Pin_9)
对于万利的板子,还要一个上电的过程,该MOS管是的电平导通。
在SPI初始化之后,我加了一句GPIO_ResetBits(GPIOD, GPIO_Pin_10);就是SD上电。注意上电之后,最好有一段延时,这样给SD内部初始化流充足的时间,避免初始化的失败。
初始化SD卡代码如下:
//sd卡复位 //reset sd card (software)
uint8 MMC_SD_Reset(void)
{
uint8 i;
uint8 retry;
uint8 r1=0;
retry = 0;
SPI_Config();
GPIO_ResetBits(GPIOD, GPIO_Pin_10);// SD卡上电,打开MOS管
delay(1000); // 重要的延时
/* MSD chip select high */
SPI_CS_Deassert();
do
{
for(i=0;i<10;i++) SPI_WriteByte(0xff);
r1 = MMC_SD_SendCommand(0, 0);//发idle命令 //send idle command
retry++;
if(retry>100) return 1;//超时退出 //time out
} while(r1 != 0x01);
retry = 0;
do
{
r1 = MMC_SD_SendCommand(1, 0);//发active命令 //send active command
retry++;
if(retry>200) return 1;//超时退出 //time out
} while(r1);
//SPI_High();
r1 = MMC_SD_SendCommand(59, 0);//关crc //disable CRC
r1 = MMC_SD_SendCommand(16, 512);//设扇区大小512 //set sector size to 512
return 0;//正常返回 //normal return
}
还有两个基本函数,即写和读SPI(读写合二为一)
unsigned char SPI_WriteByte(unsigned char data)
{
uint8 Data = 0;
/* Wait until the transmit buffer is empty */
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_TXE) == RESET);
/* Send the byte */
SPI_SendData(SPI1, data);
/* Wait until a data is received */
while (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE) == RESET);
/* Get the received data */
Data = SPI_ReceiveData(SPI1);
/* Return the shifted data */
return Data;
}
往SD卡中写一个命令的函数
//sd卡写命令 //sd send command
uint8 MMC_SD_SendCommand(uint8 cmd, uint32 arg)
{
uint8 r1;
uint8 retry=0;
SPI_WriteByte(0xff);
SPI_CS_Assert();
SPI_WriteByte(cmd | 0x40);//分别写入命令 //send command
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(0x95);
while((r1 = SPI_WriteByte(0xff)) == 0xff)//等待响应, //wait response
if(retry++ > 200) break;//超时退出 //time out error
SPI_CS_Deassert();
return r1;//返回状态值 //return state
}
有了这些函数之后就可以读写SD卡了,主要是读一个扇区及写一个扇区,注意SD卡只能是读写扇区,即512 个字节。具体代码见我的工程文件的SD_MMC.c, uint8 MMC_SD_ReadSingleBlock(uint32 sector, uint8* buffer)读第sector扇区到Buffer。uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8* buffer)是写扇区。
{
为了调试方便,我把串口1接上了(最左边哪个口),初始化成功后,把0扇区的512个字节读出来,大部分为0,只有前后的一些字节不为0,调试助手接到的字符为
3|P P¬ ���uuLt �t <t
V^ |W _s3 Ou}=Uu|Invalid partition tableError loading operating systemMissing operating system 7
每个人的电脑和SD卡不同,这些数据会有小差异,但基本相同,如果你的试验也是这些数据,那么,恭喜你,你也做成SD卡读写试验了,没成功也不要紧,检查SD卡插紧了没有。跳线接了没有,量量电压对不对,等等,一定能做成。
还有很多人用IAR,可以把我的几个文件拷到你的IAR工程,编译,调试,不难的,我开始也用的IAR。
好了,第一课就上到这里,下一次开始介绍FAT了,谢谢你的关注,如果你参考我的例子做成了,或者认为我的代码和经验有帮助,就顶我一下啊。祝你好运。 好! 好文章! 顶啊,正好现在也在调试stm32驱动sd卡 做个记号好好研究。 mark
谢谢 记号 赞扬。。。。mark 还是先找个SD memory的参考文档看看好。
SD+CARD完整参考文档ourdev_361752.rar(文件大小:5.69M) (原文件名:SD+CARD参考文档.rar) 谢谢! 顶!嘿嘿 mark 路过 万利提供的STM32F10x_Demo工程里面有SD卡的读写程序,具体在msd.c和msd.h文件中。下面是一张512M SD卡的头512byte的数据:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 2D 00 06 08 E8 E2 E9 00 00 00 17 4B 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA 楼主能否解释一下--我读头512字节成功,也就是说地址0,但我读其他512个字节老是不成功,为什么呢? 是不是读取其他512字节要激活SD卡才行啊 顶一下老帖 【14楼】 muyuyuzhong :
应该没有这个问题,你用winhex软件和读卡器在电脑读出来对比以下,看下STM32 读的对不对 记号 哈哈,我知道我为什么读取其他块错误了,原来我以为地址0是从0~511字节,地址1就是512~1023,我在读取512~1023的数据时误以为地址是1,其实要想读取512~1023的数据,地址应该是 0 + (块号数 * 块长度) ,即是 0 + 1 * 512 ,这里一个块是512个字节.
我是参照万利的例程改的,里面也包含了st7920液晶模块的串行和并行的驱动程序,感兴趣的可以看看
万利配套的SD驱动和st7920串并行驱动ourdev_437791.rar(文件大小:1.24M) (原文件名:LUCKY_API.rar)
本贴被 muyuyuzhong 编辑过,最后修改时间:2008-10-02,22:42:11. 。。。为啥每次读的512字节内容都不一样呢 深圳英贝特提供的sd卡读写范例在st2.02库下初始化SD卡有问题,单步可以执行,全速则出错。换用1.0库则无问题。请问有没有其他人碰到次问题? 一定要注意POWER— PD10 配制成输出即可
否者的话,初始化都不能成功 谢谢 请问一下,POWER线要接到SD卡的哪一个引脚啊? 我也忘了,你在 这个论坛搜索SD,可以找到许多份资料,有一个介绍了管脚 顶啊,正好现在也在调试stm32驱动sd卡 //sd卡写命令 //sd send command
uint8 MMC_SD_SendCommand(uint8 cmd, uint32 arg)
{
uint8 r1;
uint8 retry=0;
SPI_WriteByte(0xff);
SPI_CS_Assert();
SPI_WriteByte(cmd | 0x40);//分别写入命令 //send command
SPI_WriteByte(arg>>24);
SPI_WriteByte(arg>>16);
SPI_WriteByte(arg>>8);
SPI_WriteByte(arg);
SPI_WriteByte(0x95);
while((r1 = SPI_WriteByte(0xff)) == 0xff)//等待响应, //wait response
if(retry++> 200) break;//超时退出 //time out error
SPI_CS_Deassert();
return r1;//返回状态值 //return state
}
请问为什么片选之前要发个0xff啊? 楼主,为什么我的512M卡O扇区读的于WINHEX不同啊? 楼主,你的程序把我害的好惨,不过还是要谢谢你,你给了我一个模板 楼主你好,不知道为什么。我的SD卡读的时候有时候好使有时候不好使,不好使的时候居多。每次都要拔一下SD卡再插上,才能偶尔好使。但是一旦好使了,就这么复位都好使,断电之后在插上的时候还得重新拔卡,再插。才能偶尔一两次好使。特在此虚心请教,感谢楼主! lz好!我在读sd卡的时候,第一个扇区可以读,并且和winhex下看到的内容一样,但是其他的扇区都是0,不存在上面那位朋友说的地址问题,我把sector号左移9位作为命令参数发送的,请lz帮想下是怎么回事?
谢谢! 顶 MARK mark mark 看看 做个记号 mark 想问个小问题,关于:对文本写入文字
首先是写入:我先在文本所在起始扇区:开始写入54个字符
然后就是读取这54个字符:但读取的是所以扇区512个字符,所以读出来的数据里面:除了有自己写入的54个外还有512字节中其它的没用乱码出现
请问这应该怎样解决呢? 请问楼主,我也读出了SD卡的第0扇区,也是能读到partition table和operating system什么的,但是用winhex读出来的不是这些东西啊,开头是PwrShot CANON_DC FAT16等一些东西(佳能相机格式化的卡),这是怎么回事呢? mark,谢谢 请问第二课在哪里啊?好东西 ding ding ding 发送6条芯片询价信息就能获得十元话费,试试去
http://www.21ic.com/invad/invad.htm mark 说真的,SD卡读写其实没有用SPI不太好,感觉支持不好,我是从网上抄的程序,和楼主的一样。但是看了SD卡实际的读写时序,其实要复杂一些。最搞笑的就是发送命令, 要重试200次以上才有效果,当时我只重试50次,结果老是启动不了。。。。 楼主很好,我自己参考时序图写的程序一次就读取成功了,就是发现不同的卡初始化速度都有些差别,不知道怎样才能确定出一个标准的初始化速度,让不同的卡都能准确初始化。 楼主这个帖子真的很好。可工程文件在哪呢 谢谢,正在研究SD卡,太及时了。 mark~!! 最近在看SD卡读写的程序,还是楼主的介绍比较容易理解 顶 貌似我的读写扇区有问题 MARK,正在调试 mark 能支持多大的SD?16G行不行? 头晕!{:smile:} mark
页:
[1]