基于CH32V208通过SPI接口外接TF卡实现FATFS文件系统 - RISC-V MCU技术社区 - 电子技术论坛 - 广受欢迎的专业电子论坛
分享 收藏 返回

[文章]

基于CH32V208通过SPI接口外接TF卡实现FATFS文件系统

本次主要实现SPI接口的外接TF卡实现FATFS文件系统。
首先是SPI接口初始化。使用SPI1外设,对应引脚如下:

*    PA4  <===========>  SCS
*    PA5  <===========>  SCK
*    PA6  <===========>  DI/MISO
*    PA7  <===========>  DO/MOSI

SPI初始化如下:

/**
 * [url=home.php?mod=space&uid=830701]@name[/url]    drv_spi_init
 * [url=home.php?mod=space&uid=2666770]@Brief[/url]   spi 外设初始化
 * [url=home.php?mod=space&uid=3142012]@param[/url]   None
 * [url=home.php?mod=space&uid=1141835]@Return[/url]  None
 */
void drv_spi_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    SPI_InitTypeDef SPI_InitStructure={0};

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE );
    //CS
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    //SCK
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOA, &GPIO_InitStructure );
    //MISO
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init( GPIOA, &GPIO_InitStructure );
    //MOSI
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOA, &GPIO_InitStructure );

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init( SPI1, &SPI_InitStructure );

    SPI_Cmd( SPI1, ENABLE );
}

SPI发送接收数据

uint8_t spi_read_write(uint8_t _data)
{
    /*!< Loop while DAT register in not emplty */
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) ;
    /*!< Send byte through the SPI1 peripheral */
    SPI_I2S_SendData(SPI1, _data);
    /*!< Wait to receive a byte */
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)    ;
    /*!< Return the byte read from the SPI bus */
    return SPI_I2S_ReceiveData(SPI1);
}

接下来是实现TF的初始化和读写数据接口。主要参考以前移植的代码,实现很容易。

