2019-01-08 05:29:25 -05:00
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2017-05-23 22:35:12 -04:00
# pragma once
2019-01-08 05:29:25 -05:00
# include "esp_err.h"
2017-05-23 22:35:12 -04:00
# include <stdint.h>
# include <stdbool.h>
2019-06-19 04:37:55 -04:00
# include "hal/spi_flash_types.h"
2017-05-23 22:35:12 -04:00
2019-06-19 04:37:11 -04:00
# ifdef __cplusplus
extern " C " {
# endif
2019-01-08 05:29:25 -05:00
struct spi_flash_chip_t ;
typedef struct spi_flash_chip_t spi_flash_chip_t ;
2017-05-23 22:35:12 -04:00
2019-01-08 05:29:25 -05:00
typedef struct esp_flash_t esp_flash_t ;
2017-05-23 22:35:12 -04:00
/** @brief Structure for describing a region of flash */
typedef struct {
2019-06-19 08:35:55 -04:00
uint32_t offset ; ///< Start address of this region
uint32_t size ; ///< Size of the region
2017-05-23 22:35:12 -04:00
} esp_flash_region_t ;
2020-04-29 22:37:35 -04:00
/** @brief OS-level integration hooks for accessing flash chips inside a running OS
*
* It ' s in the public header because some instances should be allocated statically in the startup
* code . May be updated according to hardware version and new flash chip feature requirements ,
* shouldn ' t be treated as public API .
*
* For advanced developers , you may replace some of them with your implementations at your own
* risk .
*/
2017-05-23 22:35:12 -04:00
typedef struct {
2019-01-08 05:29:25 -05:00
/**
* Called before commencing any flash operation . Does not need to be
* recursive ( ie is called at most once for each call to ' end ' ) .
*/
esp_err_t ( * start ) ( void * arg ) ;
/** Called after completing any flash operation. */
esp_err_t ( * end ) ( void * arg ) ;
2019-09-11 14:41:00 -04:00
/** Called before any erase/write operations to check whether the region is limited by the OS */
esp_err_t ( * region_protected ) ( void * arg , size_t start_addr , size_t size ) ;
2020-05-08 05:35:22 -04:00
/** Delay for at least 'us' microseconds. Called in between 'start' and 'end'. */
2020-08-21 00:09:52 -04:00
esp_err_t ( * delay_us ) ( void * arg , uint32_t us ) ;
2020-05-29 15:52:48 -04:00
2020-04-29 22:37:35 -04:00
/** Called for get temp buffer when buffer from application cannot be directly read into/write from. */
void * ( * get_temp_buffer ) ( void * arg , size_t reqest_size , size_t * out_size ) ;
/** Called for release temp buffer. */
void ( * release_temp_buffer ) ( void * arg , void * temp_buf ) ;
esp_flash: refactor to support various type of yield
There is a periodically yield in the esp_flash driver, to ensure the
cache will not be disabled for too long on ESP32.
On ESP32-S2 and later, we need to support more different kind of yield:
1. polling conditions, including timeout, SW read request, etc.
2. wait for events, including HW done/error/auto-suspend, timeout
semaphore, etc.
The check_yield() and yield() is separated into two parts, because we
may need to insert suspend, etc. between them.
2020-09-11 06:20:08 -04:00
# define SPI_FLASH_YIELD_REQ_YIELD BIT(0)
# define SPI_FLASH_YIELD_REQ_SUSPEND BIT(1)
/** Yield to other tasks. Called during erase operations.
* @ return ESP_OK means yield needs to be called ( got an event to handle ) , while ESP_ERR_TIMEOUT means skip yield . */
esp_err_t ( * check_yield ) ( void * arg , uint32_t chip_status , uint32_t * out_request ) ;
# define SPI_FLASH_YIELD_STA_RESUME BIT(2)
2020-05-29 15:52:48 -04:00
/** Yield to other tasks. Called during erase operations. */
esp_flash: refactor to support various type of yield
There is a periodically yield in the esp_flash driver, to ensure the
cache will not be disabled for too long on ESP32.
On ESP32-S2 and later, we need to support more different kind of yield:
1. polling conditions, including timeout, SW read request, etc.
2. wait for events, including HW done/error/auto-suspend, timeout
semaphore, etc.
The check_yield() and yield() is separated into two parts, because we
may need to insert suspend, etc. between them.
2020-09-11 06:20:08 -04:00
esp_err_t ( * yield ) ( void * arg , uint32_t * out_status ) ;
/** Called for get system time. */
int64_t ( * get_system_time ) ( void * arg ) ;
2019-01-08 05:29:25 -05:00
} esp_flash_os_functions_t ;
2017-05-23 22:35:12 -04:00
/** @brief Structure to describe a SPI flash chip connected to the system.
2020-04-29 22:37:35 -04:00
Structure must be initialized before use ( passed to esp_flash_init ( ) ) . It ' s in the public
header because some instances should be allocated statically in the startup code . May be
updated according to hardware version and new flash chip feature requirements , shouldn ' t be
treated as public API .
For advanced developers , you may replace some of them with your implementations at your own
risk .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
struct esp_flash_t {
2020-05-07 02:46:41 -04:00
spi_flash_host_inst_t * host ; ///< Pointer to hardware-specific "host_driver" structure. Must be initialized before used.
2019-06-19 04:37:11 -04:00
const spi_flash_chip_t * chip_drv ; ///< Pointer to chip-model-specific "adapter" structure. If NULL, will be detected during initialisation.
2019-01-08 05:29:25 -05:00
2019-06-19 08:35:55 -04:00
const esp_flash_os_functions_t * os_func ; ///< Pointer to os-specific hook structure. Call ``esp_flash_init_os_functions()`` to setup this field, after the host is properly initialized.
void * os_func_data ; ///< Pointer to argument for os-specific hooks. Left NULL and will be initialized with ``os_func``.
2019-01-08 05:29:25 -05:00
2019-09-05 01:11:36 -04:00
esp_flash_io_mode_t read_mode ; ///< Configured SPI flash read mode. Set before ``esp_flash_init`` is called.
2022-11-28 03:54:03 -05:00
uint32_t size ; ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation. Note: this stands for the size in the binary image header. If you want to get the flash physical size, please call `esp_flash_get_physical_size`.
2019-09-09 12:56:46 -04:00
uint32_t chip_id ; ///< Detected chip id.
2020-09-18 02:32:37 -04:00
uint32_t busy : 1 ; ///< This flag is used to verify chip's status.
2022-08-23 06:53:37 -04:00
uint32_t hpm_dummy_ena : 1 ; ///< This flag is used to verify whether flash works under HPM status.
uint32_t reserved_flags : 30 ; ///< reserved.
2019-01-08 05:29:25 -05:00
} ;
2017-05-23 22:35:12 -04:00
/** @brief Initialise SPI flash chip interface.
2019-01-08 05:29:25 -05:00
*
2017-05-23 22:35:12 -04:00
* This function must be called before any other API functions are called for this chip .
*
2019-06-19 08:35:55 -04:00
* @ note Only the ` ` host ` ` and ` ` read_mode ` ` fields of the chip structure must
* be initialised before this function is called . Other fields may be
* auto - detected if left set to zero or NULL .
2017-05-23 22:35:12 -04:00
*
2019-06-19 08:35:55 -04:00
* @ note If the chip - > drv pointer is NULL , chip chip_drv will be auto - detected
* based on its manufacturer & product IDs . See
* ` ` esp_flash_registered_flash_drivers ` ` pointer for details of this process .
2017-05-23 22:35:12 -04:00
*
* @ param chip Pointer to SPI flash chip to use . If NULL , esp_flash_default_chip is substituted .
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if initialisation fails .
*/
esp_err_t esp_flash_init ( esp_flash_t * chip ) ;
/**
* Check if appropriate chip driver is set .
*
* @ param chip Pointer to SPI flash chip to use . If NULL , esp_flash_default_chip is substituted .
*
* @ return true if set , otherwise false .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
bool esp_flash_chip_driver_initialized ( const esp_flash_t * chip ) ;
2017-05-23 22:35:12 -04:00
/** @brief Read flash ID via the common "RDID" SPI flash command.
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
2019-06-19 08:35:55 -04:00
* @ param [ out ] out_id Pointer to receive ID value .
2017-05-23 22:35:12 -04:00
*
* ID is a 24 - bit value . Lower 16 bits of ' id ' are the chip ID , upper 8 bits are the manufacturer ID .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 08:35:55 -04:00
esp_err_t esp_flash_read_id ( esp_flash_t * chip , uint32_t * out_id ) ;
2017-05-23 22:35:12 -04:00
/** @brief Detect flash size based on flash ID.
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
2022-11-28 03:54:03 -05:00
* @ param [ out ] out_size Detected size in bytes , standing for the size in the binary image header .
2017-05-23 22:35:12 -04:00
*
2022-10-21 06:28:54 -04:00
* @ note 1. Most flash chips use a common format for flash ID , where the lower 4 bits specify the size as a power of 2. If
2017-05-23 22:35:12 -04:00
* the manufacturer doesn ' t follow this convention , the size may be incorrectly detected .
2022-11-28 03:54:03 -05:00
* 2. The out_size returned only stands for The out_size stands for the size in the binary image header .
2022-10-21 06:28:54 -04:00
* If you want to get the real size of the chip , please call ` esp_flash_get_physical_size ` instead .
2017-05-23 22:35:12 -04:00
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 08:35:55 -04:00
esp_err_t esp_flash_get_size ( esp_flash_t * chip , uint32_t * out_size ) ;
2017-05-23 22:35:12 -04:00
2022-10-21 06:28:54 -04:00
/** @brief Detect flash size based on flash ID.
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param [ out ] flash_size Detected size in bytes .
*
* @ note Most flash chips use a common format for flash ID , where the lower 4 bits specify the size as a power of 2. If
* the manufacturer doesn ' t follow this convention , the size may be incorrectly detected .
*
* @ return ESP_OK on success , or a flash error code if operation failed .
*/
esp_err_t esp_flash_get_physical_size ( esp_flash_t * chip , uint32_t * flash_size ) ;
2020-11-27 06:09:40 -05:00
/** @brief Read flash unique ID via the common "RDUID" SPI flash command.
2023-06-24 08:38:53 -04:00
*
* @ note This is an optional feature , which is not supported on all flash chips . READ PROGRAMMING GUIDE FIRST !
2020-11-27 06:09:40 -05:00
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( ) .
* @ param [ out ] out_id Pointer to receive unique ID value .
*
* ID is a 64 - bit value .
*
* @ return
* - ESP_OK on success , or a flash error code if operation failed .
* - ESP_ERR_NOT_SUPPORTED if the chip doesn ' t support read id .
*/
esp_err_t esp_flash_read_unique_chip_id ( esp_flash_t * chip , uint64_t * out_id ) ;
2017-05-23 22:35:12 -04:00
/** @brief Erase flash chip contents
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
*
*
2020-09-18 02:32:37 -04:00
* @ return
* - ESP_OK on success ,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation . This is indicated by WREN = 1 after the command is sent .
* - Other flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_erase_chip ( esp_flash_t * chip ) ;
2017-05-23 22:35:12 -04:00
/** @brief Erase a region of the flash chip
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param start Address to start erasing flash . Must be sector aligned .
* @ param len Length of region to erase . Must also be sector aligned .
*
2019-01-08 05:29:25 -05:00
* Sector size is specifyed in chip - > drv - > sector_size field ( typically 4096 bytes . ) ESP_ERR_INVALID_ARG will be
2017-05-23 22:35:12 -04:00
* returned if the start & length are not a multiple of this size .
*
* Erase is performed using block ( multi - sector ) erases where possible ( block size is specified in
* chip - > drv - > block_erase_size field , typically 65536 bytes ) . Remaining sectors are erased using individual sector erase
* commands .
*
2020-09-18 02:32:37 -04:00
* @ return
* - ESP_OK on success ,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation . This is indicated by WREN = 1 after the command is sent .
* - Other flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_erase_region ( esp_flash_t * chip , uint32_t start , uint32_t len ) ;
2017-05-23 22:35:12 -04:00
/** @brief Read if the entire chip is write protected
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param [ out ] write_protected Pointer to boolean , set to the value of the write protect flag .
*
2019-01-08 05:29:25 -05:00
* @ note A correct result for this flag depends on the SPI flash chip model and chip_drv in use ( via the ' chip - > drv '
2017-05-23 22:35:12 -04:00
* field ) .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_get_chip_write_protect ( esp_flash_t * chip , bool * write_protected ) ;
2017-05-23 22:35:12 -04:00
/** @brief Set write protection for the SPI flash chip
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
2019-06-19 08:35:55 -04:00
* @ param write_protect Boolean value for the write protect flag
2017-05-23 22:35:12 -04:00
*
2019-01-08 05:29:25 -05:00
* @ note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use ( via the ' chip - > drv '
2017-05-23 22:35:12 -04:00
* field ) .
*
* Some SPI flash chips may require a power cycle before write protect status can be cleared . Otherwise ,
* write protection can be removed via a follow - up call to this function .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 08:35:55 -04:00
esp_err_t esp_flash_set_chip_write_protect ( esp_flash_t * chip , bool write_protect ) ;
2017-05-23 22:35:12 -04:00
/** @brief Read the list of individually protectable regions of this SPI flash chip.
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
2019-06-19 08:35:55 -04:00
* @ param [ out ] out_regions Pointer to receive a pointer to the array of protectable regions of the chip .
* @ param [ out ] out_num_regions Pointer to an integer receiving the count of protectable regions in the array returned in ' regions ' .
2017-05-23 22:35:12 -04:00
*
2019-01-08 05:29:25 -05:00
* @ note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use ( via the ' chip - > drv '
2017-05-23 22:35:12 -04:00
* field ) .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 08:35:55 -04:00
esp_err_t esp_flash_get_protectable_regions ( const esp_flash_t * chip , const esp_flash_region_t * * out_regions , uint32_t * out_num_regions ) ;
2017-05-23 22:35:12 -04:00
/** @brief Detect if a region of the SPI flash chip is protected
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param region Pointer to a struct describing a protected region . This must match one of the regions returned from esp_flash_get_protectable_regions ( . . . ) .
2019-06-19 04:37:11 -04:00
* @ param [ out ] out_protected Pointer to a flag which is set based on the protected status for this region .
2017-05-23 22:35:12 -04:00
*
* @ note It is possible for this result to be false and write operations to still fail , if protection is enabled for the entire chip .
*
2019-01-08 05:29:25 -05:00
* @ note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use ( via the ' chip - > drv '
2017-05-23 22:35:12 -04:00
* field ) .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 04:37:11 -04:00
esp_err_t esp_flash_get_protected_region ( esp_flash_t * chip , const esp_flash_region_t * region , bool * out_protected ) ;
2017-05-23 22:35:12 -04:00
/** @brief Update the protected status for a region of the SPI flash chip
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param region Pointer to a struct describing a protected region . This must match one of the regions returned from esp_flash_get_protectable_regions ( . . . ) .
2019-06-19 04:37:11 -04:00
* @ param protect Write protection flag to set .
2017-05-23 22:35:12 -04:00
*
* @ note It is possible for the region protection flag to be cleared and write operations to still fail , if protection is enabled for the entire chip .
*
2019-01-08 05:29:25 -05:00
* @ note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use ( via the ' chip - > drv '
2017-05-23 22:35:12 -04:00
* field ) .
*
2019-01-08 05:29:25 -05:00
* @ return ESP_OK on success , or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-06-19 04:37:11 -04:00
esp_err_t esp_flash_set_protected_region ( esp_flash_t * chip , const esp_flash_region_t * region , bool protect ) ;
2017-05-23 22:35:12 -04:00
/** @brief Read data from the SPI flash chip
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
2019-01-08 05:29:25 -05:00
* @ param buffer Pointer to a buffer where the data will be read . To get better performance , this should be in the DRAM and word aligned .
2017-05-23 22:35:12 -04:00
* @ param address Address on flash to read from . Must be less than chip - > size field .
* @ param length Length ( in bytes ) of data to read .
*
* There are no alignment constraints on buffer , address or length .
*
* @ note If on - chip flash encryption is used , this function returns raw ( ie encrypted ) data . Use the flash cache
* to transparently decrypt data .
*
2019-01-08 05:29:25 -05:00
* @ return
* - ESP_OK : success
2020-02-24 22:56:13 -05:00
* - ESP_ERR_NO_MEM : Buffer is in external PSRAM which cannot be concurrently accessed , and a temporary internal buffer could not be allocated .
2019-01-08 05:29:25 -05:00
* - or a flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_read ( esp_flash_t * chip , void * buffer , uint32_t address , uint32_t length ) ;
2017-05-23 22:35:12 -04:00
/** @brief Write data to the SPI flash chip
*
* @ param chip Pointer to identify flash chip . Must have been successfully initialised via esp_flash_init ( )
* @ param address Address on flash to write to . Must be previously erased ( SPI NOR flash can only write bits 1 - > 0 ) .
2019-01-08 05:29:25 -05:00
* @ param buffer Pointer to a buffer with the data to write . To get better performance , this should be in the DRAM and word aligned .
2017-05-23 22:35:12 -04:00
* @ param length Length ( in bytes ) of data to write .
*
* There are no alignment constraints on buffer , address or length .
*
2020-09-18 02:32:37 -04:00
* @ return
* - ESP_OK on success ,
* - ESP_ERR_NOT_SUPPORTED if the chip is not able to perform the operation . This is indicated by WREN = 1 after the command is sent .
* - Other flash error code if operation failed .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_write ( esp_flash_t * chip , const void * buffer , uint32_t address , uint32_t length ) ;
2017-05-23 22:35:12 -04:00
/** @brief Encrypted and write data to the SPI flash chip using on-chip hardware flash encryption
*
2019-09-05 06:45:45 -04:00
* @ param chip Pointer to identify flash chip . Must be NULL ( the main flash chip ) . For other chips , encrypted write is not supported .
2017-05-23 22:35:12 -04:00
* @ param address Address on flash to write to . 16 byte aligned . Must be previously erased ( SPI NOR flash can only write bits 1 - > 0 ) .
* @ param buffer Pointer to a buffer with the data to write .
* @ param length Length ( in bytes ) of data to write . 16 byte aligned .
*
* @ note Both address & length must be 16 byte aligned , as this is the encryption block size
*
2019-09-05 06:45:45 -04:00
* @ return
* - ESP_OK : on success
* - ESP_ERR_NOT_SUPPORTED : encrypted write not supported for this chip .
* - ESP_ERR_INVALID_ARG : Either the address , buffer or length is invalid .
* - or other flash error code from spi_flash_write_encrypted ( ) .
2017-05-23 22:35:12 -04:00
*/
2019-01-08 05:29:25 -05:00
esp_err_t esp_flash_write_encrypted ( esp_flash_t * chip , uint32_t address , const void * buffer , uint32_t length ) ;
2019-09-05 06:45:45 -04:00
/** @brief Read and decrypt data from the SPI flash chip using on-chip hardware flash encryption
*
* @ param chip Pointer to identify flash chip . Must be NULL ( the main flash chip ) . For other chips , encrypted read is not supported .
* @ param address Address on flash to read from .
* @ param out_buffer Pointer to a buffer for the data to read to .
* @ param length Length ( in bytes ) of data to read .
*
* @ return
* - ESP_OK : on success
* - ESP_ERR_NOT_SUPPORTED : encrypted read not supported for this chip .
* - or other flash error code from spi_flash_read_encrypted ( ) .
*/
esp_err_t esp_flash_read_encrypted ( esp_flash_t * chip , uint32_t address , void * out_buffer , uint32_t length ) ;
2017-05-23 22:35:12 -04:00
/** @brief Pointer to the "default" SPI flash chip, ie the main chip attached to the MCU.
This chip is used if the ' chip ' argument pass to esp_flash_xxx API functions is ever NULL .
*/
2019-01-08 05:29:25 -05:00
extern esp_flash_t * esp_flash_default_chip ;
2017-05-23 22:35:12 -04:00
2019-06-19 04:37:11 -04:00
2019-09-05 01:11:36 -04:00
/*******************************************************************************
* Utility Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* @ brief Returns true if chip is configured for Quad I / O or Quad Fast Read .
*
* @ param chip Pointer to SPI flash chip to use . If NULL , esp_flash_default_chip is substituted .
*
* @ return true if flash works in quad mode , otherwise false
*/
static inline bool esp_flash_is_quad_mode ( const esp_flash_t * chip )
{
return ( chip - > read_mode = = SPI_FLASH_QIO ) | | ( chip - > read_mode = = SPI_FLASH_QOUT ) ;
}
2019-06-19 04:37:11 -04:00
# ifdef __cplusplus
}
# endif