历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2018年09月16日 | MSP430 SD卡SPI读写操作(4) —— FatFs文件系统实现

2018-09-16 来源:eefocus

本节介绍MSP430F5438A FatFs文件系统的移植。


FatFs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。FatFs模块与IO是分开的,因此移植时需要实现下面几个底层函数:



DSTATUS disk_initialize (BYTE drv); //初始化存储器

DSTATUS disk_status (BYTE drv); //获取存储器状态

DRESULT disk_read (BYTE drv, BYTE* buff, DWORD sector, UINT count); //读存储器

DRESULT disk_write (BYTE drv, const BYTE* buff, DWORD sector, UINT count); //写存储器

DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void* buff); //额外功能

DWORD get_fattime (void); //获取时间(此函数可以没有,和FatFs模块配置有关)


根据不同的处理器平台,需要修改 integer.h 相应的数据类型定义。

修改 ffconf.h 可以配置FatFs的功能。


下面是本人实现的MSP430F5438A平台的移植,使用官方函数库msp430_driverlib_2_60_00_02,使用IAR for msp430 6.3通过编译。


本节代码对SD卡进行了区分,程序在金士顿 8GB SDHC microSD卡经过验证可以正常运行。




diskio.h


/*-----------------------------------------------------------------------/

/  Low level disk interface modlue include file   (C)ChaN, 2014          /

/-----------------------------------------------------------------------*/

 

#ifndef _DISKIO_DEFINED

#define _DISKIO_DEFINED

 

#ifdef __cplusplus

extern "C" {

#endif

 

#include "integer.h"

 

 

/* Status of Disk Functions */

typedef BYTE    DSTATUS;

 

/* Results of Disk Functions */

typedef enum {

    RES_OK = 0,     /* 0: Successful */

    RES_ERROR,      /* 1: R/W Error */

    RES_WRPRT,      /* 2: Write Protected */

    RES_NOTRDY,     /* 3: Not Ready */

    RES_PARERR      /* 4: Invalid Parameter */

} DRESULT;

 

#define SD_INIT_CLK 125000

#define SD_HIGH_CLK 3125000

#define SD_CS_PORT GPIO_PORT_P9

#define SD_CS_PIN  GPIO_PIN0

 

/* MMC/SD command (SPI mode) */

#define CMD0 (0)           /* GO_IDLE_STATE */

#define CMD1 (1)           /* SEND_OP_COND */

#define ACMD41 (0x80+41)   /* SEND_OP_COND (SDC) */

#define CMD8 (8)           /* SEND_IF_COND */

#define CMD9 (9)           /* SEND_CSD */

#define CMD10 (10)         /* SEND_CID */

#define CMD12 (12)         /* STOP_TRANSMISSION */

#define CMD13 (13)         /* SEND_STATUS */

#define ACMD13 (0x80+13)   /* SD_STATUS (SDC) */

#define CMD16 (16)         /* SET_BLOCKLEN */

#define CMD17 (17)         /* READ_SINGLE_BLOCK */

#define CMD18 (18)         /* READ_MULTIPLE_BLOCK */

#define CMD23 (23)         /* SET_BLOCK_COUNT */

#define ACMD23 (0x80+23)   /* SET_WR_BLK_ERASE_COUNT (SDC) */

#define CMD24 (24)         /* WRITE_BLOCK */

#define CMD25 (25)         /* WRITE_MULTIPLE_BLOCK */

#define CMD32 (32)         /* ERASE_ER_BLK_START */

#define CMD33 (33)         /* ERASE_ER_BLK_END */

#define CMD38 (38)         /* ERASE */

#define CMD55 (55)         /* APP_CMD */

#define CMD58 (58)         /* READ_OCR */

/*---------------------------------------*/

/* Prototypes for disk control functions */

 

 

DSTATUS disk_initialize (BYTE drv);

DSTATUS disk_status (BYTE drv);

DRESULT disk_read (BYTE drv, BYTE* buff, DWORD sector, UINT count);

DRESULT disk_write (BYTE drv, const BYTE* buff, DWORD sector, UINT count);

DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void* buff);

 

 

