Skip to content

Commit

Permalink
Merge branch 'feat/sdspi_c5' into 'master'
Browse files Browse the repository at this point in the history
sdspi: support on c5

Closes IDF-8704

See merge request espressif/esp-idf!32635
  • Loading branch information
Icarus113 committed Aug 29, 2024
2 parents 966f2c6 + 2133ca9 commit 7a5c05e
Show file tree
Hide file tree
Showing 22 changed files with 195 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ menu "SDMMC Test Board Configuration"
bool "ESP32-P4 Function EV Board"
depends on IDF_TARGET_ESP32P4

config SDMMC_BOARD_ESP32P4_EV_BOARD_WITH_SDSPI
bool "ESP32-P4 Function EV Board with SDSPI breakout"
depends on IDF_TARGET_ESP32P4

config SDMMC_BOARD_ESP32C5_BREAKOUT
bool "ESP32-C5 breakout board"
depends on IDF_TARGET_ESP32C5

config SDMMC_BOARD_CUSTOM_SD
depends on SOC_SDMMC_HOST_SUPPORTED
bool "Custom SD (choose pins)"
Expand Down Expand Up @@ -133,6 +141,8 @@ menu "SDMMC Test Board Configuration"

config SDMMC_BOARD_CUSTOM_UNUSED
int "GPIO not routed on the board"
default 34 if IDF_TARGET_ESP32P4
default 8 if IDF_TARGET_ESP32C5
default -1

endmenu
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,62 @@ static const sdmmc_test_board_info_t s_board_info = {
},
};

#elif CONFIG_SDMMC_BOARD_ESP32P4_EV_BOARD_WITH_SDSPI

static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-P4 Function EV Board with SDSPI breakout",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 1,
.clk = 53,
.cmd_mosi = 36,
.d0_miso = 47,
.d1 = GPIO_NUM_NC,
.d2 = GPIO_NUM_NC,
.d3_cs = 33,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = CONFIG_SDMMC_BOARD_CUSTOM_CD,
.wp = CONFIG_SDMMC_BOARD_CUSTOM_WP,
.unused_pin = CONFIG_SDMMC_BOARD_CUSTOM_UNUSED,
}
},
};

#elif CONFIG_SDMMC_BOARD_ESP32C5_BREAKOUT

static const sdmmc_test_board_info_t s_board_info = {
.name = "ESP32-C5 breakout board",
.slot = {
{
.slot_exists = false
},
{
.slot_exists = true,
.bus_width = 1,
.clk = 5,
.cmd_mosi = 4,
.d0_miso = 6,
.d1 = GPIO_NUM_NC,
.d2 = GPIO_NUM_NC,
.d3_cs = 1,
.d4 = GPIO_NUM_NC,
.d5 = GPIO_NUM_NC,
.d6 = GPIO_NUM_NC,
.d7 = GPIO_NUM_NC,
.cd = CONFIG_SDMMC_BOARD_CUSTOM_CD,
.wp = CONFIG_SDMMC_BOARD_CUSTOM_WP,
.unused_pin = CONFIG_SDMMC_BOARD_CUSTOM_UNUSED,
}
},
};

#elif CONFIG_SDMMC_BOARD_CUSTOM_SD

