This section introduces the porting of the MSP430F5438A FatFs file system.
FatFs is a general file system module used to implement the FAT file system in small embedded systems. The FatFs module is separate from IO, so the following low-level functions need to be implemented during porting:
DSTATUS disk_initialize (BYTE drv); //Initialize memory
DSTATUS disk_status (BYTE drv); //Get the storage status
DRESULT disk_read (BYTE drv, BYTE* buff, DWORD sector, UINT count); //Read memory
DRESULT disk_write (BYTE drv, const BYTE* buff, DWORD sector, UINT count); //Write memory
DRESULT disk_ioctl (BYTE drv, BYTE ctrl, void* buff); //Extra functions
DWORD get_fattime (void); //Get time (this function may not be used, it is related to the FatFs module configuration)
Depending on the processor platform, the corresponding data type definition in integer.h needs to be modified.
Modify ffconf.h to configure FatFs functions.
The following is the porting of the MSP430F5438A platform implemented by me, using the official function library msp430_driverlib_2_60_00_02 and compiled using IAR for msp430 6.3.
The code in this section distinguishes the SD card, and the program has been verified to run normally on the Kingston 8GB SDHC microSD card.
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;
}
Previous article:STM8 study notes---serial port uart1
Next article:MSP430F5438A MCU FatFs transplantation notes based on SPI
Recommended ReadingLatest update time:2024-11-23 07:32
- Popular Resources
- Popular amplifiers
- MSP430 series single chip microcomputer system engineering design and practice
- oled multi-chip calling program
- Microcontroller Principles and Applications Tutorial (2nd Edition) (Zhang Yuanliang)
- Getting Started and Improving MSP430 Microcontrollers - National Undergraduate Electronic Design Competition Training Course
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- Is there any professional term for the switching power supply marked with a red circle in the picture?
- How far can a signal test system based on a sound card go?
- The most vivid analogy of inductance
- [Review and Sharing] TLP3547 Response Time
- SIMterix-Simplis Collection
- HT48R05A realizes low-cost infrared flushing solution
- The most annoying thing about making a power supply is drawing the board yourself
- 澜起科技获英特尔和永威等1000万美元风险投资
- The first FreeRTOS check-in station is open: Application scenario station, closing time is August 14
- [Evaluation of EC-01F-Kit, the NB-IoT development board of Anxinke] Evaluation summary