esp_flash: add initialization interface for SPI devices

This commit is contained in:
Michael (XIAO Xufeng) 2019-06-24 12:56:39 +08:00
parent 65c0d354e4
commit d6bd24ca67
13 changed files with 382 additions and 230 deletions

View file

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "soc/spi_periph.h" #include "soc/spi_periph.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h" #include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX #include <sys/param.h> // For MIN/MAX
#include <stdbool.h> #include <stdbool.h>
@ -39,10 +40,7 @@
#define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz #define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/// Get the start address of SPI peripheral registers by the host ID /// Get the start address of SPI peripheral registers by the host ID
#define spi_flash_ll_get_hw(n) ((n)==0||(n)==1? &SPI1:((n)==2?&SPI2:((n)==3?&SPI3:({abort();(spi_dev_t*)0;})))) #define spi_flash_ll_get_hw(host_id) ((host_id)==SPI1_HOST? &SPI1:((host_id)==SPI2_HOST?&SPI2:((host_id)==SPI3_HOST?&SPI3:({abort();(spi_dev_t*)0;}))))
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
/// type to store pre-calculated register value in above layers /// type to store pre-calculated register value in above layers
typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t; typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t;

View file

@ -23,6 +23,7 @@
#pragma once #pragma once
#include "hal/spi_flash_ll.h" #include "hal/spi_flash_ll.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h" #include "hal/spi_flash_types.h"
#include "soc/soc_memory_layout.h" #include "soc/soc_memory_layout.h"
@ -44,7 +45,7 @@ typedef struct {
/// Configuration structure for the SPI driver. /// Configuration structure for the SPI driver.
typedef struct { typedef struct {
int host_id; ///< SPI peripheral ID, 1 for SPI1, 2 for SPI2 (HSPI), 3 for SPI3 (VSPI) spi_host_device_t host_id; ///< SPI peripheral ID.
int cs_num; ///< Which cs pin is used, 0-2. int cs_num; ///< Which cs pin is used, 0-2.
bool iomux; ///< Whether the IOMUX is used, used for timing compensation. bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation. int input_delay_ns; ///< Input delay on the MISO pin after the launch clock used for timing compensation.

View file

@ -63,6 +63,8 @@ typedef enum {
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``. SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_read_mode_t; } esp_flash_read_mode_t;
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
struct spi_flash_host_driver_t; struct spi_flash_host_driver_t;
typedef struct spi_flash_host_driver_t spi_flash_host_driver_t; typedef struct spi_flash_host_driver_t spi_flash_host_driver_t;

View file

@ -17,7 +17,7 @@ else()
"spi_flash_os_func_noos.c" "spi_flash_os_func_noos.c"
"memspi_host_driver.c") "memspi_host_driver.c")
if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL) if(NOT CONFIG_SPI_FLASH_USE_LEGACY_IMPL)
list(APPEND srcs "esp_flash_api.c") list(APPEND srcs "esp_flash_api.c" "esp_flash_spi_init.c")
endif() endif()
set(priv_requires bootloader_support app_update soc) set(priv_requires bootloader_support app_update soc)
endif() endif()

View file