/* Disk Status Bits (DSTATUS) */

 

#define STA_NOINIT      0x01    /* Drive not initialized */

#define STA_NODISK      0x02    /* No medium in the drive */

#define STA_PROTECT     0x04    /* Write protected */

 

 

/* Command code for disk_ioctrl fucntion */

 

/* Generic command (Used by FatFs) */

#define CTRL_SYNC           0   /* Complete pending write process (needed at _FS_READONLY == 0) */

#define GET_SECTOR_COUNT    1   /* Get media size (needed at _USE_MKFS == 1) */

#define GET_SECTOR_SIZE     2   /* Get sector size (needed at _MAX_SS != _MIN_SS) */

#define GET_BLOCK_SIZE      3   /* Get erase block size (needed at _USE_MKFS == 1) */

#define CTRL_TRIM           4   /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */

 

/* Generic command (Not used by FatFs) */

#define CTRL_POWER          5   /* Get/Set power status */

#define CTRL_LOCK           6   /* Lock/Unlock media removal */

#define CTRL_EJECT          7   /* Eject media */

#define CTRL_FORMAT         8   /* Create physical format on the media */

 

/* MMC/SDC specific ioctl command */

#define MMC_GET_TYPE        10  /* Get card type */

#define MMC_GET_CSD         11  /* Get CSD */

#define MMC_GET_CID         12  /* Get CID */

#define MMC_GET_OCR         13  /* Get OCR */

#define MMC_GET_SDSTAT      14  /* Get SD status */

#define ISDIO_READ          55  /* Read data form SD iSDIO register */

#define ISDIO_WRITE         56  /* Write data to SD iSDIO register */

#define ISDIO_MRITE         57  /* Masked write data to SD iSDIO register */

 

/* ATA/CF specific ioctl command */

#define ATA_GET_REV         20  /* Get F/W revision */

#define ATA_GET_MODEL       21  /* Get model name */

#define ATA_GET_SN          22  /* Get serial number */

 

/* MMC card type flags (MMC_GET_TYPE) */

#define CT_MMC      0x01        /* MMC ver 3 */

#define CT_SD1      0x02        /* SD ver 1 */

#define CT_SD2      0x04        /* SD ver 2 */

#define CT_SDC      (CT_SD1|CT_SD2) /* SD */

#define CT_BLOCK    0x08        /* Block addressing */

 

#ifdef __cplusplus

}

#endif

 

#endif


diskio.c


/*-----------------------------------------------------------------------*/

/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2016        */

/*-----------------------------------------------------------------------*/

#include "driverlib.h"

#include "../gateway_clk.h"

#include "diskio.h"

 

DSTATUS Stat = STA_NOINIT;

BYTE CardType;

 

static

void SD_csInit(void)

{

  GPIO_setAsOutputPin(SD_CS_PORT,SD_CS_PIN);

}

 

static

uint8_t SD_writeByte(BYTE data)

{

  USCI_B_SPI_transmitData(USCI_B2_BASE,data);

  while(USCI_B_SPI_isBusy(USCI_B2_BASE));

  data = USCI_B_SPI_receiveData(USCI_B2_BASE);

  return data;

}

 

static

BYTE SD_waitReady(void)

{

  WORD tmr;

  for(tmr = 5000; tmr; tmr--)

  {

    if(SD_writeByte(0xFF) == 0xFF) break;

    delay_us(100);

  }

  return tmr ? 1 : 0;

}

 

static

void SD_csDisable(void)

{

  GPIO_setOutputHighOnPin(SD_CS_PORT,SD_CS_PIN);

  SD_writeByte(0xFF);

}

 

static

int SD_csEnable(void)

