mirror of
https://gitlab.com/zephray/glider.git
synced 2025-12-31 13:07:10 +00:00
542 lines
19 KiB
C
542 lines
19 KiB
C
//
|
|
// Grimoire
|
|
// Copyright 2025 Wenting Zhang
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
#include "platform.h"
|
|
#include "board.h"
|
|
#include "app.h"
|
|
|
|
/* Reset Operations */
|
|
#define RESET_ENABLE_CMD 0x66
|
|
#define RESET_MEMORY_CMD 0x99
|
|
|
|
/* Identification Operations */
|
|
#define READ_ID_CMD 0x9E
|
|
#define READ_ID_CMD2 0x9F
|
|
#define MULTIPLE_IO_READ_ID_CMD 0xAF
|
|
#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A
|
|
|
|
/* Read Operations */
|
|
#define READ_CMD 0x03
|
|
#define FAST_READ_CMD 0x0B
|
|
#define DUAL_OUT_FAST_READ_CMD 0x3B
|
|
#define DUAL_INOUT_FAST_READ_CMD 0xBB
|
|
#define QUAD_OUT_FAST_READ_CMD 0x6B
|
|
#define QUAD_INOUT_FAST_READ_CMD 0xEB
|
|
|
|
/* Write Operations */
|
|
#define WRITE_ENABLE_CMD 0x06
|
|
#define WRITE_DISABLE_CMD 0x04
|
|
|
|
/* Register Operations */
|
|
#define READ_STATUS_REG_CMD 0x05
|
|
#define WRITE_STATUS_REG_CMD 0x01
|
|
|
|
#define READ_LOCK_REG_CMD 0xE8
|
|
#define WRITE_LOCK_REG_CMD 0xE5
|
|
|
|
#define READ_FLAG_STATUS_REG_CMD 0x70
|
|
#define CLEAR_FLAG_STATUS_REG_CMD 0x50
|
|
|
|
#define READ_NONVOL_CFG_REG_CMD 0xB5
|
|
#define WRITE_NONVOL_CFG_REG_CMD 0xB1
|
|
|
|
#define READ_VOL_CFG_REG_CMD 0x85
|
|
#define WRITE_VOL_CFG_REG_CMD 0x81
|
|
|
|
#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65
|
|
#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61
|
|
|
|
/* Program Operations */
|
|
#define PAGE_PROG_CMD 0x02
|
|
#define DUAL_IN_FAST_PROG_CMD 0xA2
|
|
#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2
|
|
#define QUAD_IN_FAST_PROG_CMD 0x32
|
|
#define EXT_QUAD_IN_FAST_PROG_CMD 0x12
|
|
|
|
/* Erase Operations */
|
|
#define SUBSECTOR_ERASE_CMD 0x20
|
|
#define SECTOR_ERASE_CMD 0xD8
|
|
#define BULK_ERASE_CMD 0xC7
|
|
|
|
#define PROG_ERASE_RESUME_CMD 0x7A
|
|
#define PROG_ERASE_SUSPEND_CMD 0x75
|
|
|
|
/* One-Time Programmable Operations */
|
|
#define READ_OTP_ARRAY_CMD 0x4B
|
|
#define PROG_OTP_ARRAY_CMD 0x42
|
|
|
|
static int spif_auto_polling_mem_ready(uint32_t timeout) {
|
|
QSPI_CommandTypeDef s_command;
|
|
QSPI_AutoPollingTypeDef s_config;
|
|
|
|
/* Configure automatic polling mode to wait for memory ready */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = READ_STATUS_REG_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
s_config.Match = 0;
|
|
s_config.MatchMode = QSPI_MATCH_MODE_AND;
|
|
s_config.Interval = 0x10;
|
|
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
|
|
s_config.Mask = SPIF_SR_WIP;
|
|
s_config.StatusBytesSize = 2;
|
|
|
|
if (HAL_QSPI_AutoPolling(&hqspi, &s_command, &s_config, timeout) != HAL_OK)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int spif_reset_memory(void) {
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = RESET_ENABLE_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_NONE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
s_command.Instruction = RESET_MEMORY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
return spif_auto_polling_mem_ready(HAL_QSPI_TIMEOUT_DEFAULT_VALUE);
|
|
}
|
|
|
|
static int spif_write_enable(void) {
|
|
QSPI_CommandTypeDef s_command;
|
|
QSPI_AutoPollingTypeDef s_config;
|
|
|
|
/* Enable write operations */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = WRITE_ENABLE_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_NONE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
/* Configure automatic polling mode to wait for write enabling */
|
|
s_config.Match = SPIF_SR_WREN;
|
|
s_config.Mask = SPIF_SR_WREN;
|
|
s_config.MatchMode = QSPI_MATCH_MODE_AND;
|
|
s_config.StatusBytesSize = 1;
|
|
s_config.Interval = 0x10;
|
|
s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
|
|
|
|
s_command.Instruction = READ_STATUS_REG_CMD;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
|
|
if (HAL_QSPI_AutoPolling(&hqspi, &s_command, &s_config, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
}
|
|
|
|
static int spif_dummy_cycles_cfg(void) {
|
|
QSPI_CommandTypeDef s_command;
|
|
uint8_t reg = 0;
|
|
|
|
/* Initialize the read volatile configuration register command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = READ_VOL_CFG_REG_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.NbData = 1;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
/* Configure the command */
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
/* Reception of the data */
|
|
if (HAL_QSPI_Receive(&hqspi, (uint8_t *)(®), HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
/* Enable write operations */
|
|
if (spif_write_enable() != 0)
|
|
return -1;
|
|
|
|
/* Update volatile configuration register (with new dummy cycles) */
|
|
s_command.Instruction = WRITE_VOL_CFG_REG_CMD;
|
|
MODIFY_REG(reg, 0xF0F0, (SPIF_DUMMY_CYCLES_READ_QUAD << 4));
|
|
|
|
/* Configure the write volatile configuration register command */
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
/* Transmission of the data */
|
|
if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)(®), HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int spif_init(void) {
|
|
int result;
|
|
result = spif_reset_memory();
|
|
//result += spif_dummy_cycles_cfg();
|
|
if (result != 0) {
|
|
syslog_printf("SPI flash initialization failed");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// TODO: Should have been a semaphore
|
|
static volatile bool tx_complete = false;
|
|
static volatile bool rx_complete = false;
|
|
|
|
void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi) {
|
|
tx_complete = true;
|
|
}
|
|
|
|
void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi) {
|
|
rx_complete = true;
|
|
}
|
|
|
|
int spif_read(uint32_t addr, uint32_t size, uint8_t *dat) {
|
|
static QSPI_CommandTypeDef s_command = {
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.Instruction = QUAD_INOUT_FAST_READ_CMD,
|
|
.AddressMode = QSPI_ADDRESS_4_LINES,
|
|
.AddressSize = QSPI_ADDRESS_24_BITS,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_4_LINES,
|
|
.DummyCycles = SPIF_DUMMY_CYCLES_READ_QUAD,
|
|
.DdrMode = QSPI_DDR_MODE_DISABLE,
|
|
.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY,
|
|
.SIOOMode = QSPI_SIOO_INST_EVERY_CMD,
|
|
};
|
|
|
|
/* Initialize the read command */
|
|
s_command.Address = addr;
|
|
s_command.NbData = size;
|
|
|
|
/* Configure the command */
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
rx_complete = false;
|
|
|
|
/* Reception of the data */
|
|
if (HAL_QSPI_Receive_DMA(&hqspi, dat) != HAL_OK)
|
|
return -1;
|
|
|
|
while (!rx_complete);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int spif_write(uint32_t addr, uint32_t size, uint8_t *dat) {
|
|
QSPI_CommandTypeDef s_command;
|
|
uint32_t end_addr, current_size, current_addr;
|
|
|
|
/* Calculation of the size between the write address and the end of the page */
|
|
current_size = SPIF_PAGE_SIZE - (addr % SPIF_PAGE_SIZE);
|
|
|
|
/* Check if the size of the data is less than the remaining place in the page */
|
|
if (current_size > size) {
|
|
current_size = size;
|
|
}
|
|
|
|
/* Initialize the adress variables */
|
|
current_addr = addr;
|
|
end_addr = addr + size;
|
|
|
|
/* Initialize the program command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = QUAD_IN_FAST_PROG_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_4_LINES;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
/* Perform the write page by page */
|
|
do {
|
|
s_command.Address = current_addr;
|
|
s_command.NbData = current_size;
|
|
|
|
if (spif_write_enable() != 0)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
tx_complete = false;
|
|
|
|
if (HAL_QSPI_Transmit_DMA(&hqspi, dat) != HAL_OK)
|
|
return -1;
|
|
|
|
while (!tx_complete);
|
|
|
|
if (spif_auto_polling_mem_ready(HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != 0)
|
|
return -1;
|
|
|
|
current_addr += current_size;
|
|
dat += current_size;
|
|
current_size = ((current_addr + SPIF_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : SPIF_PAGE_SIZE;
|
|
} while (current_addr < end_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int spif_erase_block(uint32_t addr) {
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
/* Initialize the erase command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = SUBSECTOR_ERASE_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
|
|
s_command.Address = addr;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_NONE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (spif_write_enable() != 0)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (spif_auto_polling_mem_ready(SPIF_SUBSECTOR_ERASE_TIMEOUT) != 0)
|
|
return -1;
|
|
}
|
|
|
|
int spif_erase_sector(uint32_t addr) {
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
/* Initialize the erase command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = SECTOR_ERASE_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
|
|
s_command.Address = addr;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_NONE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (spif_write_enable() != 0)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (spif_auto_polling_mem_ready(SPIF_SECTOR_ERASE_TIMEOUT) != 0)
|
|
return -1;
|
|
}
|
|
|
|
int spif_erase_chip(void) {
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
/* Initialize the erase command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = BULK_ERASE_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_NONE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (spif_write_enable() != 0)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (spif_auto_polling_mem_ready(SPIF_BULK_ERASE_TIMEOUT) != 0)
|
|
return -1;
|
|
}
|
|
|
|
uint8_t spif_get_status(void) {
|
|
QSPI_CommandTypeDef s_command;
|
|
uint8_t reg;
|
|
|
|
/* Initialize the read flag status register command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = READ_FLAG_STATUS_REG_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.NbData = 1;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Receive(&hqspi, ®, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (reg & (SPIF_FSR_PRERR | SPIF_FSR_VPPERR | SPIF_FSR_PGERR | SPIF_FSR_ERERR))
|
|
return SPIF_ERROR;
|
|
else if (reg & (SPIF_FSR_PGSUS | SPIF_FSR_ERSUS))
|
|
return SPIF_SUSPENDED;
|
|
else if (reg & SPIF_FSR_READY)
|
|
return SPIF_READY;
|
|
else
|
|
return SPIF_BUSY;
|
|
}
|
|
|
|
int spif_read_id(spif_id_t *id) {
|
|
uint8_t *rxbuf = (uint8_t *)id;
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
memset(id, 0, sizeof(*id));
|
|
|
|
/* Initialize the erase command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = READ_ID_CMD;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.NbData = 20;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Receive(&hqspi, rxbuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int spif_read_jedec_id(spif_id_t *id) {
|
|
uint8_t *rxbuf = (uint8_t *)id;
|
|
QSPI_CommandTypeDef s_command;
|
|
|
|
memset(id, 0, sizeof(*id));
|
|
|
|
/* Initialize the erase command */
|
|
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
s_command.Instruction = READ_ID_CMD2;
|
|
s_command.AddressMode = QSPI_ADDRESS_NONE;
|
|
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
s_command.DataMode = QSPI_DATA_1_LINE;
|
|
s_command.DummyCycles = 0;
|
|
s_command.NbData = 3;
|
|
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
if (HAL_QSPI_Receive(&hqspi, rxbuf, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// spiffs abstraction layer
|
|
static spiffs_config spiffs_cfg;
|
|
spiffs spiffs_fs;
|
|
SemaphoreHandle_t spiffs_lock;
|
|
static uint8_t fs_work_buf[256 * 2];
|
|
static uint8_t fs_fds[32 * 4];
|
|
static uint8_t fs_cache_buf[(256 + 32) * 4];
|
|
|
|
static int32_t _spiffs_erase(uint32_t addr, uint32_t len) {
|
|
int res = 0;
|
|
if ((len == SPIF_SECTOR_SIZE) && ((addr & (SPIF_SECTOR_SIZE - 1)) == 0)) {
|
|
res = spif_erase_sector(addr);
|
|
}
|
|
else {
|
|
uint32_t i = 0;
|
|
uint32_t erase_count = (len + 4096 - 1) / 4096;
|
|
for (i = 0; i < erase_count; i++) {
|
|
res += spif_erase_block(addr + i * 4096);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int32_t _spiffs_read(uint32_t addr, uint32_t size, uint8_t *dst) {
|
|
return spif_read(addr, size, dst);
|
|
}
|
|
|
|
static int32_t _spiffs_write(uint32_t addr, uint32_t size, uint8_t *dst) {
|
|
return spif_write(addr, size, dst);
|
|
}
|
|
|
|
void spiffs_init(void) {
|
|
spiffs_lock = xSemaphoreCreateMutex();
|
|
spiffs_cfg.hal_erase_f = _spiffs_erase;
|
|
spiffs_cfg.hal_read_f = _spiffs_read;
|
|
spiffs_cfg.hal_write_f = _spiffs_write;
|
|
int res = SPIFFS_mount(&spiffs_fs, &spiffs_cfg, fs_work_buf, fs_fds,
|
|
sizeof(fs_fds), fs_cache_buf, sizeof(fs_cache_buf), NULL);
|
|
if ((res != SPIFFS_OK) && (SPIFFS_errno(&spiffs_fs) == SPIFFS_ERR_NOT_A_FS)) {
|
|
syslog_printf("Formatting SPIFFS...");
|
|
if (SPIFFS_format(&spiffs_fs) != SPIFFS_OK) {
|
|
syslog_printf("SPIFFS format failed: %d\n", SPIFFS_errno(&spiffs_fs));
|
|
}
|
|
res = SPIFFS_mount(&spiffs_fs, &spiffs_cfg, fs_work_buf, fs_fds,
|
|
sizeof(fs_fds), fs_cache_buf, sizeof(fs_cache_buf), NULL);
|
|
}
|
|
if (res != SPIFFS_OK) {
|
|
syslog_printf("SPIFFS mount failed: %d\n", SPIFFS_errno(&spiffs_fs));
|
|
}
|
|
else {
|
|
syslog_printf("SPIFFS mounted\n");
|
|
}
|
|
}
|