mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spi_master:support octal mode for esp32s2 and esp32s3
Add support for 8-line spi for lcd on esp32s2 and esp32s3 Closes https://github.com/espressif/esp-idf/issues/6371
This commit is contained in:
parent
c81d45280e
commit
8143832041
@ -63,7 +63,10 @@ extern "C"
|
||||
#define SPICOMMON_BUSFLAG_DUAL (1<<6) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
|
||||
#define SPICOMMON_BUSFLAG_WPHD (1<<7) ///< 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.
|
||||
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
#define SPICOMMON_BUSFLAG_IO4_IO7 (1<<8) ///< Check existing of IO4~IO7 pins. Or indicates IO4~IO7 pins initialized.
|
||||
#define SPICOMMON_BUSFLAG_OCTAL (SPICOMMON_BUSFLAG_QUAD|SPICOMMON_BUSFLAG_IO4_IO7) ///< Check existing of MOSI/MISO/WP/HD/SPIIO4/SPIIO5/SPIIO6/SPIIO7 pins as output. Or indicates bus able to work under octal mode.
|
||||
#endif
|
||||
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
|
||||
|
||||
/**
|
||||
@ -95,18 +98,36 @@ typedef spi_common_dma_t spi_dma_chan_t;
|
||||
* @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
|
||||
*/
|
||||
typedef struct {
|
||||
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
|
||||
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) 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 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 max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.
|
||||
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
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
union {
|
||||
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
|
||||
int data0_io_num; ///< GPIO pin for spi data0 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
union {
|
||||
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
|
||||
int data1_io_num; ///< GPIO pin for spi data1 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
int sclk_io_num; ///< GPIO pin for SPI Clock signal, or -1 if not used.
|
||||
union {
|
||||
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal, or -1 if not used.
|
||||
int data2_io_num; ///< GPIO pin for spi data2 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
union {
|
||||
int quadhd_io_num; ///< GPIO pin for HD (Hold) signal, or -1 if not used.
|
||||
int data3_io_num; ///< GPIO pin for spi data3 signal in quad/octal mode, or -1 if not used.
|
||||
};
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
int data4_io_num; ///< GPIO pin for spi data4 signal in octal mode, or -1 if not used.
|
||||
int data5_io_num; ///< GPIO pin for spi data5 signal in octal mode, or -1 if not used.
|
||||
int data6_io_num; ///< GPIO pin for spi data6 signal in octal mode, or -1 if not used.
|
||||
int data7_io_num; ///< GPIO pin for spi data7 signal in octal mode, or -1 if not used.
|
||||
#endif
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4092 if 0 when DMA enabled, or to `SOC_SPI_MAXIMUM_BUFFER_SIZE` if DMA is disabled.
|
||||
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
|
||||
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
|
||||
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
|
||||
* the driver, and their callee functions, should be put in the IRAM.
|
||||
*/
|
||||
} spi_bus_config_t;
|
||||
|
||||
|
||||
|
@ -155,6 +155,8 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
|
||||
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
|
||||
* - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs.
|
||||
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
||||
* - ``SPICOMMON_BUSFLAG_IO4_IO7``: Make sure spi data4 ~ spi data7 are set to valid output GPIOs.
|
||||
* - ``SPICOMMON_BUSFLAG_OCTAL``: Combination of ``SPICOMMON_BUSFLAG_QUAL`` and ``SPICOMMON_BUSFLAG_IO4_IO7``.
|
||||
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
|
||||
* Leave to NULL if not needed.
|
||||
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
|
||||
@ -163,6 +165,8 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
|
||||
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
|
||||
* - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected.
|
||||
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
|
||||
* - ``SPICOMMON_BUSFLAG_IO4_IO7``: The bus has spi data4 ~ spi data7 connected.
|
||||
* - ``SPICOMMON_BUSFLAG_OCTAL``: Combination of ``SPICOMMON_BUSFLAG_QUAL`` and ``SPICOMMON_BUSFLAG_IO4_IO7``.
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
|
@ -104,8 +104,13 @@ typedef struct {
|
||||
#define SPI_TRANS_VARIABLE_CMD (1<<5) ///< Use the ``command_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Use the ``dummy_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
|
||||
#define SPI_TRANS_SET_CD (1<<7) ///< Set the CD pin
|
||||
#define SPI_TRANS_CS_KEEP_ACTIVE (1<<8) ///< Keep CS active after data transfer
|
||||
#define MULTILINE_CMD (1<<9) ///< The number of lines transmitting command is the same as that transmitting data
|
||||
#define MULTILINE_ADDR (1<<10) ///< the number of lines transmitting address is the same as that transmitting data (in dual and quad mode the same as ``SPI_TRANS_MODE_DIOQIO_ADDR``)
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
#define SPI_TRANS_MODE_OCT (1<<11) ///< Transmit/receive data in 8-bit mode
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes.
|
||||
*/
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/soc_pins.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
@ -350,32 +351,113 @@ esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------IO general-------------------------------------------------------//
|
||||
static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
static bool check_iomux_pins_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
|
||||
bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
int io_mux_nums[] = {SPI2_IOMUX_PIN_NUM_MOSI_OCT, SPI2_IOMUX_PIN_NUM_MISO_OCT, SPI2_IOMUX_PIN_NUM_WP_OCT, SPI2_IOMUX_PIN_NUM_HD_OCT,
|
||||
SPI2_IOMUX_PIN_NUM_CLK_OCT, SPI2_IOMUX_PIN_NUM_IO4_OCT, SPI2_IOMUX_PIN_NUM_IO5_OCT, SPI2_IOMUX_PIN_NUM_IO6_OCT, SPI2_IOMUX_PIN_NUM_IO7_OCT};
|
||||
for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] >= 0 && io_nums[i] != io_mux_nums[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool check_iomux_pins_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (bus_config->sclk_io_num>=0 &&
|
||||
bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->quadwp_io_num>=0 &&
|
||||
bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->quadhd_io_num>=0 &&
|
||||
bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->mosi_io_num >= 0 &&
|
||||
bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (bus_config->miso_io_num>=0 &&
|
||||
bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
//Check if SPI pins could be routed to iomux.
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
//The io mux pins available for Octal mode is not the same as the ones we use for non-Octal mode.
|
||||
if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
return check_iomux_pins_oct(host, bus_config);
|
||||
}
|
||||
#endif
|
||||
return check_iomux_pins_quad(host, bus_config);
|
||||
}
|
||||
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
static void bus_iomux_pins_set_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
assert(host == SPI2_HOST);
|
||||
int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
|
||||
bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
int io_signals[] = {spi_periph_signal[host].spid_in, spi_periph_signal[host].spiq_in, spi_periph_signal[host].spiwp_in,
|
||||
spi_periph_signal[host].spihd_in,spi_periph_signal[host].spiclk_in, spi_periph_signal[host].spid4_out,
|
||||
spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid7_out};
|
||||
for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] > 0) {
|
||||
gpio_iomux_in(io_nums[i], io_signals[i]);
|
||||
// In Octal mode use function channel 2
|
||||
gpio_iomux_out(io_nums[i], SPI2_FUNC_NUM_OCT, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
static void bus_iomux_pins_set_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
||||
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
||||
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
||||
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
||||
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void bus_iomux_pins_set(spi_host_device_t host, const spi_bus_config_t* bus_config)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
|
||||
bus_iomux_pins_set_oct(host, bus_config);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bus_iomux_pins_set_quad(host, bus_config);
|
||||
}
|
||||
|
||||
/*
|
||||
Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a
|
||||
bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
|
||||
@ -383,6 +465,17 @@ it should be able to be initialized.
|
||||
*/
|
||||
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o)
|
||||
{
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
// In the driver of previous version, spi data4 ~ spi data7 are not in spi_bus_config_t struct. So the new-added pins come as 0
|
||||
// if they are not really set. Add this boolean variable to check if the user has set spi data4 ~spi data7 pins .
|
||||
bool io4_7_is_blank = !bus_config->data4_io_num && !bus_config->data5_io_num && !bus_config->data6_io_num && !bus_config->data7_io_num;
|
||||
// This boolean variable specifies if user sets pins used for octal mode (users can set spi data4 ~ spi data7 to -1).
|
||||
bool io4_7_enabled = !io4_7_is_blank && bus_config->data4_io_num >= 0 && bus_config->data5_io_num >= 0 &&
|
||||
bus_config->data6_io_num >= 0 && bus_config->data7_io_num >= 0;
|
||||
SPI_CHECK((flags & SPICOMMON_BUSFLAG_MASTER) || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Octal SPI mode / OPI mode only works when SPI is used as Master", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(host == SPI2_HOST || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Only SPI2 supports Octal SPI mode / OPI mode", ESP_ERR_INVALID_ARG);
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
uint32_t temp_flag = 0;
|
||||
|
||||
bool miso_need_output;
|
||||
@ -414,13 +507,36 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
if (bus_config->quadhd_io_num>=0) {
|
||||
SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
const bool io4_need_output = true;
|
||||
const bool io5_need_output = true;
|
||||
const bool io6_need_output = true;
|
||||
const bool io7_need_output = true;
|
||||
// set flags for OCTAL mode according to the existence of spi data4 ~ spi data7
|
||||
if (io4_7_enabled) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_IO4_IO7;
|
||||
if (bus_config->data4_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data4_io_num, "spi data4", io4_need_output);
|
||||
}
|
||||
if (bus_config->data5_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data5_io_num, "spi data5", io5_need_output);
|
||||
}
|
||||
if (bus_config->data6_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data6_io_num, "spi data6", io6_need_output);
|
||||
}
|
||||
if (bus_config->data7_io_num >= 0) {
|
||||
SPI_CHECK_PIN(bus_config->data7_io_num, "spi data7", io7_need_output);
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
|
||||
//set flags for QUAD mode according to the existence of wp and hd
|
||||
if (bus_config->quadhd_io_num >= 0 && bus_config->quadwp_io_num >= 0) temp_flag |= SPICOMMON_BUSFLAG_WPHD;
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MOSI;
|
||||
SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
|
||||
}
|
||||
if (bus_config->miso_io_num>=0) {
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
temp_flag |= SPICOMMON_BUSFLAG_MISO;
|
||||
SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
|
||||
}
|
||||
@ -443,12 +559,29 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
|
||||
if (missing_flag != 0) {
|
||||
//check pins existence
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_SCLK) ESP_LOGE(SPI_TAG, "sclk pin required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MOSI) ESP_LOGE(SPI_TAG, "mosi 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_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_SCLK) {
|
||||
ESP_LOGE(SPI_TAG, "sclk pin required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_MOSI) {
|
||||
ESP_LOGE(SPI_TAG, "mosi 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_WPHD) {
|
||||
ESP_LOGE(SPI_TAG, "both wp and hd required.");
|
||||
}
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) {
|
||||
ESP_LOGE(SPI_TAG, "not using iomux pins");
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (missing_flag & SPICOMMON_BUSFLAG_IO4_IO7) {
|
||||
ESP_LOGE(SPI_TAG, "spi data4 ~ spi data7 are required.");
|
||||
}
|
||||
#endif
|
||||
SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
@ -456,27 +589,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
//All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
|
||||
//out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
|
||||
if (bus_config->mosi_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
|
||||
gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->miso_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
|
||||
gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadwp_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
|
||||
gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->quadhd_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
|
||||
gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
if (bus_config->sclk_io_num >= 0) {
|
||||
gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
|
||||
gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
|
||||
}
|
||||
temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
|
||||
bus_iomux_pins_set(host, bus_config);
|
||||
} else {
|
||||
//Use GPIO matrix
|
||||
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
|
||||
@ -537,6 +650,26 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
|
||||
#endif
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (flags & SPICOMMON_BUSFLAG_OCTAL) {
|
||||
int io_nums[] = {bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
|
||||
uint8_t io_signals[4][2] = {{spi_periph_signal[host].spid4_out, spi_periph_signal[host].spid4_in},
|
||||
{spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid5_in},
|
||||
{spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid6_in},
|
||||
{spi_periph_signal[host].spid7_out, spi_periph_signal[host].spid7_in}};
|
||||
for (size_t i = 0; i < sizeof(io_nums) / sizeof(io_nums[0]); i++) {
|
||||
if (io_nums[i] >= 0) {
|
||||
gpio_set_direction(io_nums[i], GPIO_MODE_INPUT_OUTPUT);
|
||||
esp_rom_gpio_connect_out_signal(io_nums[i], io_signals[i][0], false, false);
|
||||
esp_rom_gpio_connect_in_signal(io_nums[i], io_signals[i][1], false);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_nums[i]]);
|
||||
#endif
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[io_nums[i]], FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
}
|
||||
|
||||
if (flags_o) *flags_o = temp_flag;
|
||||
|
@ -530,13 +530,18 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
|
||||
hal_trans.cmd = trans->cmd;
|
||||
hal_trans.addr = trans->addr;
|
||||
hal_trans.cs_keep_active = (trans->flags & SPI_TRANS_CS_KEEP_ACTIVE) ? 1 : 0;
|
||||
//Set up QIO/DIO if needed
|
||||
hal_trans.io_mode = (trans->flags & SPI_TRANS_MODE_DIO ?
|
||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_DIO : SPI_LL_IO_MODE_DUAL) :
|
||||
(trans->flags & SPI_TRANS_MODE_QIO ?
|
||||
(trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR ? SPI_LL_IO_MODE_QIO : SPI_LL_IO_MODE_QUAD) :
|
||||
SPI_LL_IO_MODE_NORMAL
|
||||
));
|
||||
|
||||
//Set up OIO/QIO/DIO if needed
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
hal_trans.line_mode.data_lines = (trans->flags & SPI_TRANS_MODE_DIO) ? 2 :
|
||||
(trans->flags & SPI_TRANS_MODE_QIO) ? 4 :
|
||||
(trans->flags & SPI_TRANS_MODE_OCT) ? 8 : 1;
|
||||
#else
|
||||
hal_trans.line_mode.data_lines = (trans->flags & SPI_TRANS_MODE_DIO) ? 2 :
|
||||
(trans->flags & SPI_TRANS_MODE_QIO) ? 4 : 1;
|
||||
#endif
|
||||
hal_trans.line_mode.addr_lines = (trans->flags & (SPI_TRANS_MODE_DIOQIO_ADDR | MULTILINE_ADDR)) ? hal_trans.line_mode.data_lines : 1;
|
||||
hal_trans.line_mode.cmd_lines = (trans->flags & MULTILINE_CMD) ? hal_trans.line_mode.data_lines : 1;
|
||||
|
||||
if (trans->flags & SPI_TRANS_VARIABLE_CMD) {
|
||||
hal_trans.cmd_bits = ((spi_transaction_ext_t *)trans)->command_bits;
|
||||
@ -686,8 +691,13 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
|
||||
SPI_CHECK(trans_desc->rxlength <= bus_attr->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(is_half_duplex || trans_desc->rxlength <= trans_desc->length, "rx length > tx length in full duplex mode", ESP_ERR_INVALID_ARG);
|
||||
//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)) && !is_half_duplex), "incompatible iface params", ESP_ERR_INVALID_ARG);
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
SPI_CHECK(!(host->id == SPI3_HOST && trans_desc->flags & SPI_TRANS_MODE_OCT), "SPI3 does not support octal mode", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible interface parameters", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && !is_half_duplex), "incompatible interface parameters", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "incompatible interface parameters", ESP_ERR_INVALID_ARG);
|
||||
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "incompatible interface parameters", ESP_ERR_INVALID_ARG);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
SPI_CHECK(!is_half_duplex || !bus_attr->dma_enabled || !rx_enabled || !tx_enabled, "SPI half duplex mode does not support using DMA with both MOSI and MISO phases.", ESP_ERR_INVALID_ARG );
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
|
@ -80,6 +80,7 @@ typedef struct {
|
||||
struct {
|
||||
unsigned int dc_as_cmd_phase: 1; /*!< D/C line value is encoded into SPI transaction command phase */
|
||||
unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */
|
||||
unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */
|
||||
} flags;
|
||||
} esp_lcd_panel_io_spi_config_t;
|
||||
|
||||
|
@ -45,6 +45,7 @@ typedef struct {
|
||||
struct {
|
||||
unsigned int dc_as_cmd_phase: 1; // D/C line value is encoded into SPI transaction command phase
|
||||
unsigned int dc_data_level: 1; // Indicates the level of DC line when tranfering data
|
||||
unsigned int octal_mode: 1; // Indicates whether the transmitting is enabled with octal mode (8 data lines)
|
||||
} flags;
|
||||
lcd_spi_trans_descriptor_t trans_pool[]; // Transaction pool
|
||||
} esp_lcd_panel_io_spi_t;
|
||||
@ -60,6 +61,9 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
|
||||
ESP_GOTO_ON_FALSE(spi_panel_io, ESP_ERR_NO_MEM, err, TAG, "no mem for spi panel io");
|
||||
|
||||
spi_device_interface_config_t devcfg = {
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
.flags = SPI_DEVICE_HALFDUPLEX, // lcd driver only use one transfer direction, so half duplex is enough.
|
||||
#endif
|
||||
.clock_speed_hz = io_config->pclk_hz,
|
||||
.mode = io_config->spi_mode,
|
||||
.spics_io_num = io_config->cs_gpio_num,
|
||||
@ -82,6 +86,7 @@ esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_p
|
||||
|
||||
spi_panel_io->flags.dc_as_cmd_phase = io_config->flags.dc_as_cmd_phase;
|
||||
spi_panel_io->flags.dc_data_level = !io_config->flags.dc_low_on_data;
|
||||
spi_panel_io->flags.octal_mode = io_config->flags.octal_mode;
|
||||
spi_panel_io->on_color_trans_done = io_config->on_color_trans_done;
|
||||
spi_panel_io->lcd_cmd_bits = io_config->lcd_cmd_bits;
|
||||
spi_panel_io->lcd_param_bits = io_config->lcd_param_bits;
|
||||
@ -147,6 +152,11 @@ static esp_err_t panel_io_spi_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
||||
lcd_trans->flags.dc_gpio_level = !spi_panel_io->flags.dc_data_level; // set D/C line to command mode
|
||||
lcd_trans->base.length = spi_panel_io->lcd_cmd_bits;
|
||||
lcd_trans->base.tx_buffer = &lcd_cmd;
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (spi_panel_io->flags.octal_mode) {
|
||||
lcd_trans->base.flags |= (MULTILINE_CMD | MULTILINE_ADDR | SPI_TRANS_MODE_OCT);
|
||||
}
|
||||
#endif
|
||||
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||
lcd_trans->base.cmd = !spi_panel_io->flags.dc_data_level;
|
||||
}
|
||||
@ -192,6 +202,11 @@ static esp_err_t panel_io_spi_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons
|
||||
if (spi_panel_io->flags.dc_as_cmd_phase) { // encoding DC value to SPI command phase when necessary
|
||||
lcd_trans->base.cmd = !spi_panel_io->flags.dc_data_level;
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (spi_panel_io->flags.octal_mode) {
|
||||
lcd_trans->base.flags |= (MULTILINE_CMD | MULTILINE_ADDR | SPI_TRANS_MODE_OCT);
|
||||
}
|
||||
#endif
|
||||
// command is short, using polling mode
|
||||
ret = spi_device_polling_transmit(spi_panel_io->spi_dev, &lcd_trans->base);
|
||||
ESP_GOTO_ON_ERROR(ret, err, TAG, "spi transmit (polling) command failed");
|
||||
|
@ -12,21 +12,27 @@
|
||||
|
||||
#define TEST_LCD_H_RES (240)
|
||||
#define TEST_LCD_V_RES (280)
|
||||
#define TEST_SPI_CLK_GPIO (2)
|
||||
#define TEST_SPI_MOSI_GPIO (4)
|
||||
#define TEST_LCD_CLK_GPIO (2)
|
||||
#define TEST_LCD_DATA0_GPIO (4)
|
||||
#define TEST_LCD_RST_GPIO (5)
|
||||
#define TEST_LCD_DC_GPIO (18)
|
||||
#define TEST_LCD_BK_LIGHT_GPIO (19)
|
||||
#define TEST_SPI_CS_GPIO (0)
|
||||
#define TEST_LCD_CS_GPIO (0)
|
||||
#define TEST_LCD_DATA1_GPIO (7)
|
||||
#define TEST_LCD_DATA2_GPIO (8)
|
||||
#define TEST_LCD_DATA3_GPIO (9)
|
||||
#define TEST_LCD_DATA4_GPIO (10)
|
||||
#define TEST_LCD_DATA5_GPIO (11)
|
||||
#define TEST_LCD_DATA6_GPIO (12)
|
||||
#define TEST_LCD_DATA7_GPIO (13)
|
||||
#define TEST_SPI_HOST_ID (1)
|
||||
#define TEST_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
|
||||
|
||||
TEST_CASE("lcd panel with spi interface (st7789)", "[lcd]")
|
||||
{
|
||||
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
|
||||
uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA);
|
||||
TEST_ASSERT_NOT_NULL(img);
|
||||
typedef bool (*trans_done_callback)(esp_lcd_panel_io_handle_t, void *, void *);
|
||||
|
||||
static void lcd_initialize(bool is_8_line_lcd, esp_lcd_panel_io_handle_t *io_handle, esp_lcd_panel_handle_t *panel_handle,
|
||||
int spi_mode, trans_done_callback on_color_trans_done, void *user_data)
|
||||
{
|
||||
gpio_config_t bk_gpio_config = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
|
||||
@ -35,33 +41,57 @@ TEST_CASE("lcd panel with spi interface (st7789)", "[lcd]")
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = -1,
|
||||
.mosi_io_num = TEST_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = TEST_SPI_CLK_GPIO,
|
||||
.mosi_io_num = TEST_LCD_DATA0_GPIO,
|
||||
.sclk_io_num = TEST_LCD_CLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = TEST_LCD_H_RES * TEST_LCD_V_RES * sizeof(uint16_t)
|
||||
};
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (is_8_line_lcd) {
|
||||
buscfg.data1_io_num = TEST_LCD_DATA1_GPIO;
|
||||
buscfg.data2_io_num = TEST_LCD_DATA2_GPIO;
|
||||
buscfg.data3_io_num = TEST_LCD_DATA3_GPIO;
|
||||
buscfg.data4_io_num = TEST_LCD_DATA4_GPIO;
|
||||
buscfg.data5_io_num = TEST_LCD_DATA5_GPIO;
|
||||
buscfg.data6_io_num = TEST_LCD_DATA6_GPIO;
|
||||
buscfg.data7_io_num = TEST_LCD_DATA7_GPIO;
|
||||
buscfg.flags = SPICOMMON_BUSFLAG_OCTAL;
|
||||
}
|
||||
#endif //SOC_SPI_SUPPORT_OCT
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST_ID, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = TEST_LCD_DC_GPIO,
|
||||
.cs_gpio_num = TEST_SPI_CS_GPIO,
|
||||
.cs_gpio_num = TEST_LCD_CS_GPIO,
|
||||
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
|
||||
.spi_mode = 0,
|
||||
.spi_mode = spi_mode,
|
||||
.trans_queue_depth = 10,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.on_color_trans_done = on_color_trans_done,
|
||||
.user_data = user_data
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, &io_handle));
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
if (is_8_line_lcd) {
|
||||
io_config.flags.octal_mode = 1;
|
||||
}
|
||||
#endif
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, io_handle));
|
||||
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_LCD_RST_GPIO,
|
||||
.color_space = ESP_LCD_COLOR_SPACE_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_new_panel_st7789(*io_handle, &panel_config, panel_handle));
|
||||
}
|
||||
|
||||
static void lcd_panel_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle)
|
||||
{
|
||||
#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t))
|
||||
uint8_t *img = heap_caps_malloc(TEST_IMG_SIZE, MALLOC_CAP_DMA);
|
||||
TEST_ASSERT_NOT_NULL(img);
|
||||
|
||||
// turn off backlight
|
||||
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
|
||||
@ -80,7 +110,8 @@ TEST_CASE("lcd panel with spi interface (st7789)", "[lcd]")
|
||||
memset(img, color_byte, TEST_IMG_SIZE);
|
||||
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start + 100, y_start + 100, img);
|
||||
}
|
||||
esp_lcd_panel_disp_off(panel_handle, true); // turn off screen
|
||||
// turn off screen
|
||||
esp_lcd_panel_disp_off(panel_handle, true);
|
||||
TEST_ESP_OK(esp_lcd_panel_del(panel_handle));
|
||||
TEST_ESP_OK(esp_lcd_panel_io_del(io_handle));
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST_ID));
|
||||
@ -89,6 +120,24 @@ TEST_CASE("lcd panel with spi interface (st7789)", "[lcd]")
|
||||
#undef TEST_IMG_SIZE
|
||||
}
|
||||
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
TEST_CASE("lcd panel with 8-line spi interface (st7789)", "[lcd]")
|
||||
{
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
lcd_initialize(true, &io_handle, &panel_handle, 3, NULL, NULL);
|
||||
lcd_panel_test(io_handle, panel_handle);
|
||||
}
|
||||
#endif // SOC_SPI_SUPPORT_OCT
|
||||
|
||||
TEST_CASE("lcd panel with 1-line spi interface (st7789)", "[lcd]")
|
||||
{
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
lcd_initialize(false, &io_handle, &panel_handle, 0, NULL, NULL);
|
||||
lcd_panel_test(io_handle, panel_handle);
|
||||
}
|
||||
|
||||
// The following test shows a porting example of LVGL GUI library
|
||||
// To run the LVGL tests, you need to clone the LVGL library into components directory firstly
|
||||
#if CONFIG_LV_USE_USER_DATA
|
||||
@ -101,50 +150,10 @@ static bool notify_lvgl_ready_to_flush(esp_lcd_panel_io_handle_t panel_io, void
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("lvgl gui with spi interface (st7789)", "[lcd][lvgl][ignore]")
|
||||
static void lvgl_gui_test(esp_lcd_panel_io_handle_t io_handle, esp_lcd_panel_handle_t panel_handle, lv_disp_t **disp)
|
||||
{
|
||||
// initialize LVGL graphics library
|
||||
lv_disp_t *disp = NULL;
|
||||
lv_init();
|
||||
|
||||
gpio_config_t bk_gpio_config = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << TEST_LCD_BK_LIGHT_GPIO
|
||||
};
|
||||
TEST_ESP_OK(gpio_config(&bk_gpio_config));
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = -1,
|
||||
.mosi_io_num = TEST_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = TEST_SPI_CLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = TEST_LCD_H_RES * TEST_LCD_V_RES * 2
|
||||
};
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST_ID, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.dc_gpio_num = TEST_LCD_DC_GPIO,
|
||||
.cs_gpio_num = TEST_SPI_CS_GPIO,
|
||||
.pclk_hz = TEST_LCD_PIXEL_CLOCK_HZ,
|
||||
.spi_mode = 0,
|
||||
.trans_queue_depth = 10,
|
||||
.on_color_trans_done = notify_lvgl_ready_to_flush,
|
||||
.user_data = &disp, // we must use "address of disp" here, since the disp object has not been allocated
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)TEST_SPI_HOST_ID, &io_config, &io_handle));
|
||||
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.reset_gpio_num = TEST_LCD_RST_GPIO,
|
||||
.color_space = ESP_LCD_COLOR_SPACE_RGB,
|
||||
.bits_per_pixel = 16,
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
|
||||
|
||||
// turn off backlight
|
||||
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 0);
|
||||
esp_lcd_panel_reset(panel_handle);
|
||||
@ -155,7 +164,28 @@ TEST_CASE("lvgl gui with spi interface (st7789)", "[lcd][lvgl][ignore]")
|
||||
// turn on backlight
|
||||
gpio_set_level(TEST_LCD_BK_LIGHT_GPIO, 1);
|
||||
|
||||
test_lvgl_task_loop(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES, &disp);
|
||||
test_lvgl_task_loop(panel_handle, TEST_LCD_H_RES, TEST_LCD_V_RES, disp);
|
||||
}
|
||||
#if SOC_SPI_SUPPORT_OCT
|
||||
TEST_CASE("lvgl gui with 8-line spi interface (st7789)", "[lcd][lvgl][ignore]")
|
||||
{
|
||||
lv_disp_t *disp = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
lcd_initialize(true, &io_handle, &panel_handle, 3, notify_lvgl_ready_to_flush, &disp);
|
||||
|
||||
lvgl_gui_test(io_handle, panel_handle, &disp);
|
||||
}
|
||||
#endif // SOC_SPI_SUPPORT_OCT
|
||||
|
||||
TEST_CASE("lvgl gui with 1-line spi interface (st7789)", "[lcd][lvgl][ignore]")
|
||||
{
|
||||
lv_disp_t *disp = NULL;
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
esp_lcd_panel_handle_t panel_handle = NULL;
|
||||
lcd_initialize(false, &io_handle, &panel_handle, 0, notify_lvgl_ready_to_flush, &disp);
|
||||
|
||||
lvgl_gui_test(io_handle, panel_handle, &disp);
|
||||
}
|
||||
|
||||
#endif // CONFIG_LV_USE_USER_DATA
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "esp32/rom/lldesc.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -37,6 +38,9 @@ extern "C" {
|
||||
#define SPI_LL_DMA_FIFO_RST_MASK (SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_EN | SPI_SLV_WR_STA_DONE | SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE | SPI_SLV_RD_BUF_DONE)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_DUAL | SPI_FREAD_QUAD | SPI_FREAD_DIO | SPI_FREAD_QIO)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_DUAL | SPI_FWRITE_QUAD | SPI_FWRITE_DIO | SPI_FWRITE_QIO)
|
||||
/// 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))
|
||||
/// This is the expected clock frequency
|
||||
@ -53,16 +57,6 @@ typedef uint32_t spi_ll_clock_val_t;
|
||||
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA.
|
||||
typedef spi_dev_t spi_dma_dev_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;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Control
|
||||
*----------------------------------------------------------------------------*/
|
||||
@ -449,37 +443,50 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
* Configure the SPI transaction line mode for the master to use.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_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;
|
||||
hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
if (line_mode.cmd_lines > 1) {
|
||||
abort();
|
||||
}
|
||||
switch (line_mode.data_lines) {
|
||||
case 2:
|
||||
if (line_mode.addr_lines == 1) {
|
||||
// 1-line-cmd + 1-line-addr + 2-line-data
|
||||
hw->ctrl.fread_dual = 1;
|
||||
hw->user.fwrite_dual = 1;
|
||||
} else if (line_mode.addr_lines == 2) {
|
||||
// 1-line-cmd + 2-line-addr + 2-line-data
|
||||
hw->ctrl.fread_dio = 1;
|
||||
hw->user.fwrite_dio = 1;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
hw->ctrl.fastrd_mode = 1;
|
||||
break;
|
||||
case 4:
|
||||
if (line_mode.addr_lines == 1) {
|
||||
// 1-line-cmd + 1-line-addr + 4-line-data
|
||||
hw->ctrl.fread_quad = 1;
|
||||
hw->user.fwrite_quad = 1;
|
||||
} else if (line_mode.addr_lines == 4) {
|
||||
// 1-line-cmd + 4-line-addr + 4-line-data
|
||||
hw->ctrl.fread_qio = 1;
|
||||
hw->user.fwrite_qio = 1;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
hw->ctrl.fastrd_mode = 1;
|
||||
break;
|
||||
default:
|
||||
// 1-line-cmd + 1-line-addr + 1-line-data
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -37,6 +38,9 @@ extern "C" {
|
||||
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
/// 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))
|
||||
/// This is the expected clock frequency
|
||||
@ -51,15 +55,6 @@ extern "C" {
|
||||
typedef uint32_t spi_ll_clock_val_t;
|
||||
typedef spi_dev_t spi_dma_dev_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;
|
||||
|
||||
// Type definition of all supported interrupts
|
||||
typedef enum {
|
||||
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
||||
@ -540,41 +535,23 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
* Configure the SPI transaction line mode for the master to use.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode)
|
||||
{
|
||||
if (io_mode == SPI_LL_IO_MODE_DIO || io_mode == SPI_LL_IO_MODE_DUAL) {
|
||||
hw->ctrl.fcmd_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.fread_dual = 1;
|
||||
hw->user.fwrite_dual = 1;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
} else if (io_mode == SPI_LL_IO_MODE_QIO || io_mode == SPI_LL_IO_MODE_QUAD) {
|
||||
hw->ctrl.fcmd_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.fread_quad = 1;
|
||||
hw->user.fwrite_quad = 1;
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
} else {
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
}
|
||||
hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
hw->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
hw->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -37,6 +38,9 @@ extern "C" {
|
||||
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
/// 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))
|
||||
/// This is the expected clock frequency
|
||||
@ -51,15 +55,6 @@ extern "C" {
|
||||
typedef uint32_t spi_ll_clock_val_t;
|
||||
typedef spi_dev_t spi_dma_dev_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;
|
||||
|
||||
// Type definition of all supported interrupts
|
||||
typedef enum {
|
||||
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
||||
@ -538,41 +533,23 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
* Configure the SPI transaction line mode for the master to use.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode)
|
||||
{
|
||||
if (io_mode == SPI_LL_IO_MODE_DIO || io_mode == SPI_LL_IO_MODE_DUAL) {
|
||||
hw->ctrl.fcmd_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.fread_dual = 1;
|
||||
hw->user.fwrite_dual = 1;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
} else if (io_mode == SPI_LL_IO_MODE_QIO || io_mode == SPI_LL_IO_MODE_QUAD) {
|
||||
hw->ctrl.fcmd_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.fread_quad = 1;
|
||||
hw->user.fwrite_quad = 1;
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
} else {
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
}
|
||||
hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
hw->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
hw->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -39,6 +40,10 @@ extern "C" {
|
||||
#define SPI_LL_DMA_FIFO_RST_MASK (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)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_OCT | SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_OCT | \
|
||||
SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_OCT | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_OCT | SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
/// 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))
|
||||
/// This is the expected clock frequency
|
||||
@ -55,15 +60,6 @@ typedef uint32_t spi_ll_clock_val_t;
|
||||
//On ESP32-S2 and earlier chips, DMA registers are part of SPI registers. So set the registers of SPI peripheral to control DMA.
|
||||
typedef spi_dev_t spi_dma_dev_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;
|
||||
|
||||
/// Type definition of all supported interrupts
|
||||
typedef enum {
|
||||
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
||||
@ -508,41 +504,27 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
* Configure the SPI transaction line mode for the master to use.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode)
|
||||
{
|
||||
if (io_mode == SPI_LL_IO_MODE_DIO || io_mode == SPI_LL_IO_MODE_DUAL) {
|
||||
hw->ctrl.fcmd_dual= (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_dual= (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.fread_dual=1;
|
||||
hw->user.fwrite_dual=1;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
} else if (io_mode == SPI_LL_IO_MODE_QIO || io_mode == SPI_LL_IO_MODE_QUAD) {
|
||||
hw->ctrl.fcmd_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.fread_quad=1;
|
||||
hw->user.fwrite_quad=1;
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
} else {
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
}
|
||||
hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
hw->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
hw->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
hw->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
hw->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
hw->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
hw->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
static inline void spi_ll_slave_set_seg_mode(spi_dev_t *hw, bool seg_trans)
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -37,6 +38,11 @@ extern "C" {
|
||||
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_OCT | SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_OCT | \
|
||||
SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_OCT | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_OCT | SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
|
||||
/// 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))
|
||||
/// This is the expected clock frequency
|
||||
@ -51,15 +57,6 @@ extern "C" {
|
||||
typedef uint32_t spi_ll_clock_val_t;
|
||||
typedef spi_dev_t spi_dma_dev_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;
|
||||
|
||||
// Type definition of all supported interrupts
|
||||
typedef enum {
|
||||
SPI_LL_INTR_TRANS_DONE = BIT(0), ///< A transaction has done
|
||||
@ -540,41 +537,27 @@ static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
* Configure the SPI transaction line mode for the master to use.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode SPI transaction line mode to use, see ``spi_line_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t line_mode)
|
||||
{
|
||||
if (io_mode == SPI_LL_IO_MODE_DIO || io_mode == SPI_LL_IO_MODE_DUAL) {
|
||||
hw->ctrl.fcmd_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_dual = (io_mode == SPI_LL_IO_MODE_DIO) ? 1 : 0;
|
||||
hw->ctrl.fread_dual = 1;
|
||||
hw->user.fwrite_dual = 1;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
} else if (io_mode == SPI_LL_IO_MODE_QIO || io_mode == SPI_LL_IO_MODE_QUAD) {
|
||||
hw->ctrl.fcmd_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.faddr_quad = (io_mode == SPI_LL_IO_MODE_QIO) ? 1 : 0;
|
||||
hw->ctrl.fread_quad = 1;
|
||||
hw->user.fwrite_quad = 1;
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
} else {
|
||||
hw->ctrl.fcmd_dual = 0;
|
||||
hw->ctrl.faddr_dual = 0;
|
||||
hw->ctrl.fread_dual = 0;
|
||||
hw->user.fwrite_dual = 0;
|
||||
hw->ctrl.fcmd_quad = 0;
|
||||
hw->ctrl.faddr_quad = 0;
|
||||
hw->ctrl.fread_quad = 0;
|
||||
hw->user.fwrite_quad = 0;
|
||||
}
|
||||
hw->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
hw->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
hw->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
hw->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
hw->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
hw->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
hw->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
hw->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
hw->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
hw->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <esp_err.h>
|
||||
#include "soc/lldesc.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/spi_types.h"
|
||||
|
||||
/**
|
||||
* Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration
|
||||
@ -100,7 +101,7 @@ typedef struct {
|
||||
uint64_t addr; ///< Address value to be sent
|
||||
uint8_t *send_buffer; ///< Data to be sent
|
||||
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
|
||||
spi_ll_io_mode_t io_mode; ///< IO mode of the master
|
||||
spi_line_mode_t line_mode; ///< SPI line mode of this transaction
|
||||
int cs_keep_active; ///< Keep CS active after transaction
|
||||
} spi_hal_trans_config_t;
|
||||
|
||||
|
@ -45,6 +45,15 @@ typedef enum {
|
||||
} spi_event_t;
|
||||
FLAG_ATTR(spi_event_t)
|
||||
|
||||
/**
|
||||
* @brief Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char cmd_lines; ///< The line width of command phase, e.g. 2-line-cmd-phase.
|
||||
unsigned char addr_lines; ///< The line width of address phase, e.g. 1-line-addr-phase.
|
||||
unsigned char data_lines; ///< The line width of data phase, e.g. 4-line-data-phase.
|
||||
} spi_line_mode_t;
|
||||
|
||||
|
||||
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
|
||||
|
||||
|
@ -66,8 +66,8 @@ void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *dev
|
||||
spi_ll_clear_int_stat(hal->hw);
|
||||
//We should be done with the transmission.
|
||||
HAL_ASSERT(spi_ll_get_running_cmd(hw) == 0);
|
||||
|
||||
spi_ll_master_set_io_mode(hw, trans->io_mode);
|
||||
//set transaction line mode
|
||||
spi_ll_master_set_line_mode(hw, trans->line_mode);
|
||||
|
||||
int extra_dummy = 0;
|
||||
//when no_dummy is not set and in half-duplex mode, sets the dummy bit if RX phase exist
|
||||
|
@ -218,6 +218,7 @@
|
||||
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
|
||||
|
||||
#define SOC_MEMSPI_IS_INDEPENDENT 1
|
||||
#define SOC_SPI_SUPPORT_OCT 1
|
||||
|
||||
/*-------------------------- SYSTIMER CAPS ----------------------------------*/
|
||||
#define SOC_SYSTIMER_COUNTER_NUM (1) // Number of counter units
|
||||
|
@ -22,21 +22,37 @@
|
||||
#define SPI_IOMUX_PIN_NUM_MISO 31
|
||||
#define SPI_IOMUX_PIN_NUM_WP 28
|
||||
|
||||
#define SPI2_FUNC_NUM FSPI_FUNC_NUM
|
||||
#define SPI2_IOMUX_PIN_NUM_HD FSPI_IOMUX_PIN_NUM_HD
|
||||
#define SPI2_IOMUX_PIN_NUM_CS FSPI_IOMUX_PIN_NUM_CS
|
||||
#define SPI2_IOMUX_PIN_NUM_MOSI FSPI_IOMUX_PIN_NUM_MOSI
|
||||
#define SPI2_IOMUX_PIN_NUM_CLK FSPI_IOMUX_PIN_NUM_CLK
|
||||
#define SPI2_IOMUX_PIN_NUM_MISO FSPI_IOMUX_PIN_NUM_MISO
|
||||
#define SPI2_IOMUX_PIN_NUM_WP FSPI_IOMUX_PIN_NUM_WP
|
||||
// There are 2 sets of GPIO pins which could be routed to FSPICS0, FSPICLK, FSPID, FSPIQ, FSPIHD, FSPIWP.
|
||||
// However, there is only one set of GPIO pins which could be routed to FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7.
|
||||
// As default (when we are not going to use Octal SPI), we make use of SPI2_FUNC_NUM to route one of the 2 sets of GPIO pins to FSPICS0 ~ FSPIWP as follows.
|
||||
#define SPI2_FUNC_NUM 4
|
||||
#define SPI2_IOMUX_PIN_NUM_HD 9
|
||||
#define SPI2_IOMUX_PIN_NUM_CS 10
|
||||
#define SPI2_IOMUX_PIN_NUM_MOSI 11
|
||||
#define SPI2_IOMUX_PIN_NUM_CLK 12
|
||||
#define SPI2_IOMUX_PIN_NUM_MISO 13
|
||||
#define SPI2_IOMUX_PIN_NUM_WP 14
|
||||
|
||||
// When using Octal SPI, we make use of SPI2_FUNC_NUM_OCT to route them as follows.
|
||||
#define SPI2_FUNC_NUM_OCT 2
|
||||
#define SPI2_IOMUX_PIN_NUM_HD_OCT 33
|
||||
#define SPI2_IOMUX_PIN_NUM_CS_OCT 34
|
||||
#define SPI2_IOMUX_PIN_NUM_MOSI_OCT 35
|
||||
#define SPI2_IOMUX_PIN_NUM_CLK_OCT 36
|
||||
#define SPI2_IOMUX_PIN_NUM_MISO_OCT 37
|
||||
#define SPI2_IOMUX_PIN_NUM_WP_OCT 38
|
||||
#define SPI2_IOMUX_PIN_NUM_IO4_OCT 10
|
||||
#define SPI2_IOMUX_PIN_NUM_IO5_OCT 11
|
||||
#define SPI2_IOMUX_PIN_NUM_IO6_OCT 12
|
||||
#define SPI2_IOMUX_PIN_NUM_IO7_OCT 13
|
||||
|
||||
//SPI3 has no iomux pins
|
||||
|
||||
//Following Macros are deprecated. Please use the Macros above
|
||||
#define FSPI_FUNC_NUM 4
|
||||
#define FSPI_IOMUX_PIN_NUM_HD 9
|
||||
#define FSPI_IOMUX_PIN_NUM_CS 10
|
||||
#define FSPI_IOMUX_PIN_NUM_MOSI 11
|
||||
#define FSPI_IOMUX_PIN_NUM_CLK 12
|
||||
#define FSPI_IOMUX_PIN_NUM_MISO 13
|
||||
#define FSPI_IOMUX_PIN_NUM_WP 14
|
||||
#define FSPI_FUNC_NUM SPI2_FUNC_NUM
|
||||
#define FSPI_IOMUX_PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
|
||||
#define FSPI_IOMUX_PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
|
||||
#define FSPI_IOMUX_PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
|
||||
#define FSPI_IOMUX_PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
|
||||
#define FSPI_IOMUX_PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
|
||||
#define FSPI_IOMUX_PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
|
||||
|
@ -50,10 +50,18 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = {
|
||||
.spiq_out = FSPIQ_OUT_IDX,
|
||||
.spiwp_out = FSPIWP_OUT_IDX,
|
||||
.spihd_out = FSPIHD_OUT_IDX,
|
||||
.spid4_out = FSPIIO4_OUT_IDX,
|
||||
.spid5_out = FSPIIO5_OUT_IDX,
|
||||
.spid6_out = FSPIIO6_OUT_IDX,
|
||||
.spid7_out = FSPIIO7_OUT_IDX,
|
||||
.spid_in = FSPID_IN_IDX,
|
||||
.spiq_in = FSPIQ_IN_IDX,
|
||||
.spiwp_in = FSPIWP_IN_IDX,
|
||||
.spihd_in = FSPIHD_IN_IDX,
|
||||
.spid4_in = FSPIIO4_IN_IDX,
|
||||
.spid5_in = FSPIIO5_IN_IDX,
|
||||
.spid6_in = FSPIIO6_IN_IDX,
|
||||
.spid7_in = FSPIIO7_IN_IDX,
|
||||
.spics_out = {FSPICS0_OUT_IDX, FSPICS1_OUT_IDX, FSPICS2_OUT_IDX},
|
||||
.spics_in = FSPICS0_IN_IDX,
|
||||
.spiclk_iomux_pin = FSPI_IOMUX_PIN_NUM_CLK,
|
||||
|
@ -126,7 +126,24 @@
|
||||
#define SOC_SIGMADELTA_CHANNEL_NUM (8) // 8 channels
|
||||
|
||||
/*-------------------------- SPI CAPS ----------------------------------------*/
|
||||
#include "spi_caps.h"
|
||||
#define SOC_SPI_PERIPH_NUM 3
|
||||
#define SOC_SPI_DMA_CHAN_NUM 3
|
||||
#define SOC_SPI_PERIPH_CS_NUM(i) 3
|
||||
#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64
|
||||
#define SOC_SPI_SUPPORT_DDRCLK 1
|
||||
#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1
|
||||
#define SOC_SPI_SUPPORT_CD_SIG 1
|
||||
#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1
|
||||
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
|
||||
|
||||
// Peripheral supports DIO, DOUT, QIO, or QOUT
|
||||
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ({(void)host_id; 1;})
|
||||
|
||||
// Peripheral supports output given level during its "dummy phase"
|
||||
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
|
||||
#define SOC_MEMSPI_IS_INDEPENDENT 1
|
||||
#define SOC_SPI_MAX_PRE_DIVIDER 16
|
||||
#define SOC_SPI_SUPPORT_OCT 1
|
||||
|
||||
/*-------------------------- SPIRAM CAPS ----------------------------------------*/
|
||||
#define SOC_SPIRAM_SUPPORTED 1
|
||||
|
@ -1,38 +0,0 @@
|
||||
// Copyright 2015-2020 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
|
||||
|
||||
#define SOC_SPI_PERIPH_NUM 3
|
||||
#define SOC_SPI_DMA_CHAN_NUM 3
|
||||
#define SOC_SPI_PERIPH_CS_NUM(i) 3
|
||||
|
||||
#define SOC_SPI_MAXIMUM_BUFFER_SIZE 64
|
||||
|
||||
#define SOC_SPI_SUPPORT_DDRCLK 1
|
||||
#define SOC_SPI_SLAVE_SUPPORT_SEG_TRANS 1
|
||||
#define SOC_SPI_SUPPORT_CD_SIG 1
|
||||
#define SOC_SPI_SUPPORT_CONTINUOUS_TRANS 1
|
||||
#define SOC_SPI_SUPPORT_SLAVE_HD_VER2 1
|
||||
|
||||
// Peripheral supports DIO, DOUT, QIO, or QOUT
|
||||
// VSPI (SPI3) only support 1-bit mode
|
||||
#define SOC_SPI_PERIPH_SUPPORT_MULTILINE_MODE(host_id) ({(void)host_id; 1;})
|
||||
|
||||
// Peripheral supports output given level during its "dummy phase"
|
||||
#define SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUTPUT 1
|
||||
|
||||
#define SOC_MEMSPI_IS_INDEPENDENT 1
|
||||
|
||||
#define SOC_SPI_MAX_PRE_DIVIDER 16
|
@ -22,6 +22,9 @@
|
||||
#define SPI_IOMUX_PIN_NUM_MISO 31
|
||||
#define SPI_IOMUX_PIN_NUM_WP 28
|
||||
|
||||
// There are 2 sets of GPIO pins which could be routed to FSPICS0, FSPICLK, FSPID, FSPIQ, FSPIHD, FSPIWP.
|
||||
// However, there is only one set of GPIO pins which could be routed to FSPIIO4, FSPIIO5, FSPIIO6, FSPIIO7.
|
||||
// As default (when we are not going to use Octal SPI), we make use of SPI2_FUNC_NUM to route one of the 2 sets of GPIO pins to FSPICS0 ~ FSPIWP as follows.
|
||||
#define SPI2_FUNC_NUM 4
|
||||
#define SPI2_IOMUX_PIN_NUM_HD 9
|
||||
#define SPI2_IOMUX_PIN_NUM_CS 10
|
||||
@ -30,4 +33,17 @@
|
||||
#define SPI2_IOMUX_PIN_NUM_MISO 13
|
||||
#define SPI2_IOMUX_PIN_NUM_WP 14
|
||||
|
||||
// When using Octal SPI, we make use of SPI2_FUNC_NUM_OCT to route them as follows.
|
||||
#define SPI2_FUNC_NUM_OCT 2
|
||||
#define SPI2_IOMUX_PIN_NUM_HD_OCT 33
|
||||
#define SPI2_IOMUX_PIN_NUM_CS_OCT 34
|
||||
#define SPI2_IOMUX_PIN_NUM_MOSI_OCT 35
|
||||
#define SPI2_IOMUX_PIN_NUM_CLK_OCT 36
|
||||
#define SPI2_IOMUX_PIN_NUM_MISO_OCT 37
|
||||
#define SPI2_IOMUX_PIN_NUM_WP_OCT 38
|
||||
#define SPI2_IOMUX_PIN_NUM_IO4_OCT 10
|
||||
#define SPI2_IOMUX_PIN_NUM_IO5_OCT 11
|
||||
#define SPI2_IOMUX_PIN_NUM_IO6_OCT 12
|
||||
#define SPI2_IOMUX_PIN_NUM_IO7_OCT 13
|
||||
|
||||
//SPI3 have no iomux pins
|
||||
|
@ -50,10 +50,18 @@ const spi_signal_conn_t spi_periph_signal[SOC_SPI_PERIPH_NUM] = {
|
||||
.spiq_out = FSPIQ_OUT_IDX,
|
||||
.spiwp_out = FSPIWP_OUT_IDX,
|
||||
.spihd_out = FSPIHD_OUT_IDX,
|
||||
.spid4_out = FSPIIO4_OUT_IDX,
|
||||
.spid5_out = FSPIIO5_OUT_IDX,
|
||||
.spid6_out = FSPIIO6_OUT_IDX,
|
||||
.spid7_out = FSPIIO7_OUT_IDX,
|
||||
.spid_in = FSPID_IN_IDX,
|
||||
.spiq_in = FSPIQ_IN_IDX,
|
||||
.spiwp_in = FSPIWP_IN_IDX,
|
||||
.spihd_in = FSPIHD_IN_IDX,
|
||||
.spid4_in = FSPIIO4_IN_IDX,
|
||||
.spid5_in = FSPIIO5_IN_IDX,
|
||||
.spid6_in = FSPIIO6_IN_IDX,
|
||||
.spid7_in = FSPIIO7_IN_IDX,
|
||||
.spics_out = {FSPICS0_OUT_IDX, FSPICS1_OUT_IDX, FSPICS2_OUT_IDX},
|
||||
.spics_in = FSPICS0_IN_IDX,
|
||||
.spiclk_iomux_pin = SPI2_IOMUX_PIN_NUM_CLK,
|
||||
|
@ -53,10 +53,18 @@ typedef struct {
|
||||
const uint8_t spiq_out;
|
||||
const uint8_t spiwp_out;
|
||||
const uint8_t spihd_out;
|
||||
const uint8_t spid4_out;
|
||||
const uint8_t spid5_out;
|
||||
const uint8_t spid6_out;
|
||||
const uint8_t spid7_out;
|
||||
const uint8_t spid_in; //GPIO mux input signals
|
||||
const uint8_t spiq_in;
|
||||
const uint8_t spiwp_in;
|
||||
const uint8_t spihd_in;
|
||||
const uint8_t spid4_in;
|
||||
const uint8_t spid5_in;
|
||||
const uint8_t spid6_in;
|
||||
const uint8_t spid7_in;
|
||||
const uint8_t spics_out[3]; // /CS GPIO output mux signals
|
||||
const uint8_t spics_in;
|
||||
const uint8_t spidqs_out;
|
||||
|
@ -47,12 +47,16 @@ Term Definition
|
||||
**Host** The SPI controller peripheral inside {IDF_TARGET_NAME} that initiates SPI transmissions over the bus, and acts as an SPI Master.
|
||||
**Device** SPI slave device. An SPI bus may be connected to one or more Devices. Each Device shares the MOSI, MISO and SCLK signals but is only active on the bus when the Host asserts the Device's individual CS line.
|
||||
**Bus** A signal bus, common to all Devices connected to one Host. In general, a bus includes the following lines: MISO, MOSI, SCLK, one or more CS lines, and, optionally, QUADWP and QUADHD. So Devices are connected to the same lines, with the exception that each Device has its own CS line. Several Devices can also share one CS line if connected in the daisy-chain manner.
|
||||
**MISO** Master In, Slave Out, a.k.a. Q. Data transmission from a Device to Host.
|
||||
**MOSI** Master Out, Slave In, a.k.a. D. Data transmission from a Host to Device.
|
||||
**MISO** Master In, Slave Out, a.k.a. Q. Data transmission from a Device to Host. Also data1 signal in octal mode.
|
||||
**MOSI** Master Out, Slave In, a.k.a. D. Data transmission from a Host to Device. Also data0 signal in octal mode.
|
||||
**SCLK** Serial Clock. Oscillating signal generated by a Host that keeps the transmission of data bits in sync.
|
||||
**CS** Chip Select. Allows a Host to select individual Device(s) connected to the bus in order to send or receive data.
|
||||
**QUADWP** Write Protect signal. Only used for 4-bit (qio/qout) transactions.
|
||||
**QUADHD** Hold signal. Only used for 4-bit (qio/qout) transactions.
|
||||
**QUADWP** Write Protect signal. Used for 4-bit (qio/qout) transactions. Also for data2 signal in octal mode.
|
||||
**QUADHD** Hold signal. Used for 4-bit (qio/qout) transactions. Also for data3 signal in octal mode.
|
||||
**DATA4** Data4 signal in octal mode.
|
||||
**DATA5** Data5 signal in octal mode.
|
||||
**DATA6** Data6 signal in octal mode.
|
||||
**DATA7** Data7 signal in octal mode.
|
||||
**Assertion** The action of activating a line.
|
||||
**De-assertion** The action of returning the line back to inactive (back to idle) status.
|
||||
**Transaction** One instance of a Host asserting a CS line, transferring data to and from a Device, and de-asserting the CS line. Transactions are atomic, which means they can never be interrupted by another transaction.
|
||||
@ -144,6 +148,41 @@ All the tasks that use interrupt transactions can be blocked by the queue. At th
|
||||
|
||||
The :cpp:func:`spi_device_polling_end` routine needs an overhead of at least 1 us to unblock other tasks when the transaction is finished. It is strongly recommended to wrap a series of polling transactions using the functions :cpp:func:`spi_device_acquire_bus` and :cpp:func:`spi_device_release_bus` to avoid the overhead. For more information, see :ref:`bus_acquiring`.
|
||||
|
||||
Transaction Line Mode
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Supported line modes are as follows:
|
||||
|
||||
====================== ====================== ====================== ==================
|
||||
Mode name Command Line Width Address Line Width Data Line Width
|
||||
====================== ====================== ====================== ==================
|
||||
**Dual Output** 1 1 2
|
||||
**Dual I/O** 1 2 2
|
||||
**Quad Output** 1 1 4
|
||||
**Quad I/O** 1 4 4
|
||||
**Octal Output** 1 1 8
|
||||
**OPI** 8 8 8
|
||||
====================== ====================== ====================== ==================
|
||||
|
||||
|
||||
To make use of these modes, `data0_io_num` to `data7_io_num` I/O pins in the struct :cpp:type:`spi_bus_config_t` and the member `flags` in the struct :cpp:type:`spi_bus_config_t` should be set as shown below:
|
||||
|
||||
+-------------------+--------------------------+
|
||||
| Mode name | Flags |
|
||||
+===================+==========================+
|
||||
| Dual Output | |
|
||||
+-------------------+ SPICOMMON_BUSFLAG_DUAL |
|
||||
| Dual I/O | |
|
||||
+-------------------+--------------------------+
|
||||
| Quad Output | |
|
||||
+-------------------+ SPICOMMON_BUSFLAG_QUAD |
|
||||
| Quad I/O | |
|
||||
+-------------------+--------------------------+
|
||||
| Octal Output | |
|
||||
+-------------------+ SPICOMMON_BUSFLAG_OCTAL |
|
||||
| OPI | |
|
||||
+-------------------+--------------------------+
|
||||
|
||||
|
||||
Command and Address Phases
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -152,6 +191,8 @@ During the command and address phases, the members :cpp:member:`cmd` and :cpp:me
|
||||
|
||||
If the lengths of the command and address phases need to be variable, declare the struct :cpp:type:`spi_transaction_ext_t`, set the flags :cpp:type:`SPI_TRANS_VARIABLE_CMD` and/or :cpp:type:`SPI_TRANS_VARIABLE_ADDR` in the member :cpp:member:`spi_transaction_ext_t::base` and configure the rest of base as usual. Then the length of each phase will be equal to :cpp:member:`command_bits` and :cpp:member:`address_bits` set in the struct :cpp:type:`spi_transaction_ext_t`.
|
||||
|
||||
If using more than one data lines to transmit, please set flags at the member `flags` in the struct :cpp:type:`spi_transaction_t`. If the number of lines transmitting command is the same as that transmitting data, please set `MULTILINE_CMD`. If the number of lines transmitting address is the same as that transmitting data, please set `MULTILINE_ADDR`.
|
||||
|
||||
|
||||
Write and Read Phases
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -163,6 +204,24 @@ Normally, the data that needs to be transferred to or from a Device will be read
|
||||
|
||||
If these requirements are not satisfied, the transaction efficiency will be affected due to the allocation and copying of temporary buffers.
|
||||
|
||||
If using more than one data lines to transmit, please set `SPI_DEVICE_HALFDUPLEX` flag at the member `flags` in the struct :cpp:type:`spi_device_interface_config_t`. And the member `flags` in the struct :cpp:type:`spi_transaction_t` should be set as below:
|
||||
|
||||
+-------------------+--------------------+
|
||||
| Mode name | Flags |
|
||||
+===================+====================+
|
||||
| Dual Output | |
|
||||
+-------------------+ SPI_TRANS_MODE_DIO |
|
||||
| Dual I/O | |
|
||||
+-------------------+--------------------+
|
||||
| Quad Output | |
|
||||
+-------------------+ SPI_TRANS_MODE_QIO |
|
||||
| Quad I/O | |
|
||||
+-------------------+--------------------+
|
||||
| Octal Output | |
|
||||
+-------------------+ SPI_TRANS_MODE_OCT |
|
||||
| OPI | |
|
||||
+-------------------+--------------------+
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
.. note::
|
||||
|
@ -31,7 +31,7 @@ Introduction
|
||||
------------
|
||||
|
||||
In the half duplex mode, the master has to use the protocol defined by the slave to communicate
|
||||
with the slave. Each transaction may consists of the following phases (list by the order they
|
||||
with the slave. Each transaction may consist of the following phases (list by the order they
|
||||
should exist):
|
||||
|
||||
- Command: 8-bit, master to slave
|
||||
|
@ -47,13 +47,37 @@ If using default settings, the hardware connection can be as below:
|
||||
|
||||
If not using default settings, the interface GPIOs should be set by macros in [lcd_tjpgd_example_main.c](main/lcd_tjpgd_example_main.c), where:
|
||||
|
||||
PIN_NUM_MOSI stands for the GPIO number connected to 'MOSI' pin at LCD screen;
|
||||
PIN_NUM_CLK stands for the GPIO number connected to 'SCK' pin at LCD screen;
|
||||
PIN_NUM_MOSI stands for the GPIO number connected to 'MOSI' pin at LCD screen;
|
||||
PIN_NUM_CS stands for the GPIO number connected to 'CS' pin at LCD screen;
|
||||
PIN_NUM_DC stands for the GPIO number connected to 'DC' pin at LCD screen;
|
||||
PIN_NUM_RST stands for the GPIO number connected to 'RST' pin at LCD screen;
|
||||
PIN_NUM_BCKL stands for the GPIO number connected to 'LED' pin at LCD screen;
|
||||
| GPIO number | LCD pin |
|
||||
| :-----------: | :--: |
|
||||
| PIN_NUM_CLK | SCK |
|
||||
| PIN_NUM_CS | CS |
|
||||
| PIN_NUM_DC | DC |
|
||||
| PIN_NUM_RST | RST |
|
||||
| PIN_NUM_BCKL | LED |
|
||||
| PIN_NUM_MOSI | MOSI |
|
||||
|
||||
|
||||
### 8-line LCD Usage
|
||||
|
||||
Firstly, please run `idf.py menuconfig` and set the `Drive a LCD with 8 data lines` option at `Example Configuration`.
|
||||
|
||||
Check if the pins below are correctly connected as the settings by macros in [lcd_tjpgd_example_main.c](main/lcd_tjpgd_example_main.c), where:
|
||||
|
||||
| GPIO number | LCD pin |
|
||||
| :-----------: | :--: |
|
||||
| PIN_NUM_CLK | SCK |
|
||||
| PIN_NUM_CS | CS |
|
||||
| PIN_NUM_DC | DC |
|
||||
| PIN_NUM_RST | RST |
|
||||
| PIN_NUM_BCKL | LED |
|
||||
| PIN_NUM_MOSI | D0 |
|
||||
| PIN_NUM_DATA1 | D1 |
|
||||
| PIN_NUM_DATA2 | D2 |
|
||||
| PIN_NUM_DATA3 | D3 |
|
||||
| PIN_NUM_DATA4 | D4 |
|
||||
| PIN_NUM_DATA5 | D5 |
|
||||
| PIN_NUM_DATA6 | D6 |
|
||||
| PIN_NUM_DATA7 | D7 |
|
||||
|
||||
|
||||
### Build and Flash
|
||||
|
@ -1,19 +1,5 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice LCD_TYPE
|
||||
prompt "LCD module type"
|
||||
default LCD_TYPE_AUTO
|
||||
help
|
||||
The type of LCD on the evaluation board.
|
||||
|
||||
config LCD_TYPE_AUTO
|
||||
bool "Auto detect"
|
||||
config LCD_TYPE_ST7789V
|
||||
bool "ST7789V (WROVER Kit v2 or v3)"
|
||||
config LCD_TYPE_ILI9341
|
||||
bool "ILI9341 (WROVER Kit v1 or DevKitJ v1)"
|
||||
endchoice
|
||||
|
||||
config LCD_OVERCLOCK
|
||||
bool
|
||||
prompt "Run LCD at higher clock speed than allowed"
|
||||
@ -23,4 +9,12 @@ menu "Example Configuration"
|
||||
in practice the driver chips work fine with a higher clock rate, and using that gives a better framerate.
|
||||
Select this to try using the out-of-spec clock rate.
|
||||
|
||||
config LCD_SPI_8_LINE_MODE
|
||||
bool
|
||||
prompt "Drive a LCD with 8 data lines"
|
||||
depends on IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default "n"
|
||||
help
|
||||
This option can be chosen when using 8-line lcd.
|
||||
|
||||
endmenu
|
||||
|
@ -14,26 +14,37 @@
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "pretty_effect.h"
|
||||
|
||||
#define LCD_HOST SPI2_HOST /*!< spi peripheral for LCD */
|
||||
|
||||
/**
|
||||
* If not using the default settings, the SPI peripheral on LCD and the GPIO numbers can be
|
||||
* changed below.
|
||||
*/
|
||||
#define LCD_HOST SPI2_HOST /*!< spi peripheral for LCD */
|
||||
|
||||
#define PIN_NUM_MOSI 23 /*!< gpio number for LCD MOSI */
|
||||
#define PIN_NUM_MOSI 23 /*!< gpio number for LCD MOSI, also the gpio number for LCD DATA0 at 8-line mode */
|
||||
#define PIN_NUM_CLK 19 /*!< gpio number for LCD clock */
|
||||
#define PIN_NUM_CS 22 /*!< gpio number for LCD CS */
|
||||
#define PIN_NUM_DC 21 /*!< gpio number for LCD DC */
|
||||
#define PIN_NUM_RST 18 /*!< gpio number for LCD RST */
|
||||
#define PIN_NUM_BCKL 5 /*!< gpio number for LCD Back Light */
|
||||
#ifdef CONFIG_LCD_SPI_8_LINE_MODE // If using 8-line LCD
|
||||
#define PIN_NUM_DATA1 6 /*!< gpio number for LCD DATA1 */
|
||||
#define PIN_NUM_DATA2 7 /*!< gpio number for LCD DATA2 */
|
||||
#define PIN_NUM_DATA3 8 /*!< gpio number for LCD DATA3 */
|
||||
#define PIN_NUM_DATA4 9 /*!< gpio number for LCD DATA4 */
|
||||
#define PIN_NUM_DATA5 10 /*!< gpio number for LCD DATA5 */
|
||||
#define PIN_NUM_DATA6 11 /*!< gpio number for LCD DATA6 */
|
||||
#define PIN_NUM_DATA7 12 /*!< gpio number for LCD DATA7 */
|
||||
#endif
|
||||
|
||||
// The pixel number in horizontal and vertical
|
||||
#define EXAMPLE_LCD_H_RES (320)
|
||||
#define EXAMPLE_LCD_V_RES (240)
|
||||
|
||||
// The SPI mode supported by the LCD
|
||||
#define LCD_SPI_MODE 0
|
||||
|
||||
// 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.
|
||||
@ -78,11 +89,22 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = -1,
|
||||
.mosi_io_num = PIN_NUM_MOSI,
|
||||
.sclk_io_num = PIN_NUM_CLK,
|
||||
#ifdef CONFIG_LCD_SPI_8_LINE_MODE
|
||||
.data1_io_num = PIN_NUM_DATA1,
|
||||
.data2_io_num = PIN_NUM_DATA2,
|
||||
.data3_io_num = PIN_NUM_DATA3,
|
||||
.data4_io_num = PIN_NUM_DATA4,
|
||||
.data5_io_num = PIN_NUM_DATA5,
|
||||
.data6_io_num = PIN_NUM_DATA6,
|
||||
.data7_io_num = PIN_NUM_DATA7,
|
||||
.flags = SPICOMMON_BUSFLAG_OCTAL,
|
||||
#else
|
||||
.miso_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
#endif
|
||||
.max_transfer_sz = PARALLEL_LINES * EXAMPLE_LCD_H_RES * 2 + 8
|
||||
};
|
||||
esp_lcd_panel_io_handle_t io_handle = NULL;
|
||||
@ -94,8 +116,11 @@ void app_main(void)
|
||||
#else
|
||||
.pclk_hz = 10 * 1000 * 1000, // Clock out at 10 MHz
|
||||
#endif
|
||||
.spi_mode = 0,
|
||||
.spi_mode = LCD_SPI_MODE,
|
||||
.trans_queue_depth = 7,
|
||||
#ifdef CONFIG_LCD_SPI_8_LINE_MODE
|
||||
.flags.octal_mode = 1,
|
||||
#endif
|
||||
};
|
||||
// Initialize the SPI bus
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
@ -26,8 +26,9 @@ static inline uint16_t get_bgnd_pixel(int x, int y)
|
||||
y+=8;
|
||||
return pixels[y][x];
|
||||
}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
#else
|
||||
//esp32s2/c3 doesn't have enough memory to hold the decoded image, calculate instead
|
||||
//TODO: add support for esp32s3 (IDF-3615)
|
||||
static inline uint16_t get_bgnd_pixel(int x, int y)
|
||||
{
|
||||
return ((x<<3)^(y<<3)^(x*y));
|
||||
@ -69,8 +70,9 @@ esp_err_t pretty_effect_init(void)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
return decode_image(&pixels);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
#else
|
||||
//esp32s2/c3 doesn't have enough memory to hold the decoded image, calculate instead
|
||||
//TODO: add support for esp32s3 (IDF-3615)
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user