diff --git a/flash/MX25L51245GZ2I-08G.c b/flash/MX25L51245GZ2I-08G.c new file mode 100644 index 0000000..c04764c --- /dev/null +++ b/flash/MX25L51245GZ2I-08G.c @@ -0,0 +1,671 @@ +/** + ****************************************************************************** + * @file : MX25L51245GZ2I-08G.c + * @brief : Driver for the flash chip on FC rev 3. + ****************************************************************************** + * @copyright + * + * Copyright (c) 2026 Sun Devil Rocketry. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is covered under the + * BSD-3-Clause. + * + * https://opensource.org/license/bsd-3-clause + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### Flash driver features ##### + ============================================================================== + [..] + (+) Implements the same APIs as the legacy driver + ****************************************************************************** + @endverbatim + */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "flash.h" + +#include "stm32h7xx_hal.h" +#include "sdr_pin_defines_A0010.h" + +/* Global Variables ----------------------------------------------------------*/ + + + +/* Private function prototypes -----------------------------------------------*/ + +static FLASH_STATUS flash_qspi_enable + ( + void + ); + +static FLASH_STATUS flash_write_enable + ( + void + ); + +static FLASH_STATUS flash_enable_4byte_addressing + ( + void + ); + +static FLASH_STATUS flash_wait_ready + ( + uint32_t timeout_ms + ); + + +/* Procedures ----------------------------------------------------------------*/ + +/** + * @brief Initializes the flash driver + * + * @details This function should be called before any other in the flash + * driver, as it initializes the driver to a known state that allows other + * commands to function properly. + * + * @param pflash_handle Pointer to the flash handle for this device. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_init + ( + HFLASH_BUFFER* pflash_handle + ) +{ +/*------------------------------------------------------------------------------ + Local variables +------------------------------------------------------------------------------*/ +FLASH_STATUS flash_status; /* Flash API function return codes */ + + +/*------------------------------------------------------------------------------ + Initializations +------------------------------------------------------------------------------*/ +flash_status = FLASH_OK; +pflash_handle -> status_register = 0; + +/*------------------------------------------------------------------------------ + API Function Implementation +------------------------------------------------------------------------------*/ +/* Protective Precondition */ +if ( pflash_handle == NULL ) + { + return FLASH_INVALID_INPUT; + } + +/* Activate QSPI */ +if ( flash_qspi_enable() != FLASH_OK ) + { + return FLASH_INIT_FAIL; + } + +/* Write enable */ +if ( flash_write_enable() != FLASH_OK ) + { + return FLASH_INIT_FAIL; + } +else + { + pflash_handle -> write_protected = false; + } + +/* Enable 4-byte addressing */ +if ( flash_enable_4byte_addressing() != FLASH_OK ) + { + return FLASH_INIT_FAIL; + } + +/* Check the flash chip status register to confirm chip can be reached */ +flash_status = flash_get_status( pflash_handle ); +if ( flash_status != FLASH_OK ) + { + return flash_status; + } +else if ( !(pflash_handle -> status_register & FLASH_STATUS_REG_QUAD_ENABLED) ) + { + return FLASH_INIT_FAIL; + } + +return FLASH_OK; + +} /* flash_init */ + + +/** + * @brief Erase the entire contents of the flash chip. + * + * @param pflash_handle A pointer to the flash handle object to be used for the operation. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_erase + ( + HFLASH_BUFFER* pflash_handle + ) +{ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; + +if ( pflash_handle == NULL ) + { + return FLASH_INVALID_INPUT; + } +else if ( pflash_handle -> write_protected ) + { + return FLASH_WRITE_PROTECTED; + } + +/* Construct command */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_CHIP_ERASE_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.AddressMode = HAL_OSPI_ADDRESS_NONE; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_NONE; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +/* Wait until the device clears BUSY bit */ +return flash_wait_ready(FLASH_TIMEOUT_ERASE); + +} /* flash_erase */ + + +/** + * @brief Erase a block of flash. + * + * @param flash_block_num The number of the block to erase (0-indexed). + * @param size The size of the block to erase. + * + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_block_erase + ( + FLASH_BLOCK flash_block_num, + FLASH_BLOCK_SIZE size + ) +{ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; +uint32_t addr = 0; +uint32_t end_addr = 0; +uint32_t opcode = 0; + +/* Convert the block number/size to addresses and operations */ +switch ( size ) + { + case FLASH_BLOCK_4K: + opcode = FLASH_SECTOR_ERASE_4KB_CMD; + addr = ((uint32_t)flash_block_num) * 0x1000u; + end_addr = (addr + 0x1000) - 1; + break; + + case FLASH_BLOCK_32K: + opcode = FLASH_BLOCK_ERASE_32KB_CMD; + addr = ((uint32_t)flash_block_num) * 0x8000u; + end_addr = (addr + 0x8000) - 1; + break; + + case FLASH_BLOCK_64K: + opcode = FLASH_BLOCK_ERASE_64KB_CMD; + addr = ((uint32_t)flash_block_num) * 0x10000u; + end_addr = (addr + 0x10000) - 1; + break; + + default: + return FLASH_INVALID_INPUT; + } + +/* Validate addresses */ +if( end_addr > FLASH_MAX_ADDR ) + { + return FLASH_INVALID_INPUT; + } + +/* Construct command */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = opcode; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.Address = addr; +spi_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE; +spi_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_NONE; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +return flash_wait_ready(FLASH_TIMEOUT_ERASE); + +} /* flash_block_erase */ + + +/** + * @brief Write up to a page (256 bytes) to the flash memory. + * + * @param pflash_handle A pointer to the flash handle object to be used for the operation. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_write + ( + HFLASH_BUFFER* pflash_handle + ) +{ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; +size_t len = 0; + +if ( (pflash_handle == NULL) || (pflash_handle->pbuffer == NULL) ) + { + return FLASH_INVALID_INPUT; + } + +len = pflash_handle->num_bytes; +if ( ( len == 0u ) + || ( len > FLASH_PAGE_SIZE ) ) + { + return FLASH_INVALID_INPUT; + } + +/* Validate addresses */ +if( ( pflash_handle->address + len ) - 1 > FLASH_MAX_ADDR ) + { + return FLASH_INVALID_INPUT; + } + +/* Assumes flash_init() already enabled QSPI + write enable */ + +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_PAGE_PROGRAM_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.Address = pflash_handle->address; +spi_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE; +spi_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_4_LINES; +spi_command.NbData = len; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +hal_status = HAL_OSPI_Transmit(&FLASH_OSPI, pflash_handle->pbuffer, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +return flash_wait_ready(FLASH_TIMEOUT_DEFAULT); + +} /* flash_write */ + + +/** + * @brief Read data from the flash memory. + * + * @param pflash_handle A pointer to the flash handle object to be used for the operation. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_read + ( + HFLASH_BUFFER* pflash_handle, + uint32_t num_bytes + ) +{ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; +size_t len = 0; + +/* Verify valid pointers */ +if ( ( pflash_handle == NULL ) + || ( pflash_handle->pbuffer == NULL ) ) + { + return FLASH_INVALID_INPUT; + } + +/* If we're reading more bytes than the buffer can handle, we fail so we prevent overflow */ +len = num_bytes; +if ( ( len == 0u ) + || ( len > pflash_handle->num_bytes ) ) + { + return FLASH_INVALID_INPUT; + } + +/* Validate addresses */ +if( ( pflash_handle->address + len ) - 1 > FLASH_MAX_ADDR ) + { + return FLASH_INVALID_INPUT; + } + +/* Construct command */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_READ_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.Address = pflash_handle->address; +spi_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE; +spi_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_4_LINES; +spi_command.NbData = len; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = FLASH_READ_DUMMY_CYCLES; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +hal_status = HAL_OSPI_Receive(&FLASH_OSPI, pflash_handle->pbuffer, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +return FLASH_OK; + +} /* flash_read */ + + +/** + * @brief Identify whether flash is currently performing an operation on the chip. + * + * @param pflash_handle A pointer to the flash handle object to be used for the operation. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_is_flash_busy + ( + HFLASH_BUFFER* pflash_handle + ) +{ +if ( pflash_handle == NULL ) + { + return FLASH_INVALID_INPUT; + } +else if ( flash_get_status( pflash_handle ) != FLASH_OK ) + { + return FLASH_FAIL; + } +else if ( ( pflash_handle->status_register & FLASH_STATUS_REG_WIP ) == 0u ) + { + return FLASH_OK; + } +else + { + return FLASH_IN_PROGRESS; + } +} + + +/** + * @brief Retrieve the status register on the flash peripheral. + * + * @param pflash_handle A pointer to the flash handle object to be used for the operation. + * @retval The status of the flash peripheral. + */ +FLASH_STATUS flash_get_status + ( + HFLASH_BUFFER* pflash_handle + ) +{ +/* Initializations */ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; + +if ( pflash_handle == NULL ) + { + return FLASH_INVALID_INPUT; + } + +/* Construct "Read Status Register" command */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_READ_STATUS_REG_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.AddressMode = HAL_OSPI_ADDRESS_NONE; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_1_LINE; +spi_command.NbData = 1; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +hal_status = HAL_OSPI_Receive(&FLASH_OSPI, &(pflash_handle->status_register), FLASH_TIMEOUT_DEFAULT); +if ( hal_status != HAL_OK ) + { + return FLASH_FAIL; + } + +return FLASH_OK; + +} /* flash_get_status */ + + +/** + * @brief Enable QSPI mode on the flash peripheral. + * + * @retval The status of the flash peripheral. + */ +static FLASH_STATUS flash_qspi_enable + ( + void + ) +{ +/* Initializations */ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; + +/* Construct QSPI enable command (single SPI mode) */ +spi_command.Instruction = FLASH_ENABLE_QSPI_CMD; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.AddressMode = HAL_OSPI_ADDRESS_NONE; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_NONE; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; + +/* Transmit (blocking) */ +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); + +if( hal_status == HAL_OK ) + { + return FLASH_OK; + } +else + { + return FLASH_FAIL; + } + +} /* flash_qspi_enable */ + + +/** + * @brief Enable writes to the flash peripheral. + * + * @retval The status of the flash peripheral. + */ +static FLASH_STATUS flash_write_enable + ( + void + ) +{ +/* Initializations */ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; + +/* Construct write enable command (no address/data) */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_WRITE_ENABLE_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.AddressMode = HAL_OSPI_ADDRESS_NONE; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_NONE; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +/* Transmit (blocking) */ +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); + +if( hal_status == HAL_OK ) + { + return FLASH_OK; + } +else + { + return FLASH_FAIL; + } + +} /* flash_write_enable */ + + +/** + * @brief Enable four-byte addresses on the flash peripheral. + * + * @retval The status of the flash peripheral. + */ +static FLASH_STATUS flash_enable_4byte_addressing + ( + void + ) +{ +/* Initializations */ +HAL_StatusTypeDef hal_status = HAL_OK; +OSPI_RegularCmdTypeDef spi_command = {0}; + +/* Construct "Enter 4-byte address mode" command (no address/data) */ +spi_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; +spi_command.FlashId = HAL_OSPI_FLASH_ID_1; +spi_command.Instruction = FLASH_ENABLE_4BYTE_ADDR_CMD; +spi_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; +spi_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; +spi_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; +spi_command.AddressMode = HAL_OSPI_ADDRESS_NONE; +spi_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; +spi_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; +spi_command.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; +spi_command.DataMode = HAL_OSPI_DATA_NONE; +spi_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; +spi_command.DummyCycles = 0; +spi_command.DQSMode = HAL_OSPI_DQS_DISABLE; +spi_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; + +hal_status = HAL_OSPI_Command(&FLASH_OSPI, &spi_command, FLASH_TIMEOUT_DEFAULT); + +if( hal_status == HAL_OK ) + { + return FLASH_OK; + } +else + { + return FLASH_FAIL; + } + +} /* flash_enable_4byte_addressing */ + + +/** + * @brief Busy-wait until the flash signals ready status. + * + * @param timeout_ms The amount of time to wait (in ms) for the operation to complete. + * @retval The status of the flash peripheral. + */ +static FLASH_STATUS flash_wait_ready + ( + uint32_t timeout_ms + ) +{ +uint32_t start = HAL_GetTick(); +HFLASH_BUFFER handle = {0}; + +while ( true ) + { + if ( flash_get_status( &handle ) != FLASH_OK ) + { + return FLASH_FAIL; + } + + if ( ( handle.status_register & FLASH_STATUS_REG_WIP ) == 0u ) + { + return FLASH_OK; + } + + if ( ( timeout_ms != 0xFFFFFFFFu ) + && ( ( HAL_GetTick() - start ) > timeout_ms ) ) + { + return FLASH_TIMEOUT; + } + } +} \ No newline at end of file diff --git a/flash/flash.c b/flash/flash.c index f682834..9c4f0c0 100644 --- a/flash/flash.c +++ b/flash/flash.c @@ -5,7 +5,12 @@ * * DESCRIPTION: * Contains API functions for writing and reading data from the engine -* controller's flash +* controller's flash. +* +* NOTE: +* This is the "legacy" flash driver for the 4MBit +* SST25VF040B-50-4I-S2AE-T flash chip used on old liquids & flight +* boards. * * COPYRIGHT: * Copyright (c) 2025 Sun Devil Rocketry. diff --git a/flash/flash.h b/flash/flash.h index 5ab5877..f059f6a 100644 --- a/flash/flash.h +++ b/flash/flash.h @@ -38,82 +38,125 @@ Includes #include /* Project includes */ +#ifndef A0010 #include "sensor.h" +#endif + +/* Aliasing -- choose implementation */ +#ifndef A0010 +#define USE_LEGACY_FLASH_DRIVER +#endif /*------------------------------------------------------------------------------ Macros ------------------------------------------------------------------------------*/ -/* Flash subcommand bitmasks */ -#define FLASH_SUBCMD_OP_BITMASK 0b11100000 -#define FLASH_NBYTES_BITMASK 0b00011111 - -/* Write protection ON/OFF States */ -#define FLASH_WP_READ_ONLY true -#define FLASH_WP_WRITE_ENABLED false - -/* Flash Chip operation codes from datasheet */ -#define FLASH_OP_HW_READ 0x03 -#define FLASH_OP_HW_READ_HS 0x0B -#define FLASH_OP_HW_4K_ERASE 0x20 -#define FLASH_OP_HW_32K_ERASE 0x52 -#define FLASH_OP_HW_64K_ERASE 0xD8 -#define FLASH_OP_HW_FULL_ERASE 0x60 -#define FLASH_OP_HW_BYTE_PROGRAM 0x02 -#define FLASH_OP_HW_AAI_PROGRAM 0xAD -#define FLASH_OP_HW_RDSR 0x05 -#define FLASH_OP_HW_EWSR 0x50 -#define FLASH_OP_HW_WRSR 0x01 -#define FLASH_OP_HW_WREN 0x06 -#define FLASH_OP_HW_WRDI 0x04 -#define FLASH_OP_HW_RDID 0x90 -#define FLASH_OP_HW_JEDEC_ID 0x9F -#define FLASH_OP_HW_EBSY 0x70 -#define FLASH_OP_HW_DBSY 0x80 - -/* Maximum Flash address */ -#define FLASH_MAX_ADDR 0x07FFFF - -/* Reset state of flash register */ -#define FLASH_REG_RESET_VAL 0b00111000 - -/* Timeouts */ -#ifndef SDR_DEBUG - #define HAL_FLASH_TIMEOUT 100 +#ifdef USE_LEGACY_FLASH_DRIVER + /* Flash subcommand bitmasks */ + #define FLASH_SUBCMD_OP_BITMASK 0b11100000 + #define FLASH_NBYTES_BITMASK 0b00011111 + + /* Write protection ON/OFF States */ + #define FLASH_WP_READ_ONLY true + #define FLASH_WP_WRITE_ENABLED false + + /* Flash Chip operation codes from datasheet */ + #define FLASH_OP_HW_READ 0x03 + #define FLASH_OP_HW_READ_HS 0x0B + #define FLASH_OP_HW_4K_ERASE 0x20 + #define FLASH_OP_HW_32K_ERASE 0x52 + #define FLASH_OP_HW_64K_ERASE 0xD8 + #define FLASH_OP_HW_FULL_ERASE 0x60 + #define FLASH_OP_HW_BYTE_PROGRAM 0x02 + #define FLASH_OP_HW_AAI_PROGRAM 0xAD + #define FLASH_OP_HW_RDSR 0x05 + #define FLASH_OP_HW_EWSR 0x50 + #define FLASH_OP_HW_WRSR 0x01 + #define FLASH_OP_HW_WREN 0x06 + #define FLASH_OP_HW_WRDI 0x04 + #define FLASH_OP_HW_RDID 0x90 + #define FLASH_OP_HW_JEDEC_ID 0x9F + #define FLASH_OP_HW_EBSY 0x70 + #define FLASH_OP_HW_DBSY 0x80 + + /* Maximum Flash address */ + #define FLASH_MAX_ADDR 0x07FFFF + + /* Reset state of flash register */ + #define FLASH_REG_RESET_VAL 0b00111000 + + /* Timeouts */ + #ifndef SDR_DEBUG + #define HAL_FLASH_TIMEOUT 100 + #else + #define HAL_FLASH_TIMEOUT 0xFFFFFFFF + #endif + + /* Flash busy/ready boolean codes */ + #define FLASH_BUSY true + #define FLASH_READY false + + /* Status register bitmasks */ + #define FLASH_BUSY_BITMASK 0b00000001 + + /* Flash Block Addresses - 4Mbit of memory -> 512kB total + 4kB min sector size -> Max 128 sectors + 32kB sector size -> 16 Pages + 64kB sector size -> 8 Pages*/ + /* Use 32kB pages for up to 15 flight's recorded */ + #define FLASH_BLOCK0_ADDR 0x000000 + #define FLASH_BLOCK1_ADDR 0x008000 + #define FLASH_BLOCK2_ADDR 0x010000 + #define FLASH_BLOCK3_ADDR 0x018000 + #define FLASH_BLOCK4_ADDR 0x020000 + #define FLASH_BLOCK5_ADDR 0x028000 + #define FLASH_BLOCK6_ADDR 0x030000 + #define FLASH_BLOCK7_ADDR 0x038000 + #define FLASH_BLOCK8_ADDR 0x040000 + #define FLASH_BLOCK9_ADDR 0x048000 + #define FLASH_BLOCK10_ADDR 0x050000 + #define FLASH_BLOCK11_ADDR 0x058000 + #define FLASH_BLOCK12_ADDR 0x060000 + #define FLASH_BLOCK13_ADDR 0x068000 + #define FLASH_BLOCK14_ADDR 0x070000 + #define FLASH_BLOCK15_ADDR 0x078000 #else - #define HAL_FLASH_TIMEOUT 0xFFFFFFFF + /* Utility Macros */ + #define FLASH_TIMEOUT_DEFAULT 100 + #define FLASH_TIMEOUT_ERASE 1000 + #define FLASH_READ_DUMMY_CYCLES 8 + #define FLASH_PAGE_SIZE 256 + #define FLASH_MAX_ADDR 0x03FFFFFF + /* Config Commands */ + #define FLASH_WRITE_ENABLE_CMD 0x06 + #define FLASH_WRITE_DISABLE_CMD 0x04 + #define FLASH_READ_STATUS_REG_CMD 0x05 + #define FLASH_READ_CFG_REG_CMD 0x15 + #define FLASH_WRITE_STATUS_CFG_REG_CMD 0x01 + #define FLASH_ENABLE_QSPI_CMD 0x35 /* MUST be performed in SPI mode */ + #define FLASH_DISABLE_QSPI_CMD 0xF5 /* MUST be performed in QSPI mode */ + #define FLASH_ENABLE_4BYTE_ADDR_CMD 0xB7 + #define FLASH_SET_BURST_LENGTH_CMD 0xC0 + /* I/O Commands */ + #define FLASH_READ_CMD 0x6B + #define FLASH_PAGE_PROGRAM_CMD 0x12 + #define FLASH_CHIP_ERASE_CMD 0xC7 + #define FLASH_SECTOR_ERASE_4KB_CMD 0x21 + #define FLASH_BLOCK_ERASE_32KB_CMD 0x5C + #define FLASH_BLOCK_ERASE_64KB_CMD 0xDC + + /* Status Register Bitmasks */ + #define FLASH_STATUS_REG_WRITE_PROTECTED 0b10000000 + #define FLASH_STATUS_REG_QUAD_ENABLED 0b01000000 + #define FLASH_STATUS_REG_BP3 0b00100000 + #define FLASH_STATUS_REG_BP2 0b00010000 + #define FLASH_STATUS_REG_BP1 0b00001000 + #define FLASH_STATUS_REG_BP0 0b00000100 + #define FLASH_STATUS_REG_WEL 0b00000010 + #define FLASH_STATUS_REG_WIP 0b00000001 #endif -/* Flash busy/ready boolean codes */ -#define FLASH_BUSY true -#define FLASH_READY false - -/* Status register bitmasks */ -#define FLASH_BUSY_BITMASK 0b00000001 - -/* Flash Block Addresses - 4Mbit of memory -> 512kB total - 4kB min sector size -> Max 128 sectors - 32kB sector size -> 16 Pages - 64kB sector size -> 8 Pages*/ -/* Use 32kB pages for up to 15 flight's recorded */ -#define FLASH_BLOCK0_ADDR 0x000000 -#define FLASH_BLOCK1_ADDR 0x008000 -#define FLASH_BLOCK2_ADDR 0x010000 -#define FLASH_BLOCK3_ADDR 0x018000 -#define FLASH_BLOCK4_ADDR 0x020000 -#define FLASH_BLOCK5_ADDR 0x028000 -#define FLASH_BLOCK6_ADDR 0x030000 -#define FLASH_BLOCK7_ADDR 0x038000 -#define FLASH_BLOCK8_ADDR 0x040000 -#define FLASH_BLOCK9_ADDR 0x048000 -#define FLASH_BLOCK10_ADDR 0x050000 -#define FLASH_BLOCK11_ADDR 0x058000 -#define FLASH_BLOCK12_ADDR 0x060000 -#define FLASH_BLOCK13_ADDR 0x068000 -#define FLASH_BLOCK14_ADDR 0x070000 -#define FLASH_BLOCK15_ADDR 0x078000 - /*------------------------------------------------------------------------------ Typdefs @@ -154,11 +197,13 @@ typedef struct _FLASH_BUFFER_TAG { /* Write protection state */ bool write_protected; + #ifdef USE_LEGACY_FLASH_DRIVER /* BPL settings for block protection */ FLASH_BPL_BITS bpl_bits; /* Write protection setting of flash BPL bits */ FLASH_BPL_WP bpl_write_protect; + #endif /* Contents of status register */ uint8_t status_register; @@ -184,6 +229,7 @@ typedef enum FLASH_STATUS { FLASH_OK = 0 , FLASH_FAIL , + FLASH_IN_PROGRESS , FLASH_UNSUPPORTED_OP , FLASH_UNRECOGNIZED_OP , FLASH_TIMEOUT , @@ -205,6 +251,7 @@ typedef enum FLASH_STATUS } FLASH_STATUS; /* Flash Block Numbers */ +#ifdef USE_LEGACY_FLASH_DRIVER typedef enum _FLASH_BLOCK { FLASH_BLOCK_0 = 0, @@ -221,8 +268,11 @@ typedef enum _FLASH_BLOCK FLASH_BLOCK_12 , FLASH_BLOCK_13 , FLASH_BLOCK_14 , - FLASH_BLOCK_15 + FLASH_BLOCK_15 } FLASH_BLOCK; +#else +typedef uint32_t FLASH_BLOCK; +#endif /* Flash Block Sizes */ typedef enum _FLASH_BLOCK_SIZE @@ -262,6 +312,7 @@ FLASH_STATUS flash_set_status uint8_t flash_status ); +#ifdef USE_LEGACY_FLASH_DRIVER /* Check if the flash chip is ready for write operations */ bool flash_is_flash_busy ( @@ -279,6 +330,13 @@ void flash_write_disable ( void ); +#else +/* Returns FLASH_IN_PROGRESS if the chip is currently programming. */ +FLASH_STATUS flash_is_flash_busy + ( + HFLASH_BUFFER* pflash_handle + ); +#endif /* Write bytes from a flash buffer to the external flash */ FLASH_STATUS flash_write