/** ****************************************************************************** * @file bsp_xxx.c * @author STMicroelectronics * @version V1.0 * @date 2013-xx-xx * @brief QSPI flash 底层应用函数bsp ****************************************************************************** * @attention * * 实验平台:野火STM32H743 开发板 * 论坛 :http://www.firebbs.cn * 淘宝 :http://firestm32.taobao.com * ****************************************************************************** */ #include "./fatfs/drivers/fatfs_flash_qspi.h" #include "ff_gen_drv.h" static volatile DSTATUS TM_FATFS_FLASH_SPI_Stat = STA_NOINIT; /* Physical drive status */ QSPI_HandleTypeDef hqspi; #define QSPIHandle hqspi const Diskio_drvTypeDef QSPI_Driver = { TM_FATFS_FLASH_SPI_disk_initialize, TM_FATFS_FLASH_SPI_disk_status, TM_FATFS_FLASH_SPI_disk_read, #if _USE_WRITE == 1 TM_FATFS_FLASH_SPI_disk_write, #endif /* _USE_WRITE == 1 */ #if _USE_IOCTL == 1 TM_FATFS_FLASH_SPI_disk_ioctl, #endif /* _USE_IOCTL == 1 */ }; /******************************************************************************* * Function Name : SPI_FLASH_Init * Description : Initializes the peripherals used by the SPI FLASH driver. * Input : None * Output : None * Return : None *******************************************************************************/ DSTATUS TM_FATFS_FLASH_SPI_disk_initialize(BYTE lun) { GPIO_InitTypeDef GPIO_InitStruct; /* 使能 QSPI 及 GPIO 时钟 */ QSPI_FLASH_CLK_ENABLE(); QSPI_FLASH_CLK_GPIO_ENABLE(); QSPI_FLASH_BK1_IO0_CLK_ENABLE(); QSPI_FLASH_BK1_IO1_CLK_ENABLE(); QSPI_FLASH_BK1_IO2_CLK_ENABLE(); QSPI_FLASH_BK1_IO3_CLK_ENABLE(); QSPI_FLASH_CS_GPIO_CLK_ENABLE(); //设置引脚 /*!< 配置 QSPI_FLASH 引脚: CLK */ GPIO_InitStruct.Pin = QSPI_FLASH_CLK_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = QSPI_FLASH_CLK_GPIO_AF; HAL_GPIO_Init(QSPI_FLASH_CLK_GPIO_PORT, &GPIO_InitStruct); /*!< 配置 QSPI_FLASH 引脚: IO0 */ GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO0_PIN; GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO0_AF; HAL_GPIO_Init(QSPI_FLASH_BK1_IO0_PORT, &GPIO_InitStruct); /*!< 配置 QSPI_FLASH 引脚: IO1 */ GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO1_PIN; GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO1_AF; HAL_GPIO_Init(QSPI_FLASH_BK1_IO1_PORT, &GPIO_InitStruct); /*!< 配置 QSPI_FLASH 引脚: IO2 */ GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO2_PIN; GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO2_AF; HAL_GPIO_Init(QSPI_FLASH_BK1_IO2_PORT, &GPIO_InitStruct); /*!< 配置 QSPI_FLASH 引脚: IO3 */ GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO3_PIN; GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO3_AF; HAL_GPIO_Init(QSPI_FLASH_BK1_IO3_PORT, &GPIO_InitStruct); /*!< 配置 SPI_FLASH_SPI 引脚: NCS */ GPIO_InitStruct.Pin = QSPI_FLASH_CS_PIN; GPIO_InitStruct.Alternate = QSPI_FLASH_CS_GPIO_AF; HAL_GPIO_Init(QSPI_FLASH_CS_GPIO_PORT, &GPIO_InitStruct); /* QSPI_FLASH 模式配置 */ hqspi.Instance = QUADSPI; hqspi.Init.ClockPrescaler = 1; hqspi.Init.FifoThreshold = 4; hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; hqspi.Init.FlashSize = 23; hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0; HAL_QSPI_Init(&hqspi); BSP_QSPI_Init(); return TM_FATFS_FLASH_SPI_disk_status(NULL); } /** * @brief Initializes the QSPI interface. * @retval QSPI memory status */ uint8_t BSP_QSPI_Init(void) { QSPI_CommandTypeDef s_command; uint8_t value = W25Q128FV_FSR_QE; /* QSPI memory reset */ if (QSPI_ResetMemory() != QSPI_OK) { return QSPI_NOT_SUPPORTED; } /* Enable write operations */ if (QSPI_WriteEnable() != QSPI_OK) { return QSPI_ERROR; } /* Set status register for Quad Enable,the Quad IO2 and IO3 pins are enable */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = WRITE_STATUS_REG2_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmit the data */ if (HAL_QSPI_Transmit(&hqspi, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* automatic polling mode to wait for memory ready */ if (QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief Reads an amount of data from the QSPI memory. * @param pData: Pointer to data to be read * @param ReadAddr: Read start address * @param Size: Size of data to read * @retval QSPI memory status */ uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) { QSPI_CommandTypeDef s_command; /* Initialize the read command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = ReadAddr; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = Size; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief Writes an amount of data to the QSPI memory. * @param pData: Pointer to data to be written * @param WriteAddr: Write start address * @param Size: Size of data to write * @retval QSPI memory status */ uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) { QSPI_CommandTypeDef s_command; uint32_t end_addr, current_size, current_addr; /* Calculation of the size between the write address and the end of the page */ current_addr = 0; while (current_addr <= WriteAddr) { current_addr += W25Q128FV_PAGE_SIZE; } current_size = current_addr - WriteAddr; /* Check if the size of the data is less than the remaining place in the page */ if (current_size > Size) { current_size = Size; } /* Initialize the adress variables */ current_addr = WriteAddr; end_addr = WriteAddr + Size; /* Initialize the program command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Perform the write page by page */ do { s_command.Address = current_addr; s_command.NbData = current_size; /* Enable write operations */ if (QSPI_WriteEnable() != QSPI_OK) { return QSPI_ERROR; } /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Transmission of the data */ if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of program */ if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; } /* Update the address and size variables for next page programming */ current_addr += current_size; pData += current_size; current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE; } while (current_addr < end_addr); return QSPI_OK; } /** * @brief Erases the specified block of the QSPI memory. * @param BlockAddress: Block address to erase * @retval QSPI memory status */ uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) { QSPI_CommandTypeDef s_command; /* Initialize the erase command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = SECTOR_ERASE_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = BlockAddress; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable() != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of erase */ if (QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief Erases the entire QSPI memory. * @retval QSPI memory status */ uint8_t BSP_QSPI_Erase_Chip(void) { QSPI_CommandTypeDef s_command; /* Initialize the erase command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = CHIP_ERASE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Enable write operations */ if (QSPI_WriteEnable() != QSPI_OK) { return QSPI_ERROR; } /* Send the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for end of erase */ if (QSPI_AutoPollingMemReady(W25Q128FV_BULK_ERASE_MAX_TIME) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief Reads current status of the QSPI memory. * @retval QSPI memory status */ uint8_t BSP_QSPI_GetStatus(void) { QSPI_CommandTypeDef s_command; uint8_t reg; /* Initialize the read flag status register command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_STATUS_REG1_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Configure the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Reception of the data */ if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Check the value of the register */ if((reg & W25Q128FV_FSR_BUSY) != 0) { return QSPI_BUSY; } else { return QSPI_OK; } } /** * @brief Return the configuration of the QSPI memory. * @param pInfo: pointer on the configuration structure * @retval QSPI memory status */ uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) { /* Configure the structure with the memory configuration */ pInfo->FlashSize = W25Q128FV_FLASH_SIZE; pInfo->EraseSectorSize = W25Q128FV_SUBSECTOR_SIZE; pInfo->EraseSectorsNumber = (W25Q128FV_FLASH_SIZE/W25Q128FV_SUBSECTOR_SIZE); pInfo->ProgPageSize = W25Q128FV_PAGE_SIZE; pInfo->ProgPagesNumber = (W25Q128FV_FLASH_SIZE/W25Q128FV_PAGE_SIZE); return QSPI_OK; } ///** // * @brief Configure the QSPI in memory-mapped mode // * @retval QSPI memory status // */ //uint8_t BSP_QSPI_MemoryMappedMode(void) //{ // QSPI_CommandTypeDef s_command; // QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; // /* Configure the command for the read instruction */ // s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; // s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; // s_command.AddressMode = QSPI_ADDRESS_4_LINES; // s_command.AddressSize = QSPI_ADDRESS_24_BITS; // s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; // s_command.DataMode = QSPI_DATA_4_LINES; // s_command.DummyCycles = W25Q128FV_DUMMY_CYCLES_READ_QUAD; // s_command.DdrMode = QSPI_DDR_MODE_DISABLE; // s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; // s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; // // /* Configure the memory mapped mode */ // s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_ENABLE; // s_mem_mapped_cfg.TimeOutPeriod = 1; // // if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) // { // return QSPI_ERROR; // } // return QSPI_OK; //} /** * @brief This function reset the QSPI memory. * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_ResetMemory() { QSPI_CommandTypeDef s_command; /* Initialize the reset enable command */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = RESET_ENABLE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* Send the command */ if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Send the reset memory command */ s_command.Instruction = RESET_MEMORY_CMD; if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait the memory is ready */ if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief This function send a Write Enable and wait it is effective. * @param hqspi: QSPI handle * @retval None */ static uint8_t QSPI_WriteEnable() { QSPI_CommandTypeDef s_command; QSPI_AutoPollingTypeDef s_config; /* Enable write operations */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = WRITE_ENABLE_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } /* Configure automatic polling mode to wait for write enabling */ s_config.Match = W25Q128FV_FSR_WREN; s_config.Mask = W25Q128FV_FSR_WREN; s_config.MatchMode = QSPI_MATCH_MODE_AND; s_config.StatusBytesSize = 1; s_config.Interval = 0x10; s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; s_command.Instruction = READ_STATUS_REG1_CMD; s_command.DataMode = QSPI_DATA_1_LINE; s_command.NbData = 1; if (HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief This function read the SR of the memory and wait the EOP. * @param hqspi: QSPI handle * @param Timeout * @retval None */ static uint8_t QSPI_AutoPollingMemReady(uint32_t Timeout) { QSPI_CommandTypeDef s_command; QSPI_AutoPollingTypeDef s_config; /* Configure automatic polling mode to wait for memory ready */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_STATUS_REG1_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; s_config.Match = 0x00; s_config.Mask = W25Q128FV_FSR_BUSY; s_config.MatchMode = QSPI_MATCH_MODE_AND; s_config.StatusBytesSize = 1; s_config.Interval = 0x10; s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; if (HAL_QSPI_AutoPolling(&QSPIHandle, &s_command, &s_config, Timeout) != HAL_OK) { return QSPI_ERROR; } return QSPI_OK; } /** * @brief 读取FLASH ID * @param 无 * @retval FLASH ID */ uint32_t QSPI_FLASH_ReadID(void) { QSPI_CommandTypeDef s_command; uint32_t Temp = 0; uint8_t pData[3]; /* Read JEDEC ID */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_JEDEC_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 3; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { printf("something wrong ....\r\n"); /* User may add here some code to deal with this error */ while(1) { } } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { printf("something wrong ....\r\n"); /* User may add here some code to deal with this error */ while(1) { } } Temp = pData[2] |( pData[1]<<8 )| ( pData[0]<<16 ); return Temp; } /** * @brief 读取FLASH Device ID * @param 无 * @retval FLASH Device ID */ uint32_t QSPI_FLASH_ReadDeviceID(void) { QSPI_CommandTypeDef s_command; uint32_t Temp = 0; uint8_t pData[3]; /*##-2-Read Device ID Test ###########################################*/ /* Read Manufacture/Device ID */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 2; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { printf("something wrong ....\r\n"); /* User may add here some code to deal with this error */ while(1) { } } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { printf("something wrong ....\r\n"); /* User may add here some code to deal with this error */ while(1) { } } Temp = pData[1] |( pData[0]<<8 ) ; return Temp; } DSTATUS TM_FATFS_FLASH_SPI_disk_status(BYTE lun) { FLASH_DEBUG_FUNC(); if(sFLASH_ID == QSPI_FLASH_ReadID()) /*检测FLASH是否正常工作*/ { return TM_FATFS_FLASH_SPI_Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */ } else { return TM_FATFS_FLASH_SPI_Stat |= STA_NOINIT; } } DRESULT TM_FATFS_FLASH_SPI_disk_ioctl(BYTE lun,BYTE cmd, void *buff) { FLASH_DEBUG_FUNC(); switch (cmd) { case GET_SECTOR_COUNT: *(DWORD * )buff = 2560; /* 扇区数量:2560*4096/1024/1024=10(MB) */ break; case GET_SECTOR_SIZE : /*获取扇区读写的大小(字)*/ *(WORD * )buff = 4096; /*flash最小写单元为页,256字节,此处取2页为一个读写单位*/ break; case GET_BLOCK_SIZE : /* 同时擦除扇区个数(双字) */ *(DWORD * )buff = 1; /*flash以1个sector为最小擦除单位*/ break; case CTRL_TRIM: break; case CTRL_SYNC : break; } return RES_OK; } DRESULT TM_FATFS_FLASH_SPI_disk_read( BYTE lun,//物理扇区,多个设备时用到(0...) BYTE *buff,//数据缓存区 DWORD sector, //扇区首地址 UINT count)//扇区个数(1..128) { FLASH_DEBUG_FUNC(); if ((TM_FATFS_FLASH_SPI_Stat & STA_NOINIT)) { return RES_NOTRDY; } sector+=1536;//扇区偏移,外部Flash文件系统空间放在外部Flash后面6M空间 BSP_QSPI_Read(buff, sector <<12, count<<12); return RES_OK; } DRESULT TM_FATFS_FLASH_SPI_disk_write( BYTE lun,//物理扇区,多个设备时用到(0...) const BYTE *buff,//数据缓存区 DWORD sector, //扇区首地址 UINT count)//扇区个数(1..128) { uint32_t write_addr; FLASH_DEBUG_FUNC(); sector+=1536;//扇区偏移,外部Flash文件系统空间放在外部Flash后面4M空间 write_addr = sector<<12; BSP_QSPI_Erase_Block(write_addr); BSP_QSPI_Write((uint8_t*)buff,write_addr,4096); return RES_OK; } /*********************************************END OF FILE**********************/