@ -31,6 +31,28 @@ Encrypted reads and writes use the old implementation, even if
flash operations are only supported with the main flash chip (and not with flash operations are only supported with the main flash chip (and not with
other flash chips on SPI1 with different CS). other flash chips on SPI1 with different CS).
Initializing a flash device
---------------------------
To use ``esp_flash_*`` APIs, you need to have a chip initialized on a certain
SPI bus.
1. Call :cpp:func:`spi_bus_initialize` to properly initialize an SPI bus.
This functions initialize the resources (I/O, DMA, interrupts) shared
among devices attached to this bus.
2. Call :cpp:func:`spi_bus_add_flash_device` to attach the flash device onto
the bus. This allocates memory, and fill the members for the
``esp_flash_t`` structure. The CS I/O is also initialized here.
3. Call :cpp:func:`esp_flash_init` to actually communicate with the chip.
This will also detect the chip type, and influence the following
operations.
.. note:: Multiple flash chips can be attached to the same bus now. However,
using ``esp_flash_*`` devices and ``spi_device_*`` devices on the
same SPI bus is not supported yet.
SPI flash access API SPI flash access API
-------------------- --------------------
@ -55,13 +77,15 @@ By default, the SPI flash size is detected by esptool.py when this bootloader is
If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``esp_flash_*`` functions (in both software & ROM) to check the bounds. If it is necessary to override the configured flash size at runtime, it is possible to set the ``chip_size`` member of the ``g_rom_flashchip`` structure. This size is used by ``esp_flash_*`` functions (in both software & ROM) to check the bounds.
Concurrency Constraints Concurrency Constraints for flash on SPI1
----------------------- -----------------------------------------
Because the SPI flash is also used for firmware execution via the instruction & data caches, these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and must only be reading data from DRAM while flash write operations occur. Because the SPI1 flash is also used for firmware execution via the instruction & data caches, these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and must only be reading data from DRAM while flash write operations occur.
If you use the API functions documented here, then these constraints are applied automatically and transparently. However, note that it will have some performance impact on other tasks in the system. If you use the API functions documented here, then these constraints are applied automatically and transparently. However, note that it will have some performance impact on other tasks in the system.
There are no such constraints and impacts for flash chips on other SPI buses than SPI0/1.
For differences between IRAM, DRAM, and flash cache, please refer to the :ref:`application memory layout <memory-layout>` documentation. For differences between IRAM, DRAM, and flash cache, please refer to the :ref:`application memory layout <memory-layout>` documentation.
To avoid reading flash cache accidentally, when one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state, and all non-IRAM-safe interrupts are disabled on both CPUs until the flash operation completes. To avoid reading flash cache accidentally, when one CPU initiates a flash write or erase operation, the other CPU is put into a blocked state, and all non-IRAM-safe interrupts are disabled on both CPUs until the flash operation completes.
@ -156,7 +180,7 @@ The ``esp_flash_t`` structure holds chip data as well as three important parts o
1. The host driver, which provides the hardware support to access the chip; 1. The host driver, which provides the hardware support to access the chip;
2. The chip driver, which provides compatibility service to different chips; 2. The chip driver, which provides compatibility service to different chips;
3. The OS functions, provides support of some OS functions (e.g. lock, delay) 3. The OS functions, provides support of some OS functions (e.g. lock, delay)
in different stages (1st/2st boot, or the app). in different stages (1st/2st boot, or the app).
Host driver Host driver
^^^^^^^^^^^ ^^^^^^^^^^^

View file

