打印
[技术问答]

请问华大官方关于HC32F460KCTA使用4线制SPIflash移植fatfs文件系统问题

[复制链接]
1243|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nczywq|  楼主 | 2022-10-24 12:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
当前遇到的问题是,直接调用低层函数读写数据是正常的,由于读写无法共存,所有读数据,我采用了复制的方式,没有采用直接指针. 我使用fatfs文件系统后,格式化正常,读正常,就是只要一新建文件,保存,当时是没有报错,但是重启板子后,挂载falsh时,就会提示没有文件系统,就是写文件时,把文件系统给写坏了,找了很久原因,希望能得到华大官方的帮助,谢谢,关键代码如下
#ifndef W25QXX_H
#define W25QXX_H

#include "qspi.h"

/**
*******************************************************************************
** \defgroup W25QXXGroup W25Q64 SPI NOR Flash driver
**
******************************************************************************/
//@{

/*******************************************************************************
* Global type definitions ('typedef')
******************************************************************************/

/*****************************************************************************/
/* Global pre-processor symbols/macros ('define')                            */
/*****************************************************************************/
/* W25QXX Flash ID */
#define W25Q80  0XEF13u
#define W25Q16  0XEF14u
#define W25Q32  0XEF15u
#define W25Q64  0XEF16u
#define W25Q128 0XEF17u

/* W25QXX Command list */
#define W25X_WriteEnable        0x06u
#define W25X_WriteDisable       0x04u
#define W25X_ReadStatusReg      0x05u
#define W25X_WriteStatusReg     0x01u
#define W25X_ReadData           0x03u
#define W25X_FastReadData       0x0Bu
#define W25X_FastReadDual       0x3Bu
#define W25X_PageProgram        0x02u
#define W25X_BlockErase         0xD8u
#define W25X_SectorErase        0x20u
#define W25X_ChipErase          0xC7u
#define W25X_PowerDown          0xB9u
#define W25X_ReleasePowerDown   0xABu
#define W25X_DeviceID           0xABu
#define W25X_ManufactDeviceID   0x90u
#define W25X_JedecDeviceID      0x9Fu

/*******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
extern uint16_t W25QXX_TYPE;

/*******************************************************************************
* Global function prototypes (definition in C source)
******************************************************************************/
int W25QXX_Init(void);
int W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
int W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

#endif

#include "w25qxx.h"
#include "string.h"

uint16_t W25QXX_TYPE = W25Q64;
uint8_t W25QXX_BUFFER[4096];

/**
*******************************************************************************
** \brief W25QXX IO initialize
**
** \param  None
**
** \retval int
**
******************************************************************************/
int W25QXX_Init(void)
{
        int result =  QspiFlash_Init();
        if (result == 0) {
        //        W25QXX_TYPE = W25QXX_ReadID();
        }
        return result;
}


/**
*******************************************************************************
** \brief W25QXX read flash content
**
** \param [in] ReadAddr                Address to be read
** \param [in] NumByteToRead           Number to be read, (MAX. 65535)
** \param [out] pBuffer                Read data buffer
**
** \retval Read result
**
******************************************************************************/
int W25QXX_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
        while(flashnoreading){};
    stc_qspi_comm_protocol_t stcQspiCommProtocol;
        MEM_ZERO_STRUCT(stcQspiCommProtocol);
        /* Switch to standard read mode */
    stcQspiCommProtocol.enReadMode = QspiReadModeFourWiresIO;
    QSPI_CommProtocolConfig(&stcQspiCommProtocol);
    /* Pointer to flash address map */
        //        pBuffer = (uint8_t *)((uint32_t)QSPI_BUS_ADDRESS + ReadAddr);
                       
                uint8_t * pFlashReadAddr = (uint8_t *)((uint32_t)QSPI_BUS_ADDRESS + ReadAddr);
                memcpy(pBuffer, pFlashReadAddr, (uint32_t)NumByteToRead);
                return 0 ;
}


