/* Copyright (C) 2022 Alif Semiconductor - All Rights Reserved. * Use, distribution and modification of this code is permitted under the * terms stated in the Alif Semiconductor Software License Agreement * * You should have received a copy of the Alif Semiconductor Software * License Agreement with this file. If not, please write to: * contact@alifsemi.com, or visit: https://alifsemi.com/license * */ /**************************************************************************//** * @file Driver_FLASH.c * @author Khushboo Singh * @email khushboo.singh@alifsemi.com * @version V1.0.0 * @date 21-Oct-2022 * @brief ISSI FLASH Driver. * @bug None. * @Note None ******************************************************************************/ #include "Driver_Flash.h" #include "Driver_OSPI.h" #include "RTE_Device.h" #include "RTE_Components.h" #include "IS25WX256.h" #include CMSIS_device_header #if !(RTE_ISSI_FLASH) #error "ISSI Flash driver is not enabled in RTE_Device.h" #endif #if !(RTE_Drivers_ISSI_FLASH) #error "ISSI Flash driver is not enabled in RTE_Components.h" #endif #define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0) /* driver version */ #ifndef DRIVER_FLASH_NUM #define DRIVER_FLASH_NUM 1 /* Default driver number */ #endif #ifndef DRIVER_OSPI_NUM #define DRIVER_OSPI_NUM RTE_ISSI_FLASH_OSPI_DRV_NUM #endif #ifndef DRIVER_OSPI_BUS_SPEED #define DRIVER_OSPI_BUS_SPEED RTE_ISSI_FLASH_OSPI_BUS_SPEED #endif /* SPI Data Flash Commands */ #define CMD_WRITE_VOL_CONFIG (0x81U) #define CMD_READ_DATA (0x7CU) #define CMD_READ_STATUS (0x05U) #define CMD_WRITE_ENABLE (0x06U) #define CMD_PAGE_PROGRAM (0x84U) #define CMD_READ_FLAG_STATUS (0x70U) #define CMD_SECTOR_ERASE (0x21U) #define CMD_BULK_ERASE (0xC7U) #define IO_MODE_ADDRESS 0x00000000U #define WAIT_CYCLE_ADDRESS 0x00000001U #define OCTAL_DDR_WO_DQS (0xC7U) #define OCTAL_DDR (0xE7U) #define DEFAULT_WAIT_CYCLES RTE_ISSI_FLASH_WAIT_CYCLES #define FLAG_STATUS_BUSY 0x80U #define FLAG_STATUS_ERROR 0x30U /* Flash Driver ISSI_Flags */ #define FLASH_INIT (0x01U) #define FLASH_POWER (0x02U) /* SPI Driver */ extern ARM_DRIVER_OSPI ARM_Driver_OSPI_(DRIVER_OSPI_NUM); static ARM_DRIVER_OSPI * ptrOSPI = &ARM_Driver_OSPI_(DRIVER_OSPI_NUM); /* SPI Bus Speed */ #define OSPI_BUS_SPEED ((uint32_t)DRIVER_OSPI_BUS_SPEED) #define OSPI_MAX_RX_COUNT 256 /* Flash Information */ ARM_FLASH_INFO ISSI_FlashInfo = { NULL, FLASH_ISSI_SECTOR_COUNT, FLASH_ISSI_SECTOR_SIZE, FLASH_ISSI_PAGE_SIZE, FLASH_ISSI_PROGRAM_UNIT, FLASH_ISSI_ERASED_VALUE, #if (ARM_FLASH_API_VERSION > 0x201U) { 0U, 0U, 0U } #endif }; /* Flash Status */ static ARM_FLASH_STATUS ISSI_FlashStatus; /* Flag to track the driver state */ static uint8_t ISSI_Flags; /* Flag to monitor OSPI events */ static volatile uint32_t issi_event_flag; /* Driver Version */ const ARM_DRIVER_VERSION DriverVersion = { ARM_FLASH_API_VERSION, ARM_FLASH_DRV_VERSION }; /* Driver Capabilities */ const ARM_FLASH_CAPABILITIES DriverCapabilities = { 0U, /* event_ready */ 1U, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */ 1U, /* erase_chip */ #if (ARM_FLASH_API_VERSION > 0x200U) 0U /* reserved */ #endif }; /** \fn void spi_callback_event(uint32_t event) \brief Call back api called from OSPI. \return none **/ static void spi_callback_event(uint32_t event) { issi_event_flag = event; } /** \fn ARM_DRIVER_VERSION ARM_Flash_GetVersion (void) \brief Get driver version. \return \ref ARM_DRIVER_VERSION **/ static ARM_DRIVER_VERSION ARM_Flash_GetVersion (void) { return DriverVersion; } /** \fn ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities (void) \brief Get driver capabilities. \return \ref ARM_FLASH_CAPABILITIES */ static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities (void) { return DriverCapabilities; } /** \fn static int32_t ControlSlaveSelect(bool enable) \brief Helper function to control the slave select line \param[in] enable : True/False to enable or disable the SS line \return \ref execution_status */ static int32_t ControlSlaveSelect(bool enable) { int32_t status; uint32_t arg; if (enable) { arg = ARM_OSPI_SS_ACTIVE; } else { arg = ARM_OSPI_SS_INACTIVE; } do { status = ptrOSPI->Control(ARM_OSPI_CONTROL_SS, arg); } while (status == ARM_DRIVER_ERROR_BUSY); return status; } /** \fn int32_t ReadStatusReg (uint32_t command, uint32_t *stat) \brief Read status register to check the status of flash device. \param[in] command : Status register/ Flag Status Register \return \ref execution_status **/ static int32_t ReadStatusReg (uint8_t command, uint8_t *stat) { int32_t status = ARM_DRIVER_OK; uint32_t cmd[3]; status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(8) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Select Slave */ status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Set command */ cmd[0] = command; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (8 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Send command and receive register value */ status = ptrOSPI->Transfer (&cmd[0], &cmd[1], 2U); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; *stat = (uint8_t) cmd[1]; status = ControlSlaveSelect(false); return status; } /** \fn int32_t SetWriteEnable (void) \brief Set write enable before writing to flash. \param[in] none \return \ref execution_status **/ static int32_t SetWriteEnable (void) { int32_t status; uint32_t cmd; uint8_t val; status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(8) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } issi_event_flag = 0; /* Select slave */ status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } cmd = CMD_WRITE_ENABLE; status = ptrOSPI->Send(&cmd, 1U); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; status = ControlSlaveSelect(false); /* Reading status register will work only when FLASH is switched to Octal mode (after PowerControl(ARM_POWER_FULL)) */ if (ISSI_Flags & FLASH_POWER) { status = ReadStatusReg(CMD_READ_STATUS, &val); if((status == ARM_DRIVER_OK) && ((val & 0x02) == 0)) { return ARM_DRIVER_ERROR; } } return status; } /** \fn int32_t ARM_Flash_Initialize (ARM_Flash_SignalEvent_t cb_event) \brief Initialize the Flash Interface. \param[in] cb_event Pointer to \ref ARM_Flash_SignalEvent \return \ref execution_status **/ static int32_t ARM_Flash_Initialize (ARM_Flash_SignalEvent_t cb_event) { int32_t status; (void)cb_event; ISSI_FlashStatus.busy = 0U; ISSI_FlashStatus.error = 0U; status = ptrOSPI->Initialize(spi_callback_event); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } ISSI_Flags |= FLASH_INIT; return ARM_DRIVER_OK; } /** \fn int32_t ARM_Flash_Uninitialize (void) \brief De-initialize the Flash Interface. \return \ref execution_status **/ static int32_t ARM_Flash_Uninitialize (void) { ISSI_Flags = 0U; return ptrOSPI->Uninitialize(); } /** \fn int32_t ARM_Flash_PowerControl (ARM_POWER_STATE state) \brief Control the Flash interface power. \param[in] state Power state \return \ref execution_status **/ static int32_t ARM_Flash_PowerControl (ARM_POWER_STATE state) { int32_t status; uint32_t cmd[5]; switch (state) { case ARM_POWER_OFF: { ISSI_Flags &= ~FLASH_POWER; ISSI_FlashStatus.busy = 0U; ISSI_FlashStatus.error = 0U; return ptrOSPI->PowerControl(ARM_POWER_OFF); } case ARM_POWER_FULL: { if ((ISSI_Flags & FLASH_INIT) == 0U) { return ARM_DRIVER_ERROR; } if ((ISSI_Flags & FLASH_POWER) == 0U) { status = ptrOSPI->PowerControl(ARM_POWER_FULL); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(8) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Prepare command and address for setting flash in octal mode */ cmd[0] = CMD_WRITE_VOL_CONFIG; cmd[1] = (uint8_t)(IO_MODE_ADDRESS >> 16); cmd[2] = (uint8_t)(IO_MODE_ADDRESS >> 8); cmd[3] = (uint8_t)(IO_MODE_ADDRESS >> 0); cmd[4] = OCTAL_DDR; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_FRAME_FORMAT, ARM_OSPI_FRF_STANDRAD); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_DDR_MODE, ARM_OSPI_DDR_DISABLE); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_24_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_FRAME_FORMAT, ARM_OSPI_FRF_STANDRAD); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_DDR_MODE, ARM_OSPI_DDR_DISABLE); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Send(cmd, 5); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; status = ControlSlaveSelect(false); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Prepare buffer with command and address to configure default wait cycles */ cmd[0] = CMD_WRITE_VOL_CONFIG; cmd[1] = WAIT_CYCLE_ADDRESS; cmd[2] = DEFAULT_WAIT_CYCLES; cmd[3] = DEFAULT_WAIT_CYCLES; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_FRAME_FORMAT, ARM_OSPI_FRF_OCTAL); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_DDR_MODE, ARM_OSPI_DDR_ENABLE); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_32_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Send(cmd, 4); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; status = ControlSlaveSelect(false); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } ISSI_FlashStatus.busy = 0U; ISSI_FlashStatus.error = 0U; ISSI_Flags |= FLASH_POWER; } return ARM_DRIVER_OK; } case ARM_POWER_LOW: return ARM_DRIVER_ERROR_UNSUPPORTED; default: return ARM_DRIVER_ERROR; } } /** \fn int32_t ARM_Flash_ReadData (uint32_t addr, void *data, uint32_t cnt) \brief Read data from Flash. \param[in] addr Data address. \param[out] data Pointer to a buffer storing the data read from Flash. \param[in] cnt Number of data items to read. \return number of data items read or \ref execution_status **/ static int32_t ARM_Flash_ReadData (uint32_t addr, void *data, uint32_t cnt) { uint32_t cmd[2], data_cnt; uint16_t *data_ptr; int32_t status, num = 0; if ((addr > (FLASH_ISSI_SECTOR_COUNT * FLASH_ISSI_SECTOR_SIZE)) || (data == NULL) || ((addr + cnt) > (FLASH_ISSI_SECTOR_COUNT * FLASH_ISSI_SECTOR_SIZE))) { return ARM_DRIVER_ERROR_PARAMETER; } data_ptr = (uint16_t *) data; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_32_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (16 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Switch to 16 bit mode for reading data */ status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(16) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while(cnt) { status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* At frequency > 2.5 MHz, max no. of frames that can be read by OSPI is 256 (RX_FIFO_DEPTH) */ data_cnt = OSPI_MAX_RX_COUNT; if (data_cnt > cnt) { data_cnt = cnt; } /* Prepare command with address */ cmd[0] = CMD_READ_DATA; cmd[1] = addr; status = ptrOSPI->Transfer(cmd, data_ptr, data_cnt); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; status = ControlSlaveSelect(false); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* For 16 bit frames, update address by data_cnt * 2*/ addr += (data_cnt * 2); cnt -= data_cnt; data_ptr += data_cnt; num += data_cnt; } status = num; return status; } /* temporary buffer used in ProgramData below */ static uint32_t cmd[261]; /** \fn int32_t ARM_Flash_ProgramData (uint32_t addr, const void *data, uint32_t cnt) \brief Program data to Flash. \param[in] addr Data address. \param[in] data Pointer to a buffer containing the data to be programmed to Flash. \param[in] cnt Number of data items to program. \return number of data items programmed or \ref execution_status **/ static int32_t ARM_Flash_ProgramData (uint32_t addr, const void *data, uint32_t cnt) { const uint16_t *data_ptr; uint8_t val = 0; int32_t status = ARM_DRIVER_OK; uint32_t num = 0, data_cnt, index, iter = 0, it = 0; if ((addr > (FLASH_ISSI_SECTOR_COUNT * FLASH_ISSI_SECTOR_SIZE)) || (data == NULL) || ((addr + cnt) > (FLASH_ISSI_SECTOR_COUNT * FLASH_ISSI_SECTOR_SIZE))) { return ARM_DRIVER_ERROR_PARAMETER; } data_ptr = data; while (cnt) { ISSI_FlashStatus.busy = 1U; ISSI_FlashStatus.error = 0U; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } data_cnt = (FLASH_ISSI_PAGE_SIZE - (addr % FLASH_ISSI_PAGE_SIZE)) >> 1; if (data_cnt > cnt) { data_cnt = cnt; } /* Prepare command with address */ cmd[0] = CMD_PAGE_PROGRAM; cmd[1] = addr; index = 2; for ( it = 0; it < data_cnt; it++) { cmd[index++] = data_ptr[iter++]; } status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_32_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Switch to 16 bit mode for program data */ status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(16) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ControlSlaveSelect(true); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } do { /* Send data along with the command and address bytes (+2) */ status = ptrOSPI->Send(cmd, (data_cnt + 2)); } while (status == ARM_DRIVER_ERROR_BUSY); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; /* For 16 bit data frames, increment the byte address with 2 * data_cnt programmed */ addr += (data_cnt * 2); num += data_cnt; cnt -= data_cnt; status = ControlSlaveSelect(false); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Read status until device ready */ do { status = ReadStatusReg(CMD_READ_FLAG_STATUS, &val); if (status != ARM_DRIVER_OK) { break; } /* Check ISSI_Flags Status register value */ if ((val & FLAG_STATUS_BUSY) != 0U) { ISSI_FlashStatus.busy = 0U; } /* Check Program and Erase bits */ if ((val & FLAG_STATUS_ERROR) == 0U) { ISSI_FlashStatus.error = 0U; } else { ISSI_FlashStatus.error = 1U; } }while ((val & FLAG_STATUS_BUSY) == 0); } status = ControlSlaveSelect(false); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Number of data items programmed */ status = (int32_t)num; return status; } /** \fn int32_t ARM_Flash_EraseSector (uint32_t addr) \brief Erase Flash Sector. \param[in] addr Sector address \return \ref execution_status **/ static int32_t ARM_Flash_EraseSector (uint32_t addr) { int32_t status; uint8_t num; uint32_t cmd[2]; if (addr > (FLASH_ISSI_SECTOR_COUNT * FLASH_ISSI_SECTOR_SIZE)) { return ARM_DRIVER_ERROR_PARAMETER; } status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status == ARM_DRIVER_OK) { ISSI_FlashStatus.busy = 1U; ISSI_FlashStatus.error = 0U; status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(8) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Select Slave */ status = ControlSlaveSelect(true); if (status == ARM_DRIVER_OK) { /* Prepare command with address */ cmd[0] = CMD_SECTOR_ERASE; cmd[1] = addr; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_32_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Send(cmd, 2U); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; do { status = ReadStatusReg(CMD_READ_FLAG_STATUS, &num); if (status != ARM_DRIVER_OK) { break; } /* Check ISSI_Flags Status register value */ if ((num & FLAG_STATUS_BUSY) != 0U) { ISSI_FlashStatus.busy = 0U; } /* Check Program and Erase bits */ if ((num & FLAG_STATUS_ERROR) == 0U) { ISSI_FlashStatus.error = 0U; } else { ISSI_FlashStatus.error = 1U; } } while ((num & FLAG_STATUS_BUSY) == 0); } status = ControlSlaveSelect(false); } return status; } /** \fn int32_t ARM_Flash_EraseChip (void) \brief Erase complete Flash. Optional function for faster full chip erase. \return \ref execution_status **/ static int32_t ARM_Flash_EraseChip (void) { uint32_t cmd; uint8_t num; int32_t status; ISSI_FlashStatus.busy = 1U; ISSI_FlashStatus.error = 0U; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = SetWriteEnable(); if (status == ARM_DRIVER_OK) { status = ptrOSPI->Control(ARM_OSPI_MODE_MASTER | ARM_OSPI_DATA_BITS(8) | ARM_OSPI_SS_MASTER_SW, OSPI_BUS_SPEED); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } /* Select Slave */ status = ControlSlaveSelect(true); if (status == ARM_DRIVER_OK) { /* Prepare command */ cmd = CMD_BULK_ERASE; status = ptrOSPI->Control(ARM_OSPI_SET_ADDR_LENGTH_WAIT_CYCLE, (ARM_OSPI_ADDR_LENGTH_0_BITS << ARM_OSPI_ADDR_LENGTH_POS) | (0 << ARM_OSPI_WAIT_CYCLE_POS)); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } status = ptrOSPI->Send(&cmd, 1U); if (status != ARM_DRIVER_OK) { return ARM_DRIVER_ERROR; } while (!issi_event_flag) { __WFE(); } if (!(issi_event_flag & ARM_OSPI_EVENT_TRANSFER_COMPLETE)) { ControlSlaveSelect(false); issi_event_flag = 0; return ARM_DRIVER_ERROR; } issi_event_flag = 0; do { status = ReadStatusReg(CMD_READ_FLAG_STATUS, &num); if (status != ARM_DRIVER_OK) { break; } /* Check ISSI_Flags Status register value */ if ((num & FLAG_STATUS_BUSY) != 0U) { ISSI_FlashStatus.busy = 0U; } /* Check Program and Erase bits */ if ((num & FLAG_STATUS_ERROR) == 0U) { ISSI_FlashStatus.error = 0U; } else { ISSI_FlashStatus.error = 1U; } } while ((num & FLAG_STATUS_BUSY) == 0); } status = ControlSlaveSelect(false); } return status; } /** \fn ARM_FLASH_STATUS ARM_Flash_GetStatus (void) \brief Get Flash status. \return Flash status \ref ARM_FLASH_STATUS **/ static ARM_FLASH_STATUS ARM_Flash_GetStatus (void) { uint8_t val; if (ISSI_FlashStatus.busy == 1U) { /* Read flag status register */ if (ReadStatusReg (CMD_READ_FLAG_STATUS, &val) == ARM_DRIVER_OK) { /* Check "Program or erase controller" bit */ if ((val & FLAG_STATUS_BUSY) != 0U) { ISSI_FlashStatus.busy = 0U; } /* Check Erase and Program bits */ if ((val & FLAG_STATUS_ERROR) == 0U) { ISSI_FlashStatus.error = 0U; } else { ISSI_FlashStatus.error = 1U; } } else { ISSI_FlashStatus.error = 1U; } } return ISSI_FlashStatus; } /** \fn ARM_FLASH_INFO * ARM_Flash_GetInfo (void) \brief Get Flash information. \return Pointer to Flash information \ref ARM_FLASH_INFO **/ static ARM_FLASH_INFO * ARM_Flash_GetInfo (void) { return &ISSI_FlashInfo; } static ARM_FLASH_INFO * GetInfo (void) { return ARM_Flash_GetInfo(); } static ARM_DRIVER_VERSION GetVersion(void) { return ARM_Flash_GetVersion(); } static ARM_FLASH_CAPABILITIES GetCapabilities(void) { return ARM_Flash_GetCapabilities(); } static ARM_FLASH_STATUS GetStatus (void) { return ARM_Flash_GetStatus(); } static int32_t EraseChip (void) { return ARM_Flash_EraseChip(); } static int32_t EraseSector (uint32_t addr) { return ARM_Flash_EraseSector (addr); } static int32_t ProgramData (uint32_t addr, const void *data, uint32_t cnt) { return ARM_Flash_ProgramData (addr, data, cnt); } static int32_t ReadData (uint32_t addr, void *data, uint32_t cnt) { return ARM_Flash_ReadData (addr, data, cnt); } static int32_t PowerControl (ARM_POWER_STATE state) { return ARM_Flash_PowerControl (state); } static int32_t Initialize (ARM_Flash_SignalEvent_t cb_event) { return ARM_Flash_Initialize (cb_event); } static int32_t Uninitialize (void) { return ARM_Flash_Uninitialize (); } /* Flash Driver Control Block */ extern ARM_DRIVER_FLASH ARM_Driver_Flash_(DRIVER_FLASH_NUM); ARM_DRIVER_FLASH ARM_Driver_Flash_(DRIVER_FLASH_NUM) = { GetVersion, GetCapabilities, Initialize, Uninitialize, PowerControl, ReadData, ProgramData, EraseSector, EraseChip, GetStatus, GetInfo };