@ -19,7 +19,6 @@
#include "spi_flash_chip_driver.h" #include "spi_flash_chip_driver.h"
#include "memspi_host_driver.h" #include "memspi_host_driver.h"
#include "esp32/rom/spi_flash.h"
#include "esp_log.h" #include "esp_log.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
@ -29,29 +28,6 @@ static const char TAG[] = "spi_flash";
#define MAX_WRITE_CHUNK 8192 /* write in chunks */ #define MAX_WRITE_CHUNK 8192 /* write in chunks */
#define MAX_READ_CHUNK 16384 #define MAX_READ_CHUNK 16384
#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define DEFAULT_FLASH_SPEED ESP_FLASH_80MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define DEFAULT_FLASH_SPEED ESP_FLASH_40MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_26M
#define DEFAULT_FLASH_SPEED ESP_FLASH_26MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_20M
#define DEFAULT_FLASH_SPEED ESP_FLASH_20MHZ
#else
#error flash frequency not defined! check sdkconfig.h
#endif
#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO)
#define DEFAULT_FLASH_MODE SPI_FLASH_QIO
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
#define DEFAULT_FLASH_MODE SPI_FLASH_QOUT
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO)
#define DEFAULT_FLASH_MODE SPI_FLASH_DIO
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
#define DEFAULT_FLASH_MODE SPI_FLASH_DOUT
#else
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#endif
#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS #ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
#define UNSAFE_WRITE_ADDRESS abort() #define UNSAFE_WRITE_ADDRESS abort()
@ -640,55 +616,6 @@ inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,ui
return (a_end > b_start && b_end > a_start); return (a_end > b_start && b_end > a_start);
} }
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = 1,\
.speed = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = true, \
.input_delay_ns = 25,\
}
static DRAM_ATTR spi_flash_host_driver_t esp_flash_default_host_drv = ESP_FLASH_DEFAULT_HOST_DRIVER();
static DRAM_ATTR memspi_host_data_t default_driver_data;
/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */
extern const esp_flash_os_functions_t esp_flash_noos_functions;
static DRAM_ATTR esp_flash_t default_chip = {
.read_mode = DEFAULT_FLASH_MODE,
.host = &esp_flash_default_host_drv,
.os_func = &esp_flash_noos_functions,
};
esp_flash_t *esp_flash_default_chip = &default_chip;
esp_err_t esp_flash_init_default_chip()
{
memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT();
//the host is already initialized, only do init for the data and load it to the host
spi_flash_hal_init(&default_driver_data, &cfg);
default_chip.host->driver_data = &default_driver_data;
// ROM TODO: account for non-standard default pins in efuse
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
esp_err_t err = esp_flash_init(&default_chip);
if (err != ESP_OK) {
return err;
}
if (default_chip.size < g_rom_flashchip.chip_size) {
ESP_EARLY_LOGE(TAG, "detected size(%dk) smaller than the size in the binary image header(%dk). probe failed.", default_chip.size/1024, g_rom_flashchip.chip_size/1024);
return ESP_ERR_FLASH_SIZE_NOT_MATCH;
} else if (default_chip.size > g_rom_flashchip.chip_size) {
ESP_EARLY_LOGW(TAG, "detected size larger than the size in the binary image header. use the size in the binary image header.");
default_chip.size = g_rom_flashchip.chip_size;
}
default_chip.size = g_rom_flashchip.chip_size;
esp_flash_default_chip = &default_chip;
return ESP_OK;
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
Adapter layer to original api before IDF v4.0 Adapter layer to original api before IDF v4.0

View file

@ -0,0 +1,206 @@
// 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.
#include "sdkconfig.h"
#include "esp_flash.h"
#include "memspi_host_driver.h"
#include "esp_flash_spi_init.h"
#include "driver/gpio.h"
#include "esp32/rom/spi_flash.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "hal/spi_types.h"
#include "driver/spi_common.h"
static const char TAG[] = "spi_flash";
#ifdef CONFIG_ESPTOOLPY_FLASHFREQ_80M
#define DEFAULT_FLASH_SPEED ESP_FLASH_80MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_40M
#define DEFAULT_FLASH_SPEED ESP_FLASH_40MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_26M
#define DEFAULT_FLASH_SPEED ESP_FLASH_26MHZ
#elif defined CONFIG_ESPTOOLPY_FLASHFREQ_20M
#define DEFAULT_FLASH_SPEED ESP_FLASH_20MHZ
#else
#error Flash frequency not defined! Check the ``CONFIG_ESPTOOLPY_FLASHFREQ_*`` options.
#endif
#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO)
#define DEFAULT_FLASH_MODE SPI_FLASH_QIO
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
#define DEFAULT_FLASH_MODE SPI_FLASH_QOUT
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO)
#define DEFAULT_FLASH_MODE SPI_FLASH_DIO
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
#define DEFAULT_FLASH_MODE SPI_FLASH_DOUT
#else
#define DEFAULT_FLASH_MODE SPI_FLASH_FASTRD
#endif
static IRAM_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux)
{
//Not using spicommon_cs_initialize since we don't want to put the whole
//spi_periph_signal into the DRAM. Copy these data from flash before the
//cache disabling
int cs_io_num = config->cs_io_num;
int spics_in = spi_periph_signal[config->host_id].spics_in;
int spics_out = spi_periph_signal[config->host_id].spics_out[config->cs_id];
uint32_t iomux_reg = GPIO_PIN_MUX_REG[cs_io_num];
//To avoid the panic caused by flash data line conflicts during cs line
//initialization, disable the cache temporarily
chip->os_func->start(chip->os_func_data);
if (use_iomux) {
GPIO.func_in_sel_cfg[spics_in].sig_in_sel = 0;
PIN_INPUT_ENABLE(iomux_reg);
GPIO.func_out_sel_cfg[spics_out].oen_sel = 0;
GPIO.func_out_sel_cfg[spics_out].oen_inv_sel = false;
PIN_FUNC_SELECT(iomux_reg, 1);
} else {
PIN_INPUT_ENABLE(iomux_reg);
if (cs_io_num < 32) {
GPIO.enable_w1ts = (0x1 << cs_io_num);
} else {
GPIO.enable1_w1ts.data = (0x1 << (cs_io_num - 32));
}
GPIO.pin[cs_io_num].pad_driver = 0;
gpio_matrix_out(cs_io_num, spics_out, false, false);
if (config->cs_id == 0) {
gpio_matrix_in(cs_io_num, spics_in, false);
}
PIN_FUNC_SELECT(iomux_reg, PIN_FUNC_GPIO);
}
chip->os_func->end(chip->os_func_data);
}
esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_device_config_t *config)
{
if (out_chip == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_flash_t *chip = NULL;
spi_flash_host_driver_t *host = NULL;
memspi_host_data_t *host_data = NULL;
esp_err_t ret = ESP_OK;
uint32_t caps = MALLOC_CAP_DEFAULT;
if (config->host_id == SPI_HOST) caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT;
chip = (esp_flash_t*)heap_caps_malloc(sizeof(esp_flash_t), caps);
host = (spi_flash_host_driver_t*)heap_caps_malloc(sizeof(spi_flash_host_driver_t), caps);
host_data = (memspi_host_data_t*)heap_caps_malloc(sizeof(memspi_host_data_t), caps);
if (!chip || !host || !host_data) {
ret = ESP_ERR_NO_MEM;
goto fail;
}
*chip = (esp_flash_t) {
.read_mode = config->io_mode,
.host = host,
};
esp_err_t err = esp_flash_init_os_functions(chip, config->host_id);
if (err != ESP_OK) {
ret = err;
goto fail;
}
bool use_iomux = spicommon_bus_using_iomux(config->host_id);
memspi_host_config_t host_cfg = {
.host_id = config->host_id,
.cs_num = config->cs_id,
.iomux = use_iomux,
.input_delay_ns = config->input_delay_ns,
.speed = config->speed,
};
err = memspi_host_init_pointers(host, host_data, &host_cfg);
if (err != ESP_OK) {
ret = err;
goto fail;
}
cs_initialize(chip, config, use_iomux);
*out_chip = chip;
return ret;
fail:
spi_bus_remove_flash_device(chip);
return ret;
}
esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip)
{
if (chip==NULL) {
return ESP_ERR_INVALID_ARG;
}
if (chip->host) {
free(chip->host->driver_data);
free(chip->host);
}
free(chip);
return ESP_OK;
}
#define ESP_FLASH_HOST_CONFIG_DEFAULT() (memspi_host_config_t){ \
.host_id = SPI_HOST,\
.speed = DEFAULT_FLASH_SPEED, \
.cs_num = 0, \
.iomux = false, \
.input_delay_ns = 0,\
}
static DRAM_ATTR spi_flash_host_driver_t esp_flash_default_host_drv = ESP_FLASH_DEFAULT_HOST_DRIVER();
static DRAM_ATTR memspi_host_data_t default_driver_data;
/* The default (ie initial boot) no-OS ROM esp_flash_os_functions_t */
extern const esp_flash_os_functions_t esp_flash_noos_functions;
static DRAM_ATTR esp_flash_t default_chip = {
.read_mode = DEFAULT_FLASH_MODE,
.host = &esp_flash_default_host_drv,
.os_func = &esp_flash_noos_functions,
};
esp_flash_t *esp_flash_default_chip = NULL;
esp_err_t esp_flash_init_default_chip()
{
memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT();
//the host is already initialized, only do init for the data and load it to the host
spi_flash_hal_init(&default_driver_data, &cfg);
default_chip.host->driver_data = &default_driver_data;
// ROM TODO: account for non-standard default pins in efuse
// ROM TODO: to account for chips which are slow to power on, maybe keep probing in a loop here
esp_err_t err = esp_flash_init(&default_chip);
if (err != ESP_OK) {
return err;
}
if (default_chip.size < g_rom_flashchip.chip_size) {
ESP_EARLY_LOGE(TAG, "Detected size(%dk) smaller than the size in the binary image header(%dk). Probe failed.", default_chip.size/1024, g_rom_flashchip.chip_size/1024);
return ESP_ERR_FLASH_SIZE_NOT_MATCH;
} else if (default_chip.size > g_rom_flashchip.chip_size) {
ESP_EARLY_LOGW(TAG, "Detected size(%dk) larger than the size in the binary image header(%dk). Using the size in the binary image header.", default_chip.size/1024, g_rom_flashchip.chip_size/1024);
default_chip.size = g_rom_flashchip.chip_size;
}
default_chip.size = g_rom_flashchip.chip_size;
esp_flash_default_chip = &default_chip;
return ESP_OK;
}
esp_err_t esp_flash_app_init()
{
return esp_flash_init_os_functions(&default_chip, 0);
}

