查看: 569  |  回复: 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)




主题

回复
  • 温馨提示: 标题不合格、重复发帖、发布广告贴,将会被删除帖子或禁止发言。 详情请参考: 社区发帖规则
  • 您当前输入了 0 个文字。还可以输入 8000 个文字。 已添加复制上传图片功能,该功能目前仅支持chrome和火狐

禁言/删除

X
请选择禁言时长:
是否清除头像:
禁言/删除备注:
昵 称:
 
温馨提示:昵称只能设置一次,设置后无法修改。
只支持中文、英文和数字。

举报

X
请选择举报类型:
请输入详细内容:

顶部