/**
*******************************************************************************
** \brief W25QXX flash write
**
** \param [in] pBuffer                 data buffer to be written
** \param [in] WriteAddr               Address to be written
** \param [in] NumByteToWrite          Number to be written, (MAX. 65535)
**
** \retval None
**
******************************************************************************/
void W25QXX_Write_NoCheck(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t pageremain;
    pageremain = (uint16_t)(256u - WriteAddr % 256u);
    if (NumByteToWrite <= pageremain)
    {
        pageremain = NumByteToWrite;
    }
    while (1)
    {
        QspiFlash_WritePage(WriteAddr,pBuffer , pageremain); //pBuffer
        if (NumByteToWrite == pageremain)
        {
            break;
        }
        else //NumByteToWrite>pageremain
        {
            pBuffer        += pageremain;
            WriteAddr      += pageremain;

            NumByteToWrite -= pageremain;
            if (NumByteToWrite > 256u)
            {
                pageremain = 256u;
            }
            else
            {
                pageremain = NumByteToWrite;
            }
        }
    }
                flashnoreading = 0 ;
}

/**
*******************************************************************************
** \brief W25QXX flash write API for MSC
**
** \param [in] pBuffer                 data buffer to be written
** \param [in] WriteAddr               Address to be written
** \param [in] NumByteToWrite          Number to be written, (MAX. 65535)
**
** \retval Write result
**
******************************************************************************/
int W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
        if(WriteAddr + NumByteToWrite -1 > (uint32_t)FLASH_MAX_ADDR){
                        return 1 ;
        }
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t * W25QXX_BUF;
    W25QXX_BUF = W25QXX_BUFFER;
    secpos     = WriteAddr / 4096u;
    secoff     = (uint16_t)(WriteAddr % 4096u);
    secremain  = 4096u - secoff;
//    DDL_Printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);           // for test
    if (NumByteToWrite <= secremain)
    {
        secremain = NumByteToWrite;                                // less than 4K
    }
    while (1)
    {
        W25QXX_Read(W25QXX_BUF, secpos * 4096u, 4096u);              // read one sector content
        stc_qspi_comm_protocol_t stcQspiCommProtocol;
            MEM_ZERO_STRUCT(stcQspiCommProtocol);
        stcQspiCommProtocol.enReadMode = QspiReadModeStandard;
        QSPI_CommProtocolConfig(&stcQspiCommProtocol);
        
        for (i = 0u; i < secremain; i++)                            // check if blank sector
        {
            if (W25QXX_BUF[secoff + i] != (uint8_t)0XFF)
            {
                break;
            }
        }
        if (i < secremain)
        {
            QspiFlash_Erase4KbSector(secpos);                           // not blank, need erase
            for (i = 0u; i < secremain; i++)                        // backup first
            {
                W25QXX_BUF[i + secoff] = pBuffer[i];
            }
            W25QXX_Write_NoCheck( W25QXX_BUF , secpos * 4096u,4096u); // write back after erase

        }
        else
        {
            W25QXX_Write_NoCheck(pBuffer , WriteAddr, secremain);
        }
        if (NumByteToWrite == secremain)
        {
            break;
        }
        else
        {
            secpos++;                                              // next sector
            secoff          = 0u;

            pBuffer        += secremain;
            WriteAddr      += secremain;
            NumByteToWrite -= secremain;
            if (NumByteToWrite > 4096u)
            {
                secremain = 4096u;
            }
            else
            {
                secremain = NumByteToWrite;
            }
        }
    }
    ;
                return 0 ;
}




/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

#include "ff.h"                        /* Obtains integer types */
#include "diskio.h"                /* Declarations of disk functions */
#include "w25qxx.h"

/* Definitions of physical drive number for each drive */
#define W25QXX                0        /* Example: Map Ramdisk to physical drive 0 */
#define FATFS_SECTOR_SIZE         512      
#define FATFS_SECTOR_COUNT         8 * 1024 * 2                        //一共8M空间
#define FATFS_BLOCK_SIZE           8                                                     //每个BLOCK有8个扇区      