View file

@ -294,10 +294,6 @@ esp_err_t esp_flash_app_init();
*/ */
esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id); esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id);
/**
* The default FreeRTOS-compatible esp_flash_os_functions_t, used for flash chips attached to the SPI1
*/
extern const esp_flash_os_functions_t esp_flash_spi1_default_os_functions;
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -0,0 +1,55 @@
// 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.
#pragma once
#include "hal/spi_types.h"
#include "esp_flash.h"
/// Configurations for the SPI Flash to init
typedef struct {
spi_host_device_t host_id; ///< Bus to use
int cs_id; ///< CS pin (signal) to use
int cs_io_num; ///< GPIO pin to output the CS signal
esp_flash_read_mode_t io_mode; ///< IO mode to read from the Flash
esp_flash_speed_t speed; ///< Speed of the Flash clock
int input_delay_ns; ///< Input delay of the data pins, in ns. Set to 0 if unknown.
} esp_flash_spi_device_config_t;
/**
* Add a SPI Flash device onto the SPI bus.
*
* The bus should be already initialized by ``spi_bus_initialization``.
*
* @param out_chip Pointer to hold the initialized chip.
* @param config Configuration of the chips to initialize.
*
* @return
* - ESP_ERR_INVALID_ARG: out_chip is NULL, or some field in the config is invalid.
* - ESP_ERR_NO_MEM: failed to allocate memory for the chip structures.
* - ESP_OK: success.
*/
esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_device_config_t *config);
/**
* Remove a SPI Flash device from the SPI bus.
*
* @param chip The flash device to remove.
*
* @return
* - ESP_ERR_INVALID_ARG: The chip is invalid.
* - ESP_OK: success.
*/
esp_err_t spi_bus_remove_flash_device(esp_flash_t *chip);