static const sdmmc_test_board_info_t s_board_info = {
Expand Down
2 changes: 2 additions & 0 deletions components/esp_driver_sdspi/include/driver/sdspi_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ typedef struct {
bool gpio_wp_polarity; /*!< GPIO write protect polarity
0 means "active low", i.e. card is protected when the GPIO is low;
1 means "active high", i.e. card is protected when GPIO is high. */
uint16_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.
} sdspi_device_config_t;

#define SDSPI_SLOT_NO_CS GPIO_NUM_NC ///< indicates that card select line is not used
Expand All @@ -89,6 +90,7 @@ typedef struct {
.gpio_wp = SDSPI_SLOT_NO_WP, \
.gpio_int = GPIO_NUM_NC, \
.gpio_wp_polarity = SDSPI_IO_ACTIVE_LOW, \
.duty_cycle_pos = 0,\
}

/**
Expand Down
3 changes: 3 additions & 0 deletions components/esp_driver_sdspi/src/sdspi_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ typedef struct {
uint8_t* block_buf;
/// semaphore of gpio interrupt
SemaphoreHandle_t semphr_int;
uint16_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.
} slot_info_t;

// Reserved for old API to be back-compatible
Expand Down Expand Up @@ -215,6 +216,7 @@ static esp_err_t configure_spi_dev(slot_info_t *slot, int clock_speed_hz)
// rather than a single SPI transaction.
.spics_io_num = GPIO_NUM_NC,
.queue_size = SDSPI_TRANSACTION_COUNT,
.duty_cycle_pos = slot->duty_cycle_pos,
};
return spi_bus_add_device(slot->host_id, &devcfg, &slot->spi_handle);
}
Expand Down Expand Up @@ -337,6 +339,7 @@ esp_err_t sdspi_host_init_device(const sdspi_device_config_t* slot_config, sdspi
*slot = (slot_info_t) {
.host_id = slot_config->host_id,
.gpio_cs = slot_config->gpio_cs,
.duty_cycle_pos = slot_config->duty_cycle_pos,
};

// Attach the SD card to the SPI bus
Expand Down
5 changes: 2 additions & 3 deletions components/esp_driver_sdspi/test_apps/.build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ components/esp_driver_sdspi/test_apps/sdspi:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
disable_test:
- if: SOC_GPSPI_SUPPORTED == 1
temporary: true
reason: will add runners later # TODO: IDF-8747
- if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3", "esp32c5", "esp32p4"]
reason: needs special runner, select few typical targets for testing
depends_components:
- sdmmc
- esp_driver_sdspi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -11,6 +11,8 @@
#include "sdmmc_test_board.h"
#include "sdmmc_test_begin_end_spi.h"
#include "sdmmc_test_cd_wp_common.h"
#include "sd_pwr_ctrl.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"

TEST_CASE("CD input works in SPI mode", "[sdspi]")
{
Expand All @@ -22,6 +24,18 @@ TEST_CASE("CD input works in SPI mode", "[sdspi]")
sdmmc_test_board_get_config_sdspi(slot, &config, &bus_config, &dev_config);
const int test_gpio = sdmmc_test_board_get_slot_info(slot)->unused_pin;
dev_config.gpio_cd = test_gpio;

#if SOC_SDMMC_IO_POWER_EXTERNAL
#define SDMMC_PWR_LDO_CHANNEL 4
sd_pwr_ctrl_ldo_config_t ldo_config = {
.ldo_chan_id = SDMMC_PWR_LDO_CHANNEL,
};
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;

TEST_ESP_OK(sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle));
config.pwr_ctrl_handle = pwr_ctrl_handle;
#endif

sdmmc_test_board_card_power_set(true);
TEST_ESP_OK(spi_bus_initialize(dev_config.host_id, &bus_config, SPI_DMA_CH_AUTO));
TEST_ESP_OK(sdspi_host_init());
Expand All @@ -31,9 +45,13 @@ TEST_CASE("CD input works in SPI mode", "[sdspi]")

sdmmc_test_cd_input(test_gpio, &config);

TEST_ESP_OK(sdspi_host_remove_device(handle));
TEST_ESP_OK(sdspi_host_deinit());
TEST_ESP_OK(spi_bus_free(SDSPI_DEFAULT_HOST));
sdmmc_test_board_card_power_set(false);
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle));
#endif
}

TEST_CASE("WP input works in SPI mode", "[sdspi]")
Expand All @@ -48,14 +66,28 @@ TEST_CASE("WP input works in SPI mode", "[sdspi]")
dev_config.gpio_wp = test_gpio;
sdmmc_test_board_card_power_set(true);
TEST_ESP_OK(spi_bus_initialize(dev_config.host_id, &bus_config, SPI_DMA_CH_AUTO));
#if SOC_SDMMC_IO_POWER_EXTERNAL
#define SDMMC_PWR_LDO_CHANNEL 4
sd_pwr_ctrl_ldo_config_t ldo_config = {
.ldo_chan_id = SDMMC_PWR_LDO_CHANNEL,
};
sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;

TEST_ESP_OK(sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle));
config.pwr_ctrl_handle = pwr_ctrl_handle;
#endif
TEST_ESP_OK(sdspi_host_init());
TEST_ESP_OK(sdspi_host_init_device(&dev_config, &handle));

config.slot = handle;

sdmmc_test_wp_input(test_gpio, &config);

TEST_ESP_OK(sdspi_host_remove_device(handle));
TEST_ESP_OK(sdspi_host_deinit());
TEST_ESP_OK(spi_bus_free(SDSPI_DEFAULT_HOST));
sdmmc_test_board_card_power_set(false);
#if SOC_SDMMC_IO_POWER_EXTERNAL
TEST_ESP_OK(sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle));
#endif
}
9 changes: 8 additions & 1 deletion components/esp_driver_sdspi/test_apps/sdspi/pytest_sdspi.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded_idf import IdfDut


@pytest.mark.esp32
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32p4
@pytest.mark.esp32c5
@pytest.mark.sdcard_spimode
def test_sdspi(dut: IdfDut) -> None:
dut.run_all_single_board_cases(reset=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_SDMMC_BOARD_ESP32C5_BREAKOUT=y
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_SDMMC_BOARD_ESP32P4_EV_BOARD_WITH_SDSPI=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CONFIG_SDMMC_BOARD_ESP32S3_EMMC_TEST=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
1 change: 1 addition & 0 deletions components/esp_driver_spi/include/driver/spi_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ typedef struct {
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.
bool data_io_default_level; ///< Output data IO default level when no transaction.
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.
esp_intr_cpu_affinity_t isr_cpu_id; ///< Select cpu core to register SPI ISR.
Expand Down
3 changes: 3 additions & 0 deletions components/esp_driver_spi/src/gpspi/spi_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,9 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
#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);
#endif
#if CONFIG_IDF_TARGET_ESP32
SPI_CHECK((bus_config->data_io_default_level == 0), "no support changing io default level ", ESP_ERR_INVALID_ARG);
#endif

bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
Expand Down
1 change: 1 addition & 0 deletions components/esp_driver_spi/src/gpspi/spi_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ static esp_err_t spi_master_init_driver(spi_host_device_t host_id)
spi_ll_enable_clock(host_id, true);
}
spi_hal_init(&host->hal, host_id);
spi_hal_config_io_default_level(&host->hal, bus_attr->bus_cfg.data_io_default_level);

if (host_id != SPI1_HOST) {
//SPI1 attributes are already initialized at start up.
Expand Down
12 changes: 10 additions & 2 deletions components/hal/include/hal/spi_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ typedef struct {
typedef struct {
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
spi_clock_source_t clock_source; ///< Clock source of each device used by LL layer
uint32_t source_pre_div; ///< Pre divider befor enter SPI peripheral
uint32_t source_pre_div; ///< Pre divider before enter SPI peripheral
int real_freq; ///< Output of the actual frequency
int timing_dummy; ///< Extra dummy needed to compensate the timing
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
Expand Down Expand Up @@ -129,7 +129,7 @@ typedef struct {
#if SOC_SPI_AS_CS_SUPPORTED
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 positive CS feature is enabled, device specific
};//boolean configurations
} spi_hal_dev_config_t;

Expand Down Expand Up @@ -168,6 +168,14 @@ typedef struct {
*/
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id);

