mirror of
https://github.com/espressif/esp-idf.git
synced 2024-09-20 00:36:01 -04:00
Merge branch 'feature/support_spi_driver_esp32s2beta' into 'feature/esp32s2beta'
spi: support new chip esp32s2beta See merge request idf/esp-idf!5224
This commit is contained in:
commit
1c69db44c9
@ -19,8 +19,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp32/rom/lldesc.h"
|
#include "soc/lldesc.h"
|
||||||
#include "soc/spi_periph.h"
|
#include "soc/spi_periph.h"
|
||||||
|
#include "hal/spi_types.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -90,23 +91,6 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
|
#define SPI_SWAP_DATA_RX(data, len) (__builtin_bswap32(data)>>(32-len))
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enum with the three SPI peripherals that are software-accessible in it
|
|
||||||
*/
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
typedef enum {
|
|
||||||
SPI_HOST=0, ///< SPI1, SPI
|
|
||||||
HSPI_HOST=1, ///< SPI2, HSPI
|
|
||||||
VSPI_HOST=2 ///< SPI3, VSPI
|
|
||||||
} spi_host_device_t;
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
typedef enum {
|
|
||||||
SPI_HOST=0, ///< SPI1, SPI
|
|
||||||
FSPI_HOST=1, ///< SPI2, FSPI
|
|
||||||
HSPI_HOST=2, ///< SPI3, HSPI
|
|
||||||
VSPI_HOST=3 ///< SPI4, VSPI
|
|
||||||
} spi_host_device_t;
|
|
||||||
#endif
|
|
||||||
/**
|
/**
|
||||||
* @brief This is a configuration structure for a SPI bus.
|
* @brief This is a configuration structure for a SPI bus.
|
||||||
*
|
*
|
||||||
@ -122,9 +106,6 @@ typedef struct {
|
|||||||
int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
|
int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
|
||||||
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
|
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
|
||||||
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
int spicd_io_num; ///< CD GPIO pin for this device, or -1 if not used
|
|
||||||
#endif
|
|
||||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
|
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
|
||||||
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
|
||||||
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
|
||||||
@ -207,7 +188,7 @@ bool spicommon_dma_chan_free(int dma_chan);
|
|||||||
|
|
||||||
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
|
#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_MASTER (1<<0) ///< Initialize I/O in master mode
|
||||||
#define SPICOMMON_BUSFLAG_NATIVE_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
|
#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.
|
||||||
#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
|
#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
|
||||||
#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
|
#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
|
||||||
#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
|
#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
|
||||||
@ -215,6 +196,9 @@ bool spicommon_dma_chan_free(int dma_chan);
|
|||||||
#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
|
#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
|
||||||
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
|
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
|
||||||
|
|
||||||
|
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connect a SPI peripheral to GPIO pins
|
* @brief Connect a SPI peripheral to GPIO pins
|
||||||
*
|
*
|
||||||
@ -228,7 +212,7 @@ bool spicommon_dma_chan_free(int dma_chan);
|
|||||||
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
|
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
|
||||||
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
|
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
|
||||||
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
|
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
|
||||||
* - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: Pins set should match the iomux pins of the controller.
|
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: Pins set should match the iomux pins of the controller.
|
||||||
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``:
|
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``:
|
||||||
* Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode.
|
* Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode.
|
||||||
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
|
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
|
||||||
@ -236,7 +220,7 @@ bool spicommon_dma_chan_free(int dma_chan);
|
|||||||
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
||||||
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
|
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
|
||||||
* Leave to NULL if not needed.
|
* Leave to NULL if not needed.
|
||||||
* - ``SPICOMMON_BUSFLAG_NATIVE_PINS``: The bus is connected to iomux pins.
|
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
|
||||||
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has
|
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has
|
||||||
* CLK/MISO/MOSI connected.
|
* CLK/MISO/MOSI connected.
|
||||||
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
|
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
|
||||||
@ -334,6 +318,15 @@ spi_dev_t *spicommon_hw_for_host(spi_host_device_t host);
|
|||||||
*/
|
*/
|
||||||
int spicommon_irqsource_for_host(spi_host_device_t host);
|
int spicommon_irqsource_for_host(spi_host_device_t host);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the IRQ source for a specific SPI DMA
|
||||||
|
*
|
||||||
|
* @param host The SPI host
|
||||||
|
*
|
||||||
|
* @return The hosts IRQ source
|
||||||
|
*/
|
||||||
|
int spicommon_irqdma_source_for_host(spi_host_device_t host);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback, to be called when a DMA engine reset is completed
|
* Callback, to be called when a DMA engine reset is completed
|
||||||
*/
|
*/
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@ -15,10 +15,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
#include "driver/spi_master.h"
|
#include "driver/spi_master.h"
|
||||||
#include "soc/spi_periph.h"
|
#include "soc/spi_periph.h"
|
||||||
#include "esp32/rom/ets_sys.h"
|
|
||||||
#include "esp_types.h"
|
#include "esp_types.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@ -32,9 +30,6 @@
|
|||||||
#include "driver/spi_common.h"
|
#include "driver/spi_common.h"
|
||||||
#include "stdatomic.h"
|
#include "stdatomic.h"
|
||||||
#include "hal/spi_hal.h"
|
#include "hal/spi_hal.h"
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
#include "cas.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char *SPI_TAG = "spi";
|
static const char *SPI_TAG = "spi";
|
||||||
|
|
||||||
@ -54,14 +49,16 @@ static const char *SPI_TAG = "spi";
|
|||||||
|
|
||||||
typedef struct spi_device_t spi_device_t;
|
typedef struct spi_device_t spi_device_t;
|
||||||
|
|
||||||
#define FUNC_SPI 1 //all pins of HSPI and VSPI shares this function number
|
|
||||||
#define FUNC_GPIO PIN_FUNC_GPIO
|
#define FUNC_GPIO PIN_FUNC_GPIO
|
||||||
|
|
||||||
|
|
||||||
#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1))
|
#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1))
|
||||||
|
|
||||||
//Periph 1 is 'claimed' by SPI flash code.
|
//Periph 1 is 'claimed' by SPI flash code.
|
||||||
static atomic_bool spi_periph_claimed[3] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false)};
|
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false),
|
||||||
|
#if SOC_SPI_PERIPH_NUM >= 4
|
||||||
|
ATOMIC_VAR_INIT(false),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
|
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
|
||||||
static uint8_t spi_dma_chan_enabled = 0;
|
static uint8_t spi_dma_chan_enabled = 0;
|
||||||
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
@ -101,15 +98,38 @@ int spicommon_irqsource_for_host(spi_host_device_t host)
|
|||||||
return spi_periph_signal[host].irq;
|
return spi_periph_signal[host].irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
spi_dev_t *spicommon_hw_for_host(spi_host_device_t host)
|
||||||
{
|
{
|
||||||
return spi_periph_signal[host].hw;
|
return spi_periph_signal[host].hw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t get_dma_periph(int dma_chan)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
if (dma_chan==1) {
|
||||||
|
return PERIPH_SPI2_DMA_MODULE;
|
||||||
|
} else if (dma_chan==2) {
|
||||||
|
return PERIPH_SPI3_DMA_MODULE;
|
||||||
|
} else if (dma_chan==3) {
|
||||||
|
return PERIPH_SPI_SHARED_DMA_MODULE;
|
||||||
|
} else {
|
||||||
|
abort();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32)
|
||||||
|
return PERIPH_SPI_DMA_MODULE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool spicommon_dma_chan_claim (int dma_chan)
|
bool spicommon_dma_chan_claim (int dma_chan)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
assert( dma_chan == 1 || dma_chan == 2 );
|
assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
|
||||||
|
|
||||||
portENTER_CRITICAL(&spi_dma_spinlock);
|
portENTER_CRITICAL(&spi_dma_spinlock);
|
||||||
if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {
|
if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {
|
||||||
@ -118,7 +138,7 @@ bool spicommon_dma_chan_claim (int dma_chan)
|
|||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
periph_module_enable( PERIPH_SPI_DMA_MODULE );
|
periph_module_enable(get_dma_periph(dma_chan));
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
if (dma_chan==1) {
|
if (dma_chan==1) {
|
||||||
periph_module_enable(PERIPH_SPI2_DMA_MODULE);
|
periph_module_enable(PERIPH_SPI2_DMA_MODULE);
|
||||||
@ -149,7 +169,7 @@ bool spicommon_dma_chan_free(int dma_chan)
|
|||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
if ( spi_dma_chan_enabled == 0 ) {
|
if ( spi_dma_chan_enabled == 0 ) {
|
||||||
//disable the DMA only when all the channels are freed.
|
//disable the DMA only when all the channels are freed.
|
||||||
periph_module_disable( PERIPH_SPI_DMA_MODULE );
|
periph_module_disable(get_dma_periph(dma_chan));
|
||||||
}
|
}
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
if (dma_chan==1) {
|
if (dma_chan==1) {
|
||||||
@ -237,7 +257,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
|
|
||||||
//check if the selected pins correspond to the iomux pins of the peripheral
|
//check if the selected pins correspond to the iomux pins of the peripheral
|
||||||
bool use_iomux = bus_uses_iomux_pins(host, bus_config);
|
bool use_iomux = bus_uses_iomux_pins(host, bus_config);
|
||||||
if (use_iomux) temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS;
|
if (use_iomux) temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||||
|
|
||||||
uint32_t missing_flag = flags & ~temp_flag;
|
uint32_t missing_flag = flags & ~temp_flag;
|
||||||
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
|
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
|
||||||
@ -249,7 +269,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required.");
|
if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required.");
|
||||||
if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
|
if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
|
||||||
if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
||||||
if (missing_flag & SPICOMMON_BUSFLAG_NATIVE_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
|
if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
|
||||||
SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +280,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (bus_config->mosi_io_num >= 0) {
|
if (bus_config->mosi_io_num >= 0) {
|
||||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(bus_config->mosi_io_num, FUNC_SPI, false);
|
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
@ -268,7 +288,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (bus_config->miso_io_num >= 0) {
|
if (bus_config->miso_io_num >= 0) {
|
||||||
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(bus_config->miso_io_num, FUNC_SPI, false);
|
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
@ -276,7 +296,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (bus_config->quadwp_io_num >= 0) {
|
if (bus_config->quadwp_io_num >= 0) {
|
||||||
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(bus_config->quadwp_io_num, FUNC_SPI, false);
|
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
@ -284,7 +304,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (bus_config->quadhd_io_num >= 0) {
|
if (bus_config->quadhd_io_num >= 0) {
|
||||||
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(bus_config->quadhd_io_num, FUNC_SPI, false);
|
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
@ -292,12 +312,12 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
if (bus_config->sclk_io_num >= 0) {
|
if (bus_config->sclk_io_num >= 0) {
|
||||||
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(bus_config->sclk_io_num, FUNC_SPI, false);
|
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
temp_flag |= SPICOMMON_BUSFLAG_NATIVE_PINS;
|
temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||||
} else {
|
} else {
|
||||||
//Use GPIO matrix
|
//Use GPIO matrix
|
||||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
|
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
|
||||||
@ -358,21 +378,12 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
|||||||
#endif
|
#endif
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
||||||
}
|
}
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
if (bus_config->spicd_io_num >= 0) {
|
|
||||||
gpio_set_direction(bus_config->spicd_io_num, GPIO_MODE_INPUT_OUTPUT);
|
|
||||||
gpio_matrix_out(bus_config->spicd_io_num, spi_periph_signal[host].spicd_out, false, false);
|
|
||||||
gpio_matrix_in(bus_config->spicd_io_num, spi_periph_signal[host].spicd_in, false);
|
|
||||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->spicd_io_num]);
|
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->spicd_io_num], FUNC_GPIO);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Select DMA channel.
|
//Select DMA channel.
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
|
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif defined(CONFIG_IDF_TARGET_ESP32S2BETA)
|
||||||
if (dma_chan==VSPI_HOST) {
|
if (dma_chan==VSPI_HOST) {
|
||||||
DPORT_SET_PERI_REG_MASK(DPORT_SPI_DMA_CHAN_SEL_REG, DPORT_SPI_SHARED_DMA_SEL_M);
|
DPORT_SET_PERI_REG_MASK(DPORT_SPI_DMA_CHAN_SEL_REG, DPORT_SPI_SHARED_DMA_SEL_M);
|
||||||
}
|
}
|
||||||
@ -430,7 +441,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
|
|||||||
//The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
|
//The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
|
||||||
gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in);
|
gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in);
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
gpio_iomux_out(cs_io_num, FUNC_SPI, false);
|
gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
|
gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
|
||||||
#endif
|
#endif
|
||||||
@ -443,9 +454,7 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
|
|||||||
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
|
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
|
||||||
}
|
}
|
||||||
if (cs_num == 0) gpio_matrix_in(cs_io_num, spi_periph_signal[host].spics_in, false);
|
if (cs_num == 0) gpio_matrix_in(cs_io_num, spi_periph_signal[host].spics_in, false);
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
|
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
|
||||||
#endif
|
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
|
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,13 +483,13 @@ void IRAM_ATTR spicommon_setup_dma_desc_links(lldesc_t *dmadesc, int len, const
|
|||||||
/*
|
/*
|
||||||
Code for workaround for DMA issue in ESP32 v0/v1 silicon
|
Code for workaround for DMA issue in ESP32 v0/v1 silicon
|
||||||
*/
|
*/
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
|
|
||||||
static volatile int dmaworkaround_channels_busy[2] = {0, 0};
|
static volatile int dmaworkaround_channels_busy[2] = {0, 0};
|
||||||
static dmaworkaround_cb_t dmaworkaround_cb;
|
static dmaworkaround_cb_t dmaworkaround_cb;
|
||||||
static void *dmaworkaround_cb_arg;
|
static void *dmaworkaround_cb_arg;
|
||||||
static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||||
static int dmaworkaround_waiting_for_chan = 0;
|
static int dmaworkaround_waiting_for_chan = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
|
bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
|
||||||
{
|
{
|
||||||
@ -501,14 +510,19 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t
|
|||||||
}
|
}
|
||||||
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
return ret;
|
return ret;
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
#else
|
||||||
|
//no need to reset
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress()
|
bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress()
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
return (dmaworkaround_waiting_for_chan != 0);
|
return (dmaworkaround_waiting_for_chan != 0);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
||||||
@ -530,9 +544,9 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
|
|||||||
|
|
||||||
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
|
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
|
||||||
{
|
{
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
dmaworkaround_channels_busy[dmachan-1] = 1;
|
dmaworkaround_channels_busy[dmachan-1] = 1;
|
||||||
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
@ -133,19 +133,11 @@ We have two bits to control the interrupt:
|
|||||||
#include "freertos/xtensa_api.h"
|
#include "freertos/xtensa_api.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "soc/soc_memory_layout.h"
|
#include "soc/soc_memory_layout.h"
|
||||||
#include "soc/dport_access.h"
|
|
||||||
#include "esp32/rom/lldesc.h"
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "stdatomic.h"
|
#include "stdatomic.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
#include "soc/dport_reg.h"
|
|
||||||
#include "esp32/rom/ets_sys.h"
|
|
||||||
#include "hal/spi_hal.h"
|
#include "hal/spi_hal.h"
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
#include "cas.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct spi_device_t spi_device_t;
|
typedef struct spi_device_t spi_device_t;
|
||||||
|
|
||||||
@ -188,9 +180,6 @@ typedef struct {
|
|||||||
int dma_chan;
|
int dma_chan;
|
||||||
int max_transfer_sz;
|
int max_transfer_sz;
|
||||||
spi_bus_config_t bus_cfg;
|
spi_bus_config_t bus_cfg;
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
int id;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
esp_pm_lock_handle_t pm_lock;
|
esp_pm_lock_handle_t pm_lock;
|
||||||
#endif
|
#endif
|
||||||
@ -207,7 +196,7 @@ struct spi_device_t {
|
|||||||
bool waiting; //the device is waiting for the exclusive control of the bus
|
bool waiting; //the device is waiting for the exclusive control of the bus
|
||||||
};
|
};
|
||||||
|
|
||||||
static spi_host_t *spihost[SPI_PERIPH_NUM];
|
static spi_host_t *spihost[SOC_SPI_PERIPH_NUM];
|
||||||
|
|
||||||
|
|
||||||
static const char *SPI_TAG = "spi_master";
|
static const char *SPI_TAG = "spi_master";
|
||||||
@ -229,7 +218,11 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
|||||||
SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED);
|
SPI_CHECK(host!=SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED);
|
||||||
|
|
||||||
SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG);
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
SPI_CHECK( dma_chan == 0 || dma_chan == host, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||||
|
#endif
|
||||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||||
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
|
||||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||||
@ -254,9 +247,6 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
|||||||
memset(spihost[host], 0, sizeof(spi_host_t));
|
memset(spihost[host], 0, sizeof(spi_host_t));
|
||||||
memcpy( &spihost[host]->bus_cfg, bus_config, sizeof(spi_bus_config_t));
|
memcpy( &spihost[host]->bus_cfg, bus_config, sizeof(spi_bus_config_t));
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
spihost[host]->id = host;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
|
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
|
||||||
&spihost[host]->pm_lock);
|
&spihost[host]->pm_lock);
|
||||||
@ -271,17 +261,10 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, const spi_bus_config_t *bus
|
|||||||
ret = err;
|
ret = err;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
|
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
|
||||||
if (host==VSPI_HOST) {
|
|
||||||
DPORT_SET_PERI_REG_BITS(DPORT_SPI_SHARED_DMA_SEL_REG, DPORT_SPI_SHARED_DMA_SEL_M, 1, DPORT_SPI_SHARED_DMA_SEL_S);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
int dma_desc_ct=0;
|
int dma_desc_ct=0;
|
||||||
spihost[host]->dma_chan=dma_chan;
|
spihost[host]->dma_chan=dma_chan;
|
||||||
if (dma_chan == 0) {
|
if (dma_chan == 0) {
|
||||||
spihost[host]->max_transfer_sz = 64;
|
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||||
} else {
|
} else {
|
||||||
//See how many dma descriptors we need and allocate them
|
//See how many dma descriptors we need and allocate them
|
||||||
dma_desc_ct=lldesc_get_required_num(bus_config->max_transfer_sz);
|
dma_desc_ct=lldesc_get_required_num(bus_config->max_transfer_sz);
|
||||||
@ -397,23 +380,27 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_
|
|||||||
if (atomic_compare_exchange_strong(&spihost[host]->device[freecs], &null, (spi_device_t *)1)) break;
|
if (atomic_compare_exchange_strong(&spihost[host]->device[freecs], &null, (spi_device_t *)1)) break;
|
||||||
}
|
}
|
||||||
SPI_CHECK(freecs!=NO_CS, "no free cs pins for host", ESP_ERR_NOT_FOUND);
|
SPI_CHECK(freecs!=NO_CS, "no free cs pins for host", ESP_ERR_NOT_FOUND);
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
//The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
|
//The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
|
||||||
//duplex mode does absolutely nothing on the ESP32.
|
//duplex mode does absolutely nothing on the ESP32.
|
||||||
SPI_CHECK( dev_config->cs_ena_pretrans <= 1 || (dev_config->address_bits == 0 && dev_config->command_bits == 0) ||
|
SPI_CHECK( dev_config->cs_ena_pretrans <= 1 || (dev_config->address_bits == 0 && dev_config->command_bits == 0) ||
|
||||||
(dev_config->flags & SPI_DEVICE_HALFDUPLEX), "In full-duplex mode, only support cs pretrans delay = 1 and without address_bits and command_bits", ESP_ERR_INVALID_ARG);
|
(dev_config->flags & SPI_DEVICE_HALFDUPLEX), "In full-duplex mode, only support cs pretrans delay = 1 and without address_bits and command_bits", ESP_ERR_INVALID_ARG);
|
||||||
|
#endif
|
||||||
|
|
||||||
duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos;
|
duty_cycle = (dev_config->duty_cycle_pos==0) ? 128 : dev_config->duty_cycle_pos;
|
||||||
|
|
||||||
int freq;
|
int freq;
|
||||||
spi_hal_context_t *hal = &spihost[host]->hal;
|
spi_hal_context_t *hal = &spihost[host]->hal;
|
||||||
hal->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
hal->half_duplex = dev_config->flags & SPI_DEVICE_HALFDUPLEX ? 1 : 0;
|
||||||
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
hal->as_cs = dev_config->flags & SPI_DEVICE_CLK_AS_CS ? 1 : 0;
|
hal->as_cs = dev_config->flags & SPI_DEVICE_CLK_AS_CS ? 1 : 0;
|
||||||
|
#endif
|
||||||
hal->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
|
hal->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
|
||||||
hal->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
hal->no_compensate = dev_config->flags & SPI_DEVICE_NO_DUMMY ? 1 : 0;
|
||||||
|
|
||||||
spi_hal_timing_conf_t temp_timing_conf;
|
spi_hal_timing_conf_t temp_timing_conf;
|
||||||
esp_err_t ret = spi_hal_get_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle,
|
esp_err_t ret = spi_hal_get_clock_conf(hal, dev_config->clock_speed_hz, duty_cycle,
|
||||||
!(spihost[host]->flags & SPICOMMON_BUSFLAG_NATIVE_PINS),
|
!(spihost[host]->flags & SPICOMMON_BUSFLAG_IOMUX_PINS),
|
||||||
dev_config->input_delay_ns, &freq,
|
dev_config->input_delay_ns, &freq,
|
||||||
&temp_timing_conf);
|
&temp_timing_conf);
|
||||||
|
|
||||||
@ -445,7 +432,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, const spi_device_interface_
|
|||||||
|
|
||||||
//Set CS pin, CS options
|
//Set CS pin, CS options
|
||||||
if (dev_config->spics_io_num >= 0) {
|
if (dev_config->spics_io_num >= 0) {
|
||||||
spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_NATIVE_PINS));
|
spicommon_cs_initialize(host, dev_config->spics_io_num, freecs, !(spihost[host]->flags&SPICOMMON_BUSFLAG_IOMUX_PINS));
|
||||||
}
|
}
|
||||||
|
|
||||||
*handle=dev;
|
*handle=dev;
|
||||||
@ -820,8 +807,12 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
|||||||
//check working mode
|
//check working mode
|
||||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (!(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX))), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
|
SPI_CHECK( !(handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) || host->dma_chan == 0 || !(trans_desc->flags & SPI_TRANS_USE_RXDATA || trans_desc->rx_buffer != NULL)
|
||||||
|| !(trans_desc->flags & SPI_TRANS_USE_TXDATA || trans_desc->tx_buffer!=NULL), "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
|| !(trans_desc->flags & SPI_TRANS_USE_TXDATA || trans_desc->tx_buffer!=NULL), "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
||||||
|
#else
|
||||||
|
(void)host;
|
||||||
|
#endif
|
||||||
//MOSI phase is skipped only when both tx_buffer and SPI_TRANS_USE_TXDATA are not set.
|
//MOSI phase is skipped only when both tx_buffer and SPI_TRANS_USE_TXDATA are not set.
|
||||||
SPI_CHECK(trans_desc->length != 0 || (trans_desc->tx_buffer == NULL && !(trans_desc->flags & SPI_TRANS_USE_TXDATA)),
|
SPI_CHECK(trans_desc->length != 0 || (trans_desc->tx_buffer == NULL && !(trans_desc->flags & SPI_TRANS_USE_TXDATA)),
|
||||||
"trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG);
|
"trans tx_buffer should be NULL and SPI_TRANS_USE_TXDATA should be cleared to skip MOSI phase.", ESP_ERR_INVALID_ARG);
|
||||||
@ -1102,4 +1093,3 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t ha
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#if CONFIG_IDF_TARGET_ESP32
|
|
||||||
#include <hal/spi_ll.h>
|
#include <hal/spi_ll.h>
|
||||||
#include <hal/spi_slave_hal.h>
|
#include <hal/spi_slave_hal.h>
|
||||||
#include <soc/lldesc.h>
|
#include <soc/lldesc.h>
|
||||||
@ -32,10 +31,9 @@
|
|||||||
#include "freertos/xtensa_api.h"
|
#include "freertos/xtensa_api.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "soc/soc_memory_layout.h"
|
#include "soc/soc_memory_layout.h"
|
||||||
#include "esp32/rom/lldesc.h"
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "esp32/rom/ets_sys.h"
|
|
||||||
static const char *SPI_TAG = "spi_slave";
|
static const char *SPI_TAG = "spi_slave";
|
||||||
#define SPI_CHECK(a, str, ret_val) \
|
#define SPI_CHECK(a, str, ret_val) \
|
||||||
if (!(a)) { \
|
if (!(a)) { \
|
||||||
@ -73,13 +71,13 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} spi_slave_t;
|
} spi_slave_t;
|
||||||
|
|
||||||
static spi_slave_t *spihost[3];
|
static spi_slave_t *spihost[SOC_SPI_PERIPH_NUM];
|
||||||
|
|
||||||
static void IRAM_ATTR spi_intr(void *arg);
|
static void IRAM_ATTR spi_intr(void *arg);
|
||||||
|
|
||||||
static inline bool bus_is_iomux(spi_slave_t *host)
|
static inline bool bus_is_iomux(spi_slave_t *host)
|
||||||
{
|
{
|
||||||
return host->flags&SPICOMMON_BUSFLAG_NATIVE_PINS;
|
return host->flags&SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeze_cs(spi_slave_t *host)
|
static void freeze_cs(spi_slave_t *host)
|
||||||
@ -105,7 +103,11 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
//We only support HSPI/VSPI, period.
|
//We only support HSPI/VSPI, period.
|
||||||
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
|
SPI_CHECK(VALID_HOST(host), "invalid host", ESP_ERR_INVALID_ARG);
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||||
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32S2BETA)
|
||||||
|
SPI_CHECK( dma_chan == 0 || dma_chan == host, "invalid dma channel", ESP_ERR_INVALID_ARG );
|
||||||
|
#endif
|
||||||
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
|
||||||
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
|
||||||
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
|
||||||
@ -150,7 +152,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
|
|||||||
spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
|
spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
|
||||||
} else {
|
} else {
|
||||||
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
|
//We're limited to non-DMA transfers: the SPI work registers can hold 64 bytes at most.
|
||||||
spihost[host]->max_transfer_sz = 16 * 4;
|
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_PM_ENABLE
|
#ifdef CONFIG_PM_ENABLE
|
||||||
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
|
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
|
||||||
@ -393,4 +395,3 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
|
|||||||
if (do_yield) portYIELD_FROM_ISR();
|
if (do_yield) portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -329,7 +329,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
|||||||
uint32_t flags_expected;
|
uint32_t flags_expected;
|
||||||
|
|
||||||
ESP_LOGI(TAG, "test 6 iomux output pins...");
|
ESP_LOGI(TAG, "test 6 iomux output pins...");
|
||||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_QUAD;
|
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_QUAD;
|
||||||
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP,
|
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP,
|
||||||
.max_transfer_sz = 8, .flags = flags_expected};
|
.max_transfer_sz = 8, .flags = flags_expected};
|
||||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||||
@ -338,7 +338,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
|||||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||||
|
|
||||||
ESP_LOGI(TAG, "test 4 iomux output pins...");
|
ESP_LOGI(TAG, "test 4 iomux output pins...");
|
||||||
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_NATIVE_PINS | SPICOMMON_BUSFLAG_DUAL;
|
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_DUAL;
|
||||||
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .miso_io_num = HSPI_IOMUX_PIN_NUM_MISO, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||||
.max_transfer_sz = 8, .flags = flags_expected};
|
.max_transfer_sz = 8, .flags = flags_expected};
|
||||||
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_MASTER, &flags_o));
|
||||||
@ -396,7 +396,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
|||||||
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
|
||||||
|
|
||||||
ESP_LOGI(TAG, "check native flag for 6 output pins...");
|
ESP_LOGI(TAG, "check native flag for 6 output pins...");
|
||||||
flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS;
|
flags_expected = SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||||
//swap MOSI and MISO
|
//swap MOSI and MISO
|
||||||
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP,
|
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = HSPI_IOMUX_PIN_NUM_HD, .quadwp_io_num = HSPI_IOMUX_PIN_NUM_WP,
|
||||||
.max_transfer_sz = 8, .flags = flags_expected};
|
.max_transfer_sz = 8, .flags = flags_expected};
|
||||||
@ -404,7 +404,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
|
|||||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, 0, flags_expected|SPICOMMON_BUSFLAG_SLAVE, &flags_o));
|
||||||
|
|
||||||
ESP_LOGI(TAG, "check native flag for 4 output pins...");
|
ESP_LOGI(TAG, "check native flag for 4 output pins...");
|
||||||
flags_expected = SPICOMMON_BUSFLAG_NATIVE_PINS;
|
flags_expected = SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||||
//swap MOSI and MISO
|
//swap MOSI and MISO
|
||||||
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
cfg = (spi_bus_config_t){.mosi_io_num = HSPI_IOMUX_PIN_NUM_MISO, .miso_io_num = HSPI_IOMUX_PIN_NUM_MOSI, .sclk_io_num = HSPI_IOMUX_PIN_NUM_CLK, .quadhd_io_num = -1, .quadwp_io_num = -1,
|
||||||
.max_transfer_sz = 8, .flags = flags_expected};
|
.max_transfer_sz = 8, .flags = flags_expected};
|
||||||
|
@ -14,10 +14,10 @@ if(NOT BOOTLOADER_BUILD)
|
|||||||
"src/lldesc.c"
|
"src/lldesc.c"
|
||||||
"src/soc_include_legacy_warn.c")
|
"src/soc_include_legacy_warn.c")
|
||||||
|
|
||||||
if(soc_name STREQUAL "esp32")
|
list(APPEND COMPONENT_SRCS "src/hal/spi_hal.c"
|
||||||
list(APPEND COMPONENT_SRCS "src/hal/spi_hal.c" "src/hal/spi_hal_iram.c"
|
"src/hal/spi_hal_iram.c"
|
||||||
"src/hal/spi_slave_hal.c" "src/hal/spi_slave_hal_iram.c")
|
"src/hal/spi_slave_hal.c"
|
||||||
endif()
|
"src/hal/spi_slave_hal_iram.c")
|
||||||
|
|
||||||
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
||||||
endif()
|
endif()
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
* See readme.md in soc/include/hal/readme.md
|
* See readme.md in soc/include/hal/readme.md
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
// The LL layer for SPI register operations
|
// The LL layer for ESP32 SPI register operations
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hal_defs.h"
|
#include "hal/hal_defs.h"
|
||||||
#include "soc/spi_periph.h"
|
#include "soc/spi_periph.h"
|
||||||
#include "esp32/rom/lldesc.h"
|
#include "esp32/rom/lldesc.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -52,6 +52,12 @@ typedef enum {
|
|||||||
SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
||||||
} spi_ll_io_mode_t;
|
} spi_ll_io_mode_t;
|
||||||
|
|
||||||
|
/// Interrupt type for different working pattern
|
||||||
|
typedef enum {
|
||||||
|
SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done
|
||||||
|
} spi_ll_slave_intr_type;
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Control
|
* Control
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
@ -259,6 +265,10 @@ static inline void spi_ll_enable_int(spi_dev_t *hw)
|
|||||||
hw->slave.trans_inten = 1;
|
hw->slave.trans_inten = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type)
|
||||||
|
{
|
||||||
|
hw->slave.trans_inten = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
* Configs: mode
|
* Configs: mode
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@ -12,8 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef _SOC_SPI_PINS_H_
|
#pragma once
|
||||||
#define _SOC_SPI_PINS_H_
|
|
||||||
|
#define SOC_SPI_PERIPH_NUM 3
|
||||||
|
#define SOC_SPI_DMA_CHAN_NUM 2
|
||||||
|
|
||||||
#define SPI_PERIPH_NUM 3
|
#define SPI_PERIPH_NUM 3
|
||||||
|
|
||||||
@ -41,4 +43,9 @@
|
|||||||
#define VSPI_IOMUX_PIN_NUM_WP 22
|
#define VSPI_IOMUX_PIN_NUM_WP 22
|
||||||
#define VSPI_IOMUX_PIN_NUM_HD 21
|
#define VSPI_IOMUX_PIN_NUM_HD 21
|
||||||
|
|
||||||
#endif /* _SOC_SPI_PINS_H_ */
|
#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64
|
||||||
|
|
||||||
|
#define SOC_SPI_SUPPORT_AS_CS 1 //Support to toggle the CS while the clock toggles
|
||||||
|
//#define SOC_SPI_SUPPORT_DDRCLK
|
||||||
|
//#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS
|
||||||
|
//#define SOC_SPI_SUPPORT_CD_SIG
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "soc/spi_periph.h"
|
#include "soc/spi_periph.h"
|
||||||
|
|
||||||
|
#define FUNC_SPI 1 //all pins of SPI1, HSPI and VSPI shares this function number
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc
|
Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc
|
||||||
*/
|
*/
|
||||||
@ -40,8 +42,8 @@ const spi_signal_conn_t spi_periph_signal[3] = {
|
|||||||
.irq = ETS_SPI1_INTR_SOURCE,
|
.irq = ETS_SPI1_INTR_SOURCE,
|
||||||
.irq_dma = ETS_SPI1_DMA_INTR_SOURCE,
|
.irq_dma = ETS_SPI1_DMA_INTR_SOURCE,
|
||||||
.module = PERIPH_SPI_MODULE,
|
.module = PERIPH_SPI_MODULE,
|
||||||
.hw = &SPI1,
|
.func = FUNC_SPI,
|
||||||
.func = SPI_FUNC_NUM
|
.hw = &SPI1
|
||||||
}, {
|
}, {
|
||||||
.spiclk_out = HSPICLK_OUT_IDX,
|
.spiclk_out = HSPICLK_OUT_IDX,
|
||||||
.spiclk_in = HSPICLK_IN_IDX,
|
.spiclk_in = HSPICLK_IN_IDX,
|
||||||
@ -64,8 +66,8 @@ const spi_signal_conn_t spi_periph_signal[3] = {
|
|||||||
.irq = ETS_SPI2_INTR_SOURCE,
|
.irq = ETS_SPI2_INTR_SOURCE,
|
||||||
.irq_dma = ETS_SPI2_DMA_INTR_SOURCE,
|
.irq_dma = ETS_SPI2_DMA_INTR_SOURCE,
|
||||||
.module = PERIPH_HSPI_MODULE,
|
.module = PERIPH_HSPI_MODULE,
|
||||||
.hw = &SPI2,
|
.func = FUNC_SPI,
|
||||||
.func = HSPI_FUNC_NUM
|
.hw = &SPI2
|
||||||
}, {
|
}, {
|
||||||
.spiclk_out = VSPICLK_OUT_IDX,
|
.spiclk_out = VSPICLK_OUT_IDX,
|
||||||
.spiclk_in = VSPICLK_IN_IDX,
|
.spiclk_in = VSPICLK_IN_IDX,
|
||||||
@ -88,7 +90,7 @@ const spi_signal_conn_t spi_periph_signal[3] = {
|
|||||||
.irq = ETS_SPI3_INTR_SOURCE,
|
.irq = ETS_SPI3_INTR_SOURCE,
|
||||||
.irq_dma = ETS_SPI3_DMA_INTR_SOURCE,
|
.irq_dma = ETS_SPI3_DMA_INTR_SOURCE,
|
||||||
.module = PERIPH_VSPI_MODULE,
|
.module = PERIPH_VSPI_MODULE,
|
||||||
.hw = &SPI3,
|
.func = FUNC_SPI,
|
||||||
.func = VSPI_FUNC_NUM
|
.hw = &SPI3
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
874
components/soc/esp32s2beta/include/hal/spi_ll.h
Normal file
874
components/soc/esp32s2beta/include/hal/spi_ll.h
Normal file
@ -0,0 +1,874 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* NOTICE
|
||||||
|
* The hal is not public api, don't use in application code.
|
||||||
|
* See readme.md in soc/include/hal/readme.md
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
// The LL layer for ESP32s2beta SPI register operations
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal/hal_defs.h"
|
||||||
|
#include "soc/spi_periph.h"
|
||||||
|
#include "esp32/rom/lldesc.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <esp_types.h>
|
||||||
|
#include <stdlib.h> //for abs()
|
||||||
|
|
||||||
|
/// Registers to reset during initialization. Don't use in app.
|
||||||
|
#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
||||||
|
/// Interrupt not used. Don't use in app.
|
||||||
|
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_TRANS_DONE_EN | SPI_INT_WR_DMA_DONE_EN | SPI_INT_RD_DMA_DONE_EN | SPI_INT_WR_BUF_DONE_EN | SPI_INT_RD_BUF_DONE_EN)
|
||||||
|
/// Swap the bit order to its correct place to send
|
||||||
|
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)data<<(32-len))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data structure holding calculated clock configuration. Since the
|
||||||
|
* calculation needs long time, it should be calculated during initialization and
|
||||||
|
* stored somewhere to be quickly used.
|
||||||
|
*/
|
||||||
|
typedef uint32_t spi_ll_clock_val_t;
|
||||||
|
|
||||||
|
/** IO modes supported by the master. */
|
||||||
|
typedef enum {
|
||||||
|
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
||||||
|
SPI_LL_IO_MODE_DIO, ///< 2-bit mode for address and data phases, 1-bit mode for command phase
|
||||||
|
SPI_LL_IO_MODE_DUAL, ///< 2-bit mode for data phases only, 1-bit mode for command and address phases
|
||||||
|
SPI_LL_IO_MODE_QIO, ///< 4-bit mode for address and data phases, 1-bit mode for command phase
|
||||||
|
SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
||||||
|
} spi_ll_io_mode_t;
|
||||||
|
|
||||||
|
/// Interrupt type for different working pattern
|
||||||
|
typedef enum {
|
||||||
|
SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done
|
||||||
|
SPI_LL_INT_TYPE_SEG = 1, ///< Wait for DMA signals
|
||||||
|
} spi_ll_slave_intr_type;
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Control
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Initialize SPI peripheral (master).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_init(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
//Reset DMA
|
||||||
|
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||||
|
hw->dma_out_link.start = 0;
|
||||||
|
hw->dma_in_link.start = 0;
|
||||||
|
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||||
|
//Reset timing
|
||||||
|
hw->ctrl2.val = 0;
|
||||||
|
|
||||||
|
//use all 64 bytes of the buffer
|
||||||
|
hw->user.usr_miso_highpart = 0;
|
||||||
|
hw->user.usr_mosi_highpart = 0;
|
||||||
|
|
||||||
|
//Disable unneeded ints
|
||||||
|
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize SPI peripheral (slave).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_init(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
//it's stupid, but if something goes wrong, try to uncomment it
|
||||||
|
//hw->slave.slave_mode = 1;
|
||||||
|
//Configure slave
|
||||||
|
hw->clock.val = 0;
|
||||||
|
hw->user.val = 0;
|
||||||
|
hw->ctrl.val = 0;
|
||||||
|
hw->user.doutdin = 1; //we only support full duplex
|
||||||
|
hw->user.sio = 0;
|
||||||
|
hw->user.tx_start_bit = 7;
|
||||||
|
hw->slave.slave_mode = 1;
|
||||||
|
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||||
|
hw->dma_out_link.start = 0;
|
||||||
|
hw->dma_in_link.start = 0;
|
||||||
|
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||||
|
hw->slave.sync_reset = 1;
|
||||||
|
hw->slave.sync_reset = 0;
|
||||||
|
//use all 64 bytes of the buffer
|
||||||
|
hw->user.usr_miso_highpart = 0;
|
||||||
|
hw->user.usr_mosi_highpart = 0;
|
||||||
|
//by default seg mode is disabled
|
||||||
|
hw->dma_conf.dma_continue = 0;
|
||||||
|
|
||||||
|
//Disable unneeded ints
|
||||||
|
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||||
|
hw->dma_int_ena.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset TX and RX DMAs.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_reset_dma(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
//Reset DMA peripheral
|
||||||
|
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||||
|
hw->dma_out_link.start = 0;
|
||||||
|
hw->dma_in_link.start = 0;
|
||||||
|
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||||
|
hw->dma_conf.out_data_burst_en = 1;
|
||||||
|
hw->dma_conf.indscr_burst_en = 1;
|
||||||
|
hw->dma_conf.outdscr_burst_en = 1;
|
||||||
|
hw->dma_in_link.dma_rx_ena = 0;
|
||||||
|
assert(hw->dma_in_link.dma_rx_ena==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start RX DMA.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_rxdma_start(spi_dev_t *hw, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
//if something breaks, uncomment this line
|
||||||
|
//hw->dma_in_link.restart = 1;
|
||||||
|
hw->dma_in_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
hw->dma_in_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start TX DMA.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param addr Address of the beginning DMA descriptor.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr)
|
||||||
|
{
|
||||||
|
//if something breaks, uncomment this line
|
||||||
|
hw->dma_out_link.restart = 1;
|
||||||
|
hw->dma_out_link.addr = (int) addr & 0xFFFFF;
|
||||||
|
hw->dma_out_link.start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to SPI buffer.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param buffer_to_send Data address to copy to the buffer.
|
||||||
|
* @param bitlen Length to copy, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < bitlen; x += 32) {
|
||||||
|
//Use memcpy to get around alignment issues for txdata
|
||||||
|
uint32_t word;
|
||||||
|
memcpy(&word, &buffer_to_send[x / 8], 4);
|
||||||
|
hw->data_buf[(x / 32)] = word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from SPI buffer.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param buffer_to_rcv Address to copy buffer data to.
|
||||||
|
* @param bitlen Length to copy, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < bitlen; x += 32) {
|
||||||
|
//Do a memcpy to get around possible alignment issues in rx_buffer
|
||||||
|
uint32_t word = hw->data_buf[x / 32];
|
||||||
|
int len = bitlen - x;
|
||||||
|
if (len > 32) {
|
||||||
|
len = 32;
|
||||||
|
}
|
||||||
|
memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether user-defined transaction is done.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*
|
||||||
|
* @return true if transaction is done, otherwise false.
|
||||||
|
*/
|
||||||
|
static inline bool spi_ll_usr_is_done(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->slave.trans_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger start of user-defined transaction.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_user_start(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->cmd.usr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current running command bit-mask. (Preview)
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*
|
||||||
|
* @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command.
|
||||||
|
*/
|
||||||
|
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->cmd.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the trans_done interrupt.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_disable_int(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->slave.int_trans_done_en = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the trans_done interrupt.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_clear_int_stat(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->slave.trans_done = 0;
|
||||||
|
hw->dma_int_clr.val = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the trans_done interrupt.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_int_stat(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->slave.trans_done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the trans_done interrupt.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_enable_int(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->slave.int_trans_done_en = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set different interrupt types for the slave.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param int_type Interrupt type
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type)
|
||||||
|
{
|
||||||
|
switch (int_type)
|
||||||
|
{
|
||||||
|
case SPI_LL_INT_TYPE_SEG:
|
||||||
|
hw->dma_int_ena.in_suc_eof = 1;
|
||||||
|
hw->dma_int_ena.out_total_eof = 1;
|
||||||
|
hw->slave.int_trans_done_en = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
hw->dma_int_ena.in_suc_eof = 0;
|
||||||
|
hw->dma_int_ena.out_total_eof = 0;
|
||||||
|
hw->slave.int_trans_done_en = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Configs: mode
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Enable/disable the postive-cs feature.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param cs One of the CS (0-2) to enable/disable the feature.
|
||||||
|
* @param pos_cs true to enable the feature, otherwise disable (default).
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs)
|
||||||
|
{
|
||||||
|
if (pos_cs) {
|
||||||
|
hw->misc.master_cs_pol |= (1 << cs);
|
||||||
|
} else {
|
||||||
|
hw->misc.master_cs_pol &= (1 << cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable the LSBFIRST feature for TX data.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param lsbfirst true if LSB of TX data to be sent first, otherwise MSB is sent first (default).
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst)
|
||||||
|
{
|
||||||
|
hw->ctrl.wr_bit_order = lsbfirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable the LSBFIRST feature for RX data.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param lsbfirst true if first bit received as LSB, otherwise as MSB (default).
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst)
|
||||||
|
{
|
||||||
|
hw->ctrl.rd_bit_order = lsbfirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set SPI mode for the peripheral as master.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param mode SPI mode to work at, 0-3.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode)
|
||||||
|
{
|
||||||
|
//Configure polarity
|
||||||
|
if (mode == 0) {
|
||||||
|
hw->misc.ck_idle_edge = 0;
|
||||||
|
hw->user.ck_out_edge = 0;
|
||||||
|
} else if (mode == 1) {
|
||||||
|
hw->misc.ck_idle_edge = 0;
|
||||||
|
hw->user.ck_out_edge = 1;
|
||||||
|
} else if (mode == 2) {
|
||||||
|
hw->misc.ck_idle_edge = 1;
|
||||||
|
hw->user.ck_out_edge = 1;
|
||||||
|
} else if (mode == 3) {
|
||||||
|
hw->misc.ck_idle_edge = 1;
|
||||||
|
hw->user.ck_out_edge = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set SPI mode for the peripheral as slave.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param mode SPI mode to work at, 0-3.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used)
|
||||||
|
{
|
||||||
|
if (mode == 0) {
|
||||||
|
hw->misc.ck_idle_edge = 0;
|
||||||
|
hw->user.rsck_i_edge = 0;
|
||||||
|
hw->user.tsck_i_edge = 0;
|
||||||
|
hw->ctrl1.rsck_data_out = 0;
|
||||||
|
hw->ctrl1.clk_mode_13 = 0;
|
||||||
|
} else if (mode == 1) {
|
||||||
|
hw->misc.ck_idle_edge = 0;
|
||||||
|
hw->user.rsck_i_edge = 1;
|
||||||
|
hw->user.tsck_i_edge = 1;
|
||||||
|
hw->ctrl1.rsck_data_out = 0;
|
||||||
|
hw->ctrl1.clk_mode_13 = 1;
|
||||||
|
} else if (mode == 2) {
|
||||||
|
hw->misc.ck_idle_edge = 1;
|
||||||
|
hw->user.rsck_i_edge = 1;
|
||||||
|
hw->user.tsck_i_edge = 1;
|
||||||
|
hw->ctrl1.rsck_data_out = 0;
|
||||||
|
hw->ctrl1.clk_mode_13 = 0;
|
||||||
|
} else if (mode == 3) {
|
||||||
|
hw->misc.ck_idle_edge = 1;
|
||||||
|
hw->user.rsck_i_edge = 0;
|
||||||
|
hw->user.tsck_i_edge = 0;
|
||||||
|
hw->ctrl1.rsck_data_out = 0;
|
||||||
|
hw->ctrl1.clk_mode_13 = 1;
|
||||||
|
}
|
||||||
|
//hw->ctrl1.rsck_data_out = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set SPI to work in full duplex or half duplex mode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param half_duplex true to work in half duplex mode, otherwise in full duplex mode.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex)
|
||||||
|
{
|
||||||
|
hw->user.doutdin = !half_duplex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set SPI to work in SIO mode or not.
|
||||||
|
*
|
||||||
|
* SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param sio_mode true to work in SIO mode, otherwise false.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||||
|
{
|
||||||
|
hw->user.sio = sio_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the io mode for the master to work at.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||||
|
{
|
||||||
|
hw->ctrl.val &= ~(SPI_FREAD_DUAL | SPI_FREAD_QUAD | SPI_FREAD_DIO | SPI_FREAD_QIO);
|
||||||
|
hw->user.val &= ~(SPI_FWRITE_DUAL | SPI_FWRITE_QUAD | SPI_FWRITE_DIO | SPI_FWRITE_QIO);
|
||||||
|
switch (io_mode) {
|
||||||
|
case SPI_LL_IO_MODE_DIO:
|
||||||
|
// hw->ctrl.fread_dio = 1;
|
||||||
|
// hw->user.fwrite_dio = 1;
|
||||||
|
break;
|
||||||
|
case SPI_LL_IO_MODE_DUAL:
|
||||||
|
hw->ctrl.fread_dual = 1;
|
||||||
|
hw->user.fwrite_dual = 1;
|
||||||
|
break;
|
||||||
|
case SPI_LL_IO_MODE_QIO:
|
||||||
|
// hw->ctrl.fread_qio = 1;
|
||||||
|
// hw->user.fwrite_qio = 1;
|
||||||
|
break;
|
||||||
|
case SPI_LL_IO_MODE_QUAD:
|
||||||
|
hw->ctrl.fread_quad = 1;
|
||||||
|
hw->user.fwrite_quad = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
// if (io_mode != SPI_LL_IO_MODE_NORMAL) {
|
||||||
|
// hw->ctrl.fastrd_mode = 1;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select one of the CS to use in current transaction.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param cs_id The cs to use, 0-2, otherwise none of them is used.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id)
|
||||||
|
{
|
||||||
|
hw->misc.cs0_dis = (cs_id == 0) ? 0 : 1;
|
||||||
|
hw->misc.cs1_dis = (cs_id == 1) ? 0 : 1;
|
||||||
|
hw->misc.cs2_dis = (cs_id == 2) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Configs: parameters
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Set the clock for master by stored value.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param val stored clock configuration calculated before (by ``spi_ll_cal_clock``).
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, spi_ll_clock_val_t *val)
|
||||||
|
{
|
||||||
|
hw->clock.val = *(uint32_t *)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the frequency of given dividers. Don't use in app.
|
||||||
|
*
|
||||||
|
* @param fapb APB clock of the system.
|
||||||
|
* @param pre Pre devider.
|
||||||
|
* @param n main divider.
|
||||||
|
*
|
||||||
|
* @return Frequency of given dividers.
|
||||||
|
*/
|
||||||
|
static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||||
|
{
|
||||||
|
return (fapb / (pre * n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the nearest frequency avaliable for master.
|
||||||
|
*
|
||||||
|
* @param fapb APB clock of the system.
|
||||||
|
* @param hz Frequncy desired.
|
||||||
|
* @param duty_cycle Duty cycle desired.
|
||||||
|
* @param out_reg Output address to store the calculated clock configurations for the return frequency.
|
||||||
|
*
|
||||||
|
* @return Actual (nearest) frequency.
|
||||||
|
*/
|
||||||
|
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||||
|
{
|
||||||
|
typeof(GPSPI2.clock) reg;
|
||||||
|
int eff_clk;
|
||||||
|
|
||||||
|
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||||
|
if (hz > ((fapb / 4) * 3)) {
|
||||||
|
//Using Fapb directly will give us the best result here.
|
||||||
|
reg.clkcnt_l = 0;
|
||||||
|
reg.clkcnt_h = 0;
|
||||||
|
reg.clkcnt_n = 0;
|
||||||
|
reg.clkdiv_pre = 0;
|
||||||
|
reg.clk_equ_sysclk = 1;
|
||||||
|
eff_clk = fapb;
|
||||||
|
} else {
|
||||||
|
//For best duty cycle resolution, we want n to be as close to 32 as possible, but
|
||||||
|
//we also need a pre/n combo that gets us as close as possible to the intended freq.
|
||||||
|
//To do this, we bruteforce n and calculate the best pre to go along with that.
|
||||||
|
//If there's a choice between pre/n combos that give the same result, use the one
|
||||||
|
//with the higher n.
|
||||||
|
int pre, n, h, l;
|
||||||
|
int bestn = -1;
|
||||||
|
int bestpre = -1;
|
||||||
|
int besterr = 0;
|
||||||
|
int errval;
|
||||||
|
for (n = 2; n <= 64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse.
|
||||||
|
//Effectively, this does pre=round((fapb/n)/hz).
|
||||||
|
pre = ((fapb / n) + (hz / 2)) / hz;
|
||||||
|
if (pre <= 0) {
|
||||||
|
pre = 1;
|
||||||
|
}
|
||||||
|
if (pre > 8192) {
|
||||||
|
pre = 8192;
|
||||||
|
}
|
||||||
|
errval = abs(spi_ll_freq_for_pre_n(fapb, pre, n) - hz);
|
||||||
|
if (bestn == -1 || errval <= besterr) {
|
||||||
|
besterr = errval;
|
||||||
|
bestn = n;
|
||||||
|
bestpre = pre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = bestn;
|
||||||
|
pre = bestpre;
|
||||||
|
l = n;
|
||||||
|
//This effectively does round((duty_cycle*n)/256)
|
||||||
|
h = (duty_cycle * n + 127) / 256;
|
||||||
|
if (h <= 0) {
|
||||||
|
h = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.clk_equ_sysclk = 0;
|
||||||
|
reg.clkcnt_n = n - 1;
|
||||||
|
reg.clkdiv_pre = pre - 1;
|
||||||
|
reg.clkcnt_h = h - 1;
|
||||||
|
reg.clkcnt_l = l - 1;
|
||||||
|
eff_clk = spi_ll_freq_for_pre_n(fapb, pre, n);
|
||||||
|
}
|
||||||
|
if (out_reg != NULL) {
|
||||||
|
*(uint32_t *)out_reg = reg.val;
|
||||||
|
}
|
||||||
|
return eff_clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate and set clock for SPI master according to desired parameters.
|
||||||
|
*
|
||||||
|
* This takes long, suggest to calculate the configuration during
|
||||||
|
* initialization by ``spi_ll_master_cal_clock`` and store the result, then
|
||||||
|
* configure the clock by stored value when used by
|
||||||
|
* ``spi_ll_msater_set_clock_by_reg``.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param fapb APB clock of the system.
|
||||||
|
* @param hz Frequncy desired.
|
||||||
|
* @param duty_cycle Duty cycle desired.
|
||||||
|
*
|
||||||
|
* @return Actual frequency that is used.
|
||||||
|
*/
|
||||||
|
static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle)
|
||||||
|
{
|
||||||
|
spi_ll_clock_val_t reg_val;
|
||||||
|
int freq = spi_ll_master_cal_clock(fapb, hz, duty_cycle, ®_val);
|
||||||
|
spi_ll_master_set_clock_by_reg(hw, ®_val);
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the mosi delay after the output edge to the signal. (Preview)
|
||||||
|
*
|
||||||
|
* The delay mode/num is a Espressif conception, may change in the new chips.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param delay_mode Delay mode, see TRM.
|
||||||
|
* @param delay_num APB clocks to delay.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num)
|
||||||
|
{
|
||||||
|
//TODO: this doesn't make sense
|
||||||
|
hw->dout_num.dout0_num = 0;
|
||||||
|
hw->dout_num.dout1_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the miso delay applied to the input signal before the internal peripheral. (Preview)
|
||||||
|
*
|
||||||
|
* The delay mode/num is a Espressif conception, may change in the new chips.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param delay_mode Delay mode, see TRM.
|
||||||
|
* @param delay_num APB clocks to delay.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num)
|
||||||
|
{
|
||||||
|
//TODO: this doesn't make sense
|
||||||
|
hw->din_num.din0_num = 1;
|
||||||
|
hw->din_num.din1_num = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set dummy clocks to output before RX phase (master), or clocks to skip
|
||||||
|
* before the data phase and after the address phase (slave).
|
||||||
|
*
|
||||||
|
* Note this phase is also used to compensate RX timing in half duplex mode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n)
|
||||||
|
{
|
||||||
|
hw->user.usr_dummy = dummy_n ? 1 : 0;
|
||||||
|
hw->user1.usr_dummy_cyclelen = dummy_n - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the delay of SPI clocks before the CS inactive edge after the last SPI clock.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold)
|
||||||
|
{
|
||||||
|
hw->ctrl2.cs_hold_time = hold - 1;
|
||||||
|
hw->user.cs_hold = hold ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the delay of SPI clocks before the first SPI clock after the CS active edge.
|
||||||
|
*
|
||||||
|
* Note ESP32 doesn't support to use this feature when command/address phases
|
||||||
|
* are used in full duplex mode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup)
|
||||||
|
{
|
||||||
|
hw->ctrl2.cs_setup_time = setup - 1;
|
||||||
|
hw->user.cs_setup = setup ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable the segment transfer feature for the slave.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param en true to enable, false to disable.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_set_seg_en(spi_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
hw->dma_conf.slv_rx_seg_trans_en = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
* Configs: data
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
/**
|
||||||
|
* Set the input length (master).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen input length, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||||
|
{
|
||||||
|
hw->miso_dlen.usr_miso_bit_len = bitlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the output length (master).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen output length, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||||
|
{
|
||||||
|
hw->mosi_dlen.usr_mosi_bit_len = bitlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum input length (slave).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen input length, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||||
|
{
|
||||||
|
hw->slv_wrbuf_dlen.bit_len = bitlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the maximum output length (slave).
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen output length, in bits.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||||
|
{
|
||||||
|
hw->slv_rdbuf_dlen.bit_len = bitlen - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the length of command phase.
|
||||||
|
*
|
||||||
|
* When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit
|
||||||
|
* command phases takes 4 cycles in 4-bit mode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen Length of command phase, in bits. 0 to disable the command phase.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen)
|
||||||
|
{
|
||||||
|
hw->user2.usr_command_bitlen = bitlen - 1;
|
||||||
|
hw->user.usr_command = bitlen ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the length of address phase.
|
||||||
|
*
|
||||||
|
* When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit
|
||||||
|
* address phases takes 4 cycles in 4-bit mode.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param bitlen Length of address phase, in bits. 0 to disable the address phase.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen)
|
||||||
|
{
|
||||||
|
hw->user1.usr_addr_bitlen = bitlen - 1;
|
||||||
|
hw->user.usr_addr = bitlen ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the address value in an intuitive way.
|
||||||
|
*
|
||||||
|
* The length and lsbfirst is required to shift and swap the address to the right place.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param address Address to set
|
||||||
|
* @param addrlen Length of the address phase
|
||||||
|
* @param lsbfirst whether the LSB first feature is enabled.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst)
|
||||||
|
{
|
||||||
|
if (lsbfirst) {
|
||||||
|
/* The output address start from the LSB of the highest byte, i.e.
|
||||||
|
* addr[24] -> addr[31]
|
||||||
|
* ...
|
||||||
|
* addr[0] -> addr[7]
|
||||||
|
* slv_wr_status[24] -> slv_wr_status[31]
|
||||||
|
* ...
|
||||||
|
* slv_wr_status[0] -> slv_wr_status[7]
|
||||||
|
* So swap the byte order to let the LSB sent first.
|
||||||
|
*/
|
||||||
|
addr = HAL_SWAP64(addr);
|
||||||
|
hw->addr = addr >> 32;
|
||||||
|
hw->slv_wr_status = addr;
|
||||||
|
} else {
|
||||||
|
// shift the address to MSB of addr (and maybe slv_wr_status) register.
|
||||||
|
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
|
||||||
|
if (addrlen > 32) {
|
||||||
|
hw->addr = addr >> (addrlen - 32);
|
||||||
|
hw->slv_wr_status = addr << (64 - addrlen);
|
||||||
|
} else {
|
||||||
|
hw->addr = addr << (32 - addrlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the command value in an intuitive way.
|
||||||
|
*
|
||||||
|
* The length and lsbfirst is required to shift and swap the command to the right place.
|
||||||
|
*
|
||||||
|
* @param hw Beginning command of the peripheral registers.
|
||||||
|
* @param command Command to set
|
||||||
|
* @param addrlen Length of the command phase
|
||||||
|
* @param lsbfirst whether the LSB first feature is enabled.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||||
|
{
|
||||||
|
if (lsbfirst) {
|
||||||
|
// The output command start from bit0 to bit 15, kept as is.
|
||||||
|
hw->user2.usr_command_value = cmd;
|
||||||
|
} else {
|
||||||
|
/* Output command will be sent from bit 7 to 0 of command_value, and
|
||||||
|
* then bit 15 to 8 of the same register field. Shift and swap to send
|
||||||
|
* more straightly.
|
||||||
|
*/
|
||||||
|
hw->user2.usr_command_value = HAL_SPI_SWAP_DATA_TX(cmd, cmdlen);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable the RX data phase.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param enable true if RX phase exist, otherwise false.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable)
|
||||||
|
{
|
||||||
|
hw->user.usr_miso = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable the TX data phase.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
* @param enable true if TX phase exist, otherwise false.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable)
|
||||||
|
{
|
||||||
|
hw->user.usr_mosi = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the slave peripheral before next transaction.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*/
|
||||||
|
static inline void spi_ll_slave_reset(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
hw->slave.sync_reset = 1;
|
||||||
|
hw->slave.sync_reset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the received bit length of the slave.
|
||||||
|
*
|
||||||
|
* @param hw Beginning address of the peripheral registers.
|
||||||
|
*
|
||||||
|
* @return Received bits of the slave.
|
||||||
|
*/
|
||||||
|
static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->slv_rd_byte.slv_rdata_bit * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef SPI_LL_RST_MASK
|
||||||
|
#undef SPI_LL_UNUSED_INT_MASK
|
@ -232,6 +232,7 @@
|
|||||||
#define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16
|
#define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16
|
||||||
#define SPI_CLK_DIV 4
|
#define SPI_CLK_DIV 4
|
||||||
#define TICKS_PER_US_ROM 40 // CPU is 80MHz
|
#define TICKS_PER_US_ROM 40 // CPU is 80MHz
|
||||||
|
#define GPIO_MATRIX_DELAY_NS 25
|
||||||
//}}
|
//}}
|
||||||
|
|
||||||
/* Overall memory map */
|
/* Overall memory map */
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
@ -12,10 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef _SOC_SPI_PINS_H_
|
#pragma once
|
||||||
#define _SOC_SPI_PINS_H_
|
|
||||||
|
|
||||||
#define SPI_PERIPH_NUM 4
|
#define SOC_SPI_PERIPH_NUM 4
|
||||||
|
#define SOC_SPI_DMA_CHAN_NUM 3
|
||||||
|
|
||||||
#define SPI_FUNC_NUM 2
|
#define SPI_FUNC_NUM 2
|
||||||
#define SPI_IOMUX_PIN_NUM_HD 27
|
#define SPI_IOMUX_PIN_NUM_HD 27
|
||||||
@ -37,4 +37,9 @@
|
|||||||
|
|
||||||
//HSPI and VSPI have no iomux pins
|
//HSPI and VSPI have no iomux pins
|
||||||
|
|
||||||
#endif
|
#define SOC_SPI_MAXIMUM_BUFFER_SIZE 72
|
||||||
|
|
||||||
|
//#define SOC_SPI_SUPPORT_AS_CS //don't support to toggle the CS while the clock toggles
|
||||||
|
#define SOC_SPI_SUPPORT_DDRCLK 1
|
||||||
|
#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1
|
||||||
|
#define SOC_SPI_SUPPORT_CD_SIG 1
|
@ -493,7 +493,7 @@ extern "C" {
|
|||||||
#define SPI_SLAVE_CS_POL_V 0x1
|
#define SPI_SLAVE_CS_POL_V 0x1
|
||||||
#define SPI_SLAVE_CS_POL_S 23
|
#define SPI_SLAVE_CS_POL_S 23
|
||||||
/* SPI_MASTER_CS_POL : R/W ;bitpos:[8:6] ;default: 3'b0 ; */
|
/* SPI_MASTER_CS_POL : R/W ;bitpos:[8:6] ;default: 3'b0 ; */
|
||||||
/*description: In the master mode the bits are the polarity of spi cs line
|
/*description: In the master mode the bits are the polarity of spi cs line
|
||||||
the value is equivalent to spi_cs ^ spi_master_cs_pol.*/
|
the value is equivalent to spi_cs ^ spi_master_cs_pol.*/
|
||||||
#define SPI_MASTER_CS_POL 0x00000007
|
#define SPI_MASTER_CS_POL 0x00000007
|
||||||
#define SPI_MASTER_CS_POL_M ((SPI_MASTER_CS_POL_V)<<(SPI_MASTER_CS_POL_S))
|
#define SPI_MASTER_CS_POL_M ((SPI_MASTER_CS_POL_V)<<(SPI_MASTER_CS_POL_S))
|
||||||
@ -543,12 +543,36 @@ extern "C" {
|
|||||||
#define SPI_TRANS_CNT_M ((SPI_TRANS_CNT_V)<<(SPI_TRANS_CNT_S))
|
#define SPI_TRANS_CNT_M ((SPI_TRANS_CNT_V)<<(SPI_TRANS_CNT_S))
|
||||||
#define SPI_TRANS_CNT_V 0xF
|
#define SPI_TRANS_CNT_V 0xF
|
||||||
#define SPI_TRANS_CNT_S 23
|
#define SPI_TRANS_CNT_S 23
|
||||||
/* SPI_INT_EN : R/W ;bitpos:[9:5] ;default: 5'b1_1111 ; */
|
/* SPI_INT_TRANS_DONE_EN : R/W ;bitpos:[9] ;default: 1'b1 ; */
|
||||||
/*description: Interrupt enable bits for the below 5 sources*/
|
/*description: spi_trans_done Interrupt enable. 1: enable 0: disable*/
|
||||||
#define SPI_INT_EN 0x0000001F
|
#define SPI_INT_TRANS_DONE_EN (BIT(9))
|
||||||
#define SPI_INT_EN_M ((SPI_INT_EN_V)<<(SPI_INT_EN_S))
|
#define SPI_INT_TRANS_DONE_EN_M (BIT(9))
|
||||||
#define SPI_INT_EN_V 0x1F
|
#define SPI_INT_TRANS_DONE_EN_V 0x1
|
||||||
#define SPI_INT_EN_S 5
|
#define SPI_INT_TRANS_DONE_EN_S 9
|
||||||
|
/* SPI_INT_WR_DMA_DONE_EN : R/W ;bitpos:[8] ;default: 1'b0 ; */
|
||||||
|
/*description: spi_slv_wr_dma Interrupt enable. 1: enable 0: disable*/
|
||||||
|
#define SPI_INT_WR_DMA_DONE_EN (BIT(8))
|
||||||
|
#define SPI_INT_WR_DMA_DONE_EN_M (BIT(8))
|
||||||
|
#define SPI_INT_WR_DMA_DONE_EN_V 0x1
|
||||||
|
#define SPI_INT_WR_DMA_DONE_EN_S 8
|
||||||
|
/* SPI_INT_RD_DMA_DONE_EN : R/W ;bitpos:[7] ;default: 1'b0 ; */
|
||||||
|
/*description: spi_slv_rd_dma Interrupt enable. 1: enable 0: disable*/
|
||||||
|
#define SPI_INT_RD_DMA_DONE_EN (BIT(7))
|
||||||
|
#define SPI_INT_RD_DMA_DONE_EN_M (BIT(7))
|
||||||
|
#define SPI_INT_RD_DMA_DONE_EN_V 0x1
|
||||||
|
#define SPI_INT_RD_DMA_DONE_EN_S 7
|
||||||
|
/* SPI_INT_WR_BUF_DONE_EN : R/W ;bitpos:[6] ;default: 1'b0 ; */
|
||||||
|
/*description: spi_slv_wr_buf Interrupt enable. 1: enable 0: disable*/
|
||||||
|
#define SPI_INT_WR_BUF_DONE_EN (BIT(6))
|
||||||
|
#define SPI_INT_WR_BUF_DONE_EN_M (BIT(6))
|
||||||
|
#define SPI_INT_WR_BUF_DONE_EN_V 0x1
|
||||||
|
#define SPI_INT_WR_BUF_DONE_EN_S 6
|
||||||
|
/* SPI_INT_RD_BUF_DONE_EN : R/W ;bitpos:[5] ;default: 1'b0 ; */
|
||||||
|
/*description: spi_slv_rd_buf Interrupt enable. 1: enable 0: disable*/
|
||||||
|
#define SPI_INT_RD_BUF_DONE_EN (BIT(5))
|
||||||
|
#define SPI_INT_RD_BUF_DONE_EN_M (BIT(5))
|
||||||
|
#define SPI_INT_RD_BUF_DONE_EN_V 0x1
|
||||||
|
#define SPI_INT_RD_BUF_DONE_EN_S 5
|
||||||
/* SPI_TRANS_DONE : R/W ;bitpos:[4] ;default: 1'b0 ; */
|
/* SPI_TRANS_DONE : R/W ;bitpos:[4] ;default: 1'b0 ; */
|
||||||
/*description: The interrupt raw bit for the completion of any operation in
|
/*description: The interrupt raw bit for the completion of any operation in
|
||||||
both the master mode and the slave mode.*/
|
both the master mode and the slave mode.*/
|
||||||
@ -693,6 +717,13 @@ extern "C" {
|
|||||||
#define SPI_INT_HOLD_ENA_S 0
|
#define SPI_INT_HOLD_ENA_S 0
|
||||||
|
|
||||||
#define SPI_DMA_CONF_REG(i) (REG_SPI_BASE(i) + 0x058)
|
#define SPI_DMA_CONF_REG(i) (REG_SPI_BASE(i) + 0x058)
|
||||||
|
/* SPI_CONTINUE_POP_DATA_CLR : R/W ;bitpos:[17] ;default: 1'b0 ; */
|
||||||
|
/*description: Disable spi slave dma to pop data continuously in next transmission
|
||||||
|
in dma half duplex slave mode. 1: disable continue transmit. 0: enable continue transmit.*/
|
||||||
|
#define SPI_CONTINUE_POP_DATA_CLR (BIT(17))
|
||||||
|
#define SPI_CONTINUE_POP_DATA_CLR_M (BIT(17))
|
||||||
|
#define SPI_CONTINUE_POP_DATA_CLR_V 0x1
|
||||||
|
#define SPI_CONTINUE_POP_DATA_CLR_S 17
|
||||||
/* SPI_DMA_CONTINUE : R/W ;bitpos:[16] ;default: 1'b0 ; */
|
/* SPI_DMA_CONTINUE : R/W ;bitpos:[16] ;default: 1'b0 ; */
|
||||||
/*description: spi dma continue tx/rx data.*/
|
/*description: spi dma continue tx/rx data.*/
|
||||||
#define SPI_DMA_CONTINUE (BIT(16))
|
#define SPI_DMA_CONTINUE (BIT(16))
|
||||||
@ -1628,7 +1659,7 @@ extern "C" {
|
|||||||
#define SPI_SOP_ITL_S 0
|
#define SPI_SOP_ITL_S 0
|
||||||
|
|
||||||
#define SPI_DATE_REG(i) (REG_SPI_BASE(i) + 0x3FC)
|
#define SPI_DATE_REG(i) (REG_SPI_BASE(i) + 0x3FC)
|
||||||
/* SPI_DATE : RW ;bitpos:[27:0] ;default: 32'h1809190 ; */
|
/* SPI_DATE : RW ;bitpos:[27:0] ;default: 32'h1810100 ; */
|
||||||
/*description: SPI register version.*/
|
/*description: SPI register version.*/
|
||||||
#define SPI_DATE 0x0FFFFFFF
|
#define SPI_DATE 0x0FFFFFFF
|
||||||
#define SPI_DATE_M ((SPI_DATE_V)<<(SPI_DATE_S))
|
#define SPI_DATE_M ((SPI_DATE_V)<<(SPI_DATE_S))
|
||||||
|
@ -173,20 +173,20 @@ typedef volatile struct {
|
|||||||
} misc;
|
} misc;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t reserved0: 4; /*reserved*/
|
uint32_t reserved0: 4; /*reserved*/
|
||||||
uint32_t trans_done: 1; /*The interrupt raw bit for the completion of any operation in both the master mode and the slave mode.*/
|
uint32_t trans_done: 1; /*The interrupt raw bit for the completion of any operation in both the master mode and the slave mode.*/
|
||||||
uint32_t rd_buf_inten: 1; /*The interrupt enable bit for the completion of read-buffer operation in the slave mode.*/
|
uint32_t int_rd_buf_done_en: 1; /*spi_slv_rd_buf Interrupt enable. 1: enable 0: disable*/
|
||||||
uint32_t wr_buf_inten: 1; /*The interrupt enable bit for the completion of write-buffer operation in the slave mode.*/
|
uint32_t int_wr_buf_done_en: 1; /*spi_slv_wr_buf Interrupt enable. 1: enable 0: disable*/
|
||||||
uint32_t rd_dma_inten: 1; /*The interrupt enable bit for the completion of read-status operation in the slave mode.*/
|
uint32_t int_rd_dma_done_en: 1; /*spi_slv_rd_dma Interrupt enable. 1: enable 0: disable*/
|
||||||
uint32_t wr_dma_inten: 1; /*The interrupt enable bit for the completion of write-status operation in the slave mode.*/
|
uint32_t int_wr_dma_done_en: 1; /*spi_slv_wr_dma Interrupt enable. 1: enable 0: disable*/
|
||||||
uint32_t trans_inten: 1; /*The interrupt enable bit for the completion of any operation in both the master mode and the slave mode.*/
|
uint32_t int_trans_done_en: 1; /*spi_trans_done Interrupt enable. 1: enable 0: disable*/
|
||||||
uint32_t reserved10:13; /*reserved*/
|
uint32_t reserved10: 13; /*reserved*/
|
||||||
uint32_t trans_cnt: 4; /*The operations counter in both the master mode and the slave mode.*/
|
uint32_t trans_cnt: 4; /*The operations counter in both the master mode and the slave mode.*/
|
||||||
uint32_t reserved27: 1; /*reserved*/
|
uint32_t reserved27: 1; /*reserved*/
|
||||||
uint32_t reserved28: 1; /*reserved*/
|
uint32_t reserved28: 1; /*reserved*/
|
||||||
uint32_t reserved29: 1; /*reserved*/
|
uint32_t reserved29: 1; /*reserved*/
|
||||||
uint32_t slave_mode: 1; /*Set SPI work mode. 1: slave mode 0: master mode.*/
|
uint32_t slave_mode: 1; /*Set SPI work mode. 1: slave mode 0: master mode.*/
|
||||||
uint32_t sync_reset: 1; /*Software reset enable reset the spi clock line cs line and data lines.*/
|
uint32_t sync_reset: 1; /*Software reset enable reset the spi clock line cs line and data lines.*/
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} slave;
|
} slave;
|
||||||
@ -254,23 +254,28 @@ typedef volatile struct {
|
|||||||
} hold;
|
} hold;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
uint32_t reserved0: 2; /*reserved*/
|
uint32_t reserved0: 2; /*reserved*/
|
||||||
uint32_t in_rst: 1; /*The bit is used to reset in dma fsm and in data fifo pointer.*/
|
uint32_t in_rst: 1; /*The bit is used to reset in dma fsm and in data fifo pointer.*/
|
||||||
uint32_t out_rst: 1; /*The bit is used to reset out dma fsm and out data fifo pointer.*/
|
uint32_t out_rst: 1; /*The bit is used to reset out dma fsm and out data fifo pointer.*/
|
||||||
uint32_t ahbm_fifo_rst: 1; /*Reset spi dma ahb master fifo pointer.*/
|
uint32_t ahbm_fifo_rst: 1; /*Reset spi dma ahb master fifo pointer.*/
|
||||||
uint32_t ahbm_rst: 1; /*Reset spi dma ahb master.*/
|
uint32_t ahbm_rst: 1; /*Reset spi dma ahb master.*/
|
||||||
uint32_t in_loop_test: 1; /*Set bit to test in link.*/
|
uint32_t in_loop_test: 1; /*Set bit to test in link.*/
|
||||||
uint32_t out_loop_test: 1; /*Set bit to test out link.*/
|
uint32_t out_loop_test: 1; /*Set bit to test out link.*/
|
||||||
uint32_t out_auto_wrback: 1; /*when the bit is set DMA continue to use the next inlink node when the length of inlink is 0.*/
|
uint32_t out_auto_wrback: 1; /*when the bit is set DMA continue to use the next inlink node when the length of inlink is 0.*/
|
||||||
uint32_t out_eof_mode: 1; /*out eof flag generation mode . 1: when dma pop all data from fifo 0:when ahb push all data to fifo.*/
|
uint32_t out_eof_mode: 1; /*out eof flag generation mode . 1: when dma pop all data from fifo 0:when ahb push all data to fifo.*/
|
||||||
uint32_t outdscr_burst_en: 1; /*read descriptor use burst mode when read data for memory.*/
|
uint32_t outdscr_burst_en: 1; /*read descriptor use burst mode when read data for memory.*/
|
||||||
uint32_t indscr_burst_en: 1; /*read descriptor use burst mode when write data to memory.*/
|
uint32_t indscr_burst_en: 1; /*read descriptor use burst mode when write data to memory.*/
|
||||||
uint32_t out_data_burst_en: 1; /*spi dma read data from memory in burst mode.*/
|
uint32_t out_data_burst_en: 1; /*spi dma read data from memory in burst mode.*/
|
||||||
uint32_t mem_trans_en: 1;
|
uint32_t mem_trans_en: 1;
|
||||||
uint32_t dma_rx_stop: 1; /*spi dma read data stop when in continue tx/rx mode.*/
|
uint32_t dma_rx_stop: 1; /*spi dma read data stop when in continue tx/rx mode.*/
|
||||||
uint32_t dma_tx_stop: 1; /*spi dma write data stop when in continue tx/rx mode.*/
|
uint32_t dma_tx_stop: 1; /*spi dma write data stop when in continue tx/rx mode.*/
|
||||||
uint32_t dma_continue: 1; /*spi dma continue tx/rx data.*/
|
uint32_t dma_continue: 1; /*spi dma continue tx/rx data.*/
|
||||||
uint32_t reserved17: 15; /*reserved*/
|
uint32_t continue_pop_data_clr: 1; /*Disable spi slave dma to pop data continuously in next transmission in dma half duplex slave mode. 1: disable continue transmit. 0: enable continue transmit.*/
|
||||||
|
uint32_t slv_rx_seg_trans_en: 1; /*enable DMA segment transfer in slave mode*/
|
||||||
|
uint32_t reserved19: 3; /*reserved*/
|
||||||
|
uint32_t infifo_full_clr: 1;
|
||||||
|
uint32_t outfifo_empty_clr: 1;
|
||||||
|
uint32_t reserved24: 8;
|
||||||
};
|
};
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
} dma_conf;
|
} dma_conf;
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
// field comments.
|
// field comments.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "spi_ll.h"
|
#include "hal/spi_ll.h"
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include "soc/lldesc.h"
|
#include "soc/lldesc.h"
|
||||||
|
|
||||||
@ -85,7 +85,9 @@ typedef struct {
|
|||||||
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
|
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
|
||||||
uint32_t dma_enabled : 1; ///< Whether the DMA is enabled, do not update after initialization
|
uint32_t dma_enabled : 1; ///< Whether the DMA is enabled, do not update after initialization
|
||||||
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
|
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
|
||||||
uint32_t as_cs : 1; ///< Whether the AS_CS feature is enabled, device specific
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
|
uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific
|
||||||
|
#endif
|
||||||
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
|
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
|
||||||
};//boolean configurations
|
};//boolean configurations
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "soc/lldesc.h"
|
#include "soc/lldesc.h"
|
||||||
#include "soc/spi_struct.h"
|
#include "soc/spi_struct.h"
|
||||||
#include <esp_types.h>
|
#include <esp_types.h>
|
||||||
|
#include "soc/spi_caps.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context that should be maintained by both the driver and the HAL.
|
* Context that should be maintained by both the driver and the HAL.
|
||||||
|
43
components/soc/include/hal/spi_types.h
Normal file
43
components/soc/include/hal/spi_types.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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 "soc/spi_caps.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enum with the three SPI peripherals that are software-accessible in it
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SPI1_HOST=0, ///< SPI1
|
||||||
|
SPI2_HOST=1, ///< SPI2
|
||||||
|
SPI3_HOST=2, ///< SPI3
|
||||||
|
#if SOC_SPI_PERIPH_NUM > 3
|
||||||
|
SPI4_HOST=3, ///< SPI4
|
||||||
|
#endif
|
||||||
|
} spi_host_device_t;
|
||||||
|
|
||||||
|
//alias for different chips
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SPI_HOST SPI1_HOST
|
||||||
|
#define HSPI_HOST SPI2_HOST
|
||||||
|
#define VSPI_HOST SPI3_HOST
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
#define SPI_HOST SPI1_HOST
|
||||||
|
#define FSPI_HOST SPI2_HOST
|
||||||
|
#define HSPI_HOST SPI3_HOST
|
||||||
|
#define VSPI_HOST SPI4_HOST
|
||||||
|
#endif
|
||||||
|
|
@ -14,7 +14,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_ESP32
|
||||||
#include "esp32/rom/lldesc.h"
|
#include "esp32/rom/lldesc.h"
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
#include "esp32s2beta/rom/lldesc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
//the size field has 12 bits, but 0 not for 4096.
|
//the size field has 12 bits, but 0 not for 4096.
|
||||||
//to avoid possible problem when the size is not word-aligned, we only use 4096-4 per desc.
|
//to avoid possible problem when the size is not word-aligned, we only use 4096-4 per desc.
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
#include "soc/periph_defs.h"
|
#include "soc/periph_defs.h"
|
||||||
#include "soc/spi_pins.h"
|
#include "soc/spi_caps.h"
|
||||||
#include "soc/spi_reg.h"
|
#include "soc/spi_reg.h"
|
||||||
#include "soc/spi_struct.h"
|
#include "soc/spi_struct.h"
|
||||||
#include "soc/gpio_sig_map.h"
|
#include "soc/gpio_sig_map.h"
|
||||||
@ -68,11 +68,11 @@ typedef struct {
|
|||||||
const uint8_t irq; //irq source for interrupt mux
|
const uint8_t irq; //irq source for interrupt mux
|
||||||
const uint8_t irq_dma; //dma irq source for interrupt mux
|
const uint8_t irq_dma; //dma irq source for interrupt mux
|
||||||
const periph_module_t module; //peripheral module, for enabling clock etc
|
const periph_module_t module; //peripheral module, for enabling clock etc
|
||||||
|
const int func; //function number for IOMUX
|
||||||
spi_dev_t *hw; //Pointer to the hardware registers
|
spi_dev_t *hw; //Pointer to the hardware registers
|
||||||
const int func;
|
|
||||||
} spi_signal_conn_t;
|
} spi_signal_conn_t;
|
||||||
|
|
||||||
extern const spi_signal_conn_t spi_periph_signal[SPI_PERIPH_NUM];
|
extern const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM];
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ esp_err_t spi_hal_get_clock_conf(const spi_hal_context_t *hal, int speed_hz, int
|
|||||||
//But these don't work for full-duplex connections.
|
//But these don't work for full-duplex connections.
|
||||||
spi_hal_cal_timing(eff_clk_n, use_gpio, input_delay_ns, &temp_conf.timing_dummy, &temp_conf.timing_miso_delay);
|
spi_hal_cal_timing(eff_clk_n, use_gpio, input_delay_ns, &temp_conf.timing_dummy, &temp_conf.timing_miso_delay);
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
const int freq_limit = spi_hal_get_freq_limit(use_gpio, input_delay_ns);
|
const int freq_limit = spi_hal_get_freq_limit(use_gpio, input_delay_ns);
|
||||||
|
|
||||||
SPI_HAL_CHECK(hal->half_duplex || temp_conf.timing_dummy == 0 || hal->no_compensate,
|
SPI_HAL_CHECK(hal->half_duplex || temp_conf.timing_dummy == 0 || hal->no_compensate,
|
||||||
@ -67,6 +68,7 @@ Try to use IOMUX pins to increase the frequency limit, or use the half duplex mo
|
|||||||
Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
Please note the SPI master can only work at divisors of 80MHz, and the driver always tries to find the closest frequency to your configuration.\n\
|
||||||
Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output data at higher speed, or read data at your own risk.",
|
Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output data at higher speed, or read data at your own risk.",
|
||||||
ESP_ERR_NOT_SUPPORTED, freq_limit / 1000. / 1000 );
|
ESP_ERR_NOT_SUPPORTED, freq_limit / 1000. / 1000 );
|
||||||
|
#endif
|
||||||
|
|
||||||
if (timing_conf) {
|
if (timing_conf) {
|
||||||
*timing_conf = temp_conf;
|
*timing_conf = temp_conf;
|
||||||
|
@ -21,7 +21,9 @@ void spi_hal_setup_device(const spi_hal_context_t *hal)
|
|||||||
{
|
{
|
||||||
//Configure clock settings
|
//Configure clock settings
|
||||||
spi_dev_t *hw = hal->hw;
|
spi_dev_t *hw = hal->hw;
|
||||||
|
#ifdef SOC_SPI_SUPPORT_AS_CS
|
||||||
spi_ll_master_set_cksel(hw, hal->cs_pin_id, hal->as_cs);
|
spi_ll_master_set_cksel(hw, hal->cs_pin_id, hal->as_cs);
|
||||||
|
#endif
|
||||||
spi_ll_master_set_pos_cs(hw, hal->cs_pin_id, hal->positive_cs);
|
spi_ll_master_set_pos_cs(hw, hal->cs_pin_id, hal->positive_cs);
|
||||||
spi_ll_master_set_clock_by_reg(hw, &hal->timing_conf->clock_reg);
|
spi_ll_master_set_clock_by_reg(hw, &hal->timing_conf->clock_reg);
|
||||||
//Configure bit order
|
//Configure bit order
|
||||||
|
@ -12,8 +12,8 @@ void spi_slave_hal_init(spi_slave_hal_context_t *hal, int host_id)
|
|||||||
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
|
//Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as
|
||||||
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
//disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling
|
||||||
//any transactions that are queued.
|
//any transactions that are queued.
|
||||||
spi_ll_enable_int(hal->hw);
|
|
||||||
spi_ll_set_int_stat(hal->hw);
|
spi_ll_set_int_stat(hal->hw);
|
||||||
|
spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal)
|
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal)
|
||||||
|
@ -14,6 +14,7 @@ void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal)
|
|||||||
|
|
||||||
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
|
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
|
||||||
{
|
{
|
||||||
|
spi_ll_slave_reset(hal->hw);
|
||||||
if (hal->use_dma) {
|
if (hal->use_dma) {
|
||||||
spi_ll_reset_dma(hal->hw);
|
spi_ll_reset_dma(hal->hw);
|
||||||
|
|
||||||
@ -32,7 +33,6 @@ void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
|
|||||||
spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
|
spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spi_ll_slave_reset(hal->hw);
|
|
||||||
|
|
||||||
spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
|
spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
|
||||||
spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
|
spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
|
||||||
@ -53,6 +53,7 @@ void spi_slave_hal_store_result(spi_slave_hal_context_t *hal)
|
|||||||
//Copy result out
|
//Copy result out
|
||||||
spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen);
|
spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen);
|
||||||
}
|
}
|
||||||
|
spi_ll_slave_set_int_type(hal->hw, SPI_LL_INT_TYPE_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
|
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
|
||||||
|
@ -87,6 +87,7 @@ INPUT = \
|
|||||||
../../components/driver/include/driver/touch_pad.h \
|
../../components/driver/include/driver/touch_pad.h \
|
||||||
../../components/driver/include/driver/uart.h \
|
../../components/driver/include/driver/uart.h \
|
||||||
../../components/esp_adc_cal/include/esp_adc_cal.h \
|
../../components/esp_adc_cal/include/esp_adc_cal.h \
|
||||||
|
../../components/soc/include/hal/spi_types.h \
|
||||||
../../components/soc/esp32/include/soc/adc_channel.h \
|
../../components/soc/esp32/include/soc/adc_channel.h \
|
||||||
../../components/soc/esp32/include/soc/dac_channel.h \
|
../../components/soc/esp32/include/soc/dac_channel.h \
|
||||||
../../components/soc/esp32/include/soc/touch_channel.h \
|
../../components/soc/esp32/include/soc/touch_channel.h \
|
||||||
|
@ -538,6 +538,7 @@ Display graphics on the 320x240 LCD of WROVER-Kits: :example:`peripherals/spi_ma
|
|||||||
API Reference - SPI Common
|
API Reference - SPI Common
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
.. include:: /_build/inc/spi_types.inc
|
||||||
.. include:: /_build/inc/spi_common.inc
|
.. include:: /_build/inc/spi_common.inc
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
set(COMPONENT_SRCS "decode_image.c"
|
set(COMPONENT_SRCS "pretty_effect.c"
|
||||||
"pretty_effect.c"
|
|
||||||
"spi_master_example_main.c")
|
"spi_master_example_main.c")
|
||||||
|
|
||||||
|
#only esp32 has enough memory to do jpeg decoding
|
||||||
|
if (CONFIG_IDF_TARGET_ESP32)
|
||||||
|
list(APPEND COMPONENT_SRCS "decode_image.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "pretty_effect.h"
|
#include "pretty_effect.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
#include "decode_image.h"
|
#include "decode_image.h"
|
||||||
|
|
||||||
uint16_t **pixels;
|
uint16_t **pixels;
|
||||||
@ -23,6 +26,13 @@ static inline uint16_t get_bgnd_pixel(int x, int y)
|
|||||||
y+=8;
|
y+=8;
|
||||||
return pixels[y][x];
|
return pixels[y][x];
|
||||||
}
|
}
|
||||||
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
//esp32s2beta doesn't have enough memory to hold the decoded image, calculate instead
|
||||||
|
static inline uint16_t get_bgnd_pixel(int x, int y)
|
||||||
|
{
|
||||||
|
return ((x<<3)^(y<<3)^(x*y));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//This variable is used to detect the next frame.
|
//This variable is used to detect the next frame.
|
||||||
@ -55,7 +65,12 @@ void pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t pretty_effect_init()
|
esp_err_t pretty_effect_init()
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
return decode_image(&pixels);
|
return decode_image(&pixels);
|
||||||
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
//esp32s2beta doesn't have enough memory to hold the decoded image, calculate instead
|
||||||
|
return ESP_OK;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@
|
|||||||
before the transaction is sent, the callback will set this line to the correct state.
|
before the transaction is sent, the callback will set this line to the correct state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define LCD_HOST HSPI_HOST
|
||||||
|
#define DMA_CHAN 2
|
||||||
|
|
||||||
#define PIN_NUM_MISO 25
|
#define PIN_NUM_MISO 25
|
||||||
#define PIN_NUM_MOSI 23
|
#define PIN_NUM_MOSI 23
|
||||||
#define PIN_NUM_CLK 19
|
#define PIN_NUM_CLK 19
|
||||||
@ -36,6 +40,19 @@
|
|||||||
#define PIN_NUM_DC 21
|
#define PIN_NUM_DC 21
|
||||||
#define PIN_NUM_RST 18
|
#define PIN_NUM_RST 18
|
||||||
#define PIN_NUM_BCKL 5
|
#define PIN_NUM_BCKL 5
|
||||||
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
#define LCD_HOST SPI2_HOST
|
||||||
|
#define DMA_CHAN LCD_HOST
|
||||||
|
|
||||||
|
#define PIN_NUM_MISO 37
|
||||||
|
#define PIN_NUM_MOSI 35
|
||||||
|
#define PIN_NUM_CLK 36
|
||||||
|
#define PIN_NUM_CS 34
|
||||||
|
|
||||||
|
#define PIN_NUM_DC 4
|
||||||
|
#define PIN_NUM_RST 5
|
||||||
|
#define PIN_NUM_BCKL 6
|
||||||
|
#endif
|
||||||
|
|
||||||
//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
|
//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
|
||||||
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
|
//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
|
||||||
@ -410,10 +427,10 @@ void app_main()
|
|||||||
.pre_cb=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
|
.pre_cb=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
|
||||||
};
|
};
|
||||||
//Initialize the SPI bus
|
//Initialize the SPI bus
|
||||||
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN);
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
//Attach the LCD to the SPI bus
|
//Attach the LCD to the SPI bus
|
||||||
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
|
ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi);
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
//Initialize the LCD
|
//Initialize the LCD
|
||||||
lcd_init(spi);
|
lcd_init(spi);
|
||||||
|
@ -57,6 +57,17 @@ Pins in use. The SPI Master can use the GPIO mux, so feel free to change these i
|
|||||||
#define GPIO_SCLK 15
|
#define GPIO_SCLK 15
|
||||||
#define GPIO_CS 14
|
#define GPIO_CS 14
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define RCV_HOST HSPI_HOST
|
||||||
|
#define DMA_CHAN 2
|
||||||
|
|
||||||
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
#define RCV_HOST SPI2_HOST
|
||||||
|
#define DMA_CHAN RCV_HOST
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
|
//Called after a transaction is queued and ready for pickup by master. We use this to set the handshake line high.
|
||||||
void my_post_setup_cb(spi_slave_transaction_t *trans) {
|
void my_post_setup_cb(spi_slave_transaction_t *trans) {
|
||||||
@ -78,7 +89,9 @@ void app_main()
|
|||||||
spi_bus_config_t buscfg={
|
spi_bus_config_t buscfg={
|
||||||
.mosi_io_num=GPIO_MOSI,
|
.mosi_io_num=GPIO_MOSI,
|
||||||
.miso_io_num=GPIO_MISO,
|
.miso_io_num=GPIO_MISO,
|
||||||
.sclk_io_num=GPIO_SCLK
|
.sclk_io_num=GPIO_SCLK,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
//Configuration for the SPI slave interface
|
//Configuration for the SPI slave interface
|
||||||
@ -106,11 +119,11 @@ void app_main()
|
|||||||
gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
|
gpio_set_pull_mode(GPIO_CS, GPIO_PULLUP_ONLY);
|
||||||
|
|
||||||
//Initialize SPI slave interface
|
//Initialize SPI slave interface
|
||||||
ret=spi_slave_initialize(HSPI_HOST, &buscfg, &slvcfg, 1);
|
ret=spi_slave_initialize(RCV_HOST, &buscfg, &slvcfg, DMA_CHAN);
|
||||||
assert(ret==ESP_OK);
|
assert(ret==ESP_OK);
|
||||||
|
|
||||||
char sendbuf[129]="";
|
WORD_ALIGNED_ATTR char sendbuf[129]="";
|
||||||
char recvbuf[129]="";
|
WORD_ALIGNED_ATTR char recvbuf[129]="";
|
||||||
memset(recvbuf, 0, 33);
|
memset(recvbuf, 0, 33);
|
||||||
spi_slave_transaction_t t;
|
spi_slave_transaction_t t;
|
||||||
memset(&t, 0, sizeof(t));
|
memset(&t, 0, sizeof(t));
|
||||||
@ -130,7 +143,7 @@ void app_main()
|
|||||||
.post_setup_cb callback that is called as soon as a transaction is ready, to let the master know it is free to transfer
|
.post_setup_cb callback that is called as soon as a transaction is ready, to let the master know it is free to transfer
|
||||||
data.
|
data.
|
||||||
*/
|
*/
|
||||||
ret=spi_slave_transmit(HSPI_HOST, &t, portMAX_DELAY);
|
ret=spi_slave_transmit(RCV_HOST, &t, portMAX_DELAY);
|
||||||
|
|
||||||
//spi_slave_transmit does not return until the master has done a transmission, so by here we have sent our data and
|
//spi_slave_transmit does not return until the master has done a transmission, so by here we have sent our data and
|
||||||
//received data from the master. Print it.
|
//received data from the master. Print it.
|
||||||
|
@ -39,12 +39,12 @@
|
|||||||
/*
|
/*
|
||||||
SPI sender (master) example.
|
SPI sender (master) example.
|
||||||
|
|
||||||
This example is supposed to work together with the SPI receiver. It uses the standard SPI pins (MISO, MOSI, SCLK, CS) to
|
This example is supposed to work together with the SPI receiver. It uses the standard SPI pins (MISO, MOSI, SCLK, CS) to
|
||||||
transmit data over in a full-duplex fashion, that is, while the master puts data on the MOSI pin, the slave puts its own
|
transmit data over in a full-duplex fashion, that is, while the master puts data on the MOSI pin, the slave puts its own
|
||||||
data on the MISO pin.
|
data on the MISO pin.
|
||||||
|
|
||||||
This example uses one extra pin: GPIO_HANDSHAKE is used as a handshake pin. The slave makes this pin high as soon as it is
|
This example uses one extra pin: GPIO_HANDSHAKE is used as a handshake pin. The slave makes this pin high as soon as it is
|
||||||
ready to receive/send data. This code connects this line to a GPIO interrupt which gives the rdySem semaphore. The main
|
ready to receive/send data. This code connects this line to a GPIO interrupt which gives the rdySem semaphore. The main
|
||||||
task waits for this semaphore to be given before queueing a transmission.
|
task waits for this semaphore to be given before queueing a transmission.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -58,6 +58,17 @@ Pins in use. The SPI Master can use the GPIO mux, so feel free to change these i
|
|||||||
#define GPIO_SCLK 15
|
#define GPIO_SCLK 15
|
||||||
#define GPIO_CS 14
|
#define GPIO_CS 14
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
|
#define SENDER_HOST HSPI_HOST
|
||||||
|
#define DMA_CHAN 2
|
||||||
|
|
||||||
|
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
|
||||||
|
#define SENDER_HOST SPI2_HOST
|
||||||
|
#define DMA_CHAN SENDER_HOST
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//The semaphore indicating the slave is ready to receive stuff.
|
//The semaphore indicating the slave is ready to receive stuff.
|
||||||
static xQueueHandle rdySem;
|
static xQueueHandle rdySem;
|
||||||
|
|
||||||
@ -132,12 +143,12 @@ void app_main()
|
|||||||
gpio_isr_handler_add(GPIO_HANDSHAKE, gpio_handshake_isr_handler, NULL);
|
gpio_isr_handler_add(GPIO_HANDSHAKE, gpio_handshake_isr_handler, NULL);
|
||||||
|
|
||||||
//Initialize the SPI bus and add the device we want to send stuff to.
|
//Initialize the SPI bus and add the device we want to send stuff to.
|
||||||
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
ret=spi_bus_initialize(SENDER_HOST, &buscfg, DMA_CHAN);
|
||||||
assert(ret==ESP_OK);
|
assert(ret==ESP_OK);
|
||||||
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &handle);
|
ret=spi_bus_add_device(SENDER_HOST, &devcfg, &handle);
|
||||||
assert(ret==ESP_OK);
|
assert(ret==ESP_OK);
|
||||||
|
|
||||||
//Assume the slave is ready for the first transmission: if the slave started up before us, we will not detect
|
//Assume the slave is ready for the first transmission: if the slave started up before us, we will not detect
|
||||||
//positive edge on the handshake line.
|
//positive edge on the handshake line.
|
||||||
xSemaphoreGive(rdySem);
|
xSemaphoreGive(rdySem);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user