/*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
        BYTE pdrv                /* Physical drive nmuber to identify the drive */
)
{
        DSTATUS stat = 0;

        switch (pdrv) {
        case W25QXX :
               

                // translate the reslut code here

                return stat;
        }
        return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
        BYTE pdrv                                /* Physical drive nmuber to identify the drive */
)
{
        DSTATUS stat;
      

        switch (pdrv) {
        case W25QXX :
                stat = W25QXX_Init();
                // translate the reslut code here
                return stat;
        }
        return STA_NOINIT;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
        BYTE pdrv,                /* Physical drive nmuber to identify the drive */
        BYTE *buff,                /* Data buffer to store read data */
        LBA_t sector,        /* Start sector in LBA */
        UINT count                /* Number of sectors to read */
)
{
//        DRESULT res;
        int result;

        switch (pdrv) {
        case W25QXX :
                // translate the arguments here
      
                       

        //        result = flashfatfsread(buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
        //                result = W25QXX_Read(buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
      
                        for(;count>0;count--)
                        {
                                result = W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
                                sector++;
                                buff+=FLASH_SECTOR_SIZE;
                        }

                // translate the reslut code here

                return (DRESULT)result;

        }

        return RES_PARERR;
}



/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if FF_FS_READONLY == 0

DRESULT disk_write (
        BYTE pdrv,                        /* Physical drive nmuber to identify the drive */
        const BYTE *buff,        /* Data to be written */
        LBA_t sector,                /* Start sector in LBA */
        UINT count                        /* Number of sectors to write */
)
{
        //DRESULT res;
        int result;

        switch (pdrv) {
        case W25QXX :
//                result = flashfatfswrite((uint8_t *)buff,sector * FATFS_SECTOR_SIZE,count * FATFS_SECTOR_SIZE);
//                result = W25QXX_Write((uint8_t *)&buff, sector * FATFS_SECTOR_SIZE, count * FATFS_SECTOR_SIZE);
      
                        for(;count>0;count--)
                        {                                                                                    
                                result = W25QXX_Write((uint8_t*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
                                sector++;
                                buff+=FLASH_SECTOR_SIZE;
                        }
                        return (DRESULT)result;   //RES_PARERR
        }

        return RES_PARERR;
}

#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
        BYTE pdrv,                /* Physical drive nmuber (0..) */
        BYTE cmd,                /* Control code */
        void *buff                /* Buffer to send/receive control data */
)
{
        DRESULT res;

        switch (pdrv) {
        case W25QXX :
                switch(cmd)
          {
                  case CTRL_SYNC:
                                res = RES_OK;
                                break;         
                  case GET_SECTOR_SIZE:
                                *(WORD*)buff = FATFS_SECTOR_SIZE;
                    res = RES_OK;
                    break;         
                  case GET_BLOCK_SIZE:
                    *(WORD*)buff = FATFS_BLOCK_SIZE;
                    res = RES_OK;
                    break;         
                  case GET_SECTOR_COUNT:
                    *(DWORD*)buff = FATFS_SECTOR_COUNT;
                    res = RES_OK;
                    break;
                  default:
                    res = RES_PARERR;
                    break;
            }

                return res;
        }

        return RES_PARERR;
}
DWORD get_fattime (void)
{                                 
        return 0;
}      

#include "qspi.h"

uint8_t flashnoreading = 1 ;

/**
*******************************************************************************
** \brief QSPI flash init function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
int QspiFlash_Init(void)
{
        stc_qspi_init_t stcQspiInit;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcQspiInit);

    /* Configuration peripheral clock */
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_QSPI, Enable);

    /* Configuration QSPI pin */
    PORT_SetFunc(QSPCK_PORT, QSPCK_PIN, Func_Qspi, Disable);
    PORT_SetFunc(QSNSS_PORT, QSNSS_PIN, Func_Qspi, Disable);
    PORT_SetFunc(QSIO0_PORT, QSIO0_PIN, Func_Qspi, Disable);
    PORT_SetFunc(QSIO1_PORT, QSIO1_PIN, Func_Qspi, Disable);
    PORT_SetFunc(QSIO2_PORT, QSIO2_PIN, Func_Qspi, Disable);
    PORT_SetFunc(QSIO3_PORT, QSIO3_PIN, Func_Qspi, Disable);

    /* Configuration QSPI structure */
    stcQspiInit.enClkDiv = QspiHclkDiv3;
    stcQspiInit.enSpiMode = QspiSpiMode3;
    stcQspiInit.enBusCommMode = QspiBusModeRomAccess;
    stcQspiInit.enPrefetchMode = QspiPrefetchStopComplete;
    stcQspiInit.enPrefetchFuncEn = Disable;
    stcQspiInit.enQssnValidExtendTime = QspiQssnValidExtendSck32;
    stcQspiInit.enQssnIntervalTime = QspiQssnIntervalQsck8;
    stcQspiInit.enQsckDutyCorr = QspiQsckDutyCorrHalfHclk;
    stcQspiInit.enVirtualPeriod = QspiVirtualPeriodQsck6;
    stcQspiInit.enWpPinLevel = QspiWpPinOutputHigh;
    stcQspiInit.enQssnSetupDelayTime = QspiQssnSetupDelay1Dot5Qsck;
    stcQspiInit.enQssnHoldDelayTime = QspiQssnHoldDelay1Dot5Qsck;
    stcQspiInit.enFourByteAddrReadEn = Disable;
    stcQspiInit.enAddrWidth = QspiAddressByteThree;
    stcQspiInit.stcCommProtocol.enReadMode = QspiReadModeFourWiresIO;
    stcQspiInit.stcCommProtocol.enTransInstrProtocol = QspiProtocolExtendSpi;
    stcQspiInit.stcCommProtocol.enTransAddrProtocol = QspiProtocolExtendSpi;
    stcQspiInit.stcCommProtocol.enReceProtocol = QspiProtocolExtendSpi;
    stcQspiInit.u8RomAccessInstr = QSPI_3BINSTR_FOUR_WIRES_IO_READ;
    int result = QSPI_Init(&stcQspiInit);
                flashnoreading = 0;                //允许读取falsh
                return result;
}
/**
*******************************************************************************
** \brief QSPI flash write enable function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
void QspiFlash_WriteEnable(void)
{
    QSPI_EnterDirectCommMode();
    QSPI_WriteDirectCommValue(FLASH_INSTR_WRITE_ENABLE);
    QSPI_ExitDirectCommMode();
}

/**
*******************************************************************************
** \brief QSPI flash wait for write operation end function
**
** \param [in] None
**
** \retval Ok                              Flash internal operation finish
** \retval ErrorTimeout                    Flash internal operation timeout
**
******************************************************************************/
en_result_t QspiFlash_WaitForWriteEnd(void)
{
    en_result_t enRet = Ok;
    uint8_t u8Status = 0u;
    uint32_t u32Timeout;
    stc_clk_freq_t stcClkFreq;

    CLK_GetClockFreq(&stcClkFreq);
    u32Timeout = stcClkFreq.sysclkFreq / 1000u;
    QSPI_EnterDirectCommMode();
    QSPI_WriteDirectCommValue(FLASH_INSTR_READ_SR1);
    do
    {
        u8Status = QSPI_ReadDirectCommValue();
        u32Timeout--;
    } while ((u32Timeout != 0u) &&
             ((u8Status & FLASH_BUSY_BIT_MASK) == FLASH_BUSY_BIT_MASK));

    if (FLASH_BUSY_BIT_MASK == u8Status)
    {
        enRet = ErrorTimeout;
    }
    QSPI_ExitDirectCommMode();

    return enRet;
}

