MSP430 SD卡SPI讀寫操作(4) —— FatFs檔案系統實現(以MSP430F5438A為例)
阿新 • • 發佈:2019-02-12
本節介紹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; }