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:
Michael (XIAO Xufeng) 2019-06-26 16:45:02 +08:00
commit 1c69db44c9
30 changed files with 1238 additions and 185 deletions

View File

@ -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
*/ */

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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
} }
}; };

View 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, &reg_val);
spi_ll_master_set_clock_by_reg(hw, &reg_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

View File

@ -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 */

View File

@ -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

View File

@ -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))

View File

@ -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;

View File

@ -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

View File

@ -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.

View 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

View File

@ -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.

View File

@ -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
} }

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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 \

View File

@ -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

View File

@ -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 ".")

View File

@ -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
} }

View File

@ -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);

View File

@ -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.

View File

@ -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);