diff options
| author | Anson Bridges <bridges.anson@gmail.com> | 2026-02-17 11:37:50 -0800 |
|---|---|---|
| committer | Anson Bridges <bridges.anson@gmail.com> | 2026-02-17 11:37:50 -0800 |
| commit | fb1611c0ca99d9e609057c46507be2af8389bb7b (patch) | |
| tree | 646ac568fdad1e6cf9e1f5767295b183bc5c5441 /firmware/rf test/Core/Src/w25q_mem.rrr | |
| parent | 6e952fe110c2a48204c8cb0a836309ab97e5979a (diff) | |
Diffstat (limited to 'firmware/rf test/Core/Src/w25q_mem.rrr')
| -rw-r--r-- | firmware/rf test/Core/Src/w25q_mem.rrr | 1521 |
1 files changed, 1521 insertions, 0 deletions
diff --git a/firmware/rf test/Core/Src/w25q_mem.rrr b/firmware/rf test/Core/Src/w25q_mem.rrr new file mode 100644 index 0000000..5f2581b --- /dev/null +++ b/firmware/rf test/Core/Src/w25q_mem.rrr @@ -0,0 +1,1521 @@ +/** + ******************************************* + * @file w25q_mem.c + * @author Dmitriy Semenov / Crazy_Geeks + * @version 0.1b + * @date 12-August-2021 + * @brief Source file for W25Qxxx lib + * @note https://github.com/Crazy-Geeks/STM32-W25Q-QSPI + ******************************************* + * + * @note https://ru.mouser.com/datasheet/2/949/w25q256jv_spi_revg_08032017-1489574.pdf + * @note https://www.st.com/resource/en/application_note/DM00227538-.pdf + */ + +/** + * @addtogroup W25Q_Driver + * @{ + */ + +#include "w25q_mem.h" + +/** + * @addtogroup W25Q_Exp Exported types + * @brief External fields and data + * @{ + */ +extern QSPI_HandleTypeDef hqspi; ///< Quad SPI HAL Instance +/// @} + +/** + * @addtogroup W25Q_PrivFi Private fields + * @brief Private variables and defines + * @{ + */ +#define w25q_delay(x) HAL_Delay(x) ///< Delay define to provide future support of RTOS +W25Q_STATUS_REG w25q_status; ///< Internal status structure instance + +/// @} + +/** + * @addtogroup W25Q_PrivFu Private Methods + * @brief Internal lib's functions + * @{ + */ +W25Q_STATE W25Q_WriteEnable(bool enable); ///< Toggle WOL bit +W25Q_STATE W25Q_EnableQSPI(bool enable); ///< Toggle QE bit +W25Q_STATE W25Q_Enter4ByteMode(bool enable); ///< Toggle ADS bit +W25Q_STATE W25Q_SetExtendedAddr(u8_t Addr); ///< Set addr in 3-byte mode +W25Q_STATE W25Q_GetExtendedAddr(u8_t *outAddr); ///< Get addr in 3-byte mode + +static inline u32_t page_to_addr(u32_t pageNum, u8_t pageShift); ///< Translate page addr to byte addr +/// @} + +/** + * @addtogroup W25Q_Pub Public methods + * @brief Public Methods + * @{ + */ + +/** + * @addtogroup W25Q_Init Init methods + * @brief Initalization + * @{ + */ + +/** + * @brief W25Q Init function + * + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_Init(void) { + W25Q_STATE state; // temp status variable + + // read id + u8_t id = 0; + state = W25Q_ReadID(&id); + if (state != W25Q_OK) + return state; + // u can check id here + + // read chip's state to private lib's struct + state = W25Q_ReadStatusStruct(NULL); + if (state != W25Q_OK) + return state; + +#if MEM_FLASH_SIZE > 128 // if 4-byte mode + + /* If power-default 4-byte + mode disabled */ + if (!w25q_status.ADP) { + u8_t buf_reg = 0; + state = W25Q_ReadStatusReg(&buf_reg, 3); + if (state != W25Q_OK) + return state; + buf_reg |= 0b10; // set ADP bit + state = W25Q_WriteStatusReg(buf_reg, 3); + if (state != W25Q_OK) + return state; + } + + /* If current 4-byte + mode disabled */ + if (!w25q_status.ADS) { + state = W25Q_Enter4ByteMode(1); + if (state != W25Q_OK) + return state; + } +#endif + + /* If Quad-SPI mode disabled */ + if (!w25q_status.QE) { + u8_t buf_reg = 0; + state = W25Q_ReadStatusReg(&buf_reg, 2); + if (state != W25Q_OK) + return state; + buf_reg |= 0b10; + state = W25Q_WriteStatusReg(buf_reg, 2); + if (state != W25Q_OK) + return state; + } + + // make another read + state = W25Q_ReadStatusStruct(NULL); + // return communication status + return state; +} + +/** + * @} + * @addtogroup W25Q_Reg Register Functions + * @brief Operations with Status Registers + * @{ + */ + +/** + * @brief W25Q Enable Volatile SR + * Makes status register volatile (temporary) + * + * @attention Func in development + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_EnableVolatileSR(void) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Read Status Register + * Read one status register + * + * @param[out] reg_data 1 byte + * @param[in] reg_num Desired register 1..3 + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadStatusReg(u8_t *reg_data, u8_t reg_num) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + + if (reg_num == 1) + com.Instruction = W25Q_READ_SR1; + else if (reg_num == 2) + com.Instruction = W25Q_READ_SR2; + else if (reg_num == 3) + com.Instruction = W25Q_READ_SR3; + else + return W25Q_PARAM_ERR; + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = 1; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + if (HAL_QSPI_Receive(&hqspi, reg_data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + + return W25Q_OK; +} + +/** + * @brief W25Q Write Status Register + * Write one status register + * + * @param[in] reg_data 1 byte + * @param[in] reg_num Desired register 1..3 + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_WriteStatusReg(u8_t reg_data, u8_t reg_num) { + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + W25Q_STATE state = W25Q_WriteEnable(1); + if (state != W25Q_OK) + return state; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + + if (reg_num == 1) + com.Instruction = W25Q_WRITE_SR1; + else if (reg_num == 2) + com.Instruction = W25Q_WRITE_SR2; + else if (reg_num == 3) + com.Instruction = W25Q_WRITE_SR3; + else + return W25Q_PARAM_ERR; + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = 1; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + if (HAL_QSPI_Transmit(&hqspi, ®_data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + + return W25Q_OK; +} + +/** + * @brief W25Q Read Status Registers + * Read all status registers to struct + * + * @param[out] status W25Q_STATUS_REG Pointer + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadStatusStruct(W25Q_STATUS_REG *status) { + // buffer enum-variable + W25Q_STATE state; + + // buffer register variables + u8_t SRs[3] = { 0, }; + + // first portion + state = W25Q_ReadStatusReg(&SRs[0], 1); + if (state != W25Q_OK) + return state; + + // second portion + state = W25Q_ReadStatusReg(&SRs[1], 2); + if (state != W25Q_OK) + return state; + + // third portion + state = W25Q_ReadStatusReg(&SRs[2], 3); + if (state != W25Q_OK) + return state; + if(status){ + status->BUSY = w25q_status.BUSY = SRs[0] & 0b1; + status->WEL = w25q_status.WEL = (SRs[0] >> 1) & 0b1; + status->QE = w25q_status.QE = (SRs[1] >> 1) & 0b1; + status->SUS = w25q_status.SUS = (SRs[1] >> 7) & 0b1; + status->ADS = w25q_status.ADS = SRs[2] & 0b1; + status->ADP = w25q_status.ADP = (SRs[2] >> 1) & 0b1; + status->SLEEP = w25q_status.SLEEP; // возможно нужно вынести в начало (тестить) + } + + return state; +} + +/** + * @brief W25Q Check Busy flag + * Fast checking Busy flag + * + * @param none + * @return W25Q_STATE enum (W25Q_OK / W25Q_BUSY) + */ +W25Q_STATE W25Q_IsBusy(void) { + W25Q_STATE state; + u8_t sr = 0; + + state = W25Q_ReadStatusReg(&sr, 1); + if (state != W25Q_OK) + return state; + + w25q_status.BUSY = sr & 0b1; + + return w25q_status.BUSY ? W25Q_BUSY : W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_Read Read Functions + * @brief Read operations - single data type variables or raw 8-bit blocks + * @{ + */ + +/** + * @brief W25Q Read single Signed Byte + * Read signed 8-bit byte variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..255) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadSByte(i8_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data; + W25Q_STATE state = W25Q_ReadRaw(&data, 1, rawAddr); + if (state != W25Q_OK) + return state; + memcpy(buf, &data, 1); + return W25Q_OK; +} + +/** + * @brief W25Q Read single Unsigned Byte + * Read unsigned 8-bit byte variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..255) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadByte(u8_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data; + W25Q_STATE state = W25Q_ReadRaw(&data, 1, rawAddr); + if (state != W25Q_OK) + return state; + buf[0] = data; + return W25Q_OK; +} + +/** + * @brief W25Q Read single Signed Word + * Read signed 16-bit word variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..254) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadSWord(i16_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 2) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[2]; + W25Q_STATE state = W25Q_ReadRaw(data, 2, rawAddr); + if (state != W25Q_OK) + return state; + memcpy(buf, data, 2); + return W25Q_OK; +} + +/** + * @brief W25Q Read single Unsigned Word + * Read unsigned 16-bit word variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..254) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadWord(u16_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 2) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[2]; + W25Q_STATE state = W25Q_ReadRaw(data, 2, rawAddr); + if (state != W25Q_OK) + return state; + memcpy(buf, data, 2); + return W25Q_OK; +} + +/** + * @brief W25Q Read single Signed Long + * Read signed 32-bit long variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..252) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadSLong(i32_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 4) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[4]; + W25Q_STATE state = W25Q_ReadRaw(data, 4, rawAddr); + if (state != W25Q_OK) + return state; + memcpy(buf, data, 4); + return W25Q_OK; +} + +/** + * @brief W25Q Read single Signed Long + * Read signed 32-bit long variable + * + * @param[out] buf Data to be read (single) + * @param[in] pageShift Byte shift inside page (0..252) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadLong(u32_t *buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 4) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[4]; + W25Q_STATE state = W25Q_ReadRaw(data, 4, rawAddr); + if (state != W25Q_OK) + return state; + memcpy(buf, data, 4); + return W25Q_OK; +} + +/** + * @brief W25Q Read any 8-bit data + * Read any 8-bit data from preffered page place + * + * @note Use memcpy to decode data + * @param[out] buf Pointer to data to be read (single or array) + * @param[in] len Length of data (1..256) + * @param[in] pageShift Byte shift inside page (0..256 - len) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadData(u8_t *buf, u16_t len, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || len == 0 || len > 256 || pageShift > 256 - len) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + return W25Q_ReadRaw(buf, len, rawAddr); +} + +/** + * @brief W25Q Read any 8-bit data from raw addr + * Read any 8-bit data from preffered chip address + * + * @note Address is in [byte] size + * @note Be carefull with page overrun + * @param[out] buf Pointer to data to be written (single or array) + * @param[in] data_len Length of data (1..256) + * @param[in] rawAddr Start address of chip's cell + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadRaw(u8_t *buf, u16_t data_len, u32_t rawAddr) { + if (data_len > 256 || data_len == 0) + return W25Q_PARAM_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... +#if MEM_FLASH_SIZE > 128U + com.Instruction = W25Q_FAST_READ_QUAD_IO_4B; // Command + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.Instruction = W25Q_FAST_READ; // Command + com.AddressSize = QSPI_ADDRESS_24_BITS; + #endif + com.AddressMode = QSPI_ADDRESS_1_LINE; + + com.Address = rawAddr; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 8; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = data_len; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + if (HAL_QSPI_Receive(&hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + return W25Q_SPI_ERR; + + return W25Q_OK; +} + +/** + * @brief W25Q Read any 8-bit data from raw addr + * Read any 8-bit data from preffered chip address by SINGLE SPI + * + * @note Works only with SINGLE SPI Line + * @param[out] buf Pointer to data array + * @param[in] len Length of array + * @param[in] Addr Address to data + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_SingleRead(u8_t *buf, u32_t len, u32_t Addr) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... +#if MEM_FLASH_SIZE > 128U + com.Instruction = W25Q_READ_DATA_4B; // Command + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.Instruction = W25Q_READ_DATA; // Command + com.AddressSize = QSPI_ADDRESS_24_BITS; +#endif + com.AddressMode = QSPI_ADDRESS_1_LINE; + + com.Address = Addr; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = len; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + if (HAL_QSPI_Receive(&hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + return W25Q_SPI_ERR; + + return W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_Write Write functions + * @brief Program/write operations - single data type variables or raw 8-bit blocks + * @{ + */ + +/** + * @brief W25Q Burst Wrap settings + * + * @attention Func in development + * + * @param[in] WrapSize Wrap size: 8/16/32/64 / 0 - disable + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_SetBurstWrap(u8_t WrapSize) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Program single Signed Byte + * Program signed 8-bit byte variable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..255) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramSByte(i8_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data; + memcpy(&data, &buf, 1); + return W25Q_ProgramRaw(&data, 1, rawAddr); +} + +/** + * @brief W25Q Program single Unsigned Byte + * Program unsigned 8-bit byte vairable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..255) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramByte(u8_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data; + memcpy(&data, &buf, 1); + return W25Q_ProgramRaw(&data, 1, rawAddr); +} + +/** + * @brief W25Q Program single Signed Word + * Program signed 16-bit word vairable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..254) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramSWord(i16_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 2) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[2]; + memcpy(data, &buf, 2); + return W25Q_ProgramRaw(data, 2, rawAddr); +} + +/** + * @brief W25Q Program single Unsigned Word + * Program unsigned 16-bit word vairable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..254) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramWord(u16_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 2) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[2]; + memcpy(data, &buf, 2); + return W25Q_ProgramRaw(data, 2, rawAddr); +} + +/** + * @brief W25Q Program single Signed Long + * Program signed 32-bit long vairable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..252) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramSLong(i32_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 4) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[4]; + memcpy(data, &buf, 4); + return W25Q_ProgramRaw(data, 4, rawAddr); +} + +/** + * @brief W25Q Program single Unigned Long + * Program unsigned 32-bit long vairable + * + * @param[in] buf Data to be written (single) + * @param[in] pageShift Byte shift inside page (0..252) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramLong(u32_t buf, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || pageShift > 256 - 4) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + u8_t data[4]; + memcpy(data, &buf, 4); + return W25Q_ProgramRaw(data, 4, rawAddr); +} + +/** + * @brief W25Q Program any 8-bit data + * Program any 8-bit data to preffered page place + * + * @note Use memcpy to prepare data + * @param[in] buf Pointer to data to be written (single or array) + * @param[in] len Length of data (1..256) + * @param[in] pageShift Byte shift inside page (0..256 - len) + * @param[in] pageNum Page number (0..PAGE_COUNT-1) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramData(u8_t *buf, u16_t len, u8_t pageShift, u32_t pageNum) { + if (pageNum >= PAGE_COUNT || len == 0 || len > 256 || pageShift > 256 - len) + return W25Q_PARAM_ERR; + u32_t rawAddr = page_to_addr(pageNum, pageShift); + return W25Q_ProgramRaw(buf, len, rawAddr); +} + +/** + * @brief W25Q Program any 8-bit data to raw addr + * Program any 8-bit data to preffered chip address + * + * @note Address is in [byte] size + * @note Be carefull with page overrun + * @param[in] buf Pointer to data to be written (single or array) + * @param[in] data_len Length of data (1..256) + * @param[in] rawAddr Start address of chip's cell + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgramRaw(u8_t *buf, u16_t data_len, u32_t rawAddr) { + if (data_len > 256 || data_len == 0) + return W25Q_PARAM_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + W25Q_STATE state = W25Q_WriteEnable(1); + if (state != W25Q_OK) + return state; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... +#if MEM_FLASH_SIZE > 128U + com.Instruction = W25Q_PAGE_PROGRAM_QUAD_INP_4B; // Command + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.Instruction = W25Q_PAGE_PROGRAM; // Command + com.AddressSize = QSPI_ADDRESS_24_BITS; + #endif + com.AddressMode = QSPI_ADDRESS_1_LINE; + + com.Address = rawAddr; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = data_len; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + if (HAL_QSPI_Transmit(&hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + return W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_Erase Erase functions + * @brief Erase sector, blocks or whole chip + * @{ + */ + +/** + * @brief W25Q Sector erase (4KB) + * Minimal size operation to erase data + * + * @note Should be executed before writing + * @param[in] SectAddr Sector start address + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_EraseSector(u32_t SectAddr) { + if (SectAddr >= SECTOR_COUNT) + return W25Q_PARAM_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + u32_t rawAddr = SectAddr * MEM_SECTOR_SIZE * 1024U; + + W25Q_STATE state = W25Q_WriteEnable(1); + if (state != W25Q_OK) + return state; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... +#if MEM_FLASH_SIZE > 128U + com.Instruction = W25Q_SECTOR_ERASE_4B; // Command + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.Instruction = W25Q_SECTOR_ERASE; // Command + com.AddressSize = QSPI_ADDRESS_24_BITS; +#endif + com.AddressMode = QSPI_ADDRESS_1_LINE; + + com.Address = rawAddr; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + return W25Q_OK; +} + +/** + * @brief W25Q Block erase (32/64 KB) + * Func to erase big block + * + * @note Should be executed before writing + * @param[in] BlockAddr Block start address + * @param[in] size Size of block: 32KB or 64KB + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_EraseBlock(u32_t BlockAddr, u8_t size) { + if (size != 32 && size != 64) + return W25Q_PARAM_ERR; + if ((size == 64 && BlockAddr >= BLOCK_COUNT) + || (size == 32 && BlockAddr >= BLOCK_COUNT * 2)) + return W25Q_PARAM_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + u32_t rawAddr = BlockAddr * MEM_SECTOR_SIZE * 1024U * 16; + if (size == 32) + rawAddr /= 2; + + W25Q_STATE state = W25Q_WriteEnable(1); + if (state != W25Q_OK) + return state; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + + if (size == 32) { + com.Instruction = W25Q_32KB_BLOCK_ERASE; // Command +#if MEM_FLASH_SIZE > 128U + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.AddressSize = QSPI_ADDRESS_24_BITS; +#endif + } else if (size == 64) { +#if MEM_FLASH_SIZE > 128U + com.Instruction = W25Q_64KB_BLOCK_ERASE_4B; // Command + com.AddressSize = QSPI_ADDRESS_32_BITS; +#else + com.Instruction = W25Q_64KB_BLOCK_ERASE; // Command + com.AddressSize = QSPI_ADDRESS_24_BITS; +#endif + } + + com.AddressMode = QSPI_ADDRESS_1_LINE; + + com.Address = rawAddr; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + return W25Q_OK; +} + +/** + * @brief W25Q Chip erase + * Func to erase all the data on chip + * + * @note Should be executed before writing + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_EraseChip(void) { + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + W25Q_STATE state = W25Q_WriteEnable(1); + if (state != W25Q_OK) + return state; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_CHIP_ERASE; // Command + + com.AddressSize = QSPI_ADDRESS_NONE; + com.AddressMode = QSPI_ADDRESS_NONE; + com.Address = 0; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + return W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_SUS Suspend functions + * @brief Pause/resume operations + * @{ + */ + +/** + * @brief W25Q Programm/Erase Suspend + * Pause programm or suspend operatiom + * + * @note SUS == 0 && BUSY == 1, otherwise ignored + * @note Power loose during suspend state may corrupt data + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgSuspend(void) { + if (W25Q_BUSY != W25Q_IsBusy()) + return W25Q_CHIP_IGNORE; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_ERASEPROG_SUSPEND; // Command + + com.AddressSize = QSPI_ADDRESS_NONE; + com.AddressMode = QSPI_ADDRESS_NONE; + com.Address = 0; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + return W25Q_OK; +} + +/** + * @brief W25Q Programm/Erase Resume + * Resume suspended state + * + * @note SUS == 1, otherwise ignored + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgResume(void) { + + W25Q_STATE state = W25Q_ReadStatusStruct(NULL); + if (state != W25Q_OK) + return state; + + if (w25q_status.SUS != 1) + return W25Q_CHIP_IGNORE; + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_ERASEPROG_RESUME; // Command + + com.AddressSize = QSPI_ADDRESS_NONE; + com.AddressMode = QSPI_ADDRESS_NONE; + com.Address = 0; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) + return W25Q_SPI_ERR; + + return W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_Sleep Sleep functions + * @brief Баю-бай, ток засыпай + * @{ + */ + +/** + * @brief W25Q Sleep / Power Down + * Set chip to low-power state + * + * @note Use WakeUP or ReadID + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_Sleep(void) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_POWERDOWN; // Command + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + w25q_delay(1); // Give a little time to sleep + + w25q_status.SLEEP = 1; + + return W25Q_OK; +} + +/** + * @brief W25Q WakeUP + * Wake UP function + * + * @param none + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_WakeUP(void) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_POWERUP; // Command + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + w25q_delay(1); // Give a little time to wake + + return W25Q_OK; +} + +/** + * @} + * @addtogroup W25Q_ID ID functions + * @brief Who am I? Хто я? + * @{ + */ + +/** + * @brief W25Q Read ID + * Function for reading chip ID + * + * @param[out] buf Pointer to output data (1 byte) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadID(u8_t *buf) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_DEVID; // Command + + com.AddressMode = QSPI_ADDRESS_1_LINE; + com.AddressSize = QSPI_ADDRESS_24_BITS; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_1_LINE; + com.NbData = 1; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + if (HAL_QSPI_Receive(&hqspi, buf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + return W25Q_OK; +} + +/** + * @brief W25Q Read chip Full ID + * Read Manufacturer ID + Device ID + * + * @attention Func in development + * @param[out] buf Pointer to data from ID register + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadFullID(u8_t *buf) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Read chip UID + * Read Unique ID + * + * @attention Func in development + * @param[out] buf Pointer to data from ID register + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadUID(u8_t *buf) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Read JEDEC ID + * Read ID by JEDEC standards + * + * @attention Func in development + * @param[out] buf Pointer to data from ID register + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadJEDECID(u8_t *buf) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Read SFDP Register + * Read device descriptor by SFDP standard + * + * @attention Func in development + * @param[out] buf Pointer to data from ID register + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadSFDPRegister(u8_t *buf) { + return W25Q_PARAM_ERR; +} + +/** + * @} + * @addtogroup W25Q_Secure Security register functions + * @brief Shhh, security + * @{ + */ + +/** + * @brief W25Q Erase Security Registers + * Clean security registers (one or all) + * + * @attention Func in development + * @param[in] numReg Number of security register (1..3 / 0-all) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_EraseSecurityRegisters(u8_t numReg) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Program Security Register + * Write data to security reg + * + * @attention Func in development + * @param[in] buf Pointer to 8-bit data bufer + * @param[in] numReg Number of security register (1..3) + * @param[in] byteAddr Byte addr in register (0..255) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ProgSecurityRegisters(u8_t *buf, u8_t numReg, u8_t byteAddr) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Read Security Register + * Read data from security reg + * + * @attention Func in development + * @param[out] buf Pointer to 8-bit data bufer + * @param[in] numReg Number of security register (1..3) + * @param[in] byteAddr Byte addr in register (0..255) + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_ReadSecurityRegisters(u8_t *buf, u8_t numReg, u8_t byteAddr) { + return W25Q_PARAM_ERR; +} + +/** + * @} + * @addtogroup W25Q_Protect Read-only protection functions + * @brief No writing! Protect block or whole chip + * @{ + */ + +/** + * @brief W25Q 4K Block lock + * Set read-only status to 4K block + * + * @attention Func in development + * @param[in] Addr Block address + * @param[in] enable 1-Enable/0-Disable + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_BlockReadOnly(u32_t Addr, bool enable) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q 4K Block lock CHECK + * Check read-only status from 4K block + * + * @attention Func in development + * @param[out] state Block read-only status (1-locked/0-unlocked) + * @param[in] Addr Block address + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_BlockReadOnlyCheck(bool *state, u32_t Addr) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Global read-only lock + * Set read-only status to the whole chip + * + * @attention Func in development + * @param[in] enable 1-enable/0-disable + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_GlobalReadOnly(bool enable){ + return W25Q_PARAM_ERR; +} + +/** + * @} + * @addtogroup W25Q_RST Reset functions + * @brief Reboot the chip + * @{ + */ + +/** + * @brief W25Q Software Reset + * Reset by register (not by external GPIO pin) + * + * @param[in] force Enable/disable (0/1) force reset - wait for BUSY and SUSpend + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_SwReset(bool force) { + + W25Q_STATE state; // temp status reg + + state = W25Q_ReadStatusStruct(NULL); // read settings + if (state != W25Q_OK) + return state; + + if (!force || w25q_status.BUSY || w25q_status.SUS) // if busy or suspend + return W25Q_CHIP_ERR; + + if (force) { + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + if (w25q_status.SUS) + W25Q_ProgResume(); + } + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = W25Q_ENABLE_RST; // Command + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + w25q_delay(1); // Give a little time to prepare + + com.Instruction = W25Q_RESET; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + w25q_delay(5); // Give a little time to reset + + state = W25Q_Init(); + + return state; +} +/// @} +// addgroup{ +/// @} +// Public { + +/** + * @brief W25Q Toggle WEL bit + * Toggle write enable latch + * + * @param[in] enable 1-enable write/0-disable write + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_WriteEnable(bool enable) { + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = enable ? W25Q_WRITE_ENABLE : W25Q_WRITE_DISABLE; + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + w25q_delay(1); // Give a little time to sleep + + w25q_status.WEL = 1; + + return W25Q_OK; +} + +/** + * @brief W25Q Toggle 4-byte mode + * + * @note Affects only ADS bit + * @param[in] enable 1-enable/0-disable + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_Enter4ByteMode(bool enable) { + + while (W25Q_IsBusy() == W25Q_BUSY) + w25q_delay(1); + + QSPI_CommandTypeDef com; + + com.InstructionMode = QSPI_INSTRUCTION_1_LINE; // QSPI_INSTRUCTION_... + com.Instruction = enable ? W25Q_ENABLE_4B_MODE : W25Q_DISABLE_4B_MODE; + + com.AddressMode = QSPI_ADDRESS_NONE; + com.AddressSize = QSPI_ADDRESS_NONE; + com.Address = 0x0U; + + com.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytes = QSPI_ALTERNATE_BYTES_NONE; + com.AlternateBytesSize = QSPI_ALTERNATE_BYTES_NONE; + + com.DummyCycles = 0; + com.DataMode = QSPI_DATA_NONE; + com.NbData = 0; + + com.DdrMode = QSPI_DDR_MODE_DISABLE; + //com.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + com.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(&hqspi, &com, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) + != HAL_OK) { + return W25Q_SPI_ERR; + } + + w25q_delay(1); // Give a little time to set command + + return W25Q_ReadStatusStruct(NULL); +} + +/** + * @brief W25Q Set extended byte + * Extended byte in 3-byte mode + * + * @attention Func in development + * @param[in] Addr 4th byte of addr + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_SetExtendedAddr(u8_t Addr) { + return W25Q_PARAM_ERR; +} + +/** + * @brief W25Q Get extended byte + * Read extended byte in 3-byte mode + * + * @attention Func in development + * @param[out] Addr 4th byte of addr + * @return W25Q_STATE enum + */ +W25Q_STATE W25Q_GetExtendedAddr(u8_t *outAddr) { + return W25Q_PARAM_ERR; +} + +/** + * @brief Page to address + * Translate page to byte-address + * + * @param[in] pageNum Number of page + * @param[in] pageShift Byte to shift inside page + * @return byte-address + */ +u32_t page_to_addr(u32_t pageNum, u8_t pageShift) { + return pageNum * MEM_PAGE_SIZE + pageShift; +} + +///@} |