{

  GPIO_setOutputLowOnPin(SD_CS_PORT,SD_CS_PIN);

  SD_writeByte(0xFF);

  if(SD_waitReady()) return 1;

  SD_csDisable();

  return 0;

}

 

static

void SD_spiInit(void)

{

  GPIO_setAsPeripheralModuleFunctionInputPin(

     GPIO_PORT_P9,

     GPIO_PIN1 + GPIO_PIN2 + GPIO_PIN3

  );

   

  //Initialize Master

  USCI_B_SPI_initMasterParam param = {0};

  param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;

  param.clockSourceFrequency = UCS_getSMCLK();

  param.desiredSpiClock = SD_INIT_CLK;

  param.msbFirst = USCI_B_SPI_MSB_FIRST;

  param.clockPhase = USCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;

  param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;

  USCI_B_SPI_initMaster(USCI_B2_BASE, ¶m);

}

 

static

void SD_spiEnable(void)

{

  USCI_B_SPI_enable(USCI_B2_BASE);

}

 

static

void SD_spiDisable(void)

{

  USCI_B_SPI_disable(USCI_B2_BASE);

}

 

static

void SD_spiSetSpeed(DWORD speed)

{

  USCI_B_SPI_changeMasterClockParam clockparam = {0};

  clockparam.clockSourceFrequency = UCS_getSMCLK();

  clockparam.desiredSpiClock = speed;

  USCI_B_SPI_changeMasterClock(USCI_B2_BASE, &clockparam);

}

 

static

BYTE SD_getResponse(void)

{

  BYTE retrytime = 0;

  BYTE response;

   

  while(retrytime <= 240)

  {

    response = SD_writeByte(0xFF);

    if(response == 0x00) break;

    if(response == 0x01) break;

    if(response == 0xFE) break;

    retrytime++;

  }

  return response;

}

 

static

BYTE SD_sendCmd(BYTE cmd,DWORD arg,const BYTE crc)

{

  BYTE rec;

  if(cmd & 0x80)

  {

    cmd &= 0x7F;

    rec = SD_sendCmd(CMD55,0,0xFF);

    if(rec > 1) return rec;

  }

   

  if(cmd != CMD12)

  {

    SD_csDisable();

    if(!SD_csEnable()) return 0xFF;

  }

   

  SD_writeByte((cmd & 0x3F) | 0x40);

  SD_writeByte(arg >> 24);

  SD_writeByte(arg >> 16);

  SD_writeByte(arg >> 8);

  SD_writeByte(arg);

  SD_writeByte(crc);

  rec = SD_getResponse(); 

  return rec;

}

 

/*-----------------------------------------------------------------------*/

/* Receive a data packet from the card                                   */

/*-----------------------------------------------------------------------*/

static

int SD_readBlock (BYTE *buff, UINT btr)

{

  BYTE d[2];

  UINT tmr;

  for (tmr = 1000; tmr; tmr--) 

  {

    if ((d[0] = SD_writeByte(0xFF)) != 0xFF) break;

    delay_us(100);

  }

  if (d[0] != 0xFE) return 0;

  do

  {

    *buff++ = SD_writeByte(0xFF);

  } while(-- btr);

  SD_writeByte(0xFF);

  SD_writeByte(0xFF);

  return 1;

}

 

/*-----------------------------------------------------------------------*/

/* Send a data packet to the card                                        */

/*-----------------------------------------------------------------------*/

static

int SD_writeBlock (const BYTE *buff, BYTE token)

{

  BYTE d;

  UINT tmr;

  if (!SD_waitReady()) return 0;

  SD_writeByte(token);

  if (token != 0xFD)

  {

    tmr = 512;

    do

    {

      SD_writeByte(*buff ++);

    } while(-- tmr);

    SD_writeByte(0xFF);

    SD_writeByte(0xFF);

    d = SD_writeByte(0xFF);

    if ((d & 0x1F) != 0x05)

    return 0;

  }

  return 1;

}

 