View file

@ -117,9 +117,4 @@ esp_err_t esp_flash_init_os_functions(esp_flash_t *chip, int host_id)
return ESP_OK; return ESP_OK;
} }
esp_err_t esp_flash_app_init()
{
return esp_flash_init_os_functions(esp_flash_default_chip, 0);
}

View file

@ -6,7 +6,8 @@
#include <unity.h> #include <unity.h>
#include "esp_flash.h" #include "esp_flash.h"
#include "spi_flash_chip_generic.h" #include "driver/spi_common.h"
#include "esp_flash_spi_init.h"
#include <esp_attr.h> #include <esp_attr.h>
#include "esp_log.h" #include "esp_log.h"
@ -14,7 +15,6 @@
#include "unity.h" #include "unity.h"
#include "driver/spi_common.h" #include "driver/spi_common.h"
#include "memspi_host_driver.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "soc/io_mux_reg.h" #include "soc/io_mux_reg.h"
@ -30,38 +30,43 @@ static uint8_t sector_buf[4096];
#define TEST_SPI_READ_MODE SPI_FLASH_FASTRD #define TEST_SPI_READ_MODE SPI_FLASH_FASTRD
//#define FORCE_GPIO_MATRIX //#define FORCE_GPIO_MATRIX
#ifdef TEST_SPI2_CS0
#define TEST_HOST HSPI_HOST
#define TEST_CS 0
#define TEST_CS_PIN HSPI_IOMUX_PIN_NUM_CS
#define HSPI_PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI #define HSPI_PIN_NUM_MOSI HSPI_IOMUX_PIN_NUM_MOSI
#define HSPI_PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO #define HSPI_PIN_NUM_MISO HSPI_IOMUX_PIN_NUM_MISO
#define HSPI_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK #define HSPI_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK
#define HSPI_PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD #define HSPI_PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD
#define HSPI_PIN_NUM_WP HSPI_IOMUX_PIN_NUM_WP #define HSPI_PIN_NUM_WP HSPI_IOMUX_PIN_NUM_WP
#define TEST_INPUT_DELAY 20
#elif defined TEST_SPI3_CS0
#define TEST_HOST VSPI_HOST
#define TEST_CS 0
#define TEST_CS_PIN VSPI_IOMUX_PIN_NUM_CS
#define VSPI_PIN_NUM_MOSI VSPI_IOMUX_PIN_NUM_MOSI #define VSPI_PIN_NUM_MOSI VSPI_IOMUX_PIN_NUM_MOSI
#define VSPI_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO #define VSPI_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO
#define VSPI_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK #define VSPI_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK
#define VSPI_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD #define VSPI_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD
#define VSPI_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP #define VSPI_PIN_NUM_WP VSPI_IOMUX_PIN_NUM_WP
#define TEST_INPUT_DELAY 0
#elif defined TEST_SPI1_CS1
#define TEST_HOST SPI_HOST
#define TEST_CS 1
// #define TEST_CS_PIN 14
#define TEST_CS_PIN 16 //the pin which is usually used by the PSRAM
// #define TEST_CS_PIN 27
#define TEST_INPUT_DELAY 25
#define EXTRA_SPI1_CLK_IO 17 //the pin which is usually used by the PSRAM clk #if defined TEST_SPI1_CS1
# define TEST_HOST SPI_HOST
# define TEST_CS 1
// #define TEST_CS_PIN 14
# define TEST_CS_PIN 16 //the pin which is usually used by the PSRAM
// #define TEST_CS_PIN 27
# define TEST_INPUT_DELAY 0
# define EXTRA_SPI1_CLK_IO 17 //the pin which is usually used by the PSRAM clk
#elif defined TEST_SPI2_CS0
# define TEST_HOST HSPI_HOST
# define TEST_CS 0
# define TEST_CS_PIN HSPI_IOMUX_PIN_NUM_CS
# define TEST_INPUT_DELAY 20
#elif defined TEST_SPI3_CS0
# define TEST_HOST VSPI_HOST
# define TEST_CS 0
# define TEST_CS_PIN VSPI_IOMUX_PIN_NUM_CS
# define TEST_INPUT_DELAY 0
#else #else
#define SKIP_EXTENDED_CHIP_TEST # define SKIP_EXTENDED_CHIP_TEST
#endif #endif
@ -71,141 +76,82 @@ static const char TAG[] = "test_esp_flash";
#ifndef SKIP_EXTENDED_CHIP_TEST #ifndef SKIP_EXTENDED_CHIP_TEST
static esp_flash_t *test_chip = NULL; static esp_flash_t *test_chip = NULL;
static esp_flash_t chip_init;
static spi_flash_host_driver_t chip_host_driver;
static memspi_host_data_t driver_data = {};
static void IRAM_ATTR cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, bool use_iomux) static void setup_bus(spi_host_device_t host_id)
{ {
int spics_in = spi_periph_signal[host].spics_in; if (host_id == SPI_HOST) {
int spics_out = spi_periph_signal[host].spics_out[cs_num]; ESP_LOGI(TAG, "setup flash on SPI1 CS1...\n");
uint32_t iomux_reg = GPIO_PIN_MUX_REG[TEST_CS_PIN]; //no need to initialize the bus, however the CLK may need one more output if it's on the usual place of PSRAM
//to avoid the panic caused by flash data line conflicts during cs line initialization, disable the cache temporarily #ifdef EXTRA_SPI1_CLK_IO
//some data from flash to be used should be read before the cache disabling gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0);
g_flash_guard_default_ops.start(); #endif
if (use_iomux) { //currently the SPI bus for main flash chip is initialized through GPIO matrix
GPIO.func_in_sel_cfg[spics_in].sig_in_sel = 0; } else if (host_id == HSPI_HOST) {
PIN_INPUT_ENABLE(iomux_reg); ESP_LOGI(TAG, "setup flash on SPI2 (HSPI) CS0...\n");
GPIO.func_out_sel_cfg[spics_out].oen_sel = 0; spi_bus_config_t hspi_bus_cfg = {
GPIO.func_out_sel_cfg[spics_out].oen_inv_sel = false; .mosi_io_num = HSPI_PIN_NUM_MOSI,
PIN_FUNC_SELECT(iomux_reg, FUNC_SPI); .miso_io_num = HSPI_PIN_NUM_MISO,
.sclk_io_num = HSPI_PIN_NUM_CLK,
.quadhd_io_num = HSPI_PIN_NUM_HD,
.quadwp_io_num = HSPI_PIN_NUM_WP,
.max_transfer_sz = 64,
};
#ifdef FORCE_GPIO_MATRIX
hspi_bus_cfg.quadhd_io_num = 23;
#endif
esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0);
TEST_ESP_OK(ret);
} else if (host_id == VSPI_HOST) {
ESP_LOGI(TAG, "setup flash on SPI3 (VSPI) CS0...\n");
spi_bus_config_t vspi_bus_cfg = {
.mosi_io_num = VSPI_PIN_NUM_MOSI,
.miso_io_num = VSPI_PIN_NUM_MISO,
.sclk_io_num = VSPI_PIN_NUM_CLK,
.quadhd_io_num = VSPI_PIN_NUM_HD,
.quadwp_io_num = VSPI_PIN_NUM_WP,
.max_transfer_sz = 64,
};
#ifdef FORCE_GPIO_MATRIX
vspi_bus_cfg.quadhd_io_num = 23;
#endif
esp_err_t ret = spi_bus_initialize(host_id, &vspi_bus_cfg, 0);
TEST_ESP_OK(ret);
} else { } else {
PIN_INPUT_ENABLE(iomux_reg); ESP_LOGE(TAG, "invalid bus");
if (cs_io_num < 32) { }
GPIO.enable_w1ts = (0x1 << cs_io_num); }
} else {
GPIO.enable1_w1ts.data = (0x1 << (cs_io_num - 32)); static void release_bus(int host_id)
} {
GPIO.pin[cs_io_num].pad_driver = 0; if (host_id == HSPI_HOST || host_id == VSPI_HOST) {
gpio_matrix_out(cs_io_num, spics_out, false, false); spi_bus_free(host_id);
if (cs_num == 0) {
gpio_matrix_in(cs_io_num, spics_in, false);
}
PIN_FUNC_SELECT(iomux_reg, PIN_FUNC_GPIO);
} }
g_flash_guard_default_ops.end();
} }
static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed) static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed)
{ {
chip_init = (esp_flash_t) { //the bus should be initialized before the flash is attached to the bus
.read_mode = io_mode, setup_bus(TEST_HOST);
};
#ifdef TEST_SPI2_CS0 esp_flash_spi_device_config_t dev_cfg = {
bool spi_chan_claimed = spicommon_periph_claim(HSPI_HOST, "spi flash"); .host_id = TEST_HOST,
TEST_ASSERT(spi_chan_claimed); .io_mode = io_mode,
spi_bus_config_t hspi_bus_cfg = {
.mosi_io_num = HSPI_PIN_NUM_MOSI,
.miso_io_num = HSPI_PIN_NUM_MISO,
.sclk_io_num = HSPI_PIN_NUM_CLK,
.quadhd_io_num = HSPI_PIN_NUM_HD,
.quadwp_io_num = HSPI_PIN_NUM_WP,
.max_transfer_sz = 64,
};
#ifdef FORCE_GPIO_MATRIX
hspi_bus_cfg.quadhd_io_num = 23;
#endif
uint32_t flags;
esp_err_t ret = spicommon_bus_initialize_io(HSPI_HOST, &hspi_bus_cfg, 0, SPICOMMON_BUSFLAG_MASTER | (&hspi_bus_cfg)->flags, &flags);
TEST_ESP_OK(ret);
bool use_iomux = (flags & SPICOMMON_BUSFLAG_NATIVE_PINS) ? 1 : 0;
printf("setup flash on SPI2 (HSPI) CS0...\n");
printf("use iomux:%d\n", use_iomux);
memspi_host_config_t cfg = {
.host_id = 2,
.speed = speed, .speed = speed,
.iomux = use_iomux, .cs_id = TEST_CS,
.cs_num = TEST_CS, .cs_io_num = TEST_CS_PIN,
.input_delay_ns = TEST_INPUT_DELAY, .input_delay_ns = TEST_INPUT_DELAY,
}; };
#elif defined TEST_SPI3_CS0 esp_err_t err = spi_bus_add_flash_device(&test_chip, &dev_cfg);
bool spi_chan_claimed = spicommon_periph_claim(VSPI_HOST, "spi flash");
TEST_ASSERT(spi_chan_claimed);
spi_bus_config_t vspi_bus_cfg = {
.mosi_io_num = VSPI_PIN_NUM_MOSI,
.miso_io_num = VSPI_PIN_NUM_MISO,
.sclk_io_num = VSPI_PIN_NUM_CLK,
.quadhd_io_num = VSPI_PIN_NUM_HD,
.quadwp_io_num = VSPI_PIN_NUM_WP,
.max_transfer_sz = 64,
};
#ifdef FORCE_GPIO_MATRIX
vspi_bus_cfg.quadhd_io_num = 23;
#endif
uint32_t flags;
esp_err_t ret = spicommon_bus_initialize_io(VSPI_HOST, &vspi_bus_cfg, 0, SPICOMMON_BUSFLAG_MASTER | (&vspi_bus_cfg)->flags, &flags);
TEST_ESP_OK(ret);
bool use_iomux = (flags & SPICOMMON_BUSFLAG_NATIVE_PINS) ? 1 : 0;
//TEST_ASSERT(use_iomux);
printf("setup flash on SPI3 (VSPI) CS0...\n");
printf("use iomux:%d\n", use_iomux);
memspi_host_config_t cfg = {
.host_id = 3,
.speed = speed,
.iomux = use_iomux,
.cs_num = TEST_CS,
.input_delay_ns = TEST_INPUT_DELAY,
};
#elif defined TEST_SPI1_CS1
printf("setup flash on SPI1 CS1...\n");
memspi_host_config_t cfg = {
.host_id = 1,
.speed = speed,
.iomux = true,
.cs_num = TEST_CS,
.input_delay_ns = TEST_INPUT_DELAY,
};
bool use_iomux = (TEST_CS_PIN == spi_periph_signal[TEST_HOST].spics0_iomux_pin) && (driver_data.cs_num == 0);
# ifdef EXTRA_SPI1_CLK_IO
gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0);
# endif
#endif
esp_err_t err = memspi_host_init_pointers(&chip_host_driver, &driver_data, &cfg);
cs_initialize(TEST_HOST, TEST_CS_PIN, driver_data.cs_num, use_iomux);
TEST_ESP_OK(err); TEST_ESP_OK(err);
chip_init.host = &chip_host_driver; err = esp_flash_init(test_chip);
esp_flash_init_os_functions(&chip_init, TEST_HOST);
err = esp_flash_init(&chip_init);
TEST_ESP_OK(err); TEST_ESP_OK(err);
test_chip = &chip_init;
} }
void teardown_test_chip() void teardown_test_chip()
{ {
if (TEST_HOST == HSPI_HOST || TEST_HOST == VSPI_HOST) { spi_bus_remove_flash_device(test_chip);
spicommon_periph_free(TEST_HOST); test_chip = NULL;
} release_bus(TEST_HOST);
} }
#endif #endif

View file

@ -132,6 +132,7 @@ INPUT = \
## Storage - API Reference ## Storage - API Reference
## ##
## SPI Flash and Partition APIs ## SPI Flash and Partition APIs
../../components/spi_flash/include/esp_flash_spi_init.h \
../../components/spi_flash/include/esp_flash.h \ ../../components/spi_flash/include/esp_flash.h \
../../components/spi_flash/include/esp_partition.h \ ../../components/spi_flash/include/esp_partition.h \
../../components/bootloader_support/include/esp_flash_encrypt.h \ ../../components/bootloader_support/include/esp_flash_encrypt.h \

View file

@ -31,6 +31,7 @@ In a single core environment (:ref:`CONFIG_FREERTOS_UNICORE` enabled), you need
API Reference - SPI Flash API Reference - SPI Flash
------------------------- -------------------------
.. include:: /_build/inc/esp_flash_spi_init.inc
.. include:: /_build/inc/esp_flash.inc .. include:: /_build/inc/esp_flash.inc
.. include:: /_build/inc/spi_flash_types.inc .. include:: /_build/inc/spi_flash_types.inc