/* ================================================================== >>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<< ------------------------------------------------------------------ Copyright (c) 2019-2023 by Lattice Semiconductor Corporation ALL RIGHTS RESERVED ------------------------------------------------------------------ IMPORTANT: THIS FILE IS USED BY OR GENERATED BY the LATTICE PROPEL™ DEVELOPMENT SUITE, WHICH INCLUDES PROPEL BUILDER AND PROPEL SDK. Lattice grants permission to use this code pursuant to the terms of the Lattice Propel License Agreement. DISCLAIMER: LATTICE MAKES NO WARRANTIES ON THIS FILE OR ITS CONTENTS, WHETHER EXPRESSED, IMPLIED, STATUTORY, OR IN ANY PROVISION OF THE LATTICE PROPEL LICENSE AGREEMENT OR COMMUNICATION WITH LICENSEE, AND LATTICE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. LATTICE DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED HEREIN WILL MEET LICENSEE 'S REQUIREMENTS, OR THAT LICENSEE' S OPERATION OF ANY DEVICE, SOFTWARE OR SYSTEM USING THIS FILE OR ITS CONTENTS WILL BE UNINTERRUPTED OR ERROR FREE, OR THAT DEFECTS HEREIN WILL BE CORRECTED. LICENSEE ASSUMES RESPONSIBILITY FOR SELECTION OF MATERIALS TO ACHIEVE ITS INTENDED RESULTS, AND FOR THE PROPER INSTALLATION, USE, AND RESULTS OBTAINED THEREFROM. LICENSEE ASSUMES THE ENTIRE RISK OF THE FILE AND ITS CONTENTS PROVING DEFECTIVE OR FAILING TO PERFORM PROPERLY AND IN SUCH EVENT, LICENSEE SHALL ASSUME THE ENTIRE COST AND RISK OF ANY REPAIR, SERVICE, CORRECTION, OR ANY OTHER LIABILITIES OR DAMAGES CAUSED BY OR ASSOCIATED WITH THE SOFTWARE.IN NO EVENT SHALL LATTICE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS FILE OR ITS CONTENTS, EVEN IF LATTICE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LATTICE 'S SOLE LIABILITY, AND LICENSEE' S SOLE REMEDY, IS SET FORTH ABOVE. LATTICE DOES NOT WARRANT OR REPRESENT THAT THIS FILE, ITS CONTENTS OR USE THEREOF DOES NOT INFRINGE ON THIRD PARTIES' INTELLECTUAL PROPERTY RIGHTS, INCLUDING ANY PATENT. IT IS THE USER' S RESPONSIBILITY TO VERIFY THE USER SOFTWARE DESIGN FOR CONSISTENCY AND FUNCTIONALITY THROUGH THE USE OF FORMAL SOFTWARE VALIDATION METHODS. ------------------------------------------------------------------ ================================================================== */ #include "flash_cntl.h" #include /**@brief Initialize the base address of the Flash controller * This function can be used to initialize the flash controller. * @param this_flash_cntl handle for the flash controller * @param base_addr base address of the flash controller * @param page_program_size page program size of the flash controller * @param page_read_size page read size of the flash controller * @return initialization success status */ uint8_t flash_cntl_init(struct flash_cntl_instance *this_flash_cntl, uint32_t base_addr, uint32_t page_program_size, uint32_t page_read_size) { volatile struct flash_cntl_dev *flash_cntl; if(this_flash_cntl == NULL) return STS_ERR; this_flash_cntl->base = base_addr; this_flash_cntl->status = IDLE; // flash_cntl idle flash_cntl = (struct flash_cntl_dev *)this_flash_cntl->base; flash_cntl->page_program_size = page_program_size; flash_cntl->page_read_size = page_read_size; return STS_OK; } /** * @brief Read the Status Register in SPI flash and return the status. * Read only Bits 0 to 7 are represents the status of the controller. * This function can be used to read the flash controller status. * @param this_flash_cntl handle for the flash controller. * @param buff buffer to read the status rgister. * @return Read ok result. */ uint8_t flash_cntl_status_read(struct flash_cntl_instance *this_flash_cntl, uint32_t *buff) { if (this_flash_cntl == NULL || buff == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; *buff = flash_cntl->reg_status_read; return STS_OK; } /** * @brief Write to the Status Register in SPI flash and return status. * The Write only status Bits 0 to 7 can be written. * This function can be used to write the status bits. * @param this_flash_cntl handle for the flash controller. * @param status status to write to the status register. * @return ok status. */ uint8_t flash_cntl_status_write(struct flash_cntl_instance *this_flash_cntl, uint8_t status) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_status_write = status; return STS_OK; } /** * @brief Read the content of page of size PAGE_SIZE. * This function can be used to read the content from the specified Page address. * The data will be read on to the buffer of address passed as an argument. * @param this_flash_cntl handle for the flash controller. * @param addr Start address of the page. * @param buff buffer to receive the page data. * @return return the read status. */ uint8_t flash_cntl_page_read(struct flash_cntl_instance *this_flash_cntl, uint32_t addr, uint8_t *buff) { if(this_flash_cntl == NULL || buff == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev *)this_flash_cntl->base; flash_cntl->reg_flash_addr = addr; flash_cntl->reg_page_read = START_TRANSACTION; // status check to make sure transaction is done flash_cntl_spi_transaction_status(this_flash_cntl); memcpy(buff, (void *)(this_flash_cntl->base + PAGE_READ_BUFF_OFFSET), PAGE_SIZE); return STS_OK; } /** * @brief Write the data to the page. * The size of the page is specified by the macro PAGE_SIZE. * This function can be used to write the data to the specified page address. * @param this_flash_cntl handle for the flash controller * @param addr address of page to which data will be written * @param buff data buffer to be write into the page * @return write status */ uint8_t flash_cntl_page_program(struct flash_cntl_instance *this_flash_cntl, uint32_t addr, uint8_t *buff) { if (this_flash_cntl == NULL || buff == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; // write en flash_cntl->reg_wr_en = 1; flash_cntl_spi_transaction_status(this_flash_cntl); memcpy((void*) (this_flash_cntl->base + PAGE_PROGRAM_BUFF_OFFSET), buff, PAGE_SIZE); flash_cntl->reg_flash_addr = addr; flash_cntl->reg_page_program = START_TRANSACTION; flash_cntl_spi_transaction_status(this_flash_cntl); // write dis flash_cntl->reg_wr_dis = 1; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief 4k,32k,64k block erase or chip erase. * There are three types of block erase namely 4k,32k and 64k block erase * each erase type consist of a erase type register. * This function also include Chip erase functionality. * The chip erase is done by setting the 0th bit of the chip erase register. * This function can be used to erase 4k,32k,64k blocks erase or Whole chip erase. * @param this_flash_cntl handle for the flash controller * @param addr start address of block to be erase * @param mode 4k mode,32k mode or 64kmode block erase or chip erase selection * @return Erase status */ uint8_t flash_cntl_erase(struct flash_cntl_instance *this_flash_cntl, uint32_t addr, uint32_t mode) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_flash_addr = addr; // write en flash_cntl->reg_wr_en = 1; flash_cntl_spi_transaction_status(this_flash_cntl); switch(mode) { case FLASH_4K_ERASE: flash_cntl->reg_4k_erase = START_TRANSACTION; break; case FLASH_32K_ERASE: flash_cntl->reg_32k_erase = START_TRANSACTION; break; case FLASH_64K_ERASE: flash_cntl->reg_64k_erase = START_TRANSACTION; break; case FLASH_CHIP_ERASE: flash_cntl->reg_chip_erase = START_TRANSACTION; break; default: break; } flash_cntl_spi_transaction_status(this_flash_cntl); // write dis flash_cntl->reg_wr_dis = 1; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief Power down or power up mode selection for the flash through flash * controller. * There are 2 flash control register for power control namely * power down and power up register.In both register 0th bit initiate a * “Deep Power Down” or “Deep Power up” command in SPI flash by writing * a 1 or 0. * This function can be used to control the power consumption by the * SPI flash. * * @param this_flash_cntl handle for the flash controller * @param power_on mode of power * @return Status of the control requested */ uint8_t flash_cntl_pw(struct flash_cntl_instance *this_flash_cntl, uint32_t power_on) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; if (power_on) { flash_cntl->reg_power_up = 1; flash_cntl->reg_power_up = 0; } else { flash_cntl->reg_power_down = 1; flash_cntl->reg_power_down = 0; } return STS_OK; } /** * @brief Read the Manufacturer ID in the SPI flash. * The read only bits 0 to 7 of Manufacture id register represents the * manufacture ID of the SPI flash. * This function can be used to read the manufacture id of SPI flash. * @param this_flash_cntl handle for the flash controller * @param manu_id manufacture id * @return Read success status */ uint8_t flash_cntl_id_read(struct flash_cntl_instance *this_flash_cntl, uint32_t *manu_id) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; *manu_id = flash_cntl->reg_mf_id; return STS_OK; } /** * @brief Write 1 to write enable register to initiate a SPI flash “Write Enable” * command. * Write 1 to 0th bit of Write enable register to enable the write operation * in the flash. * This function can be used to send the write enable command to the SPI flash. * @param this_flash_cntl handle for the flash controller. * @return status of the operation. */ uint8_t flash_cntl_write_enable(struct flash_cntl_instance *this_flash_cntl) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_wr_en = 1; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief Write 1 to 0th bit of Write Disable register to Disable the write operation * in the flash. * This function can be used to send the write Disable command to the SPI flash. * @param this_flash_cntl handle for the flash controller. * @return status of the operation. */ uint8_t flash_cntl_write_disable(struct flash_cntl_instance *this_flash_cntl) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_wr_dis = 1; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief Command that is issued to SPI flash. * Configure the SPI flash command instruction set so that the core can * be used with a variety of SPI flash vendors. * The two 32 bit register are used to send the user command to the SPI * flash namely User CMD0 and User CMD1 registers. * This function can be used to send the 64 bit User command to SPI flash. * * Note : This API developed as per SPI flash controller 1.3.0UG * * @param this_flash_cntl handle for the flash controller * @param command Flash command to be issued * @param command_length size of the command to be issued * @return length of command return data */ uint8_t flash_issue_cmd(struct flash_cntl_instance *this_flash_cntl, uint8_t *command, uint32_t command_length, uint8_t return_length) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_user_cmd0 = command[0] | (command[1] >> 8) | (command[2] >> 16) | (command[3] >> 24); flash_cntl->reg_user_cmd1 = command[4] | (command[5] >> 8) | (command[6] >> 16) | (command[7] >> 24); flash_cntl->reg_user_cmd_length = command_length; flash_cntl->reg_user_cmd_init = 0x01; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief The data that is returned by SPI flash on a user-defined command. The * total bytes is determined by value in the User Return Length register. * Read the 32 bit user return data register which contains the data return * from SPI flash for the last user command issued. * This function can be used to send the user define command to SPI flash. * * Note : This API developed as per SPI flash controller 1.3.0UG * * @param this_flash_cntl handle for the flash controller * @param buff buffer for the command data read * @return status of operation */ uint8_t flash_read_cmd_data(struct flash_cntl_instance *this_flash_cntl, uint32_t *buff) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; *buff = flash_cntl->reg_user_read_data0; return STS_OK; } /** * @brief Configure the SPI flash controller to perform fast or slow reads. * The write only bit 0 of read speed register is used to set the speed * Read from the SPI flash. * This function is used to Control whether the SPI flash reads is * performed as fast reads or slow reads. * @param this_flash_cntl handle for the flash controller * @param speed read speed 0-low speed 1-high speed * @return status of operation */ uint8_t flash_cntl_read_speed(struct flash_cntl_instance *this_flash_cntl, uint32_t speed) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->read_speed = speed; return STS_OK; } /** * @brief The number of bytes to be written to SPI flash on a Page Program. The * minimum value is 0 and maximum value is PAGE_SIZE. * The SPI flash controller writes the number of bytes specified in this * field from the Page Program Buffer to the SPI flash. * This function can be used to set the page program Size. * @param this_flash_cntl handle for the flash controller * @param size write size in bytes * @return status of operation */ uint8_t flash_cntl_page_program_size( struct flash_cntl_instance *this_flash_cntl, uint32_t size) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->page_program_size = size; return STS_OK; } /** * @brief The number of bytes to be read from SPI flash on a Page Program. The * minimum value is 0 and maximum value is PAGE_SIZE. * The SPI flash controller reads the number of bytes specified in this * field from SPI flash in to the Page Read Buffer. * This function can be used to set the page read Size. * @param this_flash_cntl handle for the flash controller * @param size read size in bytes * @return status of operation */ uint8_t flash_cntl_page_read_size(struct flash_cntl_instance *this_flash_cntl, uint32_t size) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->page_read_size = size; return STS_OK; } /** * @brief This register is used to set the SPI flash address. * 24-bit or 32-bit flash address. * If AHB Address Width is set to 24, only 24-bit flash addressing is available. * @param this_flash_cntl handle for the flash controller * @param addr flash address to be set * @return status of operation */ uint8_t flash_cntl_set_addr(struct flash_cntl_instance *this_flash_cntl, uint32_t addr) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_flash_addr = addr; return STS_OK; } /** * @brief This register is used to set the SPI flash addressing mode. * If AHB Address Width is set to 24, only 24-bit flash addressing is available. * @param this_flash_cntl handle for the flash controller * @param mode 0 : 24-bit, 1 : 32-bit * @return status of operation */ uint8_t flash_cntl_set_addr_mode(struct flash_cntl_instance *this_flash_cntl, FLASH_ADDR_MODE mode) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_flash_mode = mode; return STS_OK; } /** * @brief This register is used to enable/disable page buffer write or read in AHB-L interface. * @param this_flash_cntl handle for the flash controller * @param enable 0: Disable, 1: Enable. * @return status of operation */ uint8_t flash_cntl_page_buffer(struct flash_cntl_instance *this_flash_cntl, bool enable) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->ahbl_page_buffer_enable = enable; return STS_OK; } /** * @brief This register is used to set the User Command registers. * @param this_flash_cntl handle for the flash controller * @param cmd enum USER_CMD, list of user commands * @param value value to write in user command register * @return status of operation */ uint8_t flash_cntl_set_user_cmd(struct flash_cntl_instance *this_flash_cntl, USER_CMD cmd, uint32_t value) { if (this_flash_cntl == NULL) return STS_ERR; volatile uint32_t *user_cmd = (uint32_t*)( this_flash_cntl->base + (0x80 + (cmd * 4))); *user_cmd = value; return STS_OK; } /** * @brief This register is used to get the User Command registers. * @param this_flash_cntl handle for the flash controller * @param cmd enum USER_CMD, list of user commands * @param value value to write in user command register * @return status of operation */ uint8_t flash_cntl_get_user_cmd(struct flash_cntl_instance *this_flash_cntl, USER_CMD cmd, uint32_t *buff) { if (this_flash_cntl == NULL) return STS_ERR; volatile uint32_t *user_cmd = (uint32_t*)( this_flash_cntl->base + (0x80 + (cmd * 4))); *buff = *user_cmd; return STS_OK; } /** * @brief This API is used to disable and enable the write protect signal from the flash controller to SPI flash memory * @param this_flash_cntl Handle for the flash controller * @param wr_protection Signal to control the write protect signal * @return Status of the operation. */ uint8_t flash_cntl_write_protect(struct flash_cntl_instance *this_flash_cntl, uint8_t wr_protection) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->write_protect_reg = wr_protection; return STS_OK; } /** * @brief function to test the Write/Read interface is ready * @param instance for the flash controller to handle * @return Returns the status of the Write/Read ready */ uint8_t flash_cntl_wip(struct flash_cntl_instance *this_flash_cntl) { uint32_t flash_status = 0; if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; // read the flash status register to check WIP bit do { flash_status = flash_cntl->reg_status_read; } while (flash_status & FLASH_STS_WIP); return STS_OK; } /** * @brief function to test SPI transaction to flash is done or not * @param instance for the flash controller to handle * @return Returns the status of the transaction status */ uint8_t flash_cntl_spi_transaction_status(struct flash_cntl_instance *this_flash_cntl) { uint32_t flash_status = 0; if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; // read the flash transaction status register to check transaction status bit do { flash_status = flash_cntl->transaction_status_reg; } while (flash_status & FLASH_TRNS_RD_STATUS); return STS_OK; } /** * @brief function to set the SCLK polarity during idle transaction * and to set the SCLK phase during active transaction. * @param instance for the flash controller to handle * @param clocking mode * @return Returns status of operation */ uint8_t flash_cntl_set_clock_mode(struct flash_cntl_instance *this_flash_cntl, uint8_t mode) { if(this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev *)this_flash_cntl->base; switch(mode) { case 0: flash_cntl->sclk_polarity_reg = 0; flash_cntl->sclk_phase_reg = 0; break; case 1: flash_cntl->sclk_polarity_reg = 0; flash_cntl->sclk_phase_reg = 1; break; case 2: flash_cntl->sclk_polarity_reg = 1; flash_cntl->sclk_phase_reg = 0; break; case 3: flash_cntl->sclk_polarity_reg = 1; flash_cntl->sclk_phase_reg = 1; break; default: flash_cntl->sclk_polarity_reg = 0; flash_cntl->sclk_phase_reg = 0; break; } return STS_OK; } /** * @brief function is used to set the clock rate. * @param instance for the flash controller to handle * @param rate clock rate * @return Returns status of operation */ uint8_t flash_cntl_set_clock_rate(struct flash_cntl_instance *this_flash_cntl, uint8_t rate) { if(this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev *)this_flash_cntl->base; flash_cntl->sclk_rate = rate; return STS_OK; } /** * @brief function is used to send custom write command and returns when complete * @param instance for the flash controller to handle * @param opcode of the custom command * @param include_address custom command includes an address (1=address, 0=no address) * @param address of the custom command * @param data pointer to data buffer * @param data_len length of data buffer (0-8) * @return Returns status of operation */ uint8_t flash_cntl_user_cmd_write(struct flash_cntl_instance *this_flash_cntl, uint8_t opcode ,uint8_t include_address , uint32_t address, uint8_t *data, uint8_t data_len ) { if (this_flash_cntl == NULL) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_user_cmd_opcode = opcode; flash_cntl->reg_user_cmd_addr = address; if (data != NULL) { flash_cntl->reg_user_cmd0 = data[0] | (data[1] >> 8) | (data[2] >> 16) | (data[3] >> 24); flash_cntl->reg_user_cmd1 = data[4] | (data[5] >> 8) | (data[6] >> 16) | (data[7] >> 24); } flash_cntl->reg_user_cmd_length = data_len; flash_cntl->reg_user_cmd_config = ((0 << 2) |(include_address << 1) |(FLASH_WRITE_DIR)); //Dummy length = 0 , Include Address :include_address , User Direction = 1 : Write flash_cntl->reg_user_cmd_init = FLASH_USER_CMD_INIT; flash_cntl_spi_transaction_status(this_flash_cntl); flash_cntl->reg_wr_dis = 1; flash_cntl_spi_transaction_status(this_flash_cntl); return STS_OK; } /** * @brief function is used to send custom read command and writes response into supplied data array * @param instance for the flash controller to handle * @param opcode of the custom command * @param include_address custom command includes an address (1=address, 0=no address) * @param address of the custom command * @param number of dummy bytes in command (0-16, 0=no dummy bytes) * @param pointer to return data buffer * @param length of data buffer (0-8) * @return Returns status of operation */ uint8_t flash_cntl_user_cmd_read(struct flash_cntl_instance *this_flash_cntl, uint8_t opcode ,uint8_t include_address , uint32_t address , uint8_t dummy_len , uint8_t *data, uint8_t data_len ) { uint32_t i; if ( (this_flash_cntl == NULL) || (data == NULL) ) return STS_ERR; volatile struct flash_cntl_dev *flash_cntl = (struct flash_cntl_dev*) this_flash_cntl->base; flash_cntl->reg_user_cmd_opcode = opcode; flash_cntl->reg_user_cmd_addr = address; flash_cntl->reg_user_cmd_length = ((dummy_len-1) << 4) | (data_len & 0x0F); flash_cntl->reg_user_cmd_config= (((dummy_len > 0) << 2) |(include_address << 1) |(FLASH_READ_DIR)); //Dummy length = (dummy_len > 0) , Include Address :include_address , User Direction = 0 : Read flash_cntl->reg_user_cmd_init = FLASH_USER_CMD_INIT; flash_cntl_spi_transaction_status(this_flash_cntl); for (i=0; i < data_len; i=i+1) { data[i] = ((uint8_t *) (&flash_cntl->reg_user_read_data0))[i]; } return STS_OK; }