int MSD_Init(void)
{
    uint8_t r1;
    uint8_t buff[6] = {0};
    uint16_t retry; 

    MSD_SPI_Configuration();
    /* Check , if no card insert */
//    if( MSD_Check_Insert() )
//    { 
//        return -1;
//    }

    /* Power on and delay some times */	
    for(retry=0; retry<0x100; retry++)
    {
        _card_power_on();
    }
    /* Satrt send 74 clocks at least */
    for(retry=0; retry<10; retry++)
    {
        spi_read_write(DUMMY_BYTE);
    }
    /* Start send CMD0 till return 0x01 means in IDLE state */
    for(retry=0; retry<0xFFF; retry++)
    {
        r1 = _send_command(CMD0, 0, 0x95);
        if(r1 == 0x01)
        {
            retry = 0;
            break;
        }
    }
    /* Timeout return */
    if(retry == 0xFFF)
    {
#ifdef PRINT_INFO 
        DEBUG_OUT("Reset card into IDLE state failed!\r\n");
#endif
        return 1;
    }

    /* Get the card type, version */
    r1 = _send_command_hold(CMD8, 0x1AA, 0x87);
    /* r1=0x05 -> V1.0 */
    if(r1 == 0x05)
    {
        CardInfo.CardType = CARDTYPE_SDV1;

        /* End of CMD8, chip disable and dummy byte */
        _card_disable();
        spi_read_write(DUMMY_BYTE);
    
        /* SD1.0/MMC start initialize */
        /* Send CMD55+ACMD41, No-response is a MMC card, otherwise is a SD1.0 card */
        for(retry=0; retry<0xFFF; retry++)
        {
            r1 = _send_command(CMD55, 0, 0);    /* should be return 0x01 */
            if(r1 != 0x01)
            {
#ifdef PRINT_INFO 
                DEBUG_OUT("Send CMD55 should return 0x01, response=0x%02x\r\n", r1);
#endif
                return r1;
            }
            r1 = _send_command(ACMD41, 0, 0);   /* should be return 0x00 */
            if(r1 == 0x00)
            {
                retry = 0;
                break;
            }
        }
        /* MMC card initialize start */
        if(retry == 0xFFF)
        {
            for(retry=0; retry<0xFFF; retry++)
            {
                r1 = _send_command(CMD1, 0, 0);		/* should be return 0x00 */
                if(r1 == 0x00)
                {
                    retry = 0;
                    break;
                }
            }
            /* Timeout return */
            if(retry == 0xFFF)
            {
#ifdef PRINT_INFO
                DEBUG_OUT("Send CMD1 should return 0x00, response=0x%02x\r\n", r1);
#endif
                return 2;
            }
            CardInfo.CardType = CARDTYPE_MMC;
#ifdef PRINT_INFO 
            DEBUG_OUT("Card Type 111                 : MMC\r\n");
#endif
        }
        /* SD1.0 card detected, print information */
#ifdef PRINT_INFO
        else
        {
            DEBUG_OUT("Card Type 111                : SD V1\r\n");
        }
#endif 
    
        /* Set spi speed high */
        _card_speed_high();
        /* CRC disable */
        r1 = _send_command(CMD59, 0, 0x01);
        if(r1 != 0x00)
        {
#ifdef PRINT_INFO 
            DEBUG_OUT("Send CMD59 should return 0x00, response=0x%02x\r\n", r1);
#endif
            return r1;  /* response error, return r1 */
        }
    
        /* Set the block size */
        r1 = _send_command(CMD16, MSD_BLOCKSIZE, 0xFF);
        if(r1 != 0x00)
        {
#ifdef PRINT_INFO
            DEBUG_OUT("Send CMD16 should return 0x00, response=0x%02x\r\n", r1);
#endif
            return r1;  /* response error, return r1 */
        }
    }
    
    /* r1=0x01 -> V2.x, read OCR register, check version */
    else if(r1 == 0x01)
    {
        /* 4Bytes returned after CMD8 sent	*/
        buff[0] = spi_read_write(DUMMY_BYTE);  /* should be 0x00 */
        buff[1] = spi_read_write(DUMMY_BYTE);  /* should be 0x00 */
        buff[2] = spi_read_write(DUMMY_BYTE);  /* should be 0x01 */
        buff[3] = spi_read_write(DUMMY_BYTE);  /* should be 0xAA */
        /* End of CMD8, chip disable and dummy byte */ 
        _card_disable();
        spi_read_write(DUMMY_BYTE);
    
        /* Check voltage range be 2.7-3.6V	*/
        if(buff[2]==0x01 && buff[3]==0xAA)
        {
            for(retry=0; retry<0xFFF; retry++)
            {
                r1 = _send_command(CMD55, 0, 0);			/* should be return 0x01 */
                if(r1!=0x01)
                {
#ifdef PRINT_INFO 
                    DEBUG_OUT("Send CMD55 should return 0x01, response=0x%02x\r\n", r1);
#endif
                    return r1;
                }

                r1 = _send_command(ACMD41, 0x40000000, 0);	/* should be return 0x00 */
                if(r1 == 0x00)
                {
                    retry = 0;
                    break;
                }
            }
    
            /* Timeout return */
            if(retry == 0xFFF)
            {
#ifdef PRINT_INFO
                DEBUG_OUT("Send ACMD41 should return 0x00, response=0x%02x\r\n", r1);
#endif
                return 3;
            }

            /* Read OCR by CMD58 */
            r1 = _send_command_hold(CMD58, 0, 0);
            if(r1!=0x00)
            {
#ifdef PRINT_INFO
                DEBUG_OUT("Send CMD58 should return 0x00, response=0x%02x\r\n", r1);
#endif
                return r1;  /* response error, return r1 */
            }

            buff[0] = spi_read_write(DUMMY_BYTE);
            buff[1] = spi_read_write(DUMMY_BYTE);
            buff[2] = spi_read_write(DUMMY_BYTE);
            buff[3] = spi_read_write(DUMMY_BYTE);
            /* End of CMD58, chip disable and dummy byte */
            _card_disable();
            spi_read_write(DUMMY_BYTE);
    
            /* OCR -> CCS(bit30)  1: SDV2HC	 0: SDV2 */
            if(buff[0] & 0x40)
            {
                CardInfo.CardType = CARDTYPE_SDV2HC;
#ifdef PRINT_INFO 
                DEBUG_OUT("Card Type 222                 : SD V2HC\r\n");
#endif
            }
            else
            {
                CardInfo.CardType = CARDTYPE_SDV2;
#ifdef PRINT_INFO
                DEBUG_OUT("Card Type 222                 : SD V2\r\n");
#endif
            }
            /* Set spi speed high */
            _card_speed_high();
        }
    }
    return 0;
}
/*******************************************************************************
* Function Name  : _read_buffer
* Description    : None
* Input          : - *buff:
*                  - len:
*                  - release:
* Output         : None
* Return         : 0:NO_ERR; TRUE: Error
* Attention		 : None
*******************************************************************************/
int _read_buffer(uint8_t *buff, uint16_t len, uint8_t release)
{
    uint8_t r1;
    uint16_t retry;

    /* Card enable, Prepare to read	*/
    _card_enable();

    /* Wait start-token 0xFE */
    for(retry=0; retry<2000; retry++)
    {
        r1 = spi_read_write(DUMMY_BYTE);
        if(r1 == 0xFE)
        {
            retry = 0;
            break;
        }    
    }

    /* Timeout return	*/
    if(retry == 2000)
    {
#ifdef PRINT_INFO
        DEBUG_OUT("_read_buffer Timeout return.\n");
#endif
        _card_disable();
        return 1;
    }
    /* Start reading */
    for(retry=0; retry<len; retry++)
    {
        *(buff+retry) = spi_read_write(DUMMY_BYTE);
    }
    /* 2bytes dummy CRC */
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);
    /* chip disable and dummy byte */ 
    if(release)
    {
        _card_disable();
        spi_read_write(DUMMY_BYTE);
    }
    return 0;
}

