最近应老板要求,用mega328P做了一个小板用来将串口接收的数据存在SD卡中(主要是保存长时间的一个其他板子的串口log而做的一个小板子),停停顿顿将近2周才做完。中间还做了其他的事情,当然主要原因是水平有限,以前没怎么接触过SD卡和FATFS文件系统的移植,很久没用AVR的芯片也需要预热。
上面的都是废话。
首先这个小板的芯片选型,MEGA328P,flash—8K,RAM—2k,刚好够用,因为选择的FATFS/TINY文件系统就需要1K的ram
SD卡模式:SPI模式
文件系统:: FATFS/tiny,嵌入式小型文件系统
首先SD卡初始化
SD卡的指令有很多个,我只用到其中的几个,因此这里只介绍这几个
SD卡上电的时候需要74个时钟初始化,因此在向SD卡发送复位命令前最好先等待74个时钟(其实就是片选不要去选中SD卡,空发送8个字节的数据)
接着发送SD卡的指令,这里唠叨一下SD卡的指令:
给SD卡发送指令的长度 是6个字节,第一个字节代表CMD号 = CMD | 0x40(高2位为01),也就是发送CMD55的时候,第一个字节为 55(十进制) +0x40 = 0x77,接着是4个字节的参数,当指令无参数时写0就可以了,最后一个字节是CRC校验位的高七位,最后一位恒为1,但是SPI模式除了CMD0和CMD8需要CRC校验之外其他的就不需要CRC校验了(使用SPI方式在CMD0和CMD8之后就正式是SPI模式了,SPI模式不需要CRC校验,但是也可以通过其他指令恢复CRC校验),因此其他的指令的CRC校验位可以随意填充。
CMD0 ,参数0,CRC–0x95(包含了最后一位1) 作用:reset
CMD8,参数0X1AA,CRC–0X87,作用: 主要就是看是否支持V2.0,回复就是支持,无回复就是1.0的卡
再来看一下指令的回复:
R1类型的:
长度是一字节,最高位永远为0,其余位是错误指示位,出错时被置一,具体含义如下:
第0位,处于空闲状态:SD卡处于空闲状态,且正在运行初始化程序
第1位,擦除重置:在执行擦除前,一个擦除指令序列被清除,因为收到了一个超出擦除序列的指令。
第2位,非法指令:就是字面意思
第3位,CRC错误:就是字面意思
第4位,擦除序列错误:在擦除指令序列中发现错误
第5位,地址错误:就是字面意思
第6位,特定错误:指令的参数超出范围
第7位,永远为0
R1b
R1b是在R1的基础上增加了一个忙碌状态指示,当R1的值为0时SD卡处于忙碌状态,而当R1为任何不为0的值时,SD卡才能开始接收下一条指令。
R3
1字节的R1+4字节的OCR寄存器值
R7
1字节的R1+4字节的应答
接下来就是初始化程序了,如有不理解的地方对照一下上面的介绍,
下面这个是发送CMD的函数;
u8 SD_CMD_Send(u8 cmd,u32 arg,u8 crc)
{
u8 res;
u16 retry = 0;
SD_CS_HIGH();
spi_write_and_read_data(0xff);//等待8个时钟,让SD卡完成上一条数据的处理
SD_CS_LOW();
spi_write_and_read_data(cmd | 0x40);
spi_write_and_read_data((u8)(arg>>24));
spi_write_and_read_data((u8)(arg>>16));
spi_write_and_read_data((u8)(arg>>8));
spi_write_and_read_data((u8)(arg>>0));
spi_write_and_read_data(crc);
do{
res = spi_write_and_read_data(0xff);
}while(res&0x80 && retr