×
嵌入式 > 技术百科 > 详情

MSP430 SD卡SPI读写操作(4) —— FatFs文件系统实现

发布时间:2020-06-02 发布时间:
|

本节介绍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;

}


 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil5(MDK5)在调试(debug)过程中遇到的问题