/*******************************************************************************
* Function Name  : MSD_ReadSingleBlock
* Description    : None
* Input          : - sector:
*                  - buffer:
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
int MSD_ReadSingleBlock(uint32_t sector, uint8_t *buffer)
{
    uint8_t r1;

    /* if ver = SD2.0 HC, sector need <<9 */
    if(CardInfo.CardType != CARDTYPE_SDV2HC)
    {
        sector = sector<<9;
    }

    /* Send CMD17 : Read single block command */
    r1 = _send_command_hold(CMD17, sector, 0);	
    if(r1 != 0x00)
    {
        return 1;
    }
    /* Start read and return the result */
    r1 = _read_buffer(buffer, MSD_BLOCKSIZE, RELEASE);   //  HOLD
    /* Send stop data transmit command - CMD12 */
    _send_command(CMD12, 0, 0);
    return r1;
}

/*******************************************************************************
* Function Name  : MSD_ReadMultiBlock
* Description    : None
* Input          : - sector:
*				   - buffer:
*                  - NbrOfSector:
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
int MSD_ReadMultiBlock(uint32_t sector, uint8_t *buffer, uint32_t NbrOfSector)
{
    uint8_t r1;
    uint32_t i;

    /* if ver = SD2.0 HC, sector need <<9 */
    if(CardInfo.CardType != CARDTYPE_SDV2HC)
    {
        sector = sector<<9;
    }

    /* Send CMD18 : Read multi block command */
    r1 = _send_command_hold(CMD18, sector, 0);
    if(r1 != 0x00)
    {
        return 1;
    }

    /* Start read	*/
    for(i=0; i<NbrOfSector; i++)
    {
        if(_read_buffer(buffer+i*MSD_BLOCKSIZE, MSD_BLOCKSIZE, HOLD))
        {
            /* Send stop data transmit command - CMD12	*/
            _send_command(CMD12, 0, 0);
            /* chip disable and dummy byte */
            _card_disable();
            return 2;
        }
    }

    /* Send stop data transmit command - CMD12 */
    _send_command(CMD12, 0, 0);
    /* chip disable and dummy byte */
    _card_disable();
    spi_read_write(DUMMY_BYTE);
    return 0;
}