/*-----------------------------------------------------------------------*/

/* Get Drive Status                                                      */

/*-----------------------------------------------------------------------*/

DSTATUS disk_status (BYTE drv)

{

  if(drv) return STA_NOINIT;

  return Stat;

}

 

/*-----------------------------------------------------------------------*/

/* Inidialize a Drive                                                    */

/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (BYTE drv)

{

  BYTE n,ty,cmd,buf[4];

  UINT tmr;

  DSTATUS s;

  if(drv) return RES_NOTRDY;

   

  SD_spiInit();

  SD_spiEnable();

  SD_csInit();

  SD_csDisable();

   

  for(n = 0;n < 16;n++)

  {

    SD_writeByte(0xFF);

  } //send 128 clocks for normal voltage and sync

   

  ty = 0;

  if(SD_sendCmd(CMD0,0,0x95) == 1) //enter idle state

  {

    if(SD_sendCmd(CMD8,0x1AA,0x87) == 1) //SDV2

    {

      buf[0] = SD_writeByte(0xFF);

      buf[1] = SD_writeByte(0xFF);

      buf[2] = SD_writeByte(0xFF);

      buf[3] = SD_writeByte(0xFF);

      if(buf[2] == 0x01 && buf[3] == 0xAA)

      {

        for(tmr = 1000;tmr;tmr--)

        {

          if(SD_sendCmd(ACMD41,0x40000000,0xFF) == 0) break;

          delay_ms(1);

        }

        if(tmr && SD_sendCmd(CMD58,0,0xFF) == 0)

        {

          buf[0] = SD_writeByte(0xFF);

          buf[1] = SD_writeByte(0xFF);

          buf[2] = SD_writeByte(0xFF);

          buf[3] = SD_writeByte(0xFF);

          ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;    /* SDv2 */

    }

      }

    }

    else

    {

      if(SD_sendCmd(ACMD41,0,0xFF) <= 1) //SDV1

      {

        ty = CT_SD1;

        cmd = ACMD41;

      }

      else //MMCv3

      {

        ty = CT_MMC;

        cmd = CMD1;

      }

      for(tmr = 1000; tmr; tmr--)

      {

        if(SD_sendCmd(cmd,0,0xFF) == 0) break;

    delay_ms(1);

      }

      if(!tmr || SD_sendCmd(CMD16,512,0xFF) != 0)

        ty = 0;

    }

  }

   

  CardType = ty;

  s = ty ? 0 : STA_NOINIT;

  Stat = s;

   

  SD_csDisable();

  //SPI HIGH SPEED

  SD_spiSetSpeed(SD_HIGH_CLK);

  return s;

}

 

/*-----------------------------------------------------------------------*/

/* Read Sector(s)                                                        */

/*-----------------------------------------------------------------------*/

DRESULT disk_read (BYTE drv,BYTE *buff,DWORD sector,UINT count)

{

  BYTE cmd;

  if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;

  if (!(CardType & CT_BLOCK)) sector *= 512;

  cmd = count > 1 ? CMD18 : CMD17;

  if (SD_sendCmd(cmd, sector, 0xFF) == 0)

  {

    do

    {

      if (!SD_readBlock(buff, 512)) break;

      buff += 512;

    } while (--count);

    if (cmd == CMD18) SD_sendCmd(CMD12, 0, 0xFF);

  }

  SD_csDisable();

  return count ? RES_ERROR : RES_OK;

}

 

/*-----------------------------------------------------------------------*/

/* Write Sector(s)                                                       */

/*-----------------------------------------------------------------------*/

DRESULT disk_write (BYTE drv,const BYTE *buff,DWORD sector,UINT count)

