Merge branch 'feature/esp_flash_init_functions' into 'master'

esp_flash: add initialization interface for SPI devices

See merge request idf/esp-idf!5306
This commit is contained in:
Angus Gratton 2019-06-27 20:59:44 +08:00
commit 131978d707
18 changed files with 492 additions and 367 deletions

View file

@ -1,9 +1,9 @@
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2010-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
@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_SPI_COMMON_H_
#define _DRIVER_SPI_COMMON_H_
#pragma once
#include <stdint.h>
#include <stdbool.h>
@ -87,6 +85,50 @@ typedef struct {
} spi_bus_config_t;
/**
* @brief Initialize a SPI bus
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host SPI peripheral that controls this bus
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel
* for a SPI bus allows transfers on the bus to have sizes only limited by the amount of
* internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of
* bytes transfered to a maximum of 64. Set to 0 if only the SPI flash uses
* this bus.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan);
/**
* @brief Free a SPI bus
*
* @warning In order for this to succeed, all devices have to be removed first.
*
* @param host SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_bus_free(spi_host_device_t host);
/** @cond */ //Doxygen command to hide deprecated function (or non-public) from API Reference
/**
* @brief Try to claim a SPI peripheral
*
@ -95,6 +137,8 @@ typedef struct {
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @note This public API is deprecated.
*
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
*/
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
@ -116,6 +160,8 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source);
*
* @param host Peripheral to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_periph_in_use(spi_host_device_t host);
@ -124,6 +170,9 @@ bool spicommon_periph_in_use(spi_host_device_t host);
* @brief Return the SPI peripheral so another driver can claim it.
*
* @param host Peripheral to return
*
* @note This public API is deprecated.
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
bool spicommon_periph_free(spi_host_device_t host);
@ -135,6 +184,8 @@ bool spicommon_periph_free(spi_host_device_t host);
*
* @param dma_chan channel to claim
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_claim(int dma_chan);
@ -144,6 +195,8 @@ bool spicommon_dma_chan_claim(int dma_chan);
*
* @param dma_chan DMA channel to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_dma_chan_in_use(int dma_chan);
@ -153,10 +206,13 @@ bool spicommon_dma_chan_in_use(int dma_chan);
*
* @param dma_chan channel to return
*
* @note This public API is deprecated.
*
* @return True if success; false otherwise.
*/
bool spicommon_dma_chan_free(int dma_chan);
/// @note macros deprecated from public API
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
@ -177,6 +233,9 @@ bool spicommon_dma_chan_free(int dma_chan);
* the arguments. Depending on the IO-pads requested, the routing is done either using the
* IO_mux or using the GPIO matrix.
*
* @note This public API is deprecated. Please call ``spi_bus_initialize`` for master
* bus initialization and ``spi_slave_initialize`` for slave initialization.
*
* @param host SPI peripheral to be routed
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @param dma_chan DMA-channel (1 or 2) to use, or 0 for no DMA.
@ -205,18 +264,9 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
/**
* @brief Free the IO used by a SPI peripheral
* @deprecated Use spicommon_bus_free_io_cfg instead.
*
* @param host SPI peripheral to be freed
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io(spi_host_device_t host) __attribute__((deprecated));
/**
* @brief Free the IO used by a SPI peripheral
* @note This public API is deprecated. Please call ``spi_bus_free`` for master
* bus deinitialization and ``spi_slave_free`` for slave deinitialization.
*
* @param bus_cfg Bus config struct which defines which pins to be used.
*
@ -229,6 +279,8 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
/**
* @brief Initialize a Chip Select pin for a specific SPI peripheral
*
* @note This public API is deprecated. Please call corresponding device initialization
* functions.
*
* @param host SPI peripheral
* @param cs_io_num GPIO pin to route
@ -236,55 +288,46 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
* @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
* if the GPIO number allows it, the routing will happen through the IO_mux.
*/
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
/**
* @brief Free a chip select line
* @deprecated Use spicommon_cs_io, which inputs the gpio num rather than the cs id instead.
*
* @param host SPI peripheral
* @param cs_num CS id to free
*/
void spicommon_cs_free(spi_host_device_t host, int cs_num) __attribute__((deprecated));
/**
* @brief Free a chip select line
*
* @param cs_gpio_num CS gpio num to free
*
* @note This public API is deprecated.
*/
void spicommon_cs_free_io(int cs_gpio_num);
/**
* @brief Setup a DMA link chain
* @brief Check whether all pins used by a host are through IOMUX.
*
* This routine will set up a chain of linked DMA descriptors in the array pointed to by
* ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the
* descriptors will point to the corresponding positions in ``buffer`` and linked together. The
* end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes
* of ``data`` being read or written.
* @param host SPI peripheral
*
* @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes
* @param len Length of buffer
* @param data Data buffer to use for DMA transfer
* @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``.
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
void spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx);
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the position of the hardware registers for a specific SPI host
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host The SPI host
* @param host SPI peripheral
*
* @return A register descriptor stuct pointer, pointed at the hardware registers
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI host
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqsource_for_host(spi_host_device_t host);
@ -294,6 +337,8 @@ int spicommon_irqsource_for_host(spi_host_device_t host);
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
@ -320,6 +365,8 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
* @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback
*
* @note This public API is deprecated.
*
* @return True when a DMA reset could be executed immediately. False when it could not; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset, after that reset.
@ -330,6 +377,8 @@ bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
* @note This public API is deprecated.
*
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
*/
bool spicommon_dmaworkaround_reset_in_progress();
@ -340,6 +389,8 @@ bool spicommon_dmaworkaround_reset_in_progress();
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_idle(int dmachan);
@ -348,13 +399,13 @@ void spicommon_dmaworkaround_idle(int dmachan);
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_transfer_active(int dmachan);
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,9 +1,9 @@
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
// Copyright 2010-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
@ -12,14 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_SPI_MASTER_H_
#define _DRIVER_SPI_MASTER_H_
#pragma once
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
//for spi_bus_initialization funcions. to be back-compatible
#include "driver/spi_common.h"
/** SPI master clock is divided by 80MHz apb clock. Below defines are example frequencies, and are accurate. Be free to specify a random frequency, it will be rounded to closest frequency (to macros below if above 8MHz).
@ -154,47 +151,6 @@ typedef struct {
typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus
/**
* @brief Initialize a SPI bus
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host SPI peripheral that controls this bus
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param dma_chan Either channel 1 or 2, or 0 in the case when no DMA is required. Selecting a DMA channel
* for a SPI bus allows transfers on the bus to have sizes only limited by the amount of
* internal memory. Selecting no DMA channel (by passing the value 0) limits the amount of
* bytes transfered to a maximum of 32.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan);
/**
* @brief Free a SPI bus
*
* @warning In order for this to succeed, all devices have to be removed first.
*
* @param host SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_bus_free(spi_host_device_t host);
/**
* @brief Allocate a device on a SPI bus
*
@ -429,4 +385,3 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns);
}
#endif
#endif

View file

@ -26,6 +26,8 @@
#include "sdspi_private.h"
#include "sdspi_crc.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
/// Max number of transactions in flight (used in start_command_write_blocks)

View file

@ -100,11 +100,6 @@ int spicommon_irqdma_source_for_host(spi_host_device_t host)
return spi_periph_signal[host].irq_dma;
}
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host)
{
return spi_periph_signal[host].hw;
}
static inline uint32_t get_dma_periph(int dma_chan)
{
return PERIPH_SPI_DMA_MODULE;
@ -316,32 +311,6 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
return ESP_OK;
}
//Find any pin with output muxed to ``func`` and reset it to GPIO
static void reset_func_to_gpio(int func)
{
for (int x = 0; x < GPIO_PIN_COUNT; x++) {
if (GPIO_IS_VALID_GPIO(x) && (READ_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG + (x * 4))&GPIO_FUNC0_OUT_SEL_M) == func) {
gpio_matrix_out(x, SIG_GPIO_OUT_IDX, false, false);
}
}
}
esp_err_t spicommon_bus_free_io(spi_host_device_t host)
{
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spid_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiq_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiclk_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spiwp_iomux_pin], PIN_FUNC_GPIO);
if (REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], MCU_SEL) == 1) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spihd_iomux_pin], PIN_FUNC_GPIO);
reset_func_to_gpio(spi_periph_signal[host].spid_out);
reset_func_to_gpio(spi_periph_signal[host].spiq_out);
reset_func_to_gpio(spi_periph_signal[host].spiclk_out);
reset_func_to_gpio(spi_periph_signal[host].spiwp_out);
reset_func_to_gpio(spi_periph_signal[host].spihd_out);
return ESP_OK;
}
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
{
int pin_array[] = {
@ -377,26 +346,22 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
}
}
void spicommon_cs_free(spi_host_device_t host, int cs_io_num)
{
if (cs_io_num == 0 && REG_GET_FIELD(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], MCU_SEL) == 1) {
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[spi_periph_signal[host].spics0_iomux_pin], PIN_FUNC_GPIO);
}
reset_func_to_gpio(spi_periph_signal[host].spics_out[cs_io_num]);
}
void spicommon_cs_free_io(int cs_gpio_num)
{
assert(cs_gpio_num>=0 && GPIO_IS_VALID_GPIO(cs_gpio_num));
gpio_reset_pin(cs_gpio_num);
}
//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to.
void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx)
bool spicommon_bus_using_iomux(spi_host_device_t host)
{
lldesc_setup_link(dmadesc, data, len, isrx);
}
#define CHECK_IOMUX_PIN(HOST, PIN_NAME) if (GPIO.func_in_sel_cfg[spi_periph_signal[(HOST)].PIN_NAME##_in].sig_in_sel) return false
CHECK_IOMUX_PIN(host, spid);
CHECK_IOMUX_PIN(host, spiq);
CHECK_IOMUX_PIN(host, spiwp);
CHECK_IOMUX_PIN(host, spihd);
return true;
}
/*
Code for workaround for DMA issue in ESP32 v0/v1 silicon

View file

@ -313,7 +313,7 @@ cleanup:
free(spihost[host]);
spihost[host] = NULL;
spicommon_periph_free(host);
spicommon_dma_chan_free(dma_chan);
if (dma_chan != 0) spicommon_dma_chan_free(dma_chan);
return ret;
}

View file

@ -24,6 +24,7 @@
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
#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
/// 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;}))))
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
#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;}))))
/// type to store pre-calculated register value in above layers
typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t;

View file

@ -23,6 +23,7 @@
#pragma once
#include "hal/spi_flash_ll.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include "soc/soc_memory_layout.h"
@ -44,7 +45,7 @@ typedef struct {
/// Configuration structure for the SPI driver.
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.
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.

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``.
} 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;
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"
"memspi_host_driver.c")
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()
set(priv_requires bootloader_support app_update soc)
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
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
--------------------
@ -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.
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.
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.
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;
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)
in different stages (1st/2st boot, or the app).
in different stages (1st/2st boot, or the app).
Host driver
^^^^^^^^^^^

View file

@ -19,7 +19,6 @@
#include "spi_flash_chip_driver.h"
#include "memspi_host_driver.h"
#include "esp32/rom/spi_flash.h"
#include "esp_log.h"
#include "sdkconfig.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_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
#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);
}
#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

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);
/**
* 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
}

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;
}
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 "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_log.h"
@ -14,7 +15,6 @@
#include "unity.h"
#include "driver/spi_common.h"
#include "memspi_host_driver.h"
#include "driver/gpio.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 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_MISO HSPI_IOMUX_PIN_NUM_MISO
#define HSPI_PIN_NUM_CLK HSPI_IOMUX_PIN_NUM_CLK
#define HSPI_PIN_NUM_HD HSPI_IOMUX_PIN_NUM_HD
#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_MISO VSPI_IOMUX_PIN_NUM_MISO
#define VSPI_PIN_NUM_CLK VSPI_IOMUX_PIN_NUM_CLK
#define VSPI_PIN_NUM_HD VSPI_IOMUX_PIN_NUM_HD
#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
#define SKIP_EXTENDED_CHIP_TEST
# define SKIP_EXTENDED_CHIP_TEST
#endif
@ -71,141 +76,82 @@ static const char TAG[] = "test_esp_flash";
#ifndef SKIP_EXTENDED_CHIP_TEST
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;
int spics_out = spi_periph_signal[host].spics_out[cs_num];
uint32_t iomux_reg = GPIO_PIN_MUX_REG[TEST_CS_PIN];
//to avoid the panic caused by flash data line conflicts during cs line initialization, disable the cache temporarily
//some data from flash to be used should be read before the cache disabling
g_flash_guard_default_ops.start();
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, FUNC_SPI);
if (host_id == SPI_HOST) {
ESP_LOGI(TAG, "setup flash on SPI1 CS1...\n");
//no need to initialize the bus, however the CLK may need one more output if it's on the usual place of PSRAM
#ifdef EXTRA_SPI1_CLK_IO
gpio_matrix_out(EXTRA_SPI1_CLK_IO, SPICLK_OUT_IDX, 0, 0);
#endif
//currently the SPI bus for main flash chip is initialized through GPIO matrix
} else if (host_id == HSPI_HOST) {
ESP_LOGI(TAG, "setup flash on SPI2 (HSPI) CS0...\n");
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
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 {
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 (cs_num == 0) {
gpio_matrix_in(cs_io_num, spics_in, false);
}
PIN_FUNC_SELECT(iomux_reg, PIN_FUNC_GPIO);
ESP_LOGE(TAG, "invalid bus");
}
}
static void release_bus(int host_id)
{
if (host_id == HSPI_HOST || host_id == VSPI_HOST) {
spi_bus_free(host_id);
}
g_flash_guard_default_ops.end();
}
static void setup_new_chip(esp_flash_read_mode_t io_mode, esp_flash_speed_t speed)
{
chip_init = (esp_flash_t) {
.read_mode = io_mode,
};
//the bus should be initialized before the flash is attached to the bus
setup_bus(TEST_HOST);
#ifdef TEST_SPI2_CS0
bool spi_chan_claimed = spicommon_periph_claim(HSPI_HOST, "spi flash");
TEST_ASSERT(spi_chan_claimed);
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,
esp_flash_spi_device_config_t dev_cfg = {
.host_id = TEST_HOST,
.io_mode = io_mode,
.speed = speed,
.iomux = use_iomux,
.cs_num = TEST_CS,
.cs_id = TEST_CS,
.cs_io_num = TEST_CS_PIN,
.input_delay_ns = TEST_INPUT_DELAY,
};
#elif defined TEST_SPI3_CS0
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);
esp_err_t err = spi_bus_add_flash_device(&test_chip, &dev_cfg);
TEST_ESP_OK(err);
chip_init.host = &chip_host_driver;
esp_flash_init_os_functions(&chip_init, TEST_HOST);
err = esp_flash_init(&chip_init);
err = esp_flash_init(test_chip);
TEST_ESP_OK(err);
test_chip = &chip_init;
}
void teardown_test_chip()
{
if (TEST_HOST == HSPI_HOST || TEST_HOST == VSPI_HOST) {
spicommon_periph_free(TEST_HOST);
}
spi_bus_remove_flash_device(test_chip);
test_chip = NULL;
release_bus(TEST_HOST);
}
#endif

View file

@ -132,6 +132,7 @@ INPUT = \
## Storage - API Reference
##
## 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_partition.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
-------------------------
.. include:: /_build/inc/esp_flash_spi_init.inc
.. include:: /_build/inc/esp_flash.inc
.. include:: /_build/inc/spi_flash_types.inc