本节介绍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;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』