/**
*******************************************************************************
** \brief QSPI flash page write program function
**
** \param [in] u32Addr                     Valid flash address
**
** \param [in] pData                       Pointer to send data buffer
**
** \param [in] len                         Send data length
**
** \retval Error                           Page write program failed
** \retval Ok                              Page write program success
**
******************************************************************************/
en_result_t QspiFlash_WritePage(uint32_t u32Addr, uint8_t * pData, uint16_t len)
{
    en_result_t enRet = Ok;
    uint16_t u16Index = 0u;

    if ((u32Addr > FLASH_MAX_ADDR) || (NULL == pData) || (len > FLASH_PAGE_SIZE))
    {
        enRet = Error;
    }
    else
    {
        QspiFlash_WriteEnable();
        /* Send data to flash */
        QSPI_EnterDirectCommMode();
        QSPI_WriteDirectCommValue(FLASH_INSTR_PAGE_PROGRAM);
        QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF0000ul) >> 16));
        QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF00u) >> 8));
        QSPI_WriteDirectCommValue((uint8_t)(u32Addr & 0xFFu));
        while (len--)
        {
           QSPI_WriteDirectCommValue(pData[u16Index]);
           u16Index++;
        }
        QSPI_ExitDirectCommMode();
        /* Wait for flash idle */
        enRet = QspiFlash_WaitForWriteEnd();
    }

    return enRet;
}