/*******************************************************************************
* Function Name  : MSD_WriteSingleBlock
* Description    : None
* Input          : - sector:
*				   - buffer:
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
int MSD_WriteSingleBlock(uint32_t sector, uint8_t *buffer)
{
    uint8_t r1;
    uint16_t i;
    uint32_t retry;

    /* if ver = SD2.0 HC, sector need <<9 */
    if(CardInfo.CardType != CARDTYPE_SDV2HC)
    {
        sector = sector<<9;
    }

    /* Send CMD24 : Write single block command */
    r1 = _send_command(CMD24, sector, 0);
    if(r1 != 0x00)
    {
        return 1;
    }

    /* Card enable, Prepare to write */
    _card_enable();
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);
    /* Start data write token: 0xFE */
    spi_read_write(0xFE);
    /* Start single block write the data buffer */
    for(i=0; i<MSD_BLOCKSIZE; i++)
    {
        spi_read_write(*buffer++);
    }
    /* 2Bytes dummy CRC */
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);

    /* MSD card accept the data */
    r1 = spi_read_write(DUMMY_BYTE);
    if((r1&0x1F) != 0x05)
    {
        _card_disable();
        return 2;
    }
    /* Wait all the data programm finished */
    retry = 0;
    while(spi_read_write(DUMMY_BYTE) == 0x00)
    {
        /* Timeout return */
        if(retry++ == 0x40000)
        {
            _card_disable();
            return 3;
        }
    }
    /* chip disable and dummy byte */ 
    _card_disable();
    spi_read_write(DUMMY_BYTE);
    return 0;
}

/*******************************************************************************
* Function Name  : MSD_WriteMultiBlock
* Description    : None
* Input          : - sector:
*				   - buffer:
*                  - NbrOfSector:
* Output         : None
* Return         : None
* Attention		 : None
*******************************************************************************/
int MSD_WriteMultiBlock(uint32_t sector, uint8_t *buffer, uint32_t NbrOfSector)
{
    uint8_t r1;
    uint16_t i;
    uint32_t n;
    uint32_t retry;

    /* if ver = SD2.0 HC, sector need <<9 */
    if(CardInfo.CardType != CARDTYPE_SDV2HC)
    {
        sector = sector<<9;
    }
    /* Send command ACMD23 berfore multi write if is not a MMC card */
    if(CardInfo.CardType != CARDTYPE_MMC)
    {
        _send_command(ACMD23, NbrOfSector, 0x00);
    }
    /* Send CMD25 : Write nulti block command	*/
    r1 = _send_command(CMD25, sector, 0);
    if(r1 != 0x00)
    {
        return 1;
    }

    /* Card enable, Prepare to write */
    _card_enable();
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);
    spi_read_write(DUMMY_BYTE);

    for(n=0; n<NbrOfSector; n++)
    {
        /* Start multi block write token: 0xFC */
        spi_read_write(0xFC);
        for(i=0; i<MSD_BLOCKSIZE; i++)
        {
            spi_read_write(*buffer++);
        }
        /* 2Bytes dummy CRC */
        spi_read_write(DUMMY_BYTE);
        spi_read_write(DUMMY_BYTE);
        /* MSD card accept the data */
        r1 = spi_read_write(DUMMY_BYTE);
        if((r1&0x1F) != 0x05)
        {
            _card_disable();
            return 2;
        }

        /* Wait all the data programm finished	*/
        retry = 0;
        while(spi_read_write(DUMMY_BYTE) != 0xFF)
        {
            /* Timeout return */
            if(retry++ == 0x40000)
            {
                _card_disable();
                return 3;
            }
        }
    }
    /* Send end of transmit token: 0xFD */
    r1 = spi_read_write(0xFD);
    if(r1 == 0x00)
    {
        return 4;
    }

    /* Wait all the data programm finished */
    retry = 0;
    while(spi_read_write(DUMMY_BYTE) != 0xFF)
    {
        /* Timeout return */
        if(retry++ == 0x40000)
        {
            _card_disable();
            return 5;
        }
    }

    /* chip disable and dummy byte */
    _card_disable();
    spi_read_write(DUMMY_BYTE);

  return 0;
}