/**
* Config default output IO level when don't have transaction
*
* @param hal Context of the HAL layer.
* @param level IO level to config
*/
void spi_hal_config_io_default_level(spi_hal_context_t *hal, bool level);

/**
* Deinit the peripheral (and the context if needed).
*
Expand Down
16 changes: 10 additions & 6 deletions components/hal/spi_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id)
memset(hal, 0, sizeof(spi_hal_context_t));
spi_dev_t *hw = SPI_LL_GET_HW(host_id);
hal->hw = hw;

#if SPI_LL_MOSI_FREE_LEVEL
// Change default data line level to low which same as esp32
spi_ll_set_mosi_free_level(hw, 0);
#endif
spi_ll_master_init(hw);

//Force a transaction done interrupt. This interrupt won't fire yet because
Expand All @@ -43,6 +38,15 @@ void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id)
spi_ll_apply_config(hw);
}

void spi_hal_config_io_default_level(spi_hal_context_t *hal, bool level)
{
#if SPI_LL_MOSI_FREE_LEVEL
// Config default output data line level when don't have transaction
spi_ll_set_mosi_free_level(hal->hw, level);
spi_ll_apply_config(hal->hw);
#endif
}

void spi_hal_deinit(spi_hal_context_t *hal)
{
spi_dev_t *hw = hal->hw;
Expand All @@ -57,7 +61,7 @@ void spi_hal_sct_init(spi_hal_context_t *hal)
{
spi_ll_conf_state_enable(hal->hw, true);
spi_ll_set_magic_number(hal->hw, SPI_LL_SCT_MAGIC_NUMBER);
spi_ll_disable_int(hal->hw); //trans_done intr enabled in `add device` phase, sct mode shoud use sct_trans_done only
spi_ll_disable_int(hal->hw); //trans_done intr enabled in `add device` phase, sct mode should use sct_trans_done only
spi_ll_enable_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
spi_ll_set_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
}
Expand Down
2 changes: 0 additions & 2 deletions docs/docs_not_updated/esp32c5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ api-reference/storage/mass_mfg.rst
api-reference/storage/fatfsgen.rst
api-reference/storage/index.rst
api-reference/storage/nvs_partition_parse.rst
api-reference/peripherals/sdspi_share.rst
api-reference/peripherals/twai.rst
api-reference/peripherals/sdspi_host.rst
api-reference/peripherals/gptimer.rst
api-reference/peripherals/touch_element.rst
api-reference/peripherals/lcd.rst
Expand Down
5 changes: 2 additions & 3 deletions examples/storage/.build-test-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,8 @@ examples/storage/sd_card/sdspi:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
disable_test:
- if: IDF_TARGET not in ["esp32", "esp32c3"]
temporary: true
reason: lack of runners
- if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3", "esp32c5", "esp32p4"]
reason: needs special runner, select few typical targets for testing

examples/storage/semihost_vfs:
depends_components:
Expand Down
Loading

0 comments on commit 7a5c05e

Please sign in to comment.