{

  if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;

  if (!(CardType & CT_BLOCK)) sector *= 512;

  if (count == 1) 

  {

    if ((SD_sendCmd(CMD24, sector, 0xFF) == 0) && SD_writeBlock(buff, 0xFE))

    count = 0;

  }

  else

  {

    if (CardType & CT_SDC) SD_sendCmd(ACMD23, count, 0xFF);

    if (SD_sendCmd(CMD25, sector, 0xFF) == 0) 

    {

      do

      {

        if (!SD_writeBlock(buff, 0xFC)) break;

        buff += 512;

      } while (--count);

      if (!SD_writeBlock(0, 0xFD))

      count = 1;

    }

  }

  SD_csDisable();

  return count ? RES_ERROR : RES_OK;

}

 

/*-----------------------------------------------------------------------*/

/* Miscellaneous Functions                                               */

/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (BYTE drv,BYTE ctrl,void *buff)

{

  DRESULT res;

  BYTE n, csd[16];

  DWORD cs;

   

  if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;

   

  res = RES_ERROR;

  switch (ctrl)

  {

    case CTRL_SYNC :

      if (SD_csEnable()) res = RES_OK;

      break;

    case GET_SECTOR_COUNT :

      if ((SD_sendCmd(CMD9, 0, 0xFF) == 0) && SD_readBlock(csd, 16))

      {

        if ((csd[0] >> 6) == 1) //SDV2

        {

          cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;

          *(DWORD*)buff = cs << 10;

        }

        else //SDV1 or MMC

        {

          n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;

          cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;

          *(DWORD*)buff = cs << (n - 9);

        }

        res = RES_OK;

      }

      break;

    case GET_BLOCK_SIZE :

      *(DWORD*)buff = 128;

      res = RES_OK;

      break;

    default:

      res = RES_PARERR;

      break;

  }

  SD_csDisable();

  return res;

}


推荐阅读

史海拾趣

芯旺微电子(ChipON)公司的发展小趣事

近年来,芯旺微电子在资本市场也取得了显著的成果。公司先后完成了多轮融资,吸引了众多知名投资机构的关注和投资。同时,芯旺微电子也在积极推进上市进程,计划通过资本市场进一步拓展业务规模和提升品牌影响力。这些战略布局的实施不仅为芯旺微电子提供了更多的资金支持和发展动力,也为其未来的发展奠定了坚实的基础。

HDK(北陆电气)公司的发展小趣事

随着市场需求的不断变化和技术的不断进步,芯旺微电子不断拓展产品线,覆盖了从8位到32位不同性能的MCU产品。同时,公司还积极研发DSP、数模混合SOC等多元化产品,以满足不同领域的需求。这些产品的推出不仅丰富了芯旺微电子的产品线,也进一步提升了其在电子行业中的竞争力。

DETCO公司的发展小趣事

ElectronicsCorp最初是一个在亚洲某城市的小型电子产品制造商。它以其高质量和合理的价格迅速获得了市场份额。公司创始人李先生坚持将研发作为核心驱动力,不断投入资金研发新技术。随着时间的推移,ElectronicsCorp的产品线不断扩大,包括智能手机、平板电脑和智能家居设备。凭借持续的创新和卓越的质量,ElectronicsCorp逐渐成长为全球电子行业的领导者。

Advanced Monolythic Ceramics公司的发展小趣事

为了进一步拓展全球市场,ElectronicsCorp制定了国际化战略。公司先后在北美、欧洲和南美等地设立了研发中心和生产基地。这些海外机构不仅为ElectronicsCorp提供了更广阔的市场空间,还使其能够更深入地了解不同地区的消费者需求和文化背景。通过本土化战略的实施,ElectronicsCorp逐渐在海外市场取得了成功。

CML公司的发展小趣事

面对日益增长的市场需求,CML开始积极寻求市场扩张的机会。公司通过与各大电子产品制造商建立合作关系,将自己的产品广泛应用于电视、手机、电脑等消费电子产品中。同时,CML还积极开拓新兴市场,如汽车电子、工业控制等领域,不断扩大自己的市场份额。这些策略的实施,使得CML的业绩逐年攀升,公司规模不断壮大。

