refactor(spi): moved spi hw sharing func to hw support

Common spi functionality for sharing the SPI bus between modules is moved from esp_driver_spi to
a more fitting location in esp_hw_support (shared HW resource control).

This also allows us to decouple the spi_flash driver from esp_driver_spi, removing
esp_driver_spi and esp_ringbuf from G1 builds.
pull/12501/merge
Marius Vikhammer 2023-11-14 11:14:34 +08:00
rodzic e7734a3367
commit 52e3f09b32
18 zmienionych plików z 656 dodań i 588 usunięć

Wyświetl plik

@ -4,7 +4,7 @@ if(${target} STREQUAL "linux")
return() # This component is not supported by the POSIX/Linux simulator return() # This component is not supported by the POSIX/Linux simulator
endif() endif()
set(srcs "spi_bus_lock.c") set(srcs "")
set(public_include "include") set(public_include "include")

Wyświetl plik

@ -5,6 +5,7 @@ menu "ESP-Driver:SPI Configurations"
default n default n
depends on !FREERTOS_PLACE_FUNCTIONS_INTO_FLASH depends on !FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
select SPI_MASTER_ISR_IN_IRAM select SPI_MASTER_ISR_IN_IRAM
select ESP_SPI_BUS_LOCK_FUNCS_IN_IRAM
help help
Normally only the ISR of SPI master is placed in the IRAM, so that it Normally only the ISR of SPI master is placed in the IRAM, so that it
can work without the flash when interrupt is triggered. can work without the flash when interrupt is triggered.
@ -24,6 +25,7 @@ menu "ESP-Driver:SPI Configurations"
depends on !HEAP_PLACE_FUNCTION_INTO_FLASH depends on !HEAP_PLACE_FUNCTION_INTO_FLASH
select PERIPH_CTRL_FUNC_IN_IRAM select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_MASTER_FUNC_IN_IRAM select HAL_SPI_MASTER_FUNC_IN_IRAM
select ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
help help
Place the SPI master ISR in to IRAM to avoid possible cache miss. Place the SPI master ISR in to IRAM to avoid possible cache miss.

Wyświetl plik

