查看:
556
|
回复:
0
|
基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试
|
|
发表于2023-02-17 17:13:43
|
只看该作者
1#
电梯直达
一、前言 在STM32项目开发中,经常会用到存储芯片存储数据。 比如:关机时保存机器运行过程中的状态数据,上电再从存储芯片里读取数据恢复;在存储芯片里也会存放很多资源文件。比如,开机音乐,界面上的菜单图标,字库文件,方便设备开机加载。 为了让单片机更加方便的读写这些资源文件,通常都会加文件系统,如果没有文件系统,直接读取写扇区的方式,对数据不好管理。 这篇文章就手把手教大家,在STM32上完成FATFS文件系统的移植;主控芯片采用STM32F103ZET6, 存储芯片我这里采用(雷龙) CS创世 SD NAND 。 SD NAND 简单来说就是贴片式SD卡,使用起来与普通的SD卡一样,简单的区别就是:比TF卡稳定,比eMMC便宜。 下面章节里会详细介绍下 CS创世 SD NAND。 下面是CS创世 SD NAND 与STM32开发的板的接线实物图: 这是读写扇区测试的结果: 二、SD NAND 介绍 我当前使用的SD NAND型号是,CSNP32GCR01-AOW,容量是4GB。 下面是通过编写STM32代码读取的存储信息: 芯片的详细参数如下: 【1】不用写驱动程序自带坏块管理 【2】尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装 【3】标准SDIO接口,兼容SPI,兼容拔插式TF卡/SD卡,可替代普通TF卡/SD卡 【4】尺寸6.2x8mm,直接贴片,不占空间 【5】内置平均读写算法,通过1万次随机掉电测试 【6】耐高低温,机贴手贴都非常方便 【7】速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S) 【8】支持标准的SD 2.0协议,用户可以直接移植标准驱动代码,省去了驱动代码编程环节。支持TF卡启动的SOC都可以用SD NAND 【9】比TF卡稳定,比eMMC便宜 **下面是芯片的实物图: ** 这是官网申请的样品,焊接了转接板,可以直接插在SD卡卡槽上测试。 最终选型之后,设计PCB板时,设计接口,直接贴片上去使用,非常稳定,抖动也不会导致,外置卡TF卡这种容易松动的问题。 这是雷龙的官网: http://www.longsto.com/product/35.html 正在上传… 取消 三、编写SD NAND驱动代码 SD NAND 的驱动代码与正常的SD卡协议是一样的,支持标准的SD 2.0协议,下面我就直接贴出写好的驱动代码。 包括了模拟SPI,硬件SPI,SDIO等3种方式,完成对SD NAND 的读写。我当前使用的主控板子是STM32F103ZET6,如果你使用的板子不是这一款,可能还是其他的CPU也没关系;我这里直接贴出了SPI模拟时序的驱动代码,可以直接移植到任何单片机上使用,代码拷贝过去也只需要修改GPIO口即可,非常方便。 3.1 SPI模拟时序驱动方式 (1)整体工程代码 这是当前工程的截图: 代码采用寄存器风格编写,非常简洁。 当前工程完成SD NAND卡初始化,扇区的读写,测试芯片基本的使用情况。 (2) sd.c #include "sdcard.h" static u8 SD_Type=0; //存放SD卡的类型 /* 函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节 函数参数:data是要写入的数据 返 回 值:读到的数据 */ u8 SDCardReadWriteOneByte(u8 DataTx) { u8 i; u8 data=0; for(i=0;i<8;i++) { SDCARD_SCK=0; if(DataTx&0x80)SDCARD_MOSI=1; else SDCARD_MOSI=0; SDCARD_SCK=1; DataTx<<=1; data<<=1; if(SDCARD_MISO)data|=0x01; } return data; } //4种: 边沿两种、电平是两种 /* 函数功能:底层SD卡接口初始化 本程序SPI接口如下: PC11 片选 SDCardCS PC12 时钟 SDCardSCLK PD2 输出 SPI_MOSI--主机输出从机输入 PC8 输入 SPI_MISO--主机输入从机输出 */ void SDCardSpiInit(void) { /*1. 开启时钟*/ RCC->APB2ENR|=1<<5; //使能PORTD时钟 RCC->APB2ENR|=1<<4; //使能PORTC时钟 /*2. 配置GPIO口模式*/ GPIOC->CRH&=0xFFF00FF0; GPIOC->CRH|=0x00033008; GPIOD->CRL&=0xFFFFF0FF; GPIOD->CRL|=0x00000300; /*3. 上拉*/ GPIOC->ODR|=1<<8; GPIOC->ODR|=1<<11; GPIOC->ODR|=1<<12; GPIOD->ODR|=1<<2; } /* 函数功能:取消选择,释放SPI总线 */ void SDCardCancelCS(void) { SDCARD_CS=1; SDCardReadWriteOneByte(0xff);//提供额外的8个时钟 } /* 函数 功 能:选择sd卡,并且等待卡准备OK 函数返回值:0,成功;1,失败; */ void SDCardSelectCS(void) { SDCARD_CS=0; SDCardWaitBusy();//等待成功 } /* 函数 功 能:等待卡准备好 函数返回值:0,准备好了;其他,错误代码 */ void SDCardWaitBusy(void) { while(SDCardReadWriteOneByte(0XFF)!=0XFF){} } /* 函数功能:等待SD卡回应 函数参数: Response:要得到的回应值 返 回 值: 0,成功得到了该回应值 其他,得到回应值失败 */ u8 SDCardGetAck(u8 Response) { u16 Count=0xFFFF;//等待次数 while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应 if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回应失败 else return SDCard_RESPONSE_NO_ERROR;//正确回应 } /* 函数功能:从sd卡读取一个数据包的内容 函数参数: buf:数据缓存区 len:要读取的数据长度. 返回值: 0,成功;其他,失败; */ u8 SDCardRecvData(u8*buf,u16 len) { if(SDCardGetAck(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE while(len--)//开始接收数据 { *buf=SDCardReadWriteOneByte(0xFF); buf++; } //下面是2个伪CRC(dummy CRC) SDCardReadWriteOneByte(0xFF); SDCardReadWriteOneByte(0xFF); return 0;//读取成功 } /* 函数功能:向sd卡写入一个数据包的内容 512字节 函数参数: buf 数据缓存区 cmd 指令 返 回 值:0表示成功;其他值表示失败; */ u8 SDCardSendData(u8*buf,u8 cmd) { u16 t; SDCardWaitBusy(); //等待忙状态 SDCardReadWriteOneByte(cmd); if(cmd!=0XFD)//不是结束指令 { for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间 SDCardReadWriteOneByte(0xFF); //忽略crc SDCardReadWriteOneByte(0xFF); t=SDCardReadWriteOneByte(0xFF); //接收响应 if((t&0x1F)!=0x05)return 2; //响应错误 } return 0;//写入成功 } /* 函数功能:向SD卡发送一个命令 函数参数: u8 cmd 命令 u32 arg 命令参数 u8 crc crc校验值 返回值:SD卡返回的响应 */ u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc) { u8 r1; SDCardCancelCS(); //取消上次片选 SDCardSelectCS(); //选中SD卡 //发送数据 SDCardReadWriteOneByte(cmd | 0x40);//分别写入命令 SDCardReadWriteOneByte(arg >> 24); SDCardReadWriteOneByte(arg >> 16); SDCardReadWriteOneByte(arg >> 8); SDCardReadWriteOneByte(arg); SDCardReadWriteOneByte(crc); if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading do { r1=SDCardReadWriteOneByte(0xFF); }while(r1&0x80); //等待响应,或超时退出 return r1; //返回状态值 } /* 函数功能:获取SD卡的CID信息,包括制造商信息 函数参数:u8 *cid_data(存放CID的内存,至少16Byte) 返 回 值: 0:成功,1:错误 */ u8 GetSDCardCISDCardOutnfo(u8 *cid_data) |
|