/*******************************************************************************
* Function Name  : _send_command
* Description    : None
* Input          : - cmd:
*				   - arg:
*                  - crc:
* Output         : None
* Return         : R1 value, response from card
* Attention		 : None
*******************************************************************************/
int _send_command(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    uint8_t r1;
    uint8_t retry;

    /* Dummy byte and chip enable */
    spi_read_write(DUMMY_BYTE);
    _card_enable();

    /* Command, argument and crc */
    spi_read_write(cmd | 0x40);
    spi_read_write(arg >> 24);
    spi_read_write(arg >> 16);
    spi_read_write(arg >> 8);
    spi_read_write(arg);
    spi_read_write(crc);
  
    /* Wait response, quit till timeout */
    for(retry=0; retry<200; retry++)
    {
        r1 = spi_read_write(DUMMY_BYTE);
        if(r1 != 0xFF)
        {
            break;
        }
    }
    /* Chip disable and dummy byte */ 
    _card_disable();
    spi_read_write(DUMMY_BYTE);
    return r1;
}

/*******************************************************************************
* Function Name  : _send_command_hold
* Description    : None
* Input          : - cmd:
*				   - arg:
*                  - crc:
* Output         : None
* Return         : R1 value, response from card
* Attention		 : None
*******************************************************************************/
int _send_command_hold(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    uint8_t r1;
    uint8_t retry;

    /* Dummy byte and chip enable */
    spi_read_write(DUMMY_BYTE);
    _card_enable();

    /* Command, argument and crc */
    spi_read_write(cmd | 0x40);
    spi_read_write(arg >> 24);
    spi_read_write(arg >> 16);
    spi_read_write(arg >> 8);
    spi_read_write(arg);
    spi_read_write(crc);
  
    /* Wait response, quit till timeout */
    for(retry=0; retry<200; retry++)
    {
        r1 = spi_read_write(DUMMY_BYTE);
        if(r1 != 0xFF)
        {
            break;
        }
    }
    return r1;
}

下面就是FATFS文件系统的移植了。实现一下移植接口:

const Diskio_drvTypeDef  SD_Driver =
{
    SD_initialize,
    SD_status,
    SD_read,
#if  _USE_WRITE == 1
    SD_write,
#endif /* _USE_WRITE == 1 */

#if  _USE_IOCTL == 1
    SD_ioctl,
#endif /* _USE_IOCTL == 1 */
};


/**
  * @brief  Initializes a Drive
  * @param  lun : not used
  * @retval DSTATUS: Operation status
  */
DSTATUS SD_initialize(BYTE lun)
{
    if(MSD_Init() == 0)
    {
        MSD_GetCardInfo(&CardInfo);
        return 0;
    }else    return STA_NOINIT;
}

/**
  * @brief  Gets Disk Status
  * @param  lun : not used
  * @retval DSTATUS: Operation status
  */
DSTATUS SD_status(BYTE lun)
{
    return 0;
}

/**
  * @brief  Reads Sector(s)
  * @param  lun : not used
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
    int res;
    if( !count )
    {    
        return RES_PARERR;  /* count不能等于0,否则返回参数错误 */
    }
  
    if(count==1)    /* 1个sector的读操作 */
    {       
        res =  MSD_ReadSingleBlock(sector ,buff );
    }else   /* 多个sector的读操作 */
    {   
        res = MSD_ReadMultiBlock(sector , buff ,count);
    }
        
    if(res == 0)
    {
        return RES_OK;
    }else
    {
        return RES_ERROR;
    }

}