@ -15,6 +15,7 @@
#include "hal/dma_types.h" #include "hal/dma_types.h"
#include "soc/gdma_channel.h" #include "soc/gdma_channel.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_private/spi_share_hw_ctrl.h"
#if SOC_GDMA_SUPPORTED #if SOC_GDMA_SUPPORTED
#include "esp_private/gdma.h" #include "esp_private/gdma.h"
#endif #endif
@ -36,14 +37,6 @@ extern "C"
#define SPI_MASTER_ATTR #define SPI_MASTER_ATTR
#endif #endif
#define BUS_LOCK_DEBUG 0
#if BUS_LOCK_DEBUG
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x) assert(x)
#else
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x)
#endif
#if SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB #if SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB
#define DMA_DESC_MEM_ALIGN_SIZE 4 #define DMA_DESC_MEM_ALIGN_SIZE 4
#define SPI_GDMA_NEW_CHANNEL gdma_new_ahb_channel #define SPI_GDMA_NEW_CHANNEL gdma_new_ahb_channel
@ -54,16 +47,6 @@ typedef dma_descriptor_align4_t spi_dma_desc_t;
typedef dma_descriptor_align8_t spi_dma_desc_t; typedef dma_descriptor_align8_t spi_dma_desc_t;
#endif #endif
struct spi_bus_lock_t;
struct spi_bus_lock_dev_t;
/// Handle to the lock of an SPI bus
typedef struct spi_bus_lock_t* spi_bus_lock_handle_t;
/// Handle to lock of one of the device on an SPI bus
typedef struct spi_bus_lock_dev_t* spi_bus_lock_dev_handle_t;
/// Background operation control function
typedef void (*bg_ctrl_func_t)(void*);
/// Attributes of an SPI bus /// Attributes of an SPI bus
typedef struct { typedef struct {
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus spi_bus_config_t bus_cfg; ///< Config used to initialize the bus
@ -85,36 +68,6 @@ typedef struct {
/// Destructor called when a bus is deinitialized. /// Destructor called when a bus is deinitialized.
typedef esp_err_t (*spi_destroy_func_t)(void*); typedef esp_err_t (*spi_destroy_func_t)(void*);
/**
* @brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral.
*
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @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);
/**
* @brief Check whether the spi periph is in use.
*
* @param host Peripheral to check.
*
* @return True if in use, otherwise false.
*/
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
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
bool spicommon_periph_free(spi_host_device_t host);
/** /**
* @brief Alloc DMA for SPI * @brief Alloc DMA for SPI
* *
@ -330,449 +283,6 @@ const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id);
esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id, esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
spi_destroy_func_t f, void *arg); spi_destroy_func_t f, void *arg);
/*******************************************************************************
* SPI Bus Lock for arbitration among SPI master (intr, polling) trans, SPI flash operations and
* flash/psram cache access.
*
* NON-PUBLIC API. Don't use it directly in applications.
*
* There is the main lock corresponding to an SPI bus, of which several devices (holding child
* locks) attaching to it. Each of the device is STRONGLY RECOMMENDED to be used in only one task
* to avoid concurrency issues.
*
* Terms:
* - BG operations (BackGround operations) means some transaction that will not immediately /
* explicitly be sent in the task. It can be some cache access, or interrupt transactions.
*
* - Operation: usage of the bus, for example, do SPI transactions.
*
* - Acquiring processor: the task or the ISR that is allowed to use the bus. No operations will be
* performed if there is no acquiring processor. A processor becomes the acquiring processor if
* it ask for that when no acquiring processor exist, otherwise it has to wait for the acquiring
* processor to handle over the role to it. The acquiring processor will and will only assign one
* acquiring processor in the waiting list (if not empty) when it finishes its operation.
*
* - Acquiring device: the only device allowed to use the bus. Operations can be performed in
* either the BG or the task. When there's no acquiring device, only the ISR is allowed to be the
* acquiring processor and perform operations on the bus.
*
* When a device wants to perform operations, it either:
* 1. Acquire the bus, and operate in the task (e.g. polling transactions of SPI master, and SPI flash
* operations)
*
* 2. Request a BG operation. And the ISR will be enabled at proper time.
*
* For example if a task wants to send an interrupt transaction, it prepares the data in the task,
* call `spi_bus_lock_bg_request`, and handle sending in the ISR.
*
* 3. When a device has already acquired the bus, BG operations are also allowed. After the
* `spi_bus_lock_bg_request` is called, call `spi_bus_lock_wait_bg_done` before operations in task
* again to wait until BG operations are done.
*
* Any device may try to invoke the ISR (by `spi_bus_lock_bg_request`). The ISR will be invoked and
* become the acquiring processor immediately when the bus is not acquired by other processors. Any
* device may also try to acquire the bus (by `spi_bus_lock_acquire_start`). The device will become
* the acquiring processor immediately when the bus is not acquired and there is no request active.
*
* The acquiring processor must be aware of its acquiring role, and properly transfer the acquiring
* processor to other tasks or ISR when they have nothing else to do. Before picking a new
* acquiring processor, a new acquiring device must be picked first, if there are other devices,
* asking to be acquiring device. After that, the new acquiring processor is picked by the sequence
* below:
*
* 1. If there is an acquiring device:
* 1.1 The ISR, if acquiring device has active BG requests
* 1.2 The task of the device, if no active BG request for the device
* 2. The ISR, if there's no acquiring device, but any BG request is active
* 3. No one becomes the acquiring processor
*
* The API also helps on the arbitration of SPI cs lines. The bus is initialized with a cs_num
* argument. When attaching devices onto the bus with `spi_bus_lock_register_dev`, it will allocate
* devices with different device ID according to the flags given. If the ID is smaller than the
* cs_num given when bus is initialized, error will be returned.
*
* Usage:
* * Initialization:
* 1. Call `spi_bus_init_lock` to register a lock for a bus.
* 2. Call `spi_bus_lock_set_bg_control` to prepare BG enable/disable functions for
* the lock.
* 3. Call `spi_bus_lock_register_dev` for each devices that may make use of the
* bus, properly store the returned handle, representing those devices.
*
* * Acquiring:
* 1. Call `spi_bus_lock_acquire_start` when a device wants to use the bus
* 2. Call `spi_bus_lock_touch` to mark the bus as touched by this device. Also check if the bus
* has been touched by other devices.
* 3. (optional) Do something on the bus...
* 4. (optional) Call `spi_bus_lock_bg_request` to inform and invoke the BG. See ISR below about
* ISR operations.
* 5. (optional) If `spi_bus_lock_bg_request` is done, you have to call `spi_bus_lock_wait_bg_done`
* before touching the bus again, or do the following steps.
* 6. Call `spi_bus_lock_acquire_end` to release the bus to other devices.
*
* * ISR:
* 1. Call `spi_bus_lock_bg_entry` when entering the ISR, run or skip the closure for the previous
* operation according to the return value.
* 2. Call `spi_bus_lock_get_acquiring_dev` to get the acquiring device. If there is no acquiring
* device, call `spi_bus_lock_bg_check_dev_acq` to check and update a new acquiring device.
* 3. Call `spi_bus_lock_bg_check_dev_req` to check for request of the desired device. If the
* desired device is not requested, go to step 5.
* 4. Check, start operation for the desired device and go to step 6; otherwise if no operations
* can be performed, call `spi_bus_lock_bg_clear_req` to clear the request for this device. If
* `spi_bus_lock_bg_clear_req` is called and there is no BG requests active, goto step 6.
* 5. (optional) If the device is the acquiring device, go to step 6, otherwise
* find another desired device, and go back to step 3.
* 6. Call `spi_bus_lock_bg_exit` to try quitting the ISR. If failed, go back to step 2 to look for
* a new request again. Otherwise, quit the ISR.
*
* * Deinitialization (optional):
* 1. Call `spi_bus_lock_unregister_dev` for each device when they are no longer needed.
* 2. Call `spi_bus_deinit_lock` to release the resources occupied by the lock.
*
* Some technical details:
*
* The child-lock of each device will have its own Binary Semaphore, which allows the task serving
* this device (task A) being blocked when it fail to become the acquiring processor while it's
* calling `spi_bus_lock_acquire_start` or `spi_bus_lock_wait_bg_done`. If it is blocked, there
* must be an acquiring processor (either the ISR or another task (task B)), is doing transaction
* on the bus. After that, task A will get unblocked and become the acquiring processor when the
* ISR call `spi_bus_lock_bg_resume_acquired_dev`, or task B call `spi_bus_lock_acquire_end`.
*
* When the device wants to send ISR transaction, it should call `spi_bus_lock_bg_request` after
* the data is prepared. This function sets a request bit in the critical resource. The ISR will be
* invoked and become the new acquiring processor, when:
*
* 1. A task calls `spi_bus_lock_bg_request` while there is no acquiring processor;
* 2. A tasks calls `spi_bus_lock_bg_request` while the task is the acquiring processor. Then the
* acquiring processor is handled over to the ISR;
* 3. A tasks who is the acquiring processor release the bus by calling `spi_bus_lock_acquire_end`,
* and the ISR happens to be the next acquiring processor.
*
* The ISR will check (by `spi_bus_lock_bg_check_dev_req`) and clear a request bit (by
* `spi_bus_lock_bg_clear_req`) after it confirm that all the requests of the corresponding device
* are served. The request bit supports being written to recursively, which means, the task don't
* need to wait for `spi_bus_lock_bg_clear_req` before call another `spi_bus_lock_bg_request`. The
* API will handle the concurrency conflicts properly.
*
* The `spi_bus_lock_bg_exit` (together with `spi_bus_lock_bg_entry` called before)` is responsible
* to ensure ONE and ONLY ONE of the following will happen when the ISR try to give up its
* acquiring processor rule:
*
* 1. ISR quit, no any task unblocked while the interrupt disabled, and none of the BG bits is
* active.
* 2. ISR quit, there is an acquiring device, and the acquiring processor is passed to the task
* serving the acquiring device by unblocking the task.
* 3. The ISR failed to quit and have to try again.
******************************************************************************/
#define DEV_NUM_MAX 6 ///< Number of devices supported by this lock
/// Lock configuration struct
typedef struct {
int host_id; ///< SPI host id
int cs_num; ///< Physical cs numbers of the host
} spi_bus_lock_config_t;
/// Child-lock configuration struct
typedef struct {
uint32_t flags; ///< flags for the lock, OR-ed of `SPI_BUS_LOCK_DEV_*` flags.
#define SPI_BUS_LOCK_DEV_FLAG_CS_REQUIRED BIT(0) ///< The device needs a physical CS pin.
} spi_bus_lock_dev_config_t;
/************* Common *********************/
/**
* Initialize a lock for an SPI bus.
*
* @param out_lock Output of the handle to the lock
* @return
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_init_lock(spi_bus_lock_handle_t *out_lock, const spi_bus_lock_config_t *config);
/**
* Free the resources used by an SPI bus lock.
*
* @note All attached devices should have been unregistered before calling this
* funciton.
*
* @param lock Handle to the lock to free.
*/
void spi_bus_deinit_lock(spi_bus_lock_handle_t lock);
/**
* @brief Get the corresponding lock according to bus id.
*
* @param host_id The bus id to get the lock
* @return The lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id);
/**
* @brief Configure how the SPI bus lock enable the background operation.
*
* @note The lock will not try to stop the background operations, but wait for
* The background operations finished indicated by `spi_bus_lock_bg_resume_acquired_dev`.
*
* @param lock Handle to the lock to set
* @param bg_enable The enabling function
* @param bg_disable The disabling function, set to NULL if not required
* @param arg Argument to pass to the enabling/disabling function.
*/
void spi_bus_lock_set_bg_control(spi_bus_lock_handle_t lock, bg_ctrl_func_t bg_enable,
bg_ctrl_func_t bg_disable, void *arg);
/**
* Attach a device onto an SPI bus lock. The returning handle is used to perform
* following requests for the attached device.
*
* @param lock SPI bus lock to attach
* @param out_dev_handle Output handle corresponding to the device
* @param flags requirement of the device, bitwise OR of SPI_BUS_LOCK_FLAG_* flags
*
* @return
* - ESP_ERR_NOT_SUPPORTED: if there's no hardware resources for new devices.
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_lock_register_dev(spi_bus_lock_handle_t lock,
spi_bus_lock_dev_config_t *config,
spi_bus_lock_dev_handle_t *out_dev_handle);
/**
* Detach a device from its bus and free the resources used
*
* @param dev_handle Handle to the device.
*/
void spi_bus_lock_unregister_dev(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the parent bus lock of the device
*
* @param dev_handle Handle to the device to get bus lock
* @return The bus lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_parent(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the device ID of a lock.
*
* The callers should allocate CS pins according to this ID.
*
* @param dev_handle Handle to the device to get ID
* @return ID of the device
*/
int spi_bus_lock_get_dev_id(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief The device request to touch bus registers. Can only be called by the acquiring processor.
*
* Also check if the registers has been touched by other devices.
*
* @param dev_handle Handle to the device to operate the registers
* @return true if there has been other devices touching SPI registers.
* The caller may need to do a full-configuration. Otherwise return
* false.
*/
bool spi_bus_lock_touch(spi_bus_lock_dev_handle_t dev_handle);
/************* Acquiring service *********************/
/**
* Acquiring the SPI bus for exclusive use. Will also wait for the BG to finish all requests of
* this device before it returns.
*
* After successfully return, the caller becomes the acquiring processor.
*
* @note For the main flash bus, `bg_disable` will be called to disable the cache.
*
* @param dev_handle Handle to the device request for acquiring.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: timeout is not portMAX_DELAY
*/
esp_err_t spi_bus_lock_acquire_start(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Release the bus acquired. Will pass the acquiring processor to other blocked
* processors (tasks or ISR), and cause them to be unblocked or invoked.
*
* The acquiring device may also become NULL if no device is asking for acquiring.
* In this case, the BG may be invoked if there is any BG requests.
*
* If the new acquiring device has BG requests, the BG will be invoked before the
* task is resumed later after the BG finishes all requests of the new acquiring
* device. Otherwise the task of the new acquiring device will be resumed immediately.
*
* @param dev_handle Handle to the device releasing the bus.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: the device hasn't acquired the lock yet
*/
esp_err_t spi_bus_lock_acquire_end(spi_bus_lock_dev_handle_t dev_handle);
/**
* Get the device acquiring the bus.
*
* @note Return value is not stable as the acquiring processor may change
* when this function is called.
*
* @param lock Lock of SPI bus to get the acquiring device.
* @return The argument corresponding to the acquiring device, see
* `spi_bus_lock_register_dev`.
*/
spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi_bus_lock_handle_t lock);
/************* BG (Background, for ISR or cache) service *********************/
/**
* Call by a device to request a BG operation.
*
* Depending on the bus lock state, the BG operations may be resumed by this
* call, or pending until BG operations allowed.
*
* Cleared by `spi_bus_lock_bg_clear_req` in the BG.
*
* @param dev_handle The device requesting BG operations.
* @return always ESP_OK
*/
esp_err_t spi_bus_lock_bg_request(spi_bus_lock_dev_handle_t dev_handle);
/**
* Wait until the ISR has finished all the BG operations for the acquiring device.
* If any `spi_bus_lock_bg_request` for this device has been called after
* `spi_bus_lock_acquire_start`, this function must be called before any operation
* in the task.
*
* @note Can only be called when bus acquired by this device.
*
* @param dev_handle Handle to the device acquiring the bus.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: The device is not the acquiring bus.
* - ESP_ERR_INVALID_ARG: Timeout is not portMAX_DELAY.
*/
esp_err_t spi_bus_lock_wait_bg_done(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Handle interrupt and closure of last operation. Should be called at the beginning of the ISR,
* when the ISR is acting as the acquiring processor.
*
* @param lock The SPI bus lock
*
* @return false if the ISR has already touched the HW, should run closure of the
* last operation first; otherwise true if the ISR just start operating
* on the HW, closure should be skipped.
*/
bool spi_bus_lock_bg_entry(spi_bus_lock_handle_t lock);
/**
* Handle the scheduling of other acquiring devices, and control of HW operation
* status.
*
* If no BG request is found, call with `wip=false`. This function will return false,
* indicating there is incoming BG requests for the current acquiring device (or
* for all devices if there is no acquiring device) and the ISR needs retry.
* Otherwise may schedule a new acquiring processor (unblock the task) if there
* is, and return true.
*
* Otherwise if a BG request is started in this ISR, call with `wip=true` and the
* function will enable the interrupt to make the ISR be called again when the
* request is done.
*
* This function is safe and should still be called when the ISR just lost its acquiring processor
* role, but hasn't quit.
*
* @note This function will not change acquiring device. The ISR call
* `spi_bus_lock_bg_update_acquiring` to check for new acquiring device,
* when acquiring devices need to be served before other devices.
*
* @param lock The SPI bus lock.
* @param wip Whether an operation is being executed when quitting the ISR.
* @param do_yield[out] Not touched when no yielding required, otherwise set
* to pdTRUE.
* @return false if retry is required, indicating that there is pending BG request.
* otherwise true and quit ISR is allowed.
*/
bool spi_bus_lock_bg_exit(spi_bus_lock_handle_t lock, bool wip, BaseType_t* do_yield);
/**
* Check whether there is device asking for the acquiring device, and the desired
* device for the next operation is also recommended.
*
* @note Must be called when the ISR is acting as the acquiring processor, and
* there is no acquiring device.
*
* @param lock The SPI bus lock.
* @param out_dev_lock The recommended device for hte next operation. It's the new
* acquiring device when found, otherwise a device that has active BG request.
*
* @return true if the ISR need to quit (new acquiring device has no active BG
* request, or no active BG requests for all devices when there is no
* acquiring device), otherwise false.
*/
bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_handle_t lock, spi_bus_lock_dev_handle_t *out_dev_lock);
/**
* Check if the device has BG requests. Must be called when the ISR is acting as
* the acquiring processor.
*
* @note This is not stable, may become true again when a task request for BG
* operation (by `spi_bus_lock_bg_request`).
*
* @param dev_lock The device to check.
* @return true if the device has BG requests, otherwise false.
*/
bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Clear the pending BG operation request of a device after served. Must be
* called when the ISR is acting as the acquiring processor.
*
* @note When the return value is true, the ISR will lost the acquiring processor role. Then
* `spi_bus_lock_bg_exit` must be called and checked before calling all other functions that
* require to be called when the ISR is the acquiring processor again.
*
* @param dev_handle The device whose request is served.
* @return True if no pending requests for the acquiring device, or for all devices
* if there is no acquiring device. Otherwise false. When the return value is
* true, the ISR is no longer the acquiring processor.
*/
bool spi_bus_lock_bg_clear_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Check if there is any active BG requests.
*
* @param lock The SPI bus lock.
* @return true if any device has active BG requst, otherwise false.
*/
bool spi_bus_lock_bg_req_exist(spi_bus_lock_handle_t lock);
/*******************************************************************************
* Variable and APIs for the OS to initialize the locks for the main chip
******************************************************************************/
/// The lock for the main bus
extern const spi_bus_lock_handle_t g_main_spi_bus_lock;
/**
* @brief Initialize the main SPI bus, called during chip startup.
*
* @return always ESP_OK
*/
esp_err_t spi_bus_lock_init_main_bus(void);
/// The lock for the main flash device
extern const spi_bus_lock_dev_handle_t g_spi_lock_main_flash_dev;
/**
* @brief Initialize the main flash device, called during chip startup.
*
* @return
* - ESP_OK: if success
* - ESP_ERR_NO_MEM: memory exhausted
*/
esp_err_t spi_bus_lock_init_main_dev(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

Wyświetl plik

@ -17,6 +17,7 @@
#include "driver/spi_master.h" #include "driver/spi_master.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_common_internal.h"
#include "esp_private/spi_share_hw_ctrl.h"
#include "hal/spi_hal.h" #include "hal/spi_hal.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
@ -28,12 +29,6 @@
#include "hal/cache_ll.h" #include "hal/cache_ll.h"
#endif #endif
#if !SOC_RCC_IS_INDEPENDENT
#define SPI_COMMON_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define SPI_COMMON_RCC_CLOCK_ATOMIC()
#endif
static const char *SPI_TAG = "spi"; static const char *SPI_TAG = "spi";
#define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str) #define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str)
@ -67,20 +62,19 @@ typedef struct {
#endif #endif
} spicommon_bus_context_t; } spicommon_bus_context_t;
//Periph 1 is 'claimed' by SPI flash code.
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
#if (SOC_SPI_PERIPH_NUM >= 3)
ATOMIC_VAR_INIT(false),
#endif
#if (SOC_SPI_PERIPH_NUM >= 4)
ATOMIC_VAR_INIT(false),
#endif
};
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT(); static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT();
static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus}; static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus};
#if CONFIG_SPI_FLASH_SHARE_SPI1_BUS
/* The lock for the share SPI1 bus is registered here in a constructor due to need to access the context
This way we are able to decouple the SPI-flash driver from the spi-master driver */
static __attribute__((constructor)) void spi_bus_lock_init_main_bus(void)
{
/* Initialize bus context about the main SPI bus lock, called during chip startup. */
spi_bus_main_set_lock(g_main_spi_bus_lock);
}
#endif
#if !SOC_GDMA_SUPPORTED #if !SOC_GDMA_SUPPORTED
//Each bit stands for 1 dma channel, BIT(0) should be used for SPI1 //Each bit stands for 1 dma channel, BIT(0) should be used for SPI1
static uint8_t spi_dma_chan_enabled = 0; static uint8_t spi_dma_chan_enabled = 0;
@ -96,42 +90,6 @@ static inline bool is_valid_host(spi_host_device_t host)
#endif #endif
} }
//----------------------------------------------------------alloc spi periph-------------------------------------------------------//
//Returns true if this peripheral is successfully claimed, false if otherwise.
bool spicommon_periph_claim(spi_host_device_t host, const char* source)
{
bool false_var = false;
bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
if (ret) {
spi_claiming_func[host] = source;
SPI_COMMON_RCC_CLOCK_ATOMIC() {
spi_ll_enable_bus_clock(host, true);
spi_ll_reset_register(host);
}
} else {
ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host + 1, spi_claiming_func[host]);
}
return ret;
}
bool spicommon_periph_in_use(spi_host_device_t host)
{
return atomic_load(&spi_periph_claimed[host]);
}
//Returns true if this peripheral is successfully freed, false if otherwise.
bool spicommon_periph_free(spi_host_device_t host)
{
bool true_var = true;
bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false);
if (ret) {
SPI_COMMON_RCC_CLOCK_ATOMIC() {
spi_ll_enable_bus_clock(host, false);
}
}
return ret;
}
int spicommon_irqsource_for_host(spi_host_device_t host) int spicommon_irqsource_for_host(spi_host_device_t host)
{ {
return spi_periph_signal[host].irq; return spi_periph_signal[host].irq;

Wyświetl plik

@ -31,6 +31,7 @@
#include "esp_private/spi_slave_internal.h" #include "esp_private/spi_slave_internal.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_common_internal.h"
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "esp_private/spi_share_hw_ctrl.h"
static const char *SPI_TAG = "spi_slave"; static const char *SPI_TAG = "spi_slave";

Wyświetl plik

@ -13,6 +13,7 @@
#include "freertos/ringbuf.h" #include "freertos/ringbuf.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_common_internal.h"
#include "esp_private/spi_share_hw_ctrl.h"
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "driver/spi_slave_hd.h" #include "driver/spi_slave_hd.h"
#include "hal/spi_slave_hd_hal.h" #include "hal/spi_slave_hd_hal.h"

Wyświetl plik

@ -36,7 +36,9 @@ if(NOT BOOTLOADER_BUILD)
"port/${target}/io_mux.c" "port/${target}/io_mux.c"
"port/${target}/esp_clk_tree.c" "port/${target}/esp_clk_tree.c"
"port/esp_clk_tree_common.c" "port/esp_clk_tree_common.c"
"dma/esp_dma_utils.c") "dma/esp_dma_utils.c"
"spi_share_hw_ctrl.c"
"spi_bus_lock.c")
if(CONFIG_SOC_ADC_SUPPORTED) if(CONFIG_SOC_ADC_SUPPORTED)
list(APPEND srcs "adc_share_hw_ctrl.c") list(APPEND srcs "adc_share_hw_ctrl.c")

