492 lines
20 KiB
C
492 lines
20 KiB
C
/*!
|
|
\file mbl_qspi_flash.c
|
|
\brief Non-secure MBL qspi flash file for GD32W51x WiFi SDK
|
|
|
|
\version 2021-10-30, V1.0.0, firmware for GD32W51x
|
|
*/
|
|
|
|
/*
|
|
Copyright (c) 2021, GigaDevice Semiconductor Inc.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
3. Neither the name of the copyright holder nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "gd32w51x.h"
|
|
#include "mbl_qspi_flash.h"
|
|
#include "platform_def.h"
|
|
|
|
/*!
|
|
\brief configure qspi flash gpio
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
static void qspi_flash_gpio_config(void)
|
|
{
|
|
rcu_periph_clock_enable(RCU_GPIOA);
|
|
rcu_periph_clock_enable(RCU_GPIOB);
|
|
|
|
gpio_af_set(GPIOA, GPIO_AF_3, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
|
|
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
|
|
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
|
|
|
|
gpio_af_set(GPIOB, GPIO_AF_3, GPIO_PIN_3 | GPIO_PIN_4);
|
|
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4);
|
|
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_3 | GPIO_PIN_4);
|
|
}
|
|
|
|
/*!
|
|
\brief enable qspi flash write
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
static void qspi_flash_write_enable(void)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
qspi_autopolling_struct sConfig;
|
|
|
|
/* Enable write operations ------------------------------------------ */
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = WRITE_ENABLE_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_NONE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_NONE;
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
qspi_command(&sCommand);
|
|
|
|
/* Configure automatic polling mode to wait for write enabling ---- */
|
|
sConfig.match = 0x02;
|
|
sConfig.mask = 0x02;
|
|
sConfig.match_mode = QSPI_MATCH_MODE_AND;
|
|
sConfig.statusbytes_size = 1;
|
|
sConfig.interval = 0x10;
|
|
sConfig.auto_stop = QSPI_AUTO_STOP_ENABLE;
|
|
|
|
sCommand.instruction = READ_STATUS_REG1_CMD;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
|
|
qspi_autopolling(&sCommand, &sConfig);
|
|
}
|
|
|
|
/*!
|
|
\brief configure automatic polling mode to wait for memory ready
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
static void qspi_flash_autopolling_ready(void)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
qspi_autopolling_struct sConfig;
|
|
|
|
/* Configure automatic polling mode to wait for memory ready ------ */
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = READ_STATUS_REG1_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_NONE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
sConfig.match = 0x00;
|
|
sConfig.mask = 0x01;
|
|
sConfig.match_mode = QSPI_MATCH_MODE_AND;
|
|
sConfig.statusbytes_size = 1;
|
|
sConfig.interval = 0x10;
|
|
sConfig.auto_stop = QSPI_AUTO_STOP_ENABLE;
|
|
|
|
qspi_autopolling(&sCommand, &sConfig);
|
|
}
|
|
|
|
static void qspi_tcfg_fmc_set(void)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
|
|
#if ( QSPI_FLASH_MODE == QSPI_FLASH_4_LINES )
|
|
sCommand.instruction_mode = (BITS(8,9) & ((uint32_t)(1) << 8)); // 1 line
|
|
sCommand.instruction = (BITS(0,7) & (uint32_t)(QUAD_IO_FAST_READ_CMD)); // 0xeb
|
|
sCommand.addr_mode = (BITS(10,11) & ((uint32_t)(3) << 10)); // 4 lines
|
|
sCommand.addr_size = (BITS(12,13) & ((uint32_t)(2) << 12)); // 24 bits address
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = (BITS(14,15) & ((uint32_t)(3) << 14)); // 4 lines
|
|
sCommand.altebytes_size = 0; // 8 bits
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = (BITS(18,22) & ((uint32_t)(4) << 18)); // 4 dummy cycles
|
|
sCommand.data_mode = (BITS(24,25) & ((uint32_t)(3) << 24)); // 4 lines
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = 0;
|
|
#elif ( QSPI_FLASH_MODE == QSPI_FLASH_2_LINES )
|
|
sCommand.instruction_mode = (BITS(8,9) & ((uint32_t)(1) << 8))(0x1); // 1 line
|
|
sCommand.instruction = (BITS(0,7) & (uint32_t)(DUAL_IO_FAST_READ_CMD)); // 0xBB
|
|
sCommand.addr_mode = (BITS(10,11) & ((uint32_t)(2) << 10)); // 2 lines
|
|
sCommand.addr_size = (BITS(12,13) & ((uint32_t)(2) << 12)); // 24 bits address
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = (BITS(14,15) & ((uint32_t)(2) << 14)); // 2 lines
|
|
sCommand.altebytes_size = 0; // 8 bits
|
|
sCommand.altebytes = 0;
|
|
/*
|
|
according to GD25Q16C datasheet, there are 4 alternate bits and 2 dummy cycles for 0xBB cmd,
|
|
but GD32W51x QSPI mode has alternate bits's limit to 8bits, so set sCommand.altebytes_size
|
|
to 8, so alternate data[3:0]'s transfer costs 2 cycles on two lines transfer, so set
|
|
sCommand.dummycycles to 0(which not means there is no dummy cycles)
|
|
*/
|
|
sCommand.dummycycles = 0; // 0 dummy cycles
|
|
sCommand.data_mode = (BITS(24,25) & ((uint32_t)(2) << 24)); // 2 lines
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = 0;
|
|
#elif ( QSPI_FLASH_MODE == QSPI_FLASH_1_LINE )
|
|
sCommand.instruction_mode = (BITS(8,9) & ((uint32_t)(1) << 8))(0x1); // 1 line
|
|
sCommand.instruction = (BITS(0,7) & (uint32_t)(READ_DATA_BYTE_CMD)); // 0x03
|
|
sCommand.addr_mode = (BITS(10,11) & ((uint32_t)(1) << 10)); // 1 line
|
|
sCommand.addr_size = (BITS(12,13) & ((uint32_t)(2) << 12)); // 24 bits address
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = 0; // no alternate byte
|
|
sCommand.altebytes_size = 0; // 8 bits
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0; // 0 dummy cycles
|
|
sCommand.data_mode = (BITS(24,25) & ((uint32_t)(1) << 24)); // 1 line
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = 0;
|
|
#endif
|
|
|
|
while((QSPI_CTL & QSPI_FLAG_BUSY) != 0U){
|
|
}
|
|
QSPI_TCFGF = sCommand.instruction_mode | sCommand.instruction | sCommand.addr_mode | \
|
|
sCommand.addr_size | sCommand.addr | sCommand.altebytes_mode | sCommand.altebytes | \
|
|
sCommand.dummycycles | sCommand.data_mode | sCommand.data_length | sCommand.sioo_mode;
|
|
}
|
|
|
|
/*!
|
|
\brief configure qspi flash to quad mode
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
static void qspi_flash_quad_enable_set(void)
|
|
{
|
|
uint32_t id = 0;
|
|
uint8_t mode_s = 0;
|
|
uint16_t mode = 0;
|
|
qspi_command_struct sCommand;
|
|
|
|
qspi_flash_read_id(&id);
|
|
|
|
qspi_flash_write_enable();
|
|
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = 0;
|
|
sCommand.addr_mode = QSPI_ADDR_NONE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
sCommand.data_length = 1;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
sCommand.instruction = READ_STATUS_REG1_CMD;
|
|
qspi_command(&sCommand);
|
|
qspi_receive(&mode_s);
|
|
|
|
mode |= (uint16_t)mode_s;
|
|
|
|
sCommand.instruction = READ_STATUS_REG_CMD;
|
|
qspi_command(&sCommand);
|
|
qspi_receive(&mode_s);
|
|
|
|
mode |= (uint16_t)mode_s << 8;
|
|
|
|
if (mode & 0x0200) {
|
|
/* quad mode, do nothing */
|
|
} else {
|
|
switch ((id & 0x00ff0000) >> 16) {
|
|
case 0x16: //GD32Q32
|
|
case 0x17: //GD32Q64
|
|
case 0x18: //GD32Q128
|
|
mode = mode >> 8;
|
|
mode |= 0x02;
|
|
sCommand.instruction = WRITE_STATUS_REG_CMD;//write flash status[s15-s8]
|
|
qspi_command(&sCommand);
|
|
qspi_transmit((uint8_t *)&mode);
|
|
break;
|
|
case 0x14: //GD32Q80
|
|
case 0x15: //GD32Q16
|
|
case 0x19: //GD32Q256
|
|
/* To fully support GD32Q256, user has to set bit8(ADS) of Status Registers
|
|
to enable 4-bytes Address Mode, which enabled by cmd 0xB7(the Enter 4-Byte
|
|
Address Mode command enables accessing the address length of 32-bit for
|
|
the memory area of higher density (larger than 128Mb), The device default
|
|
is in 24-bit address mode); and then change all qspi related operations's
|
|
address size from QSPI_ADDR_24_BITS to QSPI_ADDR_32_BITS. */
|
|
default:
|
|
mode |= (0x0200);
|
|
sCommand.instruction = WRITE_STATUS_REG1_CMD;//write flash status[s15-s0]
|
|
sCommand.data_length = 2;
|
|
qspi_command(&sCommand);
|
|
qspi_transmit((uint8_t *)&mode);
|
|
break;
|
|
}
|
|
|
|
qspi_flash_autopolling_ready();
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief configure qspi flash
|
|
\param[in] clock_prescaler: prescaler of qspi clock
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void qspi_flash_config(uint32_t clock_prescaler)
|
|
{
|
|
qspi_init_struct Init;
|
|
|
|
// rcu_periph_clock_enable(RCU_GTZC);
|
|
// tzgpc_tzspc_peripheral_attributes_config(TZGPC_PERIPH_QSPI_FLASHREG, TZGPC_TZSPC_PERIPH_SEC);
|
|
|
|
qspi_flash_gpio_config();
|
|
|
|
// qspi_deinit();
|
|
rcu_periph_clock_enable(RCU_QSPI);
|
|
|
|
Init.prescaler = clock_prescaler; /* QSPI clock = AHBCLK/(ClockPrescaler+1) */
|
|
Init.fifo_threshold = 4;
|
|
Init.sample_shift = QSPI_SAMPLE_SHIFTING_HALFCYCLE; // QSPI_SAMPLE_SHIFTING_NONE;
|
|
Init.flash_size = 23; /* 2^(FlashSize+1) ***** number of address bits = FlashSize + 1*/
|
|
Init.cs_high_time = QSPI_CS_HIGH_TIME_1_CYCLE;
|
|
Init.clock_mode = QSPI_CLOCK_MODE_0;
|
|
qspi_init(&Init);
|
|
|
|
qspi_flash_quad_enable_set();
|
|
qspi_tcfg_fmc_set();
|
|
}
|
|
|
|
/*!
|
|
\brief erase qspi flash sector
|
|
\param[in] address: qspi flash address
|
|
\param[out] none
|
|
\retval 0
|
|
*/
|
|
int32_t qspi_flash_sector_erase(uint32_t address)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
|
|
qspi_flash_write_enable();
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = SECTOR_ERASE_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_1_LINE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_NONE;
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
qspi_command(&sCommand);
|
|
qspi_flash_autopolling_ready();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief erase qspi flash full chip
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval 0
|
|
*/
|
|
int32_t qspi_flash_chip_erase(void)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
|
|
qspi_flash_write_enable();
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = CHIP_ERASE_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_NONE;
|
|
sCommand.addr_size = QSPI_ADDR_8_BITS;
|
|
sCommand.addr = 0;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_NONE;
|
|
sCommand.data_length = 0;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
qspi_command(&sCommand);
|
|
qspi_flash_autopolling_ready();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief read qspi flash device id
|
|
\param[in] None
|
|
\param[out] None
|
|
\retval 0
|
|
*/
|
|
int32_t qspi_flash_read_id(void *id)
|
|
{
|
|
qspi_command_struct sCommand = {0};
|
|
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = CHIP_READ_ID_CMD;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
sCommand.data_length = 3;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
qspi_command(&sCommand);
|
|
qspi_receive(id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief read qspi flash
|
|
\param[in] adress: flash's internal address to read from
|
|
\param[out] data: pointer to the buffer that receives the data read from the flash
|
|
\param[in] size: size of data read from flash
|
|
\retval 0
|
|
*/
|
|
int32_t qspi_flash_read(uint32_t address, void *data, uint32_t size)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
|
|
#if ( QSPI_FLASH_MODE == QSPI_FLASH_4_LINES )
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = QUAD_IO_FAST_READ_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_4_LINES;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_4_LINES;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 4;
|
|
sCommand.data_mode = QSPI_DATA_4_LINES;
|
|
sCommand.data_length = size;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
#elif ( QSPI_FLASH_MODE == QSPI_FLASH_2_LINES )
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = DUAL_IO_FAST_READ_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_2_LINES;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_2_LINES;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
/*
|
|
according to GD25Q16C datasheet, there are 4 alternate bits and 2 dummy cycles for 0xBB cmd,
|
|
but GD32W51x QSPI mode has alternate bits's limit to 8bits, so set sCommand.altebytes_size
|
|
to 8, so alternate data[3:0]'s transfer costs 2 cycles on two lines transfer, so set
|
|
sCommand.dummycycles to 0(which not means there is no dummy cycles)
|
|
*/
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_2_LINES;
|
|
sCommand.data_length = size;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
#elif ( QSPI_FLASH_MODE == QSPI_FLASH_1_LINE )
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = READ_DATA_BYTE_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_1_LINE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
sCommand.data_length = size;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
#endif
|
|
|
|
qspi_command(&sCommand);
|
|
qspi_receive(data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief program qspi flash page
|
|
\param[in] adress: flash's internal address to write to
|
|
\param[in] data: pointer to the buffer that receives the data read from the flash
|
|
\param[in] size: size of data read from flash
|
|
\param[out] none
|
|
\retval 0
|
|
*/
|
|
int32_t qspi_flash_page_program(uint32_t address, const uint8_t *data, uint32_t size)
|
|
{
|
|
qspi_command_struct sCommand;
|
|
|
|
/* Writing Sequence 4 Line------------------------------------------ */
|
|
qspi_flash_write_enable();
|
|
|
|
#if ( QSPI_FLASH_MODE == QSPI_FLASH_4_LINES )
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = QUAD_IN_FAST_PROG_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_1_LINE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_4_LINES;
|
|
sCommand.data_length = size;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
#elif ( QSPI_FLASH_MODE == QSPI_FLASH_2_LINES ) || ( QSPI_FLASH_MODE == QSPI_FLASH_1_LINE )
|
|
sCommand.instruction_mode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.instruction = PAGE_PROG_CMD;
|
|
sCommand.addr_mode = QSPI_ADDR_1_LINE;
|
|
sCommand.addr_size = QSPI_ADDR_24_BITS;
|
|
sCommand.addr = address;
|
|
sCommand.altebytes_mode = QSPI_ALTE_BYTES_NONE;
|
|
sCommand.altebytes_size = QSPI_ALTE_BYTES_8_BITS;
|
|
sCommand.altebytes = 0;
|
|
sCommand.dummycycles = 0;
|
|
sCommand.data_mode = QSPI_DATA_1_LINE;
|
|
sCommand.data_length = size;
|
|
sCommand.sioo_mode = QSPI_SIOO_INST_EVERY_CMD;
|
|
#endif
|
|
qspi_command(&sCommand);
|
|
qspi_transmit((uint8_t *)data);
|
|
qspi_flash_autopolling_ready();
|
|
|
|
return 0;
|
|
}
|