/**
  * @brief  Writes Sector(s)
  * @param  lun : not used
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
    int res;
    if( !count )
    {    
        return RES_PARERR;  /* count不能等于0,否则返回参数错误 */
    }
    if(count==1)    /* 1个sector的写操作 */
    {   
        res = MSD_WriteSingleBlock(sector , (uint8_t *)(&buff[0]) ); 
    }else   /* 多个sector的写操作 */
    {   
        res = MSD_WriteMultiBlock(sector , (uint8_t *)(&buff[0]) , count );
    }
    if(res == 0)
    {
        return RES_OK;
    }else
    {
       return RES_ERROR;
    }
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation
  * @param  lun : not used
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
{
    DRESULT res = RES_ERROR;
  
    switch (cmd)
    {
        /* Make sure that no pending write process */
        case CTRL_SYNC :
        res = RES_OK;
        break;

        /* Get number of sectors on the disk (DWORD) */
        case GET_SECTOR_COUNT :
        *(DWORD*)buff = CardInfo.Capacity/CardInfo.BlockSize;
        res = RES_OK;
        break;

        /* Get R/W sector size (WORD) */
        case GET_SECTOR_SIZE :
        *(WORD*)buff = CardInfo.BlockSize;
        res = RES_OK;
        break;

        /* Get erase block size in unit of sector (DWORD) */
        case GET_BLOCK_SIZE :
        *(WORD*)buff = CardInfo.BlockSize;
        res = RES_OK;
        break;

        default:
        res = RES_PARERR;
    }
    return res;
}
#endif /* _USE_IOCTL == 1 */

下面是FATFS初始化:

int FATFS_Init(FATFS *fs,char * _path)
{
    FRESULT res;
    FATFS_LinkDriver(&SD_Driver,_path, 0);
    res = f_mount(fs,_path,1);
    printf("f_mount return =%d\r\n",res);
    
    return  res;
}

FATFS文件系统配置在ffconf.h文件内,按照自己需求配置,需要修改的部分挺少的。

下面就是main主函数测试移植效果了,主要是测试扫描TF卡内所有文件并在串口打印出来。

FATFS       fs;     /* Work area (file system object) for logical drive */
char path[256]="0:/";
uint8_t textFileBuffer[] = "Thank you for using Development Board ^_^ \r\n";

FRESULT scan_files (char* path)
{
    FRESULT     res;
    FILINFO     fno;
    DIR         dir;
    int         i;
    char        *fn;

    res = f_opendir(&dir, path);
    if (res == FR_OK)
    {
        i = strlen(path);
        for (;;)
        {
            res = f_readdir(&dir, &fno);
            if (res != FR_OK || fno.fname[0] == 0) break;
            if (fno.fname[0] == '.') continue;

#if FF_USE_LFN
            fn = *fno.fname ? fno.fname : fno.altname;  //长文件名
#else
            fn = fno.fname; //短文件名
#endif
            if (fno.fattrib & AM_DIR)   //文件夹
            {
                sprintf(&path[i], "%s/", fn);
                res = scan_files(path);
                if (res != FR_OK) break;
                path[i] = 0;
            } else //文件
            {
                printf("%s%s \r\n", path, fn);
            }
        }
        f_closedir(&dir);
    }else   printf("f_opendir %s error %d!\r\n",path,res);
    return res;
}

/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    GPIO_INIT();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);
    printf("This is TF card example.\r\n");

    if(FATFS_Init(&fs,path) == 0)
    {
        printf("FATFS Init OK.\r\n");
        scan_files(path);
    }else {
        printf("FATFS Init Fail!!!\r\n");
    }
    while(1)
    {
        GPIO_SetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1);
        printf("led on.\r\n");
        Delay_Ms(500);
        GPIO_ResetBits(GPIOA,GPIO_Pin_0 | GPIO_Pin_1);
        printf("led off.\r\n");
        Delay_Ms(500);
    }
}

开发板接线如下:
image.png

串口打印数据:
image.png

更多回帖

×
发帖