/**
*******************************************************************************
** \brief QSPI flash erase 4Kb sector function
**
** \param [in] u32Addr                     Valid flash address
**
** \retval Error                           Sector erase failed
** \retval Ok                              Sector erase success
**
******************************************************************************/
en_result_t QspiFlash_Erase4KbSector(uint32_t u32Addr)
{
    en_result_t enRet = Ok;

    if (u32Addr >= FLASH_MAX_ADDR)
    {
        enRet = Error;
    }
    else
    {
        QspiFlash_WriteEnable();
        /* Send instruction to flash */
        QSPI_EnterDirectCommMode();
        QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_4KB_SECTOR);
        QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF0000ul) >> 16));
        QSPI_WriteDirectCommValue((uint8_t)((u32Addr & 0xFF00u) >> 8));
        QSPI_WriteDirectCommValue((uint8_t)(u32Addr & 0xFFu));
        QSPI_ExitDirectCommMode();
        /* Wait for flash idle */
        enRet = QspiFlash_WaitForWriteEnd();
    }

    return enRet;
}

/**
*******************************************************************************
** \brief QSPI flash erase chip function
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
void QspiFlash_EraseChip(void)
{
    QspiFlash_WriteEnable();
    /* Send instruction to flash */
    QSPI_EnterDirectCommMode();
    QSPI_WriteDirectCommValue(FLASH_INSTR_ERASE_CHIP);
    QSPI_ExitDirectCommMode();
    /* Wait for flash idle */
    QspiFlash_WaitForWriteEnd();
}

/**
*******************************************************************************
** \brief QSPI flash read status register function
**
** \param [in] u8Reg                       Need to get status register
** \arg FLASH_INSTR_READ_SR1               Status register 1
** \arg FLASH_INSTR_READ_SR2               Status register 2
** \arg FLASH_INSTR_READ_SR3               Status register 3
**
** \retval uint8_t                         Current register value
**
******************************************************************************/
uint8_t QspiFlash_ReadStatusRegister(uint8_t u8Reg)
{
    uint8_t regSta = 0u;

    QSPI_EnterDirectCommMode();
    QSPI_WriteDirectCommValue(u8Reg);
    regSta = QSPI_ReadDirectCommValue();
    QSPI_ExitDirectCommMode();

    return regSta;
}

使用特权

评论回复
沙发
nczywq|  楼主 | 2022-11-3 14:37 | 只看该作者
找到原因了,华大官方自己的代码居然两边的函数居然不一样。QspiFlash_Erase4KbSector函数中,fatfs时,在里面 乘了4096,而在普通例程中没有乘,就导致低于4096时,一直在擦除第一个sector。自己写的例程,为什么要这么搞我们用户呢

使用特权

评论回复
板凳
jinyuhang123456| | 2023-1-5 19:14 | 只看该作者
兄弟,你用的是哪一个版本的官方代码?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

12

主题

60

帖子

2

粉丝