/* * Copyright (c) 2017-2019, Texas Instruments Incorporated * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*!***************************************************************************** * @file NVSSPI25X.h * @brief Non-Volatile Storage driver implementation * for SPI flash peripherals * * # Overview # * * The NVSSPI25X module allows you to manage SPI flash memory. * This driver works with most 256 byte/page SPI flash memory devices * such as: * * Winbond W25xx family * Macronics MX25Rxx family * Micron N25Qxx family * * The SPI flash commands used by this driver are as follows: * * @code * #define SPIFLASH_PAGE_WRITE 0x02 // Page Program (up to 256 bytes) * #define SPIFLASH_READ 0x03 // Read Data * #define SPIFLASH_READ_STATUS 0x05 // Read Status Register * #define SPIFLASH_WRITE_ENABLE 0x06 // Write Enable * #define SPIFLASH_SUBSECTOR_ERASE 0x20 // SubSector (4K bytes) Erase * #define SPIFLASH_SECTOR_ERASE 0xD8 // Sector (usually 64K bytes) Erase * #define SPIFLASH_RDP 0xAB // Release from Deep Power Down * #define SPIFLASH_DP 0xB9 // Deep Power Down * #define SPIFLASH_MASS_ERASE 0xC7 // Erase entire flash. * @endcode * * It is assumed that the SPI flash device used by this driver supports * the byte programmability of the SPIFLASH_PAGE_WRITE command and that * write page size is 256 bytes. The erase sector and subsector sizes are * assumed to be 64K and 4K respectively. * * The NVS_erase() command will issue a sector or subsector erase command * based on the input size and offset. * * The driver must query the SPI flash to ensure that the part is ready before * commands are issued. If the part responds as busy, the poll function sleeps * for a number of microseconds determined by the * #NVSSPI25X_HWAttrs.statusPollDelayUs field. A value of 0 means that the * driver will continuously poll the external flash until it is ready, which * may affect other threads ability to execute. * * ## SPI Interface Management ## * * For each managed flash region, a corresponding SPI instance must be * provided to the NVSSPI25X driver. * * The SPI instance can be opened and closed * internally by the NVSSPI25X driver, or alternatively, a SPI handle can be * provided to the NVSSPI25X driver, indicating that the SPI instance is being * opened and closed elsewhere within the application. This mode is useful * when the SPI bus is share by more than just the SPI flash device. * * If the SPI instance is to be managed internally by the NVSSPI25X driver, a SPI * instance index and bit rate must be configured in the region's HWAttrs. * If the same SPI instance is referenced by multiple flash regions * the driver will ensure that SPI_open() is invoked only once, and that * SPI_close() will only be invoked when all flash regions using the SPI * instance have been closed. * * If the SPI bus that the SPI flash device is on is shared with other * devices accessed by an application, then the SPI handle used to manage * a SPI flash region can be provided in the region's HWAttrs "spiHandle" * field. Keep in mind that the "spiHandle" field is a POINTER to a * SPI Handle, NOT a SPI Handle. This allows the user to simply initialize * this field with the name of the global variable used for the SPI handle. * In this mode, the user MUST open the SPI instance prior to opening the NVS * region instance so that the referenced spiHandle is valid. * * By default, the "spiHandle" field is set to NULL, indicating that the user * expects the NVS driver to open and close the SPI instance internally using * the 'spiIndex' and 'spiBitRate' provided in the HWAttrs. * * ## @anchor SPI_CS_MGMT SPI Flash Chip Select Management ## * * ### Option 1: NVSSPI25X Driver Manages Chip Select ### * By default, the NVSSPI25X driver will assert and de-assert a GPIO * driver managed pin to select the SPI flash device before and after * each SPI transfer to and from the device. * * To enable this behavior, a valid GPIO driver instance index must be * provided in the NVS region's [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the * NVSSPI25X_HWAttrs structure. The corresponding GPIO pin will be * configured at runtime by the NVSSPI25X driver as "GPIO_CFG_OUT_STD" * and assertion of this pin is assumed to be active LOW. * * ### Option 2: SPI Driver Manages Chip Select ### * Some SPI peripherals can be configured to manage their own chip * select. Setting the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the NVSSPI25X_HWAttrs * structure to #NVSSPI25X_SPI_MANAGES_CS informs the NVSSPI25X driver * that the SPI peripheral used by the NVS driver has been configured * that way. * * ### Option 3: User Manages Chip Select ### * Alternatively, the user can manage the assertion and de-assertion of * the SPI flash chip select entirely themselves by providing implementations * of the following 4 APIs in their application code: * * @code * void NVSSPI25X_initSpiCs(NVS_Handle nvsHandle, uint16_t csId); * @endcode * - This function is invoked within the NVS_open() API and is where the * user should do whatever is required to initialize the hardware * used for asserting and de-assering the SPI chip select signal. * - The 'nvsHandle` argument is the NVS handle associated with the * corresponding NVS region. * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. * * @code * void NVSSPI25X_deinitSpiCs(NVS_Handle nvsHandle, uint16_t csId); * @endcode * - This function is invoked within the NVS_close() API and is where the * user should do whatever is required to de-initialize the hardware * used for asserting and de-assering the SPI chip select signal. * - The 'nvsHandle` argument is the NVS handle associated with the * corresponding NVS region. * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. * * @code * void NVSSPI25X_assertSpiCs(NVS_Handle nvsHandle, uint16_t csId); * @endcode * - This function is called PRIOR to every SPI transfer to and from the SPI * flash device performed by the NVSSPI25X driver. The user code should * perform the corresponding action required to select the SPI flash * device to prepare for the SPI transfer. * - The 'nvsHandle` argument is the NVS handle associated with the * corresponding NVS region. * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. * * @code * void NVSSPI25X_deassertSpiCs(NVS_Handle nvsHandle, uint16_t csId); * @endcode * - This function is called AFTER every SPI transfer to and from the SPI * flash device performed by the NVSSPI25X driver. The user code should * perform the corresponding action required to de-select the SPI flash * device. * following the SPI transfer. * - The 'nvsHandle` argument is the NVS handle associated with the * corresponding NVS region. * - The 'csId' argument passed to this API is a copy of the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) * field of the corresponding NVS region's NVSSPI25X_HWAttrs structure. * * @warning All 4 of the above APIs must be provided by the user if this * option is used, otherwise default internal implementations of the APIs * will be called that will likely lead to application failure. */ #ifndef ti_drivers_nvs_NVSSPI25X__include #define ti_drivers_nvs_NVSSPI25X__include #include #include #include #if defined (__cplusplus) extern "C" { #endif /*! * @brief Command to perform mass erase of entire flash * * As this command can erase flash memory outside the region associated * with the NVS_Handle passed to the control command, the user must * carefully orchestrate the use of the command. * * Mass Erase is the only control command supported. */ #define NVSSPI25X_CMD_MASS_ERASE (NVS_CMD_RESERVED + 0) /*! * @brief Disable internal management of SPI chip select * * Some SPI peripherals can be configured to manage their own chip * select. Setting the [spiCsnGpioIndex] * (@ref NVSSPI25X_HWAttrs.spiCsnGpioIndex) field of the NVSSPI25X_HWAttrs * structure to #NVSSPI25X_SPI_MANAGES_CS informs the NVSSPI25X driver * that the SPI peripheral used by the NVS driver is configured * to manage its own chip select signal. */ #define NVSSPI25X_SPI_MANAGES_CS ((uint16_t)(~0)) /*! * @internal @brief NVS function pointer table * * 'NVSSPI25X_fxnTable' is a fully populated function pointer table * that can be referenced in the NVS_config[] array entries. * * Users can minimize their application code size by providing their * own custom NVS function pointer table that contains only those APIs * used by the application. */ extern const NVS_FxnTable NVSSPI25X_fxnTable; /*! * @brief NVSSPI25X attributes * * The 'regionBaseOffset' is the offset, in bytes, from the base of the * SPI flash, of the flash region to be managed. * * The 'regionSize' must be an integer multiple of the flash sector size. * * The 'sectorSize' is SPI flash device specific. This parameter should * correspond to the number of bytes erased when the * 'SPIFLASH_SUBSECTOR_ERASE' (0x20) command is issued to the device. * * The 'verifyBuf' and 'verifyBufSize' parameters are used by the * NVS_write() command when either 'NVS_WRITE_PRE_VERIFY' or * 'NVS_WRITE_POST_VERIFY' functions are requested in the 'flags' * argument. The 'verifyBuf' is used to successively read back portions * of the flash to compare with the data being written to it. * * @code * // * // Only one region write operation is performed at a time * // so a single verifyBuf can be shared by all the regions. * // * uint8_t verifyBuf[256]; * * NVSSPI25X_HWAttrs nvsSPIHWAttrs[2] = { * // * // region 0 is 1 flash sector in length. * // * { * .regionBaseOffset = 0, * .regionSize = 4096, * .sectorSize = 4096, * .verifyBuf = verifyBuf; * .verifyBufSize = 256; * .spiHandle = NULL, * .spiIndex = 0, * .spiBitRate = 40000000, * .spiCsnGpioIndex = 12, * }, * // * // region 1 is 3 flash sectors in length. * // * { * .regionBaseOffset = 4096, * .regionSize = 4096 * 3, * .sectorSize = 4096, * .verifyBuf = verifyBuf; // use shared verifyBuf * .verifyBufSize = 256; * .spiHandle = NULL, * .spiIndex = 0, * .spiBitRate = 40000000, * .spiCsnGpioIndex = 12, * } * }; * @endcode */ typedef struct { size_t regionBaseOffset; /*!< Offset from base of SPI flash */ size_t regionSize; /*!< The size of the region in bytes */ size_t sectorSize; /*!< Erase sector size */ uint8_t *verifyBuf; /*!< Write Pre/Post verify buffer */ size_t verifyBufSize; /*!< Write Pre/Post verify buffer size */ SPI_Handle *spiHandle; /*!< ptr to SPI handle if provided by user. */ uint16_t spiIndex; /*!< SPI instance index from Board file */ uint32_t spiBitRate; /*!< SPI bit rate in Hz */ /*! @brief SPI Flash Chip Select GPIO index This field should be set to either an index within the GPIO driver's GPIO_Config table, or to #NVSSPI25X_SPI_MANAGES_CS. see [SPI Flash Chip Select Management] (@ref SPI_CS_MGMT) for more details. */ uint16_t spiCsnGpioIndex; /*! @brief External Flash Status Poll Delay * * This field determines how many microseconds the driver waits after * querying the external flash status. Increasing this value can help * mitigate CPU starvation if the external flash is busy for long periods * of time, but may also result in increased latency. */ uint32_t statusPollDelayUs; } NVSSPI25X_HWAttrs; /* * @brief NVSSPI25X Object * * The application must not access any member variables of this structure! */ typedef struct { bool opened; /* Has this region been opened */ SPI_Handle spiHandle; size_t sectorBaseMask; } NVSSPI25X_Object; /* * @cond NODOC * NVSSPI25X driver public APIs */ extern void NVSSPI25X_close(NVS_Handle handle); extern int_fast16_t NVSSPI25X_control(NVS_Handle handle, uint_fast16_t cmd, uintptr_t arg); extern int_fast16_t NVSSPI25X_erase(NVS_Handle handle, size_t offset, size_t size); extern void NVSSPI25X_getAttrs(NVS_Handle handle, NVS_Attrs *attrs); extern void NVSSPI25X_init(); extern int_fast16_t NVSSPI25X_lock(NVS_Handle handle, uint32_t timeout); extern NVS_Handle NVSSPI25X_open(uint_least8_t index, NVS_Params *params); extern int_fast16_t NVSSPI25X_read(NVS_Handle handle, size_t offset, void *buffer, size_t bufferSize); extern void NVSSPI25X_unlock(NVS_Handle handle); extern int_fast16_t NVSSPI25X_write(NVS_Handle handle, size_t offset, void *buffer, size_t bufferSize, uint_fast16_t flags); /* * Weakly defined APIs that can be overridden by the user */ extern void NVSSPI25X_initSpiCs(NVS_Handle spiHandle, uint16_t csId); extern void NVSSPI25X_deinitSpiCs(NVS_Handle spiHandle, uint16_t csId); extern void NVSSPI25X_assertSpiCs(NVS_Handle spiHandle, uint16_t csId); extern void NVSSPI25X_deassertSpiCs(NVS_Handle spiHandle, uint16_t csId); /*! @endcond */ #if defined (__cplusplus) } #endif /* defined (__cplusplus) */ /** @}*/ #endif /* ti_drivers_nvs_NVSSPI25X__include */