1384 lines
41 KiB
C
1384 lines
41 KiB
C
/**************************************************************************//**
|
|
* @file spim.c
|
|
* @version V1.00
|
|
* @brief M460 series SPIM driver
|
|
*
|
|
* @copyright SPDX-License-Identifier: Apache-2.0
|
|
* @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
|
|
*****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "NuMicro.h"
|
|
|
|
|
|
/** @addtogroup Standard_Driver Standard Driver
|
|
@{
|
|
*/
|
|
|
|
/** @addtogroup SPIM_Driver SPIM Driver
|
|
@{
|
|
*/
|
|
|
|
int32_t g_SPIM_i32ErrCode = 0; /*!< SPIM global error code */
|
|
|
|
/** @addtogroup SPIM_EXPORTED_FUNCTIONS SPIM Exported Functions
|
|
@{
|
|
*/
|
|
|
|
|
|
/** @cond HIDDEN_SYMBOLS */
|
|
|
|
|
|
#define ENABLE_DEBUG 0
|
|
|
|
#if ENABLE_DEBUG
|
|
#define SPIM_DBGMSG printf
|
|
#else
|
|
#define SPIM_DBGMSG(...) do { } while (0) /* disable debug */
|
|
#endif
|
|
|
|
static volatile uint8_t g_Supported_List[] =
|
|
{
|
|
MFGID_WINBOND,
|
|
MFGID_MXIC,
|
|
MFGID_EON,
|
|
MFGID_ISSI,
|
|
MFGID_SPANSION
|
|
};
|
|
|
|
static void N_delay(int n);
|
|
static void SwitchNBitOutput(uint32_t u32NBit);
|
|
static void SwitchNBitInput(uint32_t u32NBit);
|
|
static void spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx);
|
|
static void spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx);
|
|
static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
|
|
static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
|
|
static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
|
|
static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit);
|
|
static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
|
|
static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit);
|
|
static int spim_is_write_done(uint32_t u32NBit);
|
|
static int spim_wait_write_done(uint32_t u32NBit);
|
|
static void spim_set_write_enable(int isEn, uint32_t u32NBit);
|
|
static void spim_enable_spansion_quad_mode(int isEn);
|
|
static void spim_eon_set_qpi_mode(int isEn);
|
|
static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit);
|
|
static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
|
|
uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync);
|
|
static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
|
|
uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync);
|
|
|
|
|
|
static void N_delay(int n)
|
|
{
|
|
while (n-- > 0)
|
|
{
|
|
__NOP();
|
|
}
|
|
}
|
|
|
|
static void SwitchNBitOutput(uint32_t u32NBit)
|
|
{
|
|
switch (u32NBit)
|
|
{
|
|
case 1UL:
|
|
SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
|
|
break;
|
|
|
|
case 2UL:
|
|
SPIM_ENABLE_DUAL_OUTPUT_MODE(); /* 2-bit, Output. */
|
|
break;
|
|
|
|
case 4UL:
|
|
SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 4-bit, Output. */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void SwitchNBitInput(uint32_t u32NBit)
|
|
{
|
|
switch (u32NBit)
|
|
{
|
|
case 1UL:
|
|
SPIM_ENABLE_SING_INPUT_MODE(); /* 1-bit, Input. */
|
|
break;
|
|
|
|
case 2UL:
|
|
SPIM_ENABLE_DUAL_INPUT_MODE(); /* 2-bit, Input. */
|
|
break;
|
|
|
|
case 4UL:
|
|
SPIM_ENABLE_QUAD_INPUT_MODE(); /* 4-bit, Input. */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Write data to SPI slave.
|
|
* @param pu8TxBuf Transmit buffer.
|
|
* @param u32NTx Number of bytes to transmit.
|
|
* @return None.
|
|
* @note This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
|
|
*/
|
|
static void spim_write(uint8_t pu8TxBuf[], uint32_t u32NTx)
|
|
{
|
|
uint32_t buf_idx = 0UL;
|
|
uint32_t u32TimeOutCount = 0UL;
|
|
|
|
g_SPIM_i32ErrCode = 0;
|
|
|
|
while (u32NTx)
|
|
{
|
|
uint32_t dataNum = 0UL, dataNum2;
|
|
|
|
if (u32NTx >= 16UL)
|
|
{
|
|
dataNum = 4UL;
|
|
}
|
|
else if (u32NTx >= 12UL)
|
|
{
|
|
dataNum = 3UL;
|
|
}
|
|
else if (u32NTx >= 8UL)
|
|
{
|
|
dataNum = 2UL;
|
|
}
|
|
else if (u32NTx >= 4UL)
|
|
{
|
|
dataNum = 1UL;
|
|
}
|
|
|
|
dataNum2 = dataNum;
|
|
while (dataNum2)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
memcpy(&tmp, &pu8TxBuf[buf_idx], 4U);
|
|
buf_idx += 4UL;
|
|
u32NTx -= 4UL;
|
|
|
|
dataNum2 --;
|
|
/* *((__O uint32_t *) &SPIM->TX0 + dataNum2) = tmp; */
|
|
SPIM->TX[dataNum2] = tmp;
|
|
}
|
|
|
|
if (dataNum)
|
|
{
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
|
|
SPIM_SET_DATA_WIDTH(32UL);
|
|
SPIM_SET_DATA_NUM(dataNum);
|
|
SPIM_SET_GO();
|
|
u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
SPIM_WAIT_FREE()
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (u32NTx && (u32NTx < 4UL))
|
|
{
|
|
uint32_t rnm, tmp;
|
|
|
|
rnm = u32NTx;
|
|
memcpy(&tmp, &pu8TxBuf[buf_idx], u32NTx);
|
|
buf_idx += u32NTx;
|
|
u32NTx = 0UL;
|
|
SPIM->TX[0] = tmp;
|
|
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
|
|
SPIM_SET_DATA_WIDTH(rnm * 8UL);
|
|
SPIM_SET_DATA_NUM(1UL);
|
|
SPIM_SET_GO();
|
|
u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
SPIM_WAIT_FREE()
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from SPI slave.
|
|
* @param pu8TxBuf Receive buffer.
|
|
* @param u32NRx Size of receive buffer in bytes.
|
|
* @return None.
|
|
* @note This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
|
|
*/
|
|
static void spim_read(uint8_t pu8RxBuf[], uint32_t u32NRx)
|
|
{
|
|
uint32_t buf_idx = 0UL;
|
|
uint32_t u32TimeOutCount = 0UL;
|
|
|
|
g_SPIM_i32ErrCode = 0;
|
|
|
|
while (u32NRx)
|
|
{
|
|
uint32_t dataNum = 0UL; /* number of words */
|
|
|
|
if (u32NRx >= 16UL)
|
|
{
|
|
dataNum = 4UL;
|
|
}
|
|
else if (u32NRx >= 12UL)
|
|
{
|
|
dataNum = 3UL;
|
|
}
|
|
else if (u32NRx >= 8UL)
|
|
{
|
|
dataNum = 2UL;
|
|
}
|
|
else if (u32NRx >= 4UL)
|
|
{
|
|
dataNum = 1UL;
|
|
}
|
|
|
|
if (dataNum)
|
|
{
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
|
|
SPIM_SET_DATA_WIDTH(32UL);
|
|
SPIM_SET_DATA_NUM(dataNum);
|
|
SPIM_SET_GO();
|
|
u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
SPIM_WAIT_FREE()
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (dataNum)
|
|
{
|
|
uint32_t tmp;
|
|
|
|
tmp = SPIM->RX[dataNum - 1UL];
|
|
memcpy(&pu8RxBuf[buf_idx], &tmp, 4U);
|
|
buf_idx += 4UL;
|
|
dataNum --;
|
|
u32NRx -= 4UL;
|
|
}
|
|
|
|
if (u32NRx && (u32NRx < 4UL))
|
|
{
|
|
uint32_t tmp;
|
|
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch to Normal mode. */
|
|
SPIM_SET_DATA_WIDTH(u32NRx * 8UL);
|
|
SPIM_SET_DATA_NUM(1UL);
|
|
SPIM_SET_GO();
|
|
u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
SPIM_WAIT_FREE()
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
tmp = SPIM->RX[0];
|
|
memcpy(&pu8RxBuf[buf_idx], &tmp, u32NRx);
|
|
buf_idx += u32NRx;
|
|
u32NRx = 0UL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Issue Read Status Register #1 command.
|
|
* @param dataBuf Receive buffer.
|
|
* @param u32NRx Size of receive buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_ReadStatusRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_RDSR}; /* 1-byte Read Status Register #1 command. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(u32NBit);
|
|
spim_read(dataBuf, u32NRx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/**
|
|
* @brief Issue Write Status Register #1 command.
|
|
* @param dataBuf Transmit buffer.
|
|
* @param u32NTx Size of transmit buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_WriteStatusRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_WRSR, 0x00U}; /* 1-byte Write Status Register #1 command + 1-byte data. */
|
|
|
|
cmdBuf[1] = dataBuf[0];
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/**
|
|
* @brief Issue Read Status Register #2 command.
|
|
* @param dataBuf Receive buffer.
|
|
* @param u32NRx Size of receive buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_ReadStatusRegister2(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_RDSR2}; /* 1-byte Read Status Register #1 command. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(u32NBit);
|
|
spim_read(dataBuf, u32NRx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/**
|
|
* @brief Issue Winbond Write Status Register command. This command write both Status Register-1
|
|
* and Status Register-2.
|
|
* @param dataBuf Transmit buffer.
|
|
* @param u32NTx Size of transmit buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_WriteStatusRegister2(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[3] = {OPCODE_WRSR, 0U, 0U};
|
|
|
|
cmdBuf[1] = dataBuf[0];
|
|
cmdBuf[2] = dataBuf[1];
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
#if 0 /* not used */
|
|
/**
|
|
* @brief Issue Write Status Register #3 command.
|
|
* @param dataBuf Transmit buffer.
|
|
* @param u32NTx Size of transmit buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_WriteStatusRegister3(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_WRSR3, 0x00U}; /* 1-byte Write Status Register #2 command + 1-byte data. */
|
|
cmdBuf[1] = dataBuf[0];
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Issue Read Status Register #3 command.
|
|
* @param dataBuf Receive buffer.
|
|
* @param u32NRx Size of receive buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_ReadStatusRegister3(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_RDSR3}; /* 1-byte Read Status Register #1 command. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(u32NBit);
|
|
spim_read(dataBuf, u32NRx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
#if 0 /* not used */
|
|
/**
|
|
* @brief Issue Write Security Register command.
|
|
* @param dataBuf Transmit buffer.
|
|
* @param u32NTx Size of transmit buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_WriteSecurityRegister(uint8_t dataBuf[], uint32_t u32NTx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_WRSCUR, 0x00U}; /* 1-byte Write Status Register #2 command + 1-byte data. */
|
|
cmdBuf[1] = dataBuf[0];
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Issue Read Security Register command.
|
|
* @param dataBuf Receive buffer.
|
|
* @param u32NRx Size of receive buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_ReadSecurityRegister(uint8_t dataBuf[], uint32_t u32NRx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {OPCODE_RDSCUR}; /* 1-byte Read Status Register #1 command. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(u32NBit);
|
|
spim_read(dataBuf, u32NRx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/**
|
|
* @brief Check if Erase/Write is done.
|
|
* @return 0: Not done. 1: Done.
|
|
*/
|
|
static int spim_is_write_done(uint32_t u32NBit)
|
|
{
|
|
uint8_t status[1];
|
|
SPIM_ReadStatusRegister(status, sizeof(status), u32NBit);
|
|
return !(status[0] & SR_WIP);
|
|
}
|
|
|
|
/**
|
|
* @brief Wait until Erase/Write done.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return 0 SPIM write done.
|
|
*/
|
|
static int spim_wait_write_done(uint32_t u32NBit)
|
|
{
|
|
uint32_t count;
|
|
int ret = -1;
|
|
|
|
for (count = 0UL; count < SystemCoreClock / 1000UL; count++)
|
|
{
|
|
if (spim_is_write_done(u32NBit))
|
|
{
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (ret != 0)
|
|
{
|
|
SPIM_DBGMSG("spim_wait_write_done time-out!!\n");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Issue Write Enable/disable command.
|
|
* @param isEn Enable/disable.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
static void spim_set_write_enable(int isEn, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = {0U}; /* 1-byte Write Enable command. */
|
|
cmdBuf[0] = isEn ? OPCODE_WREN : OPCODE_WRDI;
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/** @endcond HIDDEN_SYMBOLS */
|
|
|
|
/**
|
|
* @brief Get SPIM serial clock.
|
|
* @return SPI serial clock.
|
|
* @details This function calculates the serial clock of SPI in Hz.
|
|
*/
|
|
uint32_t SPIM_GetSClkFreq(void)
|
|
{
|
|
uint32_t clkDiv = SPIM_GET_CLOCK_DIVIDER();
|
|
|
|
return clkDiv ? SystemCoreClock / (clkDiv * 2U) : SystemCoreClock;
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize SPIM flash.
|
|
* @param clrWP Clear Write Protect or not.
|
|
* @return 0 Success.
|
|
* @return -1 Unrecognized manufacture ID or failed on reading manufacture ID.
|
|
*/
|
|
int SPIM_InitFlash(int clrWP)
|
|
{
|
|
uint8_t idBuf[3];
|
|
uint8_t cmdBuf[1];
|
|
uint32_t i;
|
|
int32_t ret = -1;
|
|
|
|
SPIM_SET_SS_ACTLVL(0);
|
|
|
|
/*
|
|
* Because not sure in SPI or QPI mode, do QPI reset and then SPI reset.
|
|
*/
|
|
/* QPI Reset Enable */
|
|
cmdBuf[0] = OPCODE_RSTEN;
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 1-bit, Output. */
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
/* QPI Reset */
|
|
cmdBuf[0] = OPCODE_RST;
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SPIM_ENABLE_QUAD_OUTPUT_MODE(); /* 1-bit, Output. */
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
/* SPI ResetEnable */
|
|
cmdBuf[0] = OPCODE_RSTEN;
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
/* SPI Reset */
|
|
cmdBuf[0] = OPCODE_RST;
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SPIM_ENABLE_SING_OUTPUT_MODE(); /* 1-bit, Output. */
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
if (clrWP)
|
|
{
|
|
uint8_t dataBuf[] = {0x00U};
|
|
|
|
spim_set_write_enable(1, 1UL); /* Clear Block Protect. */
|
|
SPIM_WriteStatusRegister(dataBuf, sizeof(dataBuf), 1U);
|
|
spim_wait_write_done(1UL);
|
|
}
|
|
|
|
SPIM_ReadJedecId(idBuf, sizeof(idBuf), 1UL);
|
|
|
|
/* printf("ID: 0x%x, 0x%x, px%x\n", idBuf[0], idBuf[1], idBuf[2]); */
|
|
|
|
for (i = 0UL; i < sizeof(g_Supported_List) / sizeof(g_Supported_List[0]); i++)
|
|
{
|
|
if (idBuf[0] == g_Supported_List[i])
|
|
{
|
|
ret = 0;
|
|
}
|
|
}
|
|
if (ret != 0)
|
|
{
|
|
SPIM_DBGMSG("Flash initialize failed!! 0x%x\n", idBuf[0]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Issue JEDEC ID command.
|
|
* @param idBuf ID buffer.
|
|
* @param u32NRx Size of ID buffer.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
void SPIM_ReadJedecId(uint8_t idBuf[], uint32_t u32NRx, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[] = { OPCODE_RDID }; /* 1-byte JEDEC ID command. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(u32NBit);
|
|
spim_read(idBuf, u32NRx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/** @cond HIDDEN_SYMBOLS */
|
|
|
|
static void spim_enable_spansion_quad_mode(int isEn)
|
|
{
|
|
uint8_t cmdBuf[3];
|
|
uint8_t dataBuf[1], status1;
|
|
|
|
cmdBuf[0] = 0x5U; /* Read Status Register-1 */
|
|
|
|
SPIM_SET_SS_EN(1);
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(1UL);
|
|
spim_read(dataBuf, sizeof(dataBuf));
|
|
SPIM_SET_SS_EN(0);
|
|
/* SPIM_DBGMSG("SR1 = 0x%x\n", dataBuf[0]); */
|
|
|
|
status1 = dataBuf[0];
|
|
|
|
cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
|
|
|
|
SPIM_SET_SS_EN(1);
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(1UL);
|
|
spim_read(dataBuf, sizeof(dataBuf));
|
|
SPIM_SET_SS_EN(0);
|
|
/* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
|
|
|
|
spim_set_write_enable(1, 1UL);
|
|
|
|
cmdBuf[0] = 0x1U; /* Write register */
|
|
cmdBuf[1] = status1;
|
|
|
|
if (isEn)
|
|
{
|
|
cmdBuf[2] = dataBuf[0] | 0x2U; /* set QUAD */
|
|
}
|
|
else
|
|
{
|
|
cmdBuf[2] = dataBuf[0] & ~0x2U; /* clear QUAD */
|
|
}
|
|
|
|
SPIM_SET_SS_EN(1);
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, 3UL);
|
|
SPIM_SET_SS_EN(0);
|
|
|
|
spim_set_write_enable(0, 1UL);
|
|
|
|
|
|
cmdBuf[0] = 0x35U; /* Read Configuration Register-1 */
|
|
|
|
SPIM_SET_SS_EN(1);
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SwitchNBitInput(1UL);
|
|
spim_read(dataBuf, sizeof(dataBuf));
|
|
SPIM_SET_SS_EN(0);
|
|
|
|
/* SPIM_DBGMSG("CR1 = 0x%x\n", dataBuf[0]); */
|
|
N_delay(10000);
|
|
}
|
|
|
|
/** @endcond HIDDEN_SYMBOLS */
|
|
|
|
/**
|
|
* @brief Set Quad Enable/disable.
|
|
* @param isEn Enable/disable.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return None.
|
|
*/
|
|
void SPIM_SetQuadEnable(int isEn, uint32_t u32NBit)
|
|
{
|
|
uint8_t idBuf[3];
|
|
uint8_t dataBuf[2];
|
|
|
|
SPIM_ReadJedecId(idBuf, sizeof(idBuf), u32NBit);
|
|
|
|
SPIM_DBGMSG("SPIM_SetQuadEnable - Flash ID is 0x%x\n", idBuf[0]);
|
|
|
|
switch (idBuf[0])
|
|
{
|
|
case MFGID_WINBOND: /* Winbond SPI flash */
|
|
SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
|
|
SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
|
|
SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
|
|
if (isEn)
|
|
{
|
|
dataBuf[1] |= SR2_QE;
|
|
}
|
|
else
|
|
{
|
|
dataBuf[1] &= ~SR2_QE;
|
|
}
|
|
|
|
spim_set_write_enable(1, u32NBit); /* Write Enable. */
|
|
SPIM_WriteStatusRegister2(dataBuf, sizeof(dataBuf), u32NBit);
|
|
spim_wait_write_done(u32NBit);
|
|
|
|
SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
|
|
SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
|
|
SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
|
|
break;
|
|
|
|
case MFGID_MXIC: /* MXIC SPI flash. */
|
|
case MFGID_EON:
|
|
case MFGID_ISSI: /* ISSI SPI flash. */
|
|
spim_set_write_enable(1, u32NBit); /* Write Enable. */
|
|
dataBuf[0] = isEn ? SR_QE : 0U;
|
|
SPIM_WriteStatusRegister(dataBuf, sizeof(dataBuf), u32NBit);
|
|
spim_wait_write_done(u32NBit);
|
|
break;
|
|
|
|
case MFGID_SPANSION:
|
|
spim_enable_spansion_quad_mode(isEn);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enter/exit QPI mode.
|
|
* @param isEn Enable/disable.
|
|
* @return None.
|
|
*/
|
|
static void spim_eon_set_qpi_mode(int isEn)
|
|
{
|
|
uint8_t cmdBuf[1]; /* 1-byte command. */
|
|
|
|
uint8_t status[1];
|
|
SPIM_ReadStatusRegister(status, sizeof(status), 1UL);
|
|
SPIM_DBGMSG("Status: 0x%x\n", status[0]);
|
|
|
|
if (isEn) /* Assume in SPI mode. */
|
|
{
|
|
cmdBuf[0] = OPCODE_ENQPI;
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
else /* Assume in QPI mode. */
|
|
{
|
|
cmdBuf[0] = OPCODE_EXQPI;
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(4UL);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
SPIM_ReadStatusRegister(status, sizeof(status), 1UL);
|
|
SPIM_DBGMSG("Status: 0x%x\n", status[0]);
|
|
}
|
|
|
|
|
|
static void SPIM_SPANSION_4Bytes_Enable(int isEn, uint32_t u32NBit)
|
|
{
|
|
uint8_t cmdBuf[2];
|
|
uint8_t dataBuf[1];
|
|
|
|
cmdBuf[0] = OPCODE_BRRD;
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, 1UL);
|
|
SwitchNBitInput(1UL);
|
|
spim_read(dataBuf, 1UL);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
SPIM_DBGMSG("Bank Address register= 0x%x\n", dataBuf[0]);
|
|
|
|
cmdBuf[0] = OPCODE_BRWR;
|
|
|
|
if (isEn)
|
|
{
|
|
cmdBuf[1] = dataBuf[0] | 0x80U; /* set EXTADD */
|
|
}
|
|
else
|
|
{
|
|
cmdBuf[1] = dataBuf[0] & ~0x80U; /* clear EXTADD */
|
|
}
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(1UL);
|
|
spim_write(cmdBuf, 2UL);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/** @cond HIDDEN_SYMBOLS */
|
|
|
|
/**
|
|
* @brief Query 4-byte address mode enabled or not.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return 0: 4-byte address mode disabled. 1: 4-byte address mode enabled.
|
|
*/
|
|
int SPIM_Is4ByteModeEnable(uint32_t u32NBit)
|
|
{
|
|
int isEn = 0;
|
|
int isSupt = 0;
|
|
uint8_t idBuf[3];
|
|
uint8_t dataBuf[1];
|
|
|
|
SPIM_ReadJedecId(idBuf, sizeof(idBuf), u32NBit);
|
|
|
|
/* Based on Flash size, check if 4-byte address mode is supported. */
|
|
switch (idBuf[0])
|
|
{
|
|
case MFGID_WINBOND:
|
|
case MFGID_MXIC:
|
|
case MFGID_EON:
|
|
isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
|
|
break;
|
|
|
|
case MFGID_ISSI:
|
|
isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (isSupt != 0)
|
|
{
|
|
if (idBuf[0] == MFGID_WINBOND)
|
|
{
|
|
/* Winbond SPI flash. */
|
|
SPIM_ReadStatusRegister3(dataBuf, sizeof(dataBuf), u32NBit);
|
|
isEn = !!(dataBuf[0] & SR3_ADR);
|
|
}
|
|
else if ((idBuf[0] == MFGID_MXIC) || (idBuf[0] == MFGID_EON))
|
|
{
|
|
/* MXIC/EON SPI flash. */
|
|
SPIM_ReadSecurityRegister(dataBuf, sizeof(dataBuf), u32NBit);
|
|
isEn = !!(dataBuf[0] & SCUR_4BYTE);
|
|
}
|
|
}
|
|
|
|
return isEn;
|
|
}
|
|
|
|
/** @endcond HIDDEN_SYMBOLS */
|
|
|
|
|
|
/**
|
|
* @brief Enter/Exit 4-byte address mode.
|
|
* @param isEn Enable/disable.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @return 0 success
|
|
* -1 failed
|
|
*/
|
|
int SPIM_Enable_4Bytes_Mode(int isEn, uint32_t u32NBit)
|
|
{
|
|
int isSupt = 0L, ret = -1;
|
|
uint8_t idBuf[3];
|
|
uint8_t cmdBuf[1]; /* 1-byte Enter/Exit 4-Byte Mode command. */
|
|
int32_t i32TimeOutCount = 0;
|
|
|
|
SPIM_ReadJedecId(idBuf, sizeof(idBuf), u32NBit);
|
|
|
|
/* Based on Flash size, check if 4-byte address mode is supported. */
|
|
switch (idBuf[0])
|
|
{
|
|
case MFGID_WINBOND:
|
|
isSupt = (idBuf[2] < 0x16U) ? 0L : 1L;
|
|
break;
|
|
case MFGID_MXIC:
|
|
case MFGID_EON:
|
|
isSupt = (idBuf[2] < 0x19U) ? 0L : 1L;
|
|
break;
|
|
|
|
case MFGID_ISSI:
|
|
isSupt = (idBuf[2] < 0x49U) ? 0L : 1L;
|
|
break;
|
|
|
|
case MFGID_SPANSION:
|
|
SPIM_SPANSION_4Bytes_Enable(isEn, u32NBit);
|
|
isSupt = 1L;
|
|
ret = 0L;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((isSupt) && (idBuf[0] != MFGID_SPANSION))
|
|
{
|
|
cmdBuf[0] = isEn ? OPCODE_EN4B : OPCODE_EX4B;
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
/*
|
|
* FIXME: Per test, 4BYTE Indicator bit doesn't set after EN4B, which
|
|
* doesn't match spec(MX25L25635E), so skip the check below.
|
|
*/
|
|
ret = 0;
|
|
if (idBuf[0] != MFGID_MXIC)
|
|
{
|
|
/*
|
|
* About over 100 instrucsions executed, just want to give
|
|
* a time-out about 1 seconds to avoid infinite loop
|
|
*/
|
|
i32TimeOutCount = (SystemCoreClock) / 100;
|
|
|
|
if (isEn)
|
|
{
|
|
while ((i32TimeOutCount-- > 0) && !SPIM_Is4ByteModeEnable(u32NBit)) { }
|
|
}
|
|
else
|
|
{
|
|
while ((i32TimeOutCount-- > 0) && SPIM_Is4ByteModeEnable(u32NBit)) { }
|
|
}
|
|
if (i32TimeOutCount <= 0)
|
|
ret = -1;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
void SPIM_WinbondUnlock(uint32_t u32NBit)
|
|
{
|
|
uint8_t idBuf[3];
|
|
uint8_t dataBuf[4];
|
|
|
|
SPIM_ReadJedecId(idBuf, sizeof(idBuf), u32NBit);
|
|
|
|
if ((idBuf[0] != MFGID_WINBOND) || (idBuf[1] != 0x40) || (idBuf[2] != 0x16))
|
|
{
|
|
SPIM_DBGMSG("SPIM_WinbondUnlock - Not W25Q32, do nothing.\n");
|
|
return;
|
|
}
|
|
|
|
SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
|
|
SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
|
|
SPIM_DBGMSG("Status Register: 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
|
|
dataBuf[1] &= ~0x40; /* clear Status Register-1 SEC bit */
|
|
|
|
spim_set_write_enable(1, u32NBit); /* Write Enable. */
|
|
SPIM_WriteStatusRegister2(dataBuf, sizeof(dataBuf), u32NBit);
|
|
spim_wait_write_done(u32NBit);
|
|
|
|
SPIM_ReadStatusRegister(&dataBuf[0], 1UL, u32NBit);
|
|
SPIM_ReadStatusRegister2(&dataBuf[1], 1UL, u32NBit);
|
|
SPIM_DBGMSG("Status Register (after unlock): 0x%x - 0x%x\n", dataBuf[0], dataBuf[1]);
|
|
}
|
|
|
|
/**
|
|
* @brief Erase whole chip.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @param isSync Block or not.
|
|
* @return None.
|
|
*/
|
|
void SPIM_ChipErase(uint32_t u32NBit, int isSync)
|
|
{
|
|
uint8_t cmdBuf[] = { OPCODE_CHIP_ERASE }; /* 1-byte Chip Erase command. */
|
|
|
|
spim_set_write_enable(1, u32NBit); /* Write Enable. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, sizeof(cmdBuf));
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
if (isSync)
|
|
{
|
|
spim_wait_write_done(u32NBit);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Erase one block.
|
|
* @param u32Addr Block to erase which contains the u32Addr.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u8ErsCmd Erase command.
|
|
* @param u32NBit N-bit transmit/receive.
|
|
* @param isSync Block or not.
|
|
* @return None.
|
|
*/
|
|
void SPIM_EraseBlock(uint32_t u32Addr, int is4ByteAddr, uint8_t u8ErsCmd, uint32_t u32NBit, int isSync)
|
|
{
|
|
uint8_t cmdBuf[16];
|
|
uint32_t buf_idx = 0UL;
|
|
|
|
spim_set_write_enable(1, u32NBit); /* Write Enable. */
|
|
|
|
cmdBuf[buf_idx++] = u8ErsCmd;
|
|
|
|
if (is4ByteAddr)
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 24);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr & 0xFFUL);
|
|
}
|
|
else
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr & 0xFFUL);
|
|
}
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
SwitchNBitOutput(u32NBit);
|
|
spim_write(cmdBuf, buf_idx);
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
if (isSync)
|
|
{
|
|
spim_wait_write_done(u32NBit);
|
|
}
|
|
}
|
|
|
|
|
|
/** @cond HIDDEN_SYMBOLS */
|
|
|
|
/**
|
|
* @brief Write data in the same page by I/O mode.
|
|
* @param u32Addr Start u32Address to write.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u32NTx Number of bytes to write.
|
|
* @param pu8TxBuf Transmit buffer.
|
|
* @param wrCmd Write command.
|
|
* @param u32NBitCmd N-bit transmit command.
|
|
* @param u32NBitAddr N-bit transmit u32Address.
|
|
* @param u32NBitDat N-bit transmit/receive data.
|
|
* @param isSync Block or not.
|
|
* @return None.
|
|
*/
|
|
static void SPIM_WriteInPageDataByIo(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
|
|
uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int isSync)
|
|
{
|
|
uint8_t cmdBuf[16];
|
|
uint32_t buf_idx;
|
|
|
|
spim_set_write_enable(1, u32NBitCmd); /* Write Enable. */
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
|
|
SwitchNBitOutput(u32NBitCmd);
|
|
cmdBuf[0] = wrCmd;
|
|
spim_write(cmdBuf, 1UL); /* Write out command. */
|
|
|
|
buf_idx = 0UL;
|
|
if (is4ByteAddr)
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 24);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t) u32Addr;
|
|
}
|
|
else
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t) u32Addr;
|
|
}
|
|
|
|
SwitchNBitOutput(u32NBitAddr);
|
|
spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
|
|
|
|
SwitchNBitOutput(u32NBitDat);
|
|
spim_write(pu8TxBuf, u32NTx); /* Write out data. */
|
|
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
|
|
if (isSync)
|
|
{
|
|
spim_wait_write_done(u32NBitCmd);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Write data in the same page by Page Write mode.
|
|
* @param u32Addr Start u32Address to write.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u32NTx Number of bytes to write.
|
|
* @param pu8TxBuf Transmit buffer.
|
|
* @param wrCmd Write command.
|
|
* @param isSync Block or not.
|
|
* @return None.
|
|
* @note This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
|
|
*/
|
|
static void SPIM_WriteInPageDataByPageWrite(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx,
|
|
uint8_t pu8TxBuf[], uint32_t wrCmd, int isSync)
|
|
{
|
|
uint32_t u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
|
|
g_SPIM_i32ErrCode = 0;
|
|
|
|
if ((wrCmd == CMD_QUAD_PAGE_PROGRAM_WINBOND) ||
|
|
(wrCmd == CMD_QUAD_PAGE_PROGRAM_MXIC))
|
|
{
|
|
SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
|
|
}
|
|
else if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
|
|
{
|
|
SPIM_SetQuadEnable(1, 1UL); /* Set Quad Enable. */
|
|
spim_eon_set_qpi_mode(1); /* Enter QPI mode. */
|
|
}
|
|
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEWRITE);/* Switch to Page Write mode. */
|
|
SPIM_SET_SPIM_MODE(wrCmd); /* SPIM mode. */
|
|
SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
|
|
|
|
SPIM->SRAMADDR = (uint32_t) pu8TxBuf; /* SRAM u32Address. */
|
|
SPIM->DMACNT = u32NTx; /* Transfer length. */
|
|
SPIM->FADDR = u32Addr; /* Flash u32Address.*/
|
|
SPIM_SET_GO(); /* Go. */
|
|
|
|
if (isSync)
|
|
{
|
|
SPIM_WAIT_FREE()
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wrCmd == CMD_QUAD_PAGE_PROGRAM_EON)
|
|
{
|
|
spim_eon_set_qpi_mode(0); /* Exit QPI mode. */
|
|
}
|
|
}
|
|
|
|
/** @endcond HIDDEN_SYMBOLS */
|
|
|
|
/**
|
|
* @brief Write data to SPI Flash by sending commands manually (I/O mode).
|
|
* @param u32Addr: Start u32Address to write.
|
|
* @param is4ByteAddr: 4-byte u32Address or not.
|
|
* @param u32NTx: Number of bytes to write.
|
|
* @param pu8TxBuf: Transmit buffer.
|
|
* @param wrCmd: Write command.
|
|
* @param u32NBitCmd: N-bit transmit command.
|
|
* @param u32NBitAddr: N-bit transmit u32Address.
|
|
* @param u32NBitDat: N-bit transmit/receive data.
|
|
* @return None.
|
|
*/
|
|
void SPIM_IO_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint8_t wrCmd,
|
|
uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat)
|
|
{
|
|
uint32_t pageOffset, toWr;
|
|
uint32_t buf_idx = 0UL;
|
|
|
|
pageOffset = u32Addr % 256UL;
|
|
|
|
if ((pageOffset + u32NTx) <= 256UL) /* Do all the bytes fit onto one page ? */
|
|
{
|
|
SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, u32NTx, &pu8TxBuf[buf_idx],
|
|
wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
|
|
}
|
|
else
|
|
{
|
|
toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
|
|
|
|
SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
|
|
wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
|
|
u32Addr += toWr; /* Advance indicator. */
|
|
u32NTx -= toWr;
|
|
buf_idx += toWr;
|
|
|
|
while (u32NTx)
|
|
{
|
|
toWr = 256UL;
|
|
if (toWr > u32NTx)
|
|
{
|
|
toWr = u32NTx;
|
|
}
|
|
|
|
SPIM_WriteInPageDataByIo(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx],
|
|
wrCmd, u32NBitCmd, u32NBitAddr, u32NBitDat, 1);
|
|
u32Addr += toWr; /* Advance indicator. */
|
|
u32NTx -= toWr;
|
|
buf_idx += toWr;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from SPI Flash by sending commands manually (I/O mode).
|
|
* @param u32Addr Start u32Address to read.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u32NRx Number of bytes to read.
|
|
* @param pu8RxBuf Receive buffer.
|
|
* @param rdCmd Read command.
|
|
* @param u32NBitCmd N-bit transmit command.
|
|
* @param u32NBitAddr N-bit transmit u32Address.
|
|
* @param u32NBitDat N-bit transmit/receive data.
|
|
* @param u32NDummy Number of dummy bytes following address.
|
|
* @return None.
|
|
*/
|
|
void SPIM_IO_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[], uint8_t rdCmd,
|
|
uint32_t u32NBitCmd, uint32_t u32NBitAddr, uint32_t u32NBitDat, int u32NDummy)
|
|
{
|
|
uint8_t cmdBuf[16];
|
|
uint32_t buf_idx;
|
|
|
|
SPIM_SET_SS_EN(1); /* CS activated. */
|
|
|
|
cmdBuf[0] = rdCmd;
|
|
SwitchNBitOutput(u32NBitCmd);
|
|
spim_write(cmdBuf, 1UL); /* Write out command. */
|
|
|
|
buf_idx = 0UL;
|
|
if (is4ByteAddr)
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 24);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t) u32Addr;
|
|
}
|
|
else
|
|
{
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 16);
|
|
cmdBuf[buf_idx++] = (uint8_t)(u32Addr >> 8);
|
|
cmdBuf[buf_idx++] = (uint8_t) u32Addr;
|
|
}
|
|
SwitchNBitOutput(u32NBitAddr);
|
|
spim_write(cmdBuf, buf_idx); /* Write out u32Address. */
|
|
|
|
buf_idx = 0UL;
|
|
while (u32NDummy --)
|
|
{
|
|
cmdBuf[buf_idx++] = 0x00U;
|
|
}
|
|
|
|
/* Same bit mode as above. */
|
|
spim_write(cmdBuf, buf_idx); /* Write out dummy bytes. */
|
|
|
|
SwitchNBitInput(u32NBitDat);
|
|
spim_read(pu8RxBuf, u32NRx); /* Read back data. */
|
|
|
|
SPIM_SET_SS_EN(0); /* CS deactivated. */
|
|
}
|
|
|
|
/**
|
|
* @brief Write data to SPI Flash by Page Write mode.
|
|
* @param u32Addr Start address to write.
|
|
* @param is4ByteAddr 4-byte address or not.
|
|
* @param u32NTx Number of bytes to write.
|
|
* @param pu8TxBuf Transmit buffer.
|
|
* @param wrCmd Write command.
|
|
* @return None.
|
|
*/
|
|
void SPIM_DMA_Write(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NTx, uint8_t pu8TxBuf[], uint32_t wrCmd)
|
|
{
|
|
uint32_t pageOffset, toWr;
|
|
uint32_t buf_idx = 0UL;
|
|
|
|
pageOffset = u32Addr % 256UL;
|
|
|
|
if ((pageOffset + u32NTx) <= 256UL)
|
|
{
|
|
/* Do all the bytes fit onto one page ? */
|
|
SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, u32NTx, pu8TxBuf, wrCmd, 1);
|
|
}
|
|
else
|
|
{
|
|
toWr = 256UL - pageOffset; /* Size of data remaining on the first page. */
|
|
|
|
SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
|
|
|
|
u32Addr += toWr; /* Advance indicator. */
|
|
u32NTx -= toWr;
|
|
buf_idx += toWr;
|
|
|
|
while (u32NTx)
|
|
{
|
|
toWr = 256UL;
|
|
if (toWr > u32NTx)
|
|
{
|
|
toWr = u32NTx;
|
|
}
|
|
|
|
SPIM_WriteInPageDataByPageWrite(u32Addr, is4ByteAddr, toWr, &pu8TxBuf[buf_idx], wrCmd, 1);
|
|
|
|
u32Addr += toWr; /* Advance indicator. */
|
|
u32NTx -= toWr;
|
|
buf_idx += toWr;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Read data from SPI Flash by Page Read mode.
|
|
* @param u32Addr Start address to read.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u32NRx Number of bytes to read.
|
|
* @param pu8RxBuf Receive buffer.
|
|
* @param u32RdCmd Read command.
|
|
* @param isSync Block or not.
|
|
* @return None.
|
|
* @note This function sets g_SPIM_i32ErrCode to SPIM_TIMEOUT_ERR if waiting SPIM time-out.
|
|
*/
|
|
void SPIM_DMA_Read(uint32_t u32Addr, int is4ByteAddr, uint32_t u32NRx, uint8_t pu8RxBuf[],
|
|
uint32_t u32RdCmd, int isSync)
|
|
{
|
|
uint32_t u32TimeOutCount = SystemCoreClock; /* 1 second time-out */
|
|
|
|
g_SPIM_i32ErrCode = 0;
|
|
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_PAGEREAD); /* Switch to Page Read mode. */
|
|
SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
|
|
SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-Byte Address. */
|
|
|
|
SPIM->SRAMADDR = (uint32_t) pu8RxBuf; /* SRAM u32Address. */
|
|
SPIM->DMACNT = u32NRx; /* Transfer length. */
|
|
SPIM->FADDR = u32Addr; /* Flash u32Address.*/
|
|
SPIM_SET_GO(); /* Go. */
|
|
|
|
if (isSync)
|
|
{
|
|
SPIM_WAIT_FREE() /* Wait for DMA done. */
|
|
{
|
|
if (--u32TimeOutCount == 0)
|
|
{
|
|
g_SPIM_i32ErrCode = SPIM_TIMEOUT_ERR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Enter Direct Map mode.
|
|
* @param is4ByteAddr 4-byte u32Address or not.
|
|
* @param u32RdCmd Read command.
|
|
* @param u32IdleIntvl Idle interval.
|
|
* @return None.
|
|
*/
|
|
void SPIM_EnterDirectMapMode(int is4ByteAddr, uint32_t u32RdCmd, uint32_t u32IdleIntvl)
|
|
{
|
|
SPIM_SET_4BYTE_ADDR_EN(is4ByteAddr); /* Enable/disable 4-byte u32Address. */
|
|
SPIM_SET_SPIM_MODE(u32RdCmd); /* SPIM mode. */
|
|
SPIM_SET_IDL_INTVL(u32IdleIntvl); /* Idle interval. */
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_DIRECTMAP); /* Switch to Direct Map mode. */
|
|
}
|
|
|
|
/**
|
|
* @brief Exit Direct Map mode.
|
|
* @return None.
|
|
*/
|
|
void SPIM_ExitDirectMapMode(void)
|
|
{
|
|
SPIM_SET_OPMODE(SPIM_CTL0_OPMODE_IO); /* Switch back to Normal mode. */
|
|
}
|
|
|
|
|
|
/*@}*/ /* end of group SPIM_EXPORTED_FUNCTIONS */
|
|
|
|
/*@}*/ /* end of group SPIM_Driver */
|
|
|
|
/*@}*/ /* end of group Standard_Driver */
|