展恒电子(Broadic)公司的发展小趣事

展恒电子始终坚持以品质为核心,严格把控产品质量。在与上海芯北电子科技有限公司的合作中,双方共同保证产品品质的一致性、兼容性和安全性。在合作期间,展恒电子成功向客户供应了数百万片芯片,并得到了客户的高度认可和信任。这种对品质的坚持和追求,使得展恒电子在电子行业中赢得了良好的声誉,也为公司的长期发展奠定了坚实的基础。

这五个故事从不同角度展示了展恒电子(Broadic)在电子行业中的发展历程和成就,体现了其在技术创新、市场拓展、品质保证等方面的实力和努力。通过不断努力和创新,展恒电子已经在电子行业中取得了显著的成果,并将继续为行业的发展贡献自己的力量。

问答坊 | AI 解惑

本文介绍目前性价比最高的先进锂电池充电管理芯片CN3052/CN3056

1 引言 CN305X系列是美国硅谷留学回来创办的半导体公司生产的先进锂电池充电管理芯片,CN305X系列芯片适合单节(4.1V或4.2V)和锂聚合物(Li-Pol)电池的充电需要,同时根据不同的应用提供了SOP和MSOP的可选封装形式,利用该芯片设计的充电器外围电路 ...…

查看全部问答>

提供一个下载期刊论文的资源

http://qbs.hznet.com.cn/bbs/ 1.杭州IP的直接进就可以了; 2.非杭州IP的用户请搜索一个可用的杭州代理IP,然后进去下载。…

查看全部问答>

50高分求助:CE软件盘为何无法输入

自己编写了一个软键盘,在模拟器上可以输入,可拿到2440板子上就不行了,不知是什么原因,下面是源代码,请高手帮我看看: HWND m_hFocus; CKeyboardDlg *pCharKeyboardDlg; CNumKeyboardDlg *pNumKeyboardDlg; //////////////////////////// ...…

查看全部问答>

问个udp广播的问题

我的设备有两个网卡驱动,一个是物理网口驱动,另一个是虚拟网口的驱动,物理网口的ip是192.168.110.4 ,虚拟网口的ip是192.168.11.6.我写了个udp广播的程序,发送广播,但是每次都是从物理网口发出去的,我怎样才能让他从虚拟网口发出去呢?是不是我的程序 ...…

查看全部问答>

节能灯及日光灯整流器用振荡磁环的选择

节能灯及日光灯整流器用振荡磁环的选择 背影子 时间:2010-08-23 转载  现节能灯和电子日光灯的应用已普及,但真正节能和质量好的却不是那么好做,关健是磁性材料的选择和使用上存在问题,这里主要谈一下脉冲变压器磁环,这是 ...…

查看全部问答>

DIY区能不能讨论一下开个机器人的专区?

不知道坛子里的人对机器人是否感兴趣?如果感兴趣的人多了,我们也可以组织对机器人进行DIY呀!~…

查看全部问答>

给我的16*64点阵电子钟穿衣服

2008年的时候曾经制作过16*64点阵屏幕,同时也制作出一个电子钟 一直没有找到合适的外壳,目前终于发现了合适的外壳,把我的16*64电子钟完善了一下     这个铝外壳成本不底哦, 传图片     [ 本帖最后由 飞雪008 于 20 ...…

查看全部问答>

win7应该安装ISE和modelsim的那个版本啊???????

win7系统安装ISE和modelsim,应该安装哪个版本啊?求助高手啊!!!!!…

查看全部问答>

现在做数字电源用什么IC好噢?

大家好!现在做数字电源用什么IC好噢?Ti又出了个UCD3138,可惜里面的原理图都看不清楚。…

查看全部问答>

Beaglebone怎么操作八位并口?

在Linux中当然可以一位一位地写,但是怎么直接操作一个8位并口呢?…

查看全部问答>