Files
SDK_GD32W51x/NSPE/Firmware/GD32W51x_standard_peripheral/Source/gd32w51x_qspi.c
2023-05-18 18:53:00 +08:00

928 lines
39 KiB
C

/*!
\file gd32w51x_qspi.c
\brief QSPI driver
\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_qspi.h"
/* configure QSPI functionalmode */
static void qspi_config(qspi_command_struct* cmd, uint32_t functionalmode);
/* configure QSPI functionalmode in FMC mode secure register */
static void qspi_config_fmc_s(qspi_command_struct* cmd, uint32_t functionalmode);
/*!
\brief reset QSPI
\param[in] none
\param[out] none
\retval none
*/
void qspi_deinit(void)
{
rcu_periph_reset_enable(RCU_QSPIRST);
rcu_periph_reset_disable(RCU_QSPIRST);
}
/*!
\brief initialize the parameters of QSPI struct with the default values
\param[in] qspi_struct: QSPI parameter stuct
\param[out] none
\retval none
*/
void qspi_init_struct_para_init(qspi_init_struct* qspi_struct)
{
/* set the QSPI struct with the default values */
qspi_struct->clock_mode = QSPI_CLOCK_MODE_0;
qspi_struct->prescaler = 3;
qspi_struct->fifo_threshold = 16;
qspi_struct->sample_shift = QSPI_SAMPLE_SHIFTING_NONE;
qspi_struct->flash_size = 0x1F;
qspi_struct->cs_high_time = QSPI_CS_HIGH_TIME_1_CYCLE;
}
/*!
\brief initialize QSPI parameter
\param[in] qspi_struct: QSPI parameter initialization stuct members of the structure
and the member values are shown as below:
clockmode: QSPI_CLOCK_MODE_0, QSPI_CLOCK_MODE_3
fifothreshold: between 1 and 16
sampleshift: QSPI_SAMPLE_SHIFTING_NONE, QSPI_SAMPLE_SHIFTING_HALFCYCLE, QSPI_SAMPLE_SHIFTING_ONECYCLE
flashsize: between 0 and 28
chipselecthightime: QSPI_CS_HIGH_TIME_1_CYCLE, QSPI_CS_HIGH_TIME_2_CYCLE, QSPI_CS_HIGH_TIME_3_CYCLE,
QSPI_CS_HIGH_TIME_4_CYCLE, QSPI_CS_HIGH_TIME_5_CYCLE, QSPI_CS_HIGH_TIME_6_CYCLE,
QSPI_CS_HIGH_TIME_7_CYCLE, QSPI_CS_HIGH_TIME_8_CYCLE
prescale: between 0 and 255
\param[out] none
\retval none
*/
void qspi_init(qspi_init_struct* qspi_struct)
{
uint32_t reg = 0U;
reg = QSPI_CTL;
reg &= ~(QSPI_CTL);
reg |= ((qspi_struct->fifo_threshold - 1U) << 8);
QSPI_CTL = reg;
/* wait till BUSY flag reset */
while((QSPI_CTL & QSPI_CTL_BUSY) != 0U){
}
/* configure prescaler, sampleshift */
reg = QSPI_CTL;
reg &= ~((QSPI_CTL_PSC) | QSPI_SAMPLE_SHIFTING_HALFCYCLE);
reg |= (qspi_struct->prescaler << 24) | qspi_struct->sample_shift;
QSPI_CTL = reg;
/* configure flashsize, chipselecthightime, clockmode */
reg = QSPI_DCFG;
reg &= ~((QSPI_DCFG_FMSZ) | QSPI_CS_HIGH_TIME_8_CYCLE | QSPI_DCFG_CKMOD);
reg |= ((qspi_struct->flash_size << 16) | qspi_struct->cs_high_time | qspi_struct->clock_mode);
QSPI_DCFG = reg;
QSPI_CTL |= QSPI_CTL_QSPIEN;
QSPI_STAT |= QSPI_STAT_TERRIE;
}
/*!
\brief QSPI command parameter
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[out] none
\retval none
*/
void qspi_command(qspi_command_struct* cmd)
{
while((QSPI_CTL & QSPI_FLAG_BUSY) != 0U){
}
/* call the configuration function */
qspi_config(cmd, QSPI_INDIRECT_WRITE);
if(cmd->data_mode == QSPI_DATA_NONE){
/* when there is no data phase, the transfer start as soon as the configuration is done
so wait until TC flag is set to go back in idle state */
while((QSPI_STAT & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC = QSPI_STATC_TCC;
}
}
/*!
\brief enable quad SPI
\param[in] none
\param[out] none
\retval none
*/
void quad_spi_enable(void)
{
QSPI_CTL |= (uint32_t)QSPI_CTL_QSPIEN;
}
/*!
\brief disable quad SPI
\param[in] none
\param[out] none
\retval none
*/
void quad_spi_disable(void)
{
QSPI_CTL &= (uint32_t)(~QSPI_CTL_QSPIEN);
}
/*!
\brief enable QSPI DMA
\param[in] none
\param[out] none
\retval none
*/
void qspi_dma_enable(void)
{
QSPI_STAT |= (uint32_t)(QSPI_STAT_DMAEN);
}
/*!
\brief disable QSPI DMA
\param[in] qspi_periph: QSPI
\param[out] none
\retval none
*/
void qspi_dma_disable(void)
{
QSPI_STAT &= (uint32_t)(~QSPI_STAT_DMAEN);
}
/*!
\brief configure QSPI functionalmode
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] functionalmode: QSPI functionalmode select
only one parameter can be selected which is shown as below:
\arg QSPI_INDIRECT_WRITE
\arg QSPI_INDIRECT_READ
\arg QSPI_AUTO_POLLING
\arg QSPI_MEMORY_MAPPED
\param[out] none
\retval none
*/
static void qspi_config(qspi_command_struct* cmd, uint32_t functionalmode)
{
if((cmd->data_mode != QSPI_DATA_NONE) && (functionalmode != QSPI_MEMORY_MAPPED)){
/* configure QSPI_DTLEN register with the number of data to read or write */
QSPI_DTLEN = cmd->data_length - 1U;
}
if(cmd->instruction_mode != QSPI_INSTRUCTION_NONE){
if(cmd->altebytes_mode != QSPI_ALTE_BYTES_NONE){
/* configure QSPI_ALTE register with alternate bytes value */
QSPI_ALTE = cmd->altebytes;
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with instruction, address and alternate bytes */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_size | cmd->altebytes_mode |
cmd->addr_size | cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED ){
/* configure QSPI_ADDR register with address value */
QSPI_ADDR = cmd->addr;
}
}
else{
/* command with instruction and alternate bytes */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_size | cmd->altebytes_mode |
cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
}
}
else{
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with instruction and address */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_size | cmd->addr_mode |
cmd->instruction_mode | cmd->instruction | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR register with address value */
QSPI_ADDR = cmd->addr;
}
}
else{
/* command with only instruction */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
}
}
}
else{
if(cmd->altebytes_mode != QSPI_ALTE_BYTES_NONE){
/* configure QSPI_ALTE register with alternate bytes value */
QSPI_ALTE = cmd->altebytes;
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with address and alternate bytes */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->altebytes_size | cmd->addr_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR register with address value */
QSPI_ADDR = cmd->addr;
}
}
else{
/* command with only alternate bytes */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->altebytes_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
}
}
else{
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with only address */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR register with address value */
QSPI_ADDR = cmd->addr;
}
}
else{
/* command with only data phase */
if(cmd->data_mode != QSPI_DATA_NONE){
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_mode |
cmd->instruction_mode | functionalmode;
}
}
}
}
}
/*!
\brief QSPI transmit data
\param[in] tdata: 8-bit data
\param[out] none
\retval none
*/
void qspi_transmit(uint8_t *tdata)
{
uint32_t TxCounter;
TxCounter = QSPI_DTLEN + 1U;
QSPI_TCFG = (QSPI_TCFG & ~QSPI_MEMORY_MAPPED) | QSPI_INDIRECT_WRITE;
while(TxCounter > 0U){
while((QSPI_STAT & QSPI_FLAG_FT) == 0U){
}
*(uint8_t *)(QSPI + 0x00000020U) = *tdata++;
TxCounter--;
}
while((QSPI_STAT & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC = QSPI_STATC_TCC;
}
/*!
\brief QSPI receive data
\param[in] rdata: empty array
\param[out] 8-bit data array
\retval none
*/
void qspi_receive(uint8_t *rdata)
{
uint32_t RxCounter, addr;
RxCounter = QSPI_DTLEN + 1U;
addr = QSPI_ADDR;
QSPI_TCFG = (QSPI_TCFG & ~QSPI_MEMORY_MAPPED) | QSPI_INDIRECT_READ;
/* start the transfer by re-writing the address in ADDR register */
QSPI_ADDR = addr;
while(RxCounter > 0U){
while((QSPI_STAT & (QSPI_FLAG_FT | QSPI_FLAG_TC)) == 0U){
}
*rdata++ = *(uint8_t *)(QSPI + 0x00000020U);
RxCounter--;
}
while((QSPI_STAT & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC = QSPI_STATC_TCC;
}
/*!
\brief configure QSPI autopolling mode
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] cfg: autopolling struct initialization stuct members of the structure
and the member values are shown as below:
match: between 0 and 0xFFFFFFFF
mask: between 0 and 0xFFFFFFFF
interval: between 0 and 0xFFFF
statusbytessize: between 1 and 4
matchmode: QSPI_MATCH_MODE_AND, QSPI_MATCH_MODE_OR
automaticstop: QSPI_AUTO_STOP_DISABLE, QSPI_AUTO_STOP_ENABLE
\param[out] none
\retval none
*/
void qspi_autopolling(qspi_command_struct *cmd, qspi_autopolling_struct *cfg)
{
/* wait till BUSY flag reset */
while((QSPI_CTL & QSPI_FLAG_BUSY) != 0U){
}
QSPI_STATMATCH = cfg->match;
QSPI_STATMK = cfg->mask;
QSPI_INTERVAL = cfg->interval;
QSPI_CTL = (QSPI_CTL & (~(QSPI_CTL_SPS | QSPI_CTL_SPMOD))) | (cfg->match_mode | cfg->auto_stop);
cmd->data_length = cfg->statusbytes_size;
qspi_config(cmd, QSPI_AUTO_POLLING);
while((QSPI_STAT & QSPI_FLAG_SM) == 0U){
}
QSPI_STATC = QSPI_STATC_SMC;
}
/*!
\brief configure QSPI memorymapped mode
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] timeout: 0-0xFFFF
\param[in] toen: QSPI_TOEN_DISABLE, QSPI_TOEN_ENABLE
\param[out] none
\retval none
*/
void qspi_memorymapped(qspi_command_struct *cmd, uint16_t timeout, uint32_t toen)
{
while((QSPI_CTL & QSPI_FLAG_BUSY) != 0U){
}
/* configure QSPI: CTL register with timeout counter enable */
QSPI_CTL = (QSPI_CTL & ~QSPI_CTL_TMOUTEN) | toen;
if(toen == QSPI_CTL_TMOUTEN){
/* configure QSPI: TMOUT register with the timeout value */
QSPI_TMOUT = timeout;
QSPI_STATC = QSPI_STATC_TMOUTC;
/* enable the QSPI TimeOut interrupt */
QSPI_CTL |= QSPI_FLAG_TMOUTIE;
}
qspi_config(cmd, QSPI_MEMORY_MAPPED);
}
/*!
\brief abort the current transmission.
\param[in] none
\param[out] none
\retval none
*/
void qspi_abort(void)
{
QSPI_CTL |= QSPI_CTL_ABORT;
}
/* if QSPI in FMC mode, use above functions to access secure region. */
/*!
\brief QSPI command parameter
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[out] none
\retval none
*/
void qspi_command_fmc_s(qspi_command_struct* cmd)
{
while((QSPI_CTL & QSPI_FLAG_BUSY) != 0U){
}
/* call the configuration function */
qspi_config_fmc_s(cmd, QSPI_INDIRECT_WRITE);
if(cmd->data_mode == QSPI_DATA_NONE){
/* when there is no data phase, the transfer start as soon as the configuration is done
so wait until TC flag is set to go back in idle state */
while((QSPI_STAT_SEC & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC_SEC = QSPI_STATC_TCC;
}
}
/*!
\brief configure QSPI functionalmode in FMC mode secure register
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] functionalmode: QSPI functionalmode select
only one parameter can be selected which is shown as below:
\arg QSPI_INDIRECT_WRITE
\arg QSPI_INDIRECT_READ
\arg QSPI_AUTO_POLLING
\arg QSPI_MEMORY_MAPPED
\param[out] none
\retval none
*/
static void qspi_config_fmc_s(qspi_command_struct* cmd, uint32_t functionalmode)
{
if((cmd->data_mode != QSPI_DATA_NONE) && (functionalmode != QSPI_MEMORY_MAPPED)){
/* configure QSPI_DTLEN register with the number of data to read or write */
QSPI_DTLEN_SEC = cmd->data_length - 1U;
}
if(cmd->instruction_mode != QSPI_INSTRUCTION_NONE){
if(cmd->altebytes_mode != QSPI_ALTE_BYTES_NONE){
/* configure QSPI_ALTE register with alternate bytes value */
QSPI_ALTE_SEC = cmd->altebytes;
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with instruction, address and alternate bytes */
/* configure QSPI_TCFG register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_size | cmd->altebytes_mode |
cmd->addr_size | cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED ){
/* configure QSPI_ADDR register with address value */
QSPI_ADDR_SEC = cmd->addr;
}
}
else{
/* command with instruction and alternate bytes */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_size | cmd->altebytes_mode |
cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
}
}
else{
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with instruction and address */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_size | cmd->addr_mode |
cmd->instruction_mode | cmd->instruction | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR_SEC register with address value */
QSPI_ADDR_SEC = cmd->addr;
}
}
else{
/* command with only instruction */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_mode | cmd->instruction_mode |
cmd->instruction | functionalmode;
}
}
}
else{
if(cmd->altebytes_mode != QSPI_ALTE_BYTES_NONE){
/* configure QSPI_ALTE_SEC register with alternate bytes value */
QSPI_ALTE_SEC = cmd->altebytes;
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with address and alternate bytes */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->altebytes_size | cmd->addr_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR_SEC register with address value */
QSPI_ADDR_SEC = cmd->addr;
}
}
else{
/* command with only alternate bytes */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->altebytes_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
}
}
else{
if(cmd->addr_mode != QSPI_ADDR_NONE){
/* command with only address */
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_size |
cmd->addr_mode | cmd->instruction_mode | functionalmode;
if(functionalmode != QSPI_MEMORY_MAPPED){
/* configure QSPI_ADDR_SEC register with address value */
QSPI_ADDR_SEC = cmd->addr;
}
}
else{
/* command with only data phase */
if(cmd->data_mode != QSPI_DATA_NONE){
/* configure QSPI_TCFG_SEC register with all communications parameters */
QSPI_TCFG_SEC = cmd->data_mode | (cmd->dummycycles << 18) | cmd->sioo_mode |
cmd->altebytes_mode | cmd->addr_mode |
cmd->instruction_mode | functionalmode;
}
}
}
}
}
/*!
\brief QSPI transmit data in FMC mode secure register
\param[in] tdata: 8-bit data
\param[out] none
\retval none
*/
void qspi_transmit_fmc_s(uint8_t *tdata)
{
uint32_t TxCounter;
TxCounter = QSPI_DTLEN_SEC + 1U;
QSPI_TCFG_SEC = (QSPI_TCFG_SEC & ~QSPI_MEMORY_MAPPED) | QSPI_INDIRECT_WRITE;
while(TxCounter > 0U){
while((QSPI_STAT_SEC & QSPI_FLAG_FT) == 0U){
}
*(uint8_t *)(QSPI + 0x00000120U) = *tdata++;
TxCounter--;
}
while((QSPI_STAT_SEC & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC_SEC = QSPI_STATC_TCC;
}
/*!
\brief QSPI receive data in FMC mode secure register
\param[in] rdata: empty array
\param[out] 8-bit data array
\retval none
*/
void qspi_receive_fmc_s(uint8_t *rdata)
{
uint32_t RxCounter, addr;
RxCounter = QSPI_DTLEN_SEC + 1U;
addr = QSPI_ADDR_SEC;
QSPI_TCFG_SEC = (QSPI_TCFG_SEC & ~QSPI_MEMORY_MAPPED) | QSPI_INDIRECT_READ;
/* start the transfer by re-writing the address in ADDR register */
QSPI_ADDR_SEC = addr;
while(RxCounter > 0U){
while((QSPI_STAT_SEC & (QSPI_FLAG_FT | QSPI_FLAG_TC)) == 0U){
}
*rdata++ = *(uint8_t *)(QSPI + 0x00000120U);
RxCounter--;
}
while((QSPI_STAT_SEC & QSPI_FLAG_TC) == 0U){
}
QSPI_STATC_SEC = QSPI_STATC_TCC;
}
/*!
\brief configure QSPI autopolling mode in FMC mode secure register
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] cfg: autopolling struct initialization stuct members of the structure
and the member values are shown as below:
match: between 0 and 0xFFFFFFFF
mask: between 0 and 0xFFFFFFFF
interval: between 0 and 0xFFFF
statusbytessize: between 1 and 4
matchmode: QSPI_MATCH_MODE_AND, QSPI_MATCH_MODE_OR
automaticstop: QSPI_AUTOMATIC_STOP_DISABLE, QSPI_AUTOMATIC_STOP_ENABLE
\param[out] none
\retval none
*/
void qspi_autopolling_fmc_s(qspi_command_struct *cmd, qspi_autopolling_struct *cfg)
{
/* wait till BUSY flag reset */
while((QSPI_STAT_SEC & QSPI_FLAG_BUSY) != 0U){
}
QSPI_STATMATCH = cfg->match;
QSPI_STATMK = cfg->mask;
QSPI_INTERVAL = cfg->interval;
QSPI_CTL = (QSPI_CTL & (~(QSPI_CTL_SPS | QSPI_CTL_SPMOD))) | (cfg->match_mode | cfg->auto_stop);
cmd->data_length = cfg->statusbytes_size;
qspi_config_fmc_s(cmd, QSPI_AUTO_POLLING);
while((QSPI_STAT_SEC & QSPI_FLAG_SM) == 0U){
}
QSPI_STATC_SEC = QSPI_STATC_SMC;
}
/*!
\brief configure QSPI memorymapped mode in FMC mode secure register
\param[in] cmd: QSPI command parameter initialization stuct members of the structure
and the member values are shown as below:
instruction: reference flash commands description
address: 0-flash size
alternatebytes: 0-0xFFFFFFFF
addresssize: QSPI_ADDR_8_BITS, QSPI_ADDR_16_BITS, QSPI_ADDR_24_BITS, QSPI_ADDR_32_BITS
alternatebytessize: QSPI_ALTE_BYTES_8_BITS, QSPI_ALTE_BYTES_16_BITS,
QSPI_ALTE_BYTES_24_BITS, QSPI_ALTE_BYTES_32_BITS
dummycycles: between 0 and 31
instructionmode: QSPI_INSTRUCTION_NONE, QSPI_INSTRUCTION_1_LINE,
QSPI_INSTRUCTION_2_LINES, QSPI_INSTRUCTION_4_LINES
addressmode: QSPI_ADDR_NONE, QSPI_ADDR_1_LINE, QSPI_ADDR_2_LINES, QSPI_ADDR_4_LINES
alternatebytemode: QSPI_ALTE_BYTES_NONE, QSPI_ALTE_BYTES_1_LINE,
QSPI_ALTE_BYTES_2_LINES, QSPI_ALTE_BYTES_4_LINES
datamode: QSPI_DATA_NONE, QSPI_DATA_1_LINE, QSPI_DATA_2_LINES, QSPI_DATA_4_LINES
nbdata: 0-0xFFFFFFFF
sioomode: QSPI_SIOO_INST_EVERY_CMD, QSPI_SIOO_INST_ONLY_FIRST_CMD
\param[in] timeout: 0-0xFFFF
\param[in] toen: QSPI_TMOUTEN_DISABLE, QSPI_TMOUTEN_ENABLE
\param[out] none
\retval none
*/
void qspi_memorymapped_fmc_s(qspi_command_struct *cmd, uint16_t timeout, uint32_t toen)
{
while((QSPI_STAT_SEC & QSPI_FLAG_BUSY) != 0U){
}
/* configure QSPI: CTL register with timeout counter enable */
QSPI_CTL = (QSPI_CTL & ~QSPI_CTL_TMOUTEN) | toen;
if(toen == QSPI_CTL_TMOUTEN){
/* configure QSPI: TMOUT register with the timeout value */
QSPI_TMOUT = timeout;
QSPI_STATC_SEC = QSPI_STATC_TMOUTC;
/* enable the QSPI timeout interrupt */
QSPI_CTL |= QSPI_FLAG_TMOUTIE;
}
qspi_config_fmc_s(cmd, QSPI_MEMORY_MAPPED);
}
/*!
\brief enable QSPI interrupt
\param[in] interrupt: QSPI interrupt
only one parameter can be selected which is shown as below:
\arg QSPI_INT_TC: transfer complete interrupt
\arg QSPI_INT_FT: FIFO threshold interrupt
\arg QSPI_INT_TERR: transfer error interrupt
\arg QSPI_INT_SM: status match interrupt
\arg QSPI_INT_TMOUT: timeout interrupt
\arg QSPI_INT_WS: wrong start sequence interrupt
\param[out] none
\retval none
*/
void qspi_interrupt_enable( uint8_t interrupt)
{
switch(interrupt){
/* QSPI transfer complete interrupt */
case QSPI_INT_TC:
QSPI_STAT |= (uint32_t)QSPI_STAT_TCIE;
break;
/* QSPI FIFO threshold interrupt */
case QSPI_INT_FT:
QSPI_STAT |= (uint32_t)QSPI_STAT_FTIE;
break;
/* QSPI transfer error interrupt */
case QSPI_INT_TERR:
QSPI_STAT |= (uint32_t)QSPI_STAT_TERRIE;
break;
/* QSPI status match interrupt */
case QSPI_INT_SM:
QSPI_STAT |= (uint32_t)QSPI_STAT_SMIE;
break;
/* QSPI timeout interrupt */
case QSPI_INT_TMOUT:
QSPI_STAT |= (uint32_t)QSPI_STAT_TMOUTIE;
break;
/* QSPI wrong start sequence interrupt */
case QSPI_INT_WS:
QSPI_STAT |= (uint32_t)QSPI_STAT_WSIE;
break;
default:
break;
}
}
/*!
\brief disable QSPI interrupt
\param[in] interrupt: QSPI interrupt
only one parameter can be selected which is shown as below:
\arg QSPI_INT_TC: transfer complete interrupt
\arg QSPI_INT_FT: FIFO threshold interrupt
\arg QSPI_INT_TERR: transfer error interrupt
\arg QSPI_INT_SM: status match interrupt
\arg QSPI_INT_TMOUT: timeout interrupt
\arg QSPI_INT_WS: wrong start sequence interrupt
\param[out] none
\retval none
*/
void qspi_interrupt_disable( uint8_t interrupt)
{
switch(interrupt){
/* QSPI transfer complete interrupt */
case QSPI_INT_TC:
QSPI_STAT &= (uint32_t)QSPI_STAT_TCIE;
break;
/* QSPI FIFO threshold interrupt */
case QSPI_INT_FT:
QSPI_STAT &= (uint32_t)QSPI_STAT_FTIE;
break;
/* QSPI transfer error interrupt */
case QSPI_INT_TERR:
QSPI_STAT &= (uint32_t)QSPI_STAT_TERRIE;
break;
/* QSPI status match interrupt */
case QSPI_INT_SM:
QSPI_STAT &= (uint32_t)QSPI_STAT_SMIE;
break;
/* QSPI timeout interrupt */
case QSPI_INT_TMOUT:
QSPI_STAT &= (uint32_t)QSPI_STAT_TMOUTIE;
break;
/* QSPI wrong start sequence interrupt */
case QSPI_INT_WS:
QSPI_STAT &= (uint32_t)QSPI_STAT_WSIE;
break;
default:
break;
}
}
/*!
\brief get QSPI flag status
\param[in] flag: QSPI flag status
one or more parameters can be selected which are shown as below:
\arg QSPI_FLAG_TERR: transfer error flag
\arg QSPI_FLAG_TC: transfer complete flag
\arg QSPI_FLAG_FT: FIFO threshold flag
\arg QSPI_FLAG_SM: status match flag
\arg QSPI_FLAG_TMOUT: timeout flag
\arg QSPI_FLAG_WS: wrong start sequence flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus qspi_flag_get(uint32_t flag)
{
if(RESET != (QSPI_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear QSPI flag status
\param[in] flag: QSPI flag status
one or more parameters can be selected which are shown as below:
\arg QSPI_FLAG_TERR: transfer error flag
\arg QSPI_FLAG_TC: transfer complete flag
\arg QSPI_FLAG_SM: status match flag
\arg QSPI_FLAG_TMOUT: timeout flag
\arg QSPI_FLAG_WS: wrong start sequence flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
void qspi_flag_clear( uint32_t flag)
{
QSPI_STATC |= (uint32_t)flag;
}