MSP430 SD card SPI read and write operations (4) —— FatFs file system implementation

Publisher:theta18Latest update time:2018-09-16 Source: eefocusKeywords:MSP430 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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;

}


Keywords:MSP430 Reference address:MSP430 SD card SPI read and write operations (4) —— FatFs file system implementation

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

Two wake-up methods for MSP430 power saving mode
1 Introduction to MSP430 power saving mode MSP430 is famous for its low power consumption. It can connect two external clock sources - XIN and XT2IN. There is also an internal DC0 oscillator, which can generate an internal clock of up to 8 MHz. Generally, the frequency of XT2IN is high frequency, which is selected a
[Microcontroller]
Two wake-up methods for MSP430 power saving mode
Research on WDT in MSP430 microcontroller
Introduction   Software reliability has always been a critical issue. Anyone who uses software may experience the problem of a computer freezing or a program running away, and this situation also exists in embedded systems. Due to the limited anti-interference ability of microcontrollers, instrumentation at industrial
[Microcontroller]
Design of ultra-low power consumption electronic thermometer based on MSP430 single chip microcomputer
0 Introduction The ultra-low power electronic thermometer designed in this paper can measure and display the temperature of the measured point through the temperature sensor, and can be extended and controlled. The thermometer has an electronic clock, a detection range of 10℃~30℃, a detection resolution of 1℃
[Microcontroller]
Design of ultra-low power consumption electronic thermometer based on MSP430 single chip microcomputer
AD9850 Driver--MSP430 Version
I was busy drawing boards, working on op amps and filtering some time ago, and rarely updated the program. I found that MSP430 was not very easy to use, especially the Timer. However, it was also related to my use of an internal crystal oscillator. Before generating a sine wave, it was too troublesome to use MSP430 to
[Microcontroller]
Highly robust broken glass detector solution based on low-cost single-chip microprocessor
     introduction      A broken glass detector (GBD) is mainly used to detect broken glass in doors and windows of residential homes or commercial buildings. GBD can also be classified as a monitoring device to improve the security of home or commercial environments and prevent illegal entry. GBD can work independent
[Microcontroller]
Highly robust broken glass detector solution based on low-cost single-chip microprocessor
Design of a new intelligent water meter based on MSP430F413
In response to a series of problems caused by the backwardness of traditional water meters, the Ministry of Construction of China has put forward the requirement that "three meters should be installed in every household" for urban residents. Therefore, many domestic water meter manufacturers are currently exploring
[Microcontroller]
Design of a new intelligent water meter based on MSP430F413
MSP430 DCO Control Register
DCOCTL  8 bits are DCO.2 DCO.1 DCO.0 MOD.4 MOD.3 MOD.2 MOD.1 MOD.0 DCO.2~DCO.0 define one of 8 frequencies, and the frequency is defined by the current injected into the DC generator MOD.4~MOD.0 define the Fdco+1 cycle inserted in 32 DCO cycles, and the remaining DCO cycles are Fdco cycles BCSCTL1  8 bits are
[Microcontroller]
Logic interface technology of low power MSP430 microcontroller in 3V and 5V mixed system
MSP430 ultra-low power microprocessor is a new type of single-chip microcomputer launched by TI. It has a 16-bit streamlined instruction structure, contains a 12-bit fast ADC/Slope ADC, contains 60K bytes of FLASH ROM, 2K bytes of RAM, and has rich on-chip resources, including ADC, PWM, several TIME, serial port, WATCH
[Microcontroller]
Logic interface technology of low power MSP430 microcontroller in 3V and 5V mixed system
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号