173 lines
5.9 KiB
C
173 lines
5.9 KiB
C
/* x25q_port.c */
|
|
|
|
#include "x25q.h"
|
|
#include "board_init.h"
|
|
|
|
/* index table be used to X25Q_BusWidth_Type translate to QSPI_BusWidth_Type. */
|
|
const static QSPI_BusWidth_Type X25Q_BUSWIDTH[5] = {QSPI_BusWidth_None, QSPI_BusWidth_1b, QSPI_BusWidth_2b, QSPI_BusWidth_4b};
|
|
/* index table be used to X25Q_WordWidth_Type translate to QSPI_WordWidth_Type. */
|
|
const static QSPI_WordWidth_Type X25Q_WORDWIDTH[4] = {QSPI_WordWidth_8b, QSPI_WordWidth_16b, QSPI_WordWidth_24b, QSPI_WordWidth_32b};
|
|
|
|
static void X25Q_QSPI_EnableDirectRead(void); /* enable qspi direct read. */
|
|
static void X25Q_QSPI_Init(void); /* init qspi module. */
|
|
static void X25Q_QSPI_TranslateXfer(QSPI_IndirectXferConf_Type * xfer_conf, X25Q_Xfer_Type * x25q_xfer); /* translate X25Q_Xfer_Type to QSPI_IndirectXferConf_Type. */
|
|
static void X25Q_QSPI_Read(X25Q_Xfer_Type * xfer); /* QSPI read. */
|
|
static void X25Q_QSPI_Write(X25Q_Xfer_Type * xfer); /* QSPI write. */
|
|
|
|
/* init spi module. */
|
|
void X25Q_HAL_Init(void)
|
|
{
|
|
X25Q_QSPI_Init();
|
|
X25Q_QSPI_EnableDirectRead(); /* enable direct read mode. */
|
|
}
|
|
|
|
/* read from spi module. */
|
|
void X25Q_HAL_Read(X25Q_Xfer_Type * xfer)
|
|
{
|
|
switch (xfer->DeviceIndex)
|
|
{
|
|
case X25Q_Device_W25Q64:
|
|
X25Q_QSPI_Read(xfer);
|
|
break;
|
|
default: /* invalid device index. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* write to spi module. */
|
|
void X25Q_HAL_Write(X25Q_Xfer_Type * xfer)
|
|
{
|
|
switch (xfer->DeviceIndex)
|
|
{
|
|
case X25Q_Device_W25Q64:
|
|
X25Q_QSPI_Write(xfer);
|
|
break;
|
|
default: /* invalid device index. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* init qspi module. */
|
|
static void X25Q_QSPI_Init(void)
|
|
{
|
|
QSPI_Init_Type qspi_init;
|
|
qspi_init.SckDiv = BOARD_QSPI_SCKDIV;
|
|
qspi_init.CsHighLevelCycles = BOARD_QSPI_CS_HIGH_CYCLE;
|
|
qspi_init.SpiMode = QSPI_SpiMode_3; /* suggest using SPI Mode 3. */
|
|
qspi_init.RxSampleDelay = BOARD_QSPI_RX_SAMPLE_DELAY;
|
|
|
|
QSPI_Init(BOARD_QSPI_PORT, &qspi_init);
|
|
}
|
|
|
|
static void X25Q_QSPI_EnableDirectRead(void)
|
|
{
|
|
/* enable QSPI direct read. */
|
|
QSPI_DirectXferConf_Type direct_conf;
|
|
direct_conf.CmdBusWidth = BOARD_QSPI_DIRECT_CMD_BUSWIDTH; /* fast read quad, cmd phase bus is 1b. */
|
|
direct_conf.CmdValue = BOARD_QSPI_DIRECT_CMD_VALUE; /* instruction. */
|
|
direct_conf.AddrBusWidth = BOARD_QSPI_DIRECT_ADR_BUSWIDTH; /* fast read quad, addr phase bus is 1b. */
|
|
direct_conf.AddrWordWidth = BOARD_QSPI_DIRECT_ADR_WORDWIDTH; /* 24 bit addr. */
|
|
direct_conf.AltBusWidth = QSPI_BusWidth_None; /* no alt phase. */
|
|
direct_conf.DummyCycles = BOARD_QSPI_DIRECT_DMY_CYCLES; /* wait 8 dummy cycles. */
|
|
direct_conf.DataBusWidth = BOARD_QSPI_DIRECT_DAT_BUSWIDTH; /* fast read quad, data phase bus is 4b. */
|
|
|
|
QSPI_EnableDirectRead(BOARD_QSPI_PORT, &direct_conf);
|
|
}
|
|
|
|
/* QSPI read. */
|
|
static void X25Q_QSPI_Read(X25Q_Xfer_Type * xfer)
|
|
{
|
|
QSPI_IndirectXferConf_Type xfer_conf;
|
|
|
|
/* translate xfer content to xfer_conf. */
|
|
X25Q_QSPI_TranslateXfer(&xfer_conf, xfer);
|
|
|
|
/* prepare to read data. */
|
|
QSPI_SetIndirectReadConf(BOARD_QSPI_PORT, &xfer_conf);
|
|
|
|
uint32_t dummy_remain = xfer->DummyBytes;
|
|
uint32_t data_count = 0u;
|
|
|
|
/* read data & dummy bytes. */
|
|
while( (QSPI_STATUS_XFER_DONE | QSPI_STATUS_FIFO_EMPTY) != (QSPI_GetStatus(BOARD_QSPI_PORT) & (QSPI_STATUS_XFER_DONE | QSPI_STATUS_FIFO_EMPTY) ) )
|
|
{
|
|
if ( 0u == (QSPI_GetStatus(BOARD_QSPI_PORT) & QSPI_STATUS_FIFO_EMPTY) )
|
|
{
|
|
if (dummy_remain > 0u)
|
|
{
|
|
QSPI_GetIndirectData(BOARD_QSPI_PORT); /* skip dummy byte. */
|
|
dummy_remain--;
|
|
}
|
|
else
|
|
{
|
|
xfer->DataBuf[data_count++] = QSPI_GetIndirectData(BOARD_QSPI_PORT); /* recv data. */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* clear xfer done status. */
|
|
QSPI_ClearStatus(BOARD_QSPI_PORT, QSPI_STATUS_XFER_DONE);
|
|
}
|
|
|
|
/* QSPI write. */
|
|
static void X25Q_QSPI_Write(X25Q_Xfer_Type * xfer)
|
|
{
|
|
QSPI_IndirectXferConf_Type xfer_conf;
|
|
|
|
/* translate xfer content to xfer_conf. */
|
|
X25Q_QSPI_TranslateXfer(&xfer_conf, xfer);
|
|
|
|
/* prepare to write data. */
|
|
QSPI_SetIndirectWriteConf(BOARD_QSPI_PORT, &xfer_conf);
|
|
|
|
uint32_t dummy_remain = xfer->DummyBytes;
|
|
uint32_t data_count = 0u;
|
|
|
|
/* write data & dummy bytes. */
|
|
while( QSPI_STATUS_XFER_DONE != (QSPI_GetStatus(BOARD_QSPI_PORT) & QSPI_STATUS_XFER_DONE) )
|
|
{
|
|
if ( 0u == (QSPI_GetStatus(BOARD_QSPI_PORT) & QSPI_STATUS_FIFO_FULL) )
|
|
{
|
|
if (dummy_remain > 0u)
|
|
{
|
|
QSPI_PutIndirectData(BOARD_QSPI_PORT, 0xFF); /* skip dummy byte. */
|
|
dummy_remain--;
|
|
}
|
|
else if (data_count < xfer->DataLen)
|
|
{
|
|
QSPI_PutIndirectData(BOARD_QSPI_PORT, xfer->DataBuf[data_count]); /* put data. */
|
|
data_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* clear xfer done status. */
|
|
QSPI_ClearStatus(BOARD_QSPI_PORT, QSPI_STATUS_XFER_DONE);
|
|
}
|
|
|
|
/* translate X25Q_Xfer_Type to QSPI_IndirectXferConf_Type. */
|
|
static void X25Q_QSPI_TranslateXfer(QSPI_IndirectXferConf_Type * xfer_conf, X25Q_Xfer_Type * x25q_xfer)
|
|
{
|
|
/* cmd phase. */
|
|
xfer_conf->CmdBusWidth = X25Q_BUSWIDTH[x25q_xfer->CmdBusWidth];
|
|
xfer_conf->CmdValue = x25q_xfer->CmdValue;
|
|
|
|
/* addr phase. */
|
|
xfer_conf->AddrBusWidth = X25Q_BUSWIDTH[x25q_xfer->AddrBusWidth];
|
|
xfer_conf->AddrWordWidth = X25Q_WORDWIDTH[x25q_xfer->AddrWordWidth];
|
|
xfer_conf->AddrValue = x25q_xfer->AddrValue;
|
|
|
|
/* no alt phase. */
|
|
xfer_conf->AltBusWidth = QSPI_BusWidth_None;
|
|
|
|
/* replace dummy phase by ignoring data. */
|
|
xfer_conf->DummyCycles = 0u;
|
|
|
|
/* data phase, including dummy bytes. */
|
|
xfer_conf->DataBusWidth = X25Q_BUSWIDTH[x25q_xfer->DataBusWidth];
|
|
xfer_conf->DataWordWidth = QSPI_WordWidth_8b;
|
|
xfer_conf->DataLen = x25q_xfer->DataLen + x25q_xfer->DummyBytes;
|
|
}
|
|
|
|
/* EOF. */
|