Wyświetl plik

@ -341,4 +341,11 @@ menu "Hardware Settings"
clock support isn't done yet. So with this option, clock support isn't done yet. So with this option,
we use xtal on FPGA as the clock source. we use xtal on FPGA as the clock source.
config ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
bool
default n
config ESP_SPI_BUS_LOCK_FUNCS_IN_IRAM
bool
default n
endmenu endmenu

Wyświetl plik

@ -0,0 +1,511 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
#include "esp_private/periph_ctrl.h"
#include "freertos/FreeRTOS.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define SPI_COMMON_RCC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define SPI_COMMON_RCC_CLOCK_ATOMIC()
#endif
#define BUS_LOCK_DEBUG 0
#if BUS_LOCK_DEBUG
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x) assert(x)
#else
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x)
#endif
struct spi_bus_lock_t;
struct spi_bus_lock_dev_t;
/// Handle to the lock of an SPI bus
typedef struct spi_bus_lock_t* spi_bus_lock_handle_t;
/// Handle to lock of one of the device on an SPI bus
typedef struct spi_bus_lock_dev_t* spi_bus_lock_dev_handle_t;
/// Background operation control function
typedef void (*bg_ctrl_func_t)(void*);
/**
* @brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral.
*
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @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);
/**
* @brief Check whether the spi periph is in use.
*
* @param host Peripheral to check.
*
* @return True if in use, otherwise false.
*/
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
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
bool spicommon_periph_free(spi_host_device_t host);
/*******************************************************************************
* SPI Bus Lock for arbitration among SPI master (intr, polling) trans, SPI flash operations and
* flash/psram cache access.
*
* NON-PUBLIC API. Don't use it directly in applications.
*
* There is the main lock corresponding to an SPI bus, of which several devices (holding child
* locks) attaching to it. Each of the device is STRONGLY RECOMMENDED to be used in only one task
* to avoid concurrency issues.
*
* Terms:
* - BG operations (BackGround operations) means some transaction that will not immediately /
* explicitly be sent in the task. It can be some cache access, or interrupt transactions.
*
* - Operation: usage of the bus, for example, do SPI transactions.
*
* - Acquiring processor: the task or the ISR that is allowed to use the bus. No operations will be
* performed if there is no acquiring processor. A processor becomes the acquiring processor if
* it ask for that when no acquiring processor exist, otherwise it has to wait for the acquiring
* processor to handle over the role to it. The acquiring processor will and will only assign one
* acquiring processor in the waiting list (if not empty) when it finishes its operation.
*
* - Acquiring device: the only device allowed to use the bus. Operations can be performed in
* either the BG or the task. When there's no acquiring device, only the ISR is allowed to be the
* acquiring processor and perform operations on the bus.
*
* When a device wants to perform operations, it either:
* 1. Acquire the bus, and operate in the task (e.g. polling transactions of SPI master, and SPI flash
* operations)
*
* 2. Request a BG operation. And the ISR will be enabled at proper time.
*
* For example if a task wants to send an interrupt transaction, it prepares the data in the task,
* call `spi_bus_lock_bg_request`, and handle sending in the ISR.
*
* 3. When a device has already acquired the bus, BG operations are also allowed. After the
* `spi_bus_lock_bg_request` is called, call `spi_bus_lock_wait_bg_done` before operations in task
* again to wait until BG operations are done.
*
* Any device may try to invoke the ISR (by `spi_bus_lock_bg_request`). The ISR will be invoked and
* become the acquiring processor immediately when the bus is not acquired by other processors. Any
* device may also try to acquire the bus (by `spi_bus_lock_acquire_start`). The device will become
* the acquiring processor immediately when the bus is not acquired and there is no request active.
*
* The acquiring processor must be aware of its acquiring role, and properly transfer the acquiring
* processor to other tasks or ISR when they have nothing else to do. Before picking a new
* acquiring processor, a new acquiring device must be picked first, if there are other devices,
* asking to be acquiring device. After that, the new acquiring processor is picked by the sequence
* below:
*
* 1. If there is an acquiring device:
* 1.1 The ISR, if acquiring device has active BG requests
* 1.2 The task of the device, if no active BG request for the device
* 2. The ISR, if there's no acquiring device, but any BG request is active
* 3. No one becomes the acquiring processor
*
* The API also helps on the arbitration of SPI cs lines. The bus is initialized with a cs_num
* argument. When attaching devices onto the bus with `spi_bus_lock_register_dev`, it will allocate
* devices with different device ID according to the flags given. If the ID is smaller than the
* cs_num given when bus is initialized, error will be returned.
*
* Usage:
* * Initialization:
* 1. Call `spi_bus_init_lock` to register a lock for a bus.
* 2. Call `spi_bus_lock_set_bg_control` to prepare BG enable/disable functions for
* the lock.
* 3. Call `spi_bus_lock_register_dev` for each devices that may make use of the
* bus, properly store the returned handle, representing those devices.
*
* * Acquiring:
* 1. Call `spi_bus_lock_acquire_start` when a device wants to use the bus
* 2. Call `spi_bus_lock_touch` to mark the bus as touched by this device. Also check if the bus
* has been touched by other devices.
* 3. (optional) Do something on the bus...
* 4. (optional) Call `spi_bus_lock_bg_request` to inform and invoke the BG. See ISR below about
* ISR operations.
* 5. (optional) If `spi_bus_lock_bg_request` is done, you have to call `spi_bus_lock_wait_bg_done`
* before touching the bus again, or do the following steps.
* 6. Call `spi_bus_lock_acquire_end` to release the bus to other devices.
*
* * ISR:
* 1. Call `spi_bus_lock_bg_entry` when entering the ISR, run or skip the closure for the previous
* operation according to the return value.
* 2. Call `spi_bus_lock_get_acquiring_dev` to get the acquiring device. If there is no acquiring
* device, call `spi_bus_lock_bg_check_dev_acq` to check and update a new acquiring device.
* 3. Call `spi_bus_lock_bg_check_dev_req` to check for request of the desired device. If the
* desired device is not requested, go to step 5.
* 4. Check, start operation for the desired device and go to step 6; otherwise if no operations
* can be performed, call `spi_bus_lock_bg_clear_req` to clear the request for this device. If
* `spi_bus_lock_bg_clear_req` is called and there is no BG requests active, goto step 6.
* 5. (optional) If the device is the acquiring device, go to step 6, otherwise
* find another desired device, and go back to step 3.
* 6. Call `spi_bus_lock_bg_exit` to try quitting the ISR. If failed, go back to step 2 to look for
* a new request again. Otherwise, quit the ISR.
*
* * Deinitialization (optional):
* 1. Call `spi_bus_lock_unregister_dev` for each device when they are no longer needed.
* 2. Call `spi_bus_deinit_lock` to release the resources occupied by the lock.
*
* Some technical details:
*
* The child-lock of each device will have its own Binary Semaphore, which allows the task serving
* this device (task A) being blocked when it fail to become the acquiring processor while it's
* calling `spi_bus_lock_acquire_start` or `spi_bus_lock_wait_bg_done`. If it is blocked, there
* must be an acquiring processor (either the ISR or another task (task B)), is doing transaction
* on the bus. After that, task A will get unblocked and become the acquiring processor when the
* ISR call `spi_bus_lock_bg_resume_acquired_dev`, or task B call `spi_bus_lock_acquire_end`.
*
* When the device wants to send ISR transaction, it should call `spi_bus_lock_bg_request` after
* the data is prepared. This function sets a request bit in the critical resource. The ISR will be
* invoked and become the new acquiring processor, when:
*
* 1. A task calls `spi_bus_lock_bg_request` while there is no acquiring processor;
* 2. A tasks calls `spi_bus_lock_bg_request` while the task is the acquiring processor. Then the
* acquiring processor is handled over to the ISR;
* 3. A tasks who is the acquiring processor release the bus by calling `spi_bus_lock_acquire_end`,
* and the ISR happens to be the next acquiring processor.
*
* The ISR will check (by `spi_bus_lock_bg_check_dev_req`) and clear a request bit (by
* `spi_bus_lock_bg_clear_req`) after it confirm that all the requests of the corresponding device
* are served. The request bit supports being written to recursively, which means, the task don't
* need to wait for `spi_bus_lock_bg_clear_req` before call another `spi_bus_lock_bg_request`. The
* API will handle the concurrency conflicts properly.
*
* The `spi_bus_lock_bg_exit` (together with `spi_bus_lock_bg_entry` called before)` is responsible
* to ensure ONE and ONLY ONE of the following will happen when the ISR try to give up its
* acquiring processor rule:
*
* 1. ISR quit, no any task unblocked while the interrupt disabled, and none of the BG bits is
* active.
* 2. ISR quit, there is an acquiring device, and the acquiring processor is passed to the task
* serving the acquiring device by unblocking the task.
* 3. The ISR failed to quit and have to try again.
******************************************************************************/
#define DEV_NUM_MAX 6 ///< Number of devices supported by this lock
/// Lock configuration struct
typedef struct {
int host_id; ///< SPI host id
int cs_num; ///< Physical cs numbers of the host
} spi_bus_lock_config_t;
/// Child-lock configuration struct
typedef struct {
uint32_t flags; ///< flags for the lock, OR-ed of `SPI_BUS_LOCK_DEV_*` flags.
#define SPI_BUS_LOCK_DEV_FLAG_CS_REQUIRED BIT(0) ///< The device needs a physical CS pin.
} spi_bus_lock_dev_config_t;
/************* Common *********************/
/**
* Initialize a lock for an SPI bus.
*
* @param out_lock Output of the handle to the lock
* @return
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_init_lock(spi_bus_lock_handle_t *out_lock, const spi_bus_lock_config_t *config);
/**
* Free the resources used by an SPI bus lock.
*
* @note All attached devices should have been unregistered before calling this
* funciton.
*
* @param lock Handle to the lock to free.
*/
void spi_bus_deinit_lock(spi_bus_lock_handle_t lock);
/**
* @brief Get the corresponding lock according to bus id.
*
* @param host_id The bus id to get the lock
* @return The lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id);
/**
* @brief Configure how the SPI bus lock enable the background operation.
*
* @note The lock will not try to stop the background operations, but wait for
* The background operations finished indicated by `spi_bus_lock_bg_resume_acquired_dev`.
*
* @param lock Handle to the lock to set
* @param bg_enable The enabling function
* @param bg_disable The disabling function, set to NULL if not required
* @param arg Argument to pass to the enabling/disabling function.
*/
void spi_bus_lock_set_bg_control(spi_bus_lock_handle_t lock, bg_ctrl_func_t bg_enable,
bg_ctrl_func_t bg_disable, void *arg);
/**
* Attach a device onto an SPI bus lock. The returning handle is used to perform
* following requests for the attached device.
*
* @param lock SPI bus lock to attach
* @param out_dev_handle Output handle corresponding to the device
* @param flags requirement of the device, bitwise OR of SPI_BUS_LOCK_FLAG_* flags
*
* @return
* - ESP_ERR_NOT_SUPPORTED: if there's no hardware resources for new devices.
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_lock_register_dev(spi_bus_lock_handle_t lock,
spi_bus_lock_dev_config_t *config,
spi_bus_lock_dev_handle_t *out_dev_handle);
/**
* Detach a device from its bus and free the resources used
*
* @param dev_handle Handle to the device.
*/
void spi_bus_lock_unregister_dev(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the parent bus lock of the device
*
* @param dev_handle Handle to the device to get bus lock
* @return The bus lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_parent(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the device ID of a lock.
*
* The callers should allocate CS pins according to this ID.
*
* @param dev_handle Handle to the device to get ID
* @return ID of the device
*/
int spi_bus_lock_get_dev_id(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief The device request to touch bus registers. Can only be called by the acquiring processor.
*
* Also check if the registers has been touched by other devices.
*
* @param dev_handle Handle to the device to operate the registers
* @return true if there has been other devices touching SPI registers.
* The caller may need to do a full-configuration. Otherwise return
* false.
*/
bool spi_bus_lock_touch(spi_bus_lock_dev_handle_t dev_handle);
/************* Acquiring service *********************/
/**
* Acquiring the SPI bus for exclusive use. Will also wait for the BG to finish all requests of
* this device before it returns.
*
* After successfully return, the caller becomes the acquiring processor.
*
* @note For the main flash bus, `bg_disable` will be called to disable the cache.
*
* @param dev_handle Handle to the device request for acquiring.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: timeout is not portMAX_DELAY
*/
esp_err_t spi_bus_lock_acquire_start(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Release the bus acquired. Will pass the acquiring processor to other blocked
* processors (tasks or ISR), and cause them to be unblocked or invoked.
*
* The acquiring device may also become NULL if no device is asking for acquiring.
* In this case, the BG may be invoked if there is any BG requests.
*
* If the new acquiring device has BG requests, the BG will be invoked before the
* task is resumed later after the BG finishes all requests of the new acquiring
* device. Otherwise the task of the new acquiring device will be resumed immediately.
*
* @param dev_handle Handle to the device releasing the bus.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: the device hasn't acquired the lock yet
*/
esp_err_t spi_bus_lock_acquire_end(spi_bus_lock_dev_handle_t dev_handle);
/**
* Get the device acquiring the bus.
*
* @note Return value is not stable as the acquiring processor may change
* when this function is called.
*
* @param lock Lock of SPI bus to get the acquiring device.
* @return The argument corresponding to the acquiring device, see
* `spi_bus_lock_register_dev`.
*/
spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi_bus_lock_handle_t lock);
/************* BG (Background, for ISR or cache) service *********************/
/**
* Call by a device to request a BG operation.
*
* Depending on the bus lock state, the BG operations may be resumed by this
* call, or pending until BG operations allowed.
*
* Cleared by `spi_bus_lock_bg_clear_req` in the BG.
*
* @param dev_handle The device requesting BG operations.
* @return always ESP_OK
*/
esp_err_t spi_bus_lock_bg_request(spi_bus_lock_dev_handle_t dev_handle);
/**
* Wait until the ISR has finished all the BG operations for the acquiring device.
* If any `spi_bus_lock_bg_request` for this device has been called after
* `spi_bus_lock_acquire_start`, this function must be called before any operation
* in the task.
*
* @note Can only be called when bus acquired by this device.
*
* @param dev_handle Handle to the device acquiring the bus.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: The device is not the acquiring bus.
* - ESP_ERR_INVALID_ARG: Timeout is not portMAX_DELAY.
*/
esp_err_t spi_bus_lock_wait_bg_done(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Handle interrupt and closure of last operation. Should be called at the beginning of the ISR,
* when the ISR is acting as the acquiring processor.
*
* @param lock The SPI bus lock
*
* @return false if the ISR has already touched the HW, should run closure of the
* last operation first; otherwise true if the ISR just start operating
* on the HW, closure should be skipped.
*/
bool spi_bus_lock_bg_entry(spi_bus_lock_handle_t lock);
/**
* Handle the scheduling of other acquiring devices, and control of HW operation
* status.
*
* If no BG request is found, call with `wip=false`. This function will return false,
* indicating there is incoming BG requests for the current acquiring device (or
* for all devices if there is no acquiring device) and the ISR needs retry.
* Otherwise may schedule a new acquiring processor (unblock the task) if there
* is, and return true.
*
* Otherwise if a BG request is started in this ISR, call with `wip=true` and the
* function will enable the interrupt to make the ISR be called again when the
* request is done.
*
* This function is safe and should still be called when the ISR just lost its acquiring processor
* role, but hasn't quit.
*
* @note This function will not change acquiring device. The ISR call
* `spi_bus_lock_bg_update_acquiring` to check for new acquiring device,
* when acquiring devices need to be served before other devices.
*
* @param lock The SPI bus lock.
* @param wip Whether an operation is being executed when quitting the ISR.
* @param do_yield[out] Not touched when no yielding required, otherwise set
* to pdTRUE.
* @return false if retry is required, indicating that there is pending BG request.
* otherwise true and quit ISR is allowed.
*/
bool spi_bus_lock_bg_exit(spi_bus_lock_handle_t lock, bool wip, BaseType_t* do_yield);
/**
* Check whether there is device asking for the acquiring device, and the desired
* device for the next operation is also recommended.
*
* @note Must be called when the ISR is acting as the acquiring processor, and
* there is no acquiring device.
*
* @param lock The SPI bus lock.
* @param out_dev_lock The recommended device for hte next operation. It's the new
* acquiring device when found, otherwise a device that has active BG request.
*
* @return true if the ISR need to quit (new acquiring device has no active BG
* request, or no active BG requests for all devices when there is no
* acquiring device), otherwise false.
*/
bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_handle_t lock, spi_bus_lock_dev_handle_t *out_dev_lock);
/**
* Check if the device has BG requests. Must be called when the ISR is acting as
* the acquiring processor.
*
* @note This is not stable, may become true again when a task request for BG
* operation (by `spi_bus_lock_bg_request`).
*
* @param dev_lock The device to check.
* @return true if the device has BG requests, otherwise false.
*/
bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Clear the pending BG operation request of a device after served. Must be
* called when the ISR is acting as the acquiring processor.
*
* @note When the return value is true, the ISR will lost the acquiring processor role. Then
* `spi_bus_lock_bg_exit` must be called and checked before calling all other functions that
* require to be called when the ISR is the acquiring processor again.
*
* @param dev_handle The device whose request is served.
* @return True if no pending requests for the acquiring device, or for all devices
* if there is no acquiring device. Otherwise false. When the return value is
* true, the ISR is no longer the acquiring processor.
*/
bool spi_bus_lock_bg_clear_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Check if there is any active BG requests.
*
* @param lock The SPI bus lock.
* @return true if any device has active BG requst, otherwise false.
*/
bool spi_bus_lock_bg_req_exist(spi_bus_lock_handle_t lock);
/*******************************************************************************
* Variable and APIs for the OS to initialize the locks for the main chip
******************************************************************************/
/// The lock for the main bus
extern const spi_bus_lock_handle_t g_main_spi_bus_lock;
/// The lock for the main flash device
extern const spi_bus_lock_dev_handle_t g_spi_lock_main_flash_dev;
/**
* @brief Initialize the main flash device, called during chip startup.
*
* @return
* - ESP_OK: if success
* - ESP_ERR_NO_MEM: memory exhausted
*/
esp_err_t spi_bus_lock_init_main_dev(void);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -8,7 +8,7 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include <stdatomic.h> #include <stdatomic.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "stdatomic.h" #include "stdatomic.h"
@ -17,6 +17,18 @@
#include <strings.h> #include <strings.h>
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#ifdef CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
#define SPI_BUS_LOCK_ISR_ATTR IRAM_ATTR
#else
#define SPI_BUS_LOCK_ISR_ATTR
#endif
#ifdef CONFIG_ESP_SPI_BUS_LOCK_FUNCS_IN_IRAM
#define SPI_BUSLOCK_ATTR IRAM_ATTR
#else
#define SPI_BUSLOCK_ATTR
#endif
/* /*
* This lock is designed to solve the conflicts between SPI devices (used in tasks) and * This lock is designed to solve the conflicts between SPI devices (used in tasks) and
* the background operations (ISR or cache access). * the background operations (ISR or cache access).
@ -262,7 +274,7 @@ static inline int dev_lock_get_id(spi_bus_lock_dev_t *dev_lock);
/******************************************************************************* /*******************************************************************************
* atomic operations to the status * atomic operations to the status
******************************************************************************/ ******************************************************************************/
SPI_MASTER_ISR_ATTR static inline uint32_t lock_status_fetch_set(spi_bus_lock_t *lock, uint32_t set) SPI_BUS_LOCK_ISR_ATTR static inline uint32_t lock_status_fetch_set(spi_bus_lock_t *lock, uint32_t set)
{ {
return atomic_fetch_or(&lock->status, set); return atomic_fetch_or(&lock->status, set);
} }
@ -277,7 +289,7 @@ IRAM_ATTR static inline uint32_t lock_status_fetch(spi_bus_lock_t *lock)
return atomic_load(&lock->status); return atomic_load(&lock->status);
} }
SPI_MASTER_ISR_ATTR static inline void lock_status_init(spi_bus_lock_t *lock) SPI_BUS_LOCK_ISR_ATTR static inline void lock_status_init(spi_bus_lock_t *lock)
{ {
atomic_store(&lock->status, 0); atomic_store(&lock->status, 0);
} }
@ -300,7 +312,7 @@ IRAM_ATTR static inline uint32_t lock_status_clear(spi_bus_lock_t* lock, uint32_
* Most of them should be atomic, and special attention should be paid to the operation * Most of them should be atomic, and special attention should be paid to the operation
* sequence. * sequence.
******************************************************************************/ ******************************************************************************/
SPI_MASTER_ISR_ATTR static inline void resume_dev_in_isr(spi_bus_lock_dev_t *dev_lock, BaseType_t *do_yield) SPI_BUS_LOCK_ISR_ATTR static inline void resume_dev_in_isr(spi_bus_lock_dev_t *dev_lock, BaseType_t *do_yield)
{ {
xSemaphoreGiveFromISR(dev_lock->semphr, do_yield); xSemaphoreGiveFromISR(dev_lock->semphr, do_yield);
} }
@ -310,7 +322,7 @@ IRAM_ATTR static inline void resume_dev(const spi_bus_lock_dev_t *dev_lock)
xSemaphoreGive(dev_lock->semphr); xSemaphoreGive(dev_lock->semphr);
} }
SPI_MASTER_ISR_ATTR static inline void bg_disable(spi_bus_lock_t *lock) SPI_BUS_LOCK_ISR_ATTR static inline void bg_disable(spi_bus_lock_t *lock)
{ {
BUS_LOCK_DEBUG_EXECUTE_CHECK(lock->bg_disable); BUS_LOCK_DEBUG_EXECUTE_CHECK(lock->bg_disable);
lock->bg_disable(lock->bg_arg); lock->bg_disable(lock->bg_arg);
@ -324,7 +336,7 @@ IRAM_ATTR static inline void bg_enable(spi_bus_lock_t* lock)
// Set the REQ bit. If we become the acquiring processor, invoke the ISR and pass that to it. // Set the REQ bit. If we become the acquiring processor, invoke the ISR and pass that to it.
// The caller will never become the acquiring processor after this function returns. // The caller will never become the acquiring processor after this function returns.
SPI_MASTER_ATTR static inline void req_core(spi_bus_lock_dev_t *dev_handle) SPI_BUSLOCK_ATTR static inline void req_core(spi_bus_lock_dev_t *dev_handle)
{ {
spi_bus_lock_t *lock = dev_handle->parent; spi_bus_lock_t *lock = dev_handle->parent;
@ -351,7 +363,7 @@ SPI_MASTER_ATTR static inline void req_core(spi_bus_lock_dev_t *dev_handle)
} }
//Set the LOCK bit. Handle related stuff and return true if we become the acquiring processor. //Set the LOCK bit. Handle related stuff and return true if we become the acquiring processor.
SPI_MASTER_ISR_ATTR static inline bool acquire_core(spi_bus_lock_dev_t *dev_handle) SPI_BUS_LOCK_ISR_ATTR static inline bool acquire_core(spi_bus_lock_dev_t *dev_handle)
{ {
spi_bus_lock_t* lock = dev_handle->parent; spi_bus_lock_t* lock = dev_handle->parent;
@ -455,7 +467,7 @@ IRAM_ATTR static inline void acquire_end_core(spi_bus_lock_dev_t *dev_handle)
// Move the REQ bits to corresponding PEND bits. Must be called by acquiring processor. // Move the REQ bits to corresponding PEND bits. Must be called by acquiring processor.
// Have no side effects on the acquiring device/processor. // Have no side effects on the acquiring device/processor.
SPI_MASTER_ISR_ATTR static inline void update_pend_core(spi_bus_lock_t *lock, uint32_t status) SPI_BUS_LOCK_ISR_ATTR static inline void update_pend_core(spi_bus_lock_t *lock, uint32_t status)
{ {
uint32_t active_req_bits = status & REQ_MASK; uint32_t active_req_bits = status & REQ_MASK;
#if PENDING_SHIFT > REQ_SHIFT #if PENDING_SHIFT > REQ_SHIFT
@ -472,7 +484,7 @@ SPI_MASTER_ISR_ATTR static inline void update_pend_core(spi_bus_lock_t *lock, ui
// Clear the PEND bit (not REQ bit!) of a device, return the suggestion whether we can try to quit the ISR. // Clear the PEND bit (not REQ bit!) of a device, return the suggestion whether we can try to quit the ISR.
// Lost the acquiring processor immediately when the BG bits for active device are inactive, indiciating by the return value. // Lost the acquiring processor immediately when the BG bits for active device are inactive, indiciating by the return value.
// Can be called only when ISR is acting as the acquiring processor. // Can be called only when ISR is acting as the acquiring processor.
SPI_MASTER_ISR_ATTR static inline bool clear_pend_core(spi_bus_lock_dev_t *dev_handle) SPI_BUS_LOCK_ISR_ATTR static inline bool clear_pend_core(spi_bus_lock_dev_t *dev_handle)
{ {
bool finished; bool finished;
spi_bus_lock_t *lock = dev_handle->parent; spi_bus_lock_t *lock = dev_handle->parent;
@ -495,7 +507,7 @@ SPI_MASTER_ISR_ATTR static inline bool clear_pend_core(spi_bus_lock_dev_t *dev_h
// Return true if the ISR has already touched the HW, which means previous operations should // Return true if the ISR has already touched the HW, which means previous operations should
// be terminated first, before we use the HW again. Otherwise return false. // be terminated first, before we use the HW again. Otherwise return false.
// In either case `in_isr` will be marked as true, until call to `bg_exit_core` with `wip=false` successfully. // In either case `in_isr` will be marked as true, until call to `bg_exit_core` with `wip=false` successfully.
SPI_MASTER_ISR_ATTR static inline bool bg_entry_core(spi_bus_lock_t *lock) SPI_BUS_LOCK_ISR_ATTR static inline bool bg_entry_core(spi_bus_lock_t *lock)
{ {
BUS_LOCK_DEBUG_EXECUTE_CHECK(!lock->acquiring_dev || lock->acq_dev_bg_active); BUS_LOCK_DEBUG_EXECUTE_CHECK(!lock->acquiring_dev || lock->acq_dev_bg_active);
/* /*
@ -521,7 +533,7 @@ SPI_MASTER_ISR_ATTR static inline bool bg_entry_core(spi_bus_lock_t *lock)
// When called with `wip=true`, means the ISR is performing some operations. Will enable the interrupt again and exit unconditionally. // When called with `wip=true`, means the ISR is performing some operations. Will enable the interrupt again and exit unconditionally.
// When called with `wip=false`, will only return `true` when there is no coming BG request. If return value is `false`, the ISR should try again. // When called with `wip=false`, will only return `true` when there is no coming BG request. If return value is `false`, the ISR should try again.
// Will not change acquiring device. // Will not change acquiring device.
SPI_MASTER_ISR_ATTR static inline bool bg_exit_core(spi_bus_lock_t *lock, bool wip, BaseType_t *do_yield) SPI_BUS_LOCK_ISR_ATTR static inline bool bg_exit_core(spi_bus_lock_t *lock, bool wip, BaseType_t *do_yield)
{ {
//See comments in `bg_entry_core`, re-enable interrupt disabled in entry if we do need the interrupt //See comments in `bg_entry_core`, re-enable interrupt disabled in entry if we do need the interrupt
if (wip) { if (wip) {
@ -558,7 +570,7 @@ IRAM_ATTR static inline void dev_wait_prepare(spi_bus_lock_dev_t *dev_handle)
xSemaphoreTake(dev_handle->semphr, 0); xSemaphoreTake(dev_handle->semphr, 0);
} }
SPI_MASTER_ISR_ATTR static inline esp_err_t dev_wait(spi_bus_lock_dev_t *dev_handle, TickType_t wait) SPI_BUS_LOCK_ISR_ATTR static inline esp_err_t dev_wait(spi_bus_lock_dev_t *dev_handle, TickType_t wait)
{ {
BaseType_t ret = xSemaphoreTake(dev_handle->semphr, wait); BaseType_t ret = xSemaphoreTake(dev_handle->semphr, wait);
@ -748,7 +760,7 @@ IRAM_ATTR esp_err_t spi_bus_lock_acquire_end(spi_bus_lock_dev_t *dev_handle)
return ESP_OK; return ESP_OK;
} }
SPI_MASTER_ISR_ATTR spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi_bus_lock_t *lock) SPI_BUS_LOCK_ISR_ATTR spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi_bus_lock_t *lock)
{ {
return lock->acquiring_dev; return lock->acquiring_dev;
} }
@ -756,17 +768,17 @@ SPI_MASTER_ISR_ATTR spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi
/******************************************************************************* /*******************************************************************************
* BG (background operation) service * BG (background operation) service
******************************************************************************/ ******************************************************************************/
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_entry(spi_bus_lock_t* lock) SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_entry(spi_bus_lock_t* lock)
{ {
return bg_entry_core(lock); return bg_entry_core(lock);
} }
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_exit(spi_bus_lock_t* lock, bool wip, BaseType_t* do_yield) SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_exit(spi_bus_lock_t* lock, bool wip, BaseType_t* do_yield)
{ {
return bg_exit_core(lock, wip, do_yield); return bg_exit_core(lock, wip, do_yield);
} }
SPI_MASTER_ATTR esp_err_t spi_bus_lock_bg_request(spi_bus_lock_dev_t *dev_handle) SPI_BUSLOCK_ATTR esp_err_t spi_bus_lock_bg_request(spi_bus_lock_dev_t *dev_handle)
{ {
req_core(dev_handle); req_core(dev_handle);
return ESP_OK; return ESP_OK;
@ -799,14 +811,14 @@ IRAM_ATTR esp_err_t spi_bus_lock_wait_bg_done(spi_bus_lock_dev_handle_t dev_hand
return ESP_OK; return ESP_OK;
} }
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_clear_req(spi_bus_lock_dev_t *dev_handle) SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_clear_req(spi_bus_lock_dev_t *dev_handle)
{ {
bool finished = clear_pend_core(dev_handle); bool finished = clear_pend_core(dev_handle);
ESP_EARLY_LOGV(TAG, "dev %d served from bg.", dev_lock_get_id(dev_handle)); ESP_EARLY_LOGV(TAG, "dev %d served from bg.", dev_lock_get_id(dev_handle));
return finished; return finished;
} }
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_t *lock, SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_t *lock,
spi_bus_lock_dev_handle_t *out_dev_lock) spi_bus_lock_dev_handle_t *out_dev_lock)
{ {
BUS_LOCK_DEBUG_EXECUTE_CHECK(!lock->acquiring_dev); BUS_LOCK_DEBUG_EXECUTE_CHECK(!lock->acquiring_dev);
@ -814,7 +826,7 @@ SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_t *lock,
return schedule_core(lock, status, out_dev_lock); return schedule_core(lock, status, out_dev_lock);
} }
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_t *dev_lock) SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_t *dev_lock)
{ {
spi_bus_lock_t* lock = dev_lock->parent; spi_bus_lock_t* lock = dev_lock->parent;
uint32_t status = lock_status_fetch(lock); uint32_t status = lock_status_fetch(lock);
@ -830,7 +842,7 @@ SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_t *dev_l
} }
} }
SPI_MASTER_ISR_ATTR bool spi_bus_lock_bg_req_exist(spi_bus_lock_t *lock) SPI_BUS_LOCK_ISR_ATTR bool spi_bus_lock_bg_req_exist(spi_bus_lock_t *lock)
{ {
uint32_t status = lock_status_fetch(lock); uint32_t status = lock_status_fetch(lock);
return status & BG_MASK; return status & BG_MASK;
@ -855,12 +867,6 @@ static spi_bus_lock_t main_spi_bus_lock = {
}; };
const spi_bus_lock_handle_t g_main_spi_bus_lock = &main_spi_bus_lock; const spi_bus_lock_handle_t g_main_spi_bus_lock = &main_spi_bus_lock;
esp_err_t spi_bus_lock_init_main_bus(void)
{
spi_bus_main_set_lock(g_main_spi_bus_lock);
return ESP_OK;
}
static StaticSemaphore_t main_flash_semphr; static StaticSemaphore_t main_flash_semphr;
static spi_bus_lock_dev_t lock_main_flash_dev = { static spi_bus_lock_dev_t lock_main_flash_dev = {

Wyświetl plik

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_private/spi_share_hw_ctrl.h"
#include <stdatomic.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "hal/spi_ll.h"
#include "esp_log.h"
static const char* SPI_TAG = "spi_share_hw_ctrl";
//Periph 1 is 'claimed' by SPI flash code.
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
#if (SOC_SPI_PERIPH_NUM >= 3)
ATOMIC_VAR_INIT(false),
#endif
#if (SOC_SPI_PERIPH_NUM >= 4)
ATOMIC_VAR_INIT(false),
#endif
};
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
//----------------------------------------------------------alloc spi periph-------------------------------------------------------//
//Returns true if this peripheral is successfully claimed, false if otherwise.
bool spicommon_periph_claim(spi_host_device_t host, const char* source)
{
bool false_var = false;
bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
if (ret) {
spi_claiming_func[host] = source;
SPI_COMMON_RCC_CLOCK_ATOMIC() {
spi_ll_enable_bus_clock(host, true);
spi_ll_reset_register(host);
}
} else {
ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host + 1, spi_claiming_func[host]);
}
return ret;
}
bool spicommon_periph_in_use(spi_host_device_t host)
{
return atomic_load(&spi_periph_claimed[host]);
}
//Returns true if this peripheral is successfully freed, false if otherwise.
bool spicommon_periph_free(spi_host_device_t host)
{
bool true_var = true;
bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false);
if (ret) {
SPI_COMMON_RCC_CLOCK_ATOMIC() {
spi_ll_enable_bus_clock(host, false);
}
}
return ret;
}

Wyświetl plik

@ -63,11 +63,9 @@ else()
# [refactor-todo] requirements due to init code, # [refactor-todo] requirements due to init code,
# should be removable once using component init functions # should be removable once using component init functions
# link-time registration is used. # link-time registration is used.
# [refactor-todo] requires "esp_driver_spi" for headers:
# - spi_common_internal.h
# [refactor-todo] esp_partition required for virtual efuse # [refactor-todo] esp_partition required for virtual efuse
# init code. Move to esp_efuse component. # init code. Move to esp_efuse component.
pthread bootloader_support efuse esp_driver_spi esp_partition pthread bootloader_support efuse esp_partition esp_pm
LDFRAGMENTS "linker.lf" "app.lf") LDFRAGMENTS "linker.lf" "app.lf")
add_subdirectory(port) add_subdirectory(port)

Wyświetl plik

@ -12,7 +12,7 @@
#include "bootloader_clock.h" #include "bootloader_clock.h"
#include "hal/wdt_hal.h" #include "hal/wdt_hal.h"
#include "esp_private/spi_common_internal.h" // [refactor-todo]: for spicommon_periph_in_use #include "esp_private/spi_share_hw_ctrl.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_cpu.h" #include "esp_cpu.h"

Wyświetl plik

@ -49,7 +49,7 @@ else()
list(APPEND srcs ${cache_srcs}) list(APPEND srcs ${cache_srcs})
set(priv_requires bootloader_support app_update soc esp_mm set(priv_requires bootloader_support app_update soc esp_mm
esp_driver_gpio esp_driver_spi # TODO: IDF-8503 move spi_bus_lock to esp_hw_support component esp_driver_gpio
) )
endif() endif()

Wyświetl plik

@ -14,7 +14,7 @@
#include "esp_log.h" #include "esp_log.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "hal/spi_types.h" #include "hal/spi_types.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h"
#include "hal/spi_flash_hal.h" #include "hal/spi_flash_hal.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "esp_flash_internal.h" #include "esp_flash_internal.h"
@ -165,6 +165,17 @@ static bool use_bus_lock(int host_id)
#endif #endif
} }
static bool bus_using_iomux(spi_host_device_t host)
{
#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;
}
static esp_err_t acquire_spi_device(const esp_flash_spi_device_config_t *config, int* out_dev_id, spi_bus_lock_dev_handle_t* out_dev_handle) static esp_err_t acquire_spi_device(const esp_flash_spi_device_config_t *config, int* out_dev_id, spi_bus_lock_dev_handle_t* out_dev_handle)
{ {
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
@ -246,7 +257,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d
//avoid conflicts with main flash //avoid conflicts with main flash
assert(config->host_id != SPI1_HOST || dev_id != 0); assert(config->host_id != SPI1_HOST || dev_id != 0);
bool use_iomux = spicommon_bus_using_iomux(config->host_id); bool use_iomux = bus_using_iomux(config->host_id);
memspi_host_config_t host_cfg = { memspi_host_config_t host_cfg = {
.host_id = config->host_id, .host_id = config->host_id,
.cs_num = dev_id, .cs_num = dev_id,

Wyświetl plik

@ -8,7 +8,7 @@
#include "esp_err.h" #include "esp_err.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_flash.h" #include "esp_flash.h"

Wyświetl plik

@ -20,7 +20,7 @@
#include "esp_private/spi_flash_os.h" #include "esp_private/spi_flash_os.h"
#include "esp_private/cache_utils.h" #include "esp_private/cache_utils.h"
#include "esp_private/spi_common_internal.h" #include "esp_private/spi_share_hw_ctrl.h"
#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM) #define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM)
static const char TAG[] = "spi_flash"; static const char TAG[] = "spi_flash";
@ -326,7 +326,7 @@ esp_err_t esp_flash_init_main_bus_lock(void)
* is set. Thus, we must not call them if the macro is not defined, else the linker * is set. Thus, we must not call them if the macro is not defined, else the linker
* would trigger errors. */ * would trigger errors. */
#if CONFIG_SPI_FLASH_SHARE_SPI1_BUS #if CONFIG_SPI_FLASH_SHARE_SPI1_BUS
spi_bus_lock_init_main_bus(); /* bus_lock is registered by `spi_bus_lock_init_main_bus` constructor in spi_common.c */
spi_bus_lock_set_bg_control(g_main_spi_bus_lock, cache_enable, cache_disable, NULL); spi_bus_lock_set_bg_control(g_main_spi_bus_lock, cache_enable, cache_disable, NULL);
esp_err_t err = spi_bus_lock_init_main_dev(); esp_err_t err = spi_bus_lock_init_main_dev();

Wyświetl plik

@ -33,9 +33,9 @@ set(extra_components_which_shouldnt_be_included
bootloader_support bootloader_support
# [refactor-todo]: should cxx be in G1? Can it exist without FreeRTOS? # [refactor-todo]: should cxx be in G1? Can it exist without FreeRTOS?
cxx cxx
# [refactor-todo]: driver is a dependency of esp_pm, spi_flash, vfs, esp_wifi # [refactor-todo]: esp_driver_gpio is a dependency of esp_pm (should be removed from g1 builds),
# all of these should be removed from G1 except for spi_flash. # spi_flash, esp_hw_support
esp_driver_gpio esp_driver_spi esp_driver_gpio
# esp_app_format is dependency of bootloader_support, app_update # esp_app_format is dependency of bootloader_support, app_update
esp_app_format esp_app_format
# esp_bootloader_format is dependency of bootloader_support, app_update # esp_bootloader_format is dependency of bootloader_support, app_update
@ -48,8 +48,6 @@ set(extra_components_which_shouldnt_be_included
# conditional on related Kconfig option. It is also used by esp_wifi, driver, mbedtls, # conditional on related Kconfig option. It is also used by esp_wifi, driver, mbedtls,
# all of which should be removed from G1-only build. # all of which should be removed from G1-only build.
esp_pm esp_pm
# esp_ringbuf is a dependency of driver, which should be removed.
esp_ringbuf
# esp_timer is a dependency of freertos, esp_event, esp_wifi, driver. # esp_timer is a dependency of freertos, esp_event, esp_wifi, driver.
# For freertos, it can be made a weak dependency conditional on FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER # For freertos, it can be made a weak dependency conditional on FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
esp_timer esp_timer