Merge branch 'refactor/esp_driver_spi' into 'master'

refactor(spi): make spi driver as component

Closes IDF-8371

See merge request espressif/esp-idf!26549
This commit is contained in:
Armando (Dou Yiwen) 2023-11-09 21:41:29 +08:00
commit 2b173ce727
82 changed files with 823 additions and 712 deletions

View File

@ -5,8 +5,7 @@ if(${target} STREQUAL "linux")
endif()
# Always compiled source files
set(srcs
"spi/spi_bus_lock.c")
set(srcs)
# Always included headers
set(includes "include"
@ -21,8 +20,8 @@ set(includes "include"
"rmt/include"
"sdio_slave/include"
"sdmmc/include"
"sdspi/include"
"sigma_delta/include"
"spi/include"
"temperature_sensor/include"
"touch_sensor/include"
"twai/include"
@ -153,19 +152,13 @@ if(CONFIG_SOC_SDM_SUPPORTED)
"deprecated/sigma_delta_legacy.c")
endif()
# SPI related source files
# SDSPI related source files
if(CONFIG_SOC_GPSPI_SUPPORTED)
list(APPEND srcs "spi/gpspi/spi_common.c"
"spi/gpspi/spi_master.c"
"spi/gpspi/spi_slave.c"
"spi/sdspi/sdspi_crc.c"
"spi/sdspi/sdspi_host.c"
"spi/sdspi/sdspi_transaction.c")
list(APPEND srcs "sdspi/sdspi_crc.c"
"sdspi/sdspi_host.c"
"sdspi/sdspi_transaction.c")
endif()
if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2)
list(APPEND srcs "spi/gpspi/spi_slave_hd.c")
endif()
# Temperature Sensor related source files
if(CONFIG_SOC_TEMP_SENSOR_SUPPORTED)
@ -218,7 +211,7 @@ else()
REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support
# for backward compatibility, the driver component needs to
# have a public dependency on other "esp_driver_foo" components
esp_driver_gpio esp_driver_pcnt esp_driver_gptimer
esp_driver_gpio esp_driver_pcnt esp_driver_gptimer esp_driver_spi
LDFRAGMENTS ${ldfragments}
)
endif()

View File

@ -62,68 +62,6 @@ menu "Driver Configurations"
endmenu # ADC Configuration
menu "SPI Configuration"
config SPI_MASTER_IN_IRAM
bool "Place transmitting functions of SPI master into IRAM"
default n
depends on !FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
select SPI_MASTER_ISR_IN_IRAM
help
Normally only the ISR of SPI master is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
This configuration won't be available if `CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` is enabled.
During unit test, this is enabled to measure the ideal case of api.
config SPI_MASTER_ISR_IN_IRAM
bool "Place SPI master ISR function into IRAM"
default y
depends on !HEAP_PLACE_FUNCTION_INTO_FLASH
select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_MASTER_FUNC_IN_IRAM
help
Place the SPI master ISR in to IRAM to avoid possible cache miss.
Enabling this configuration is possible only when HEAP_PLACE_FUNCTION_INTO_FLASH
is disabled since the spi master uses can allocate transactions buffers into DMA
memory section using the heap component API that ipso facto has to be placed in IRAM.
Also you can forbid the ISR being disabled during flash writing
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
config SPI_SLAVE_IN_IRAM
bool "Place transmitting functions of SPI slave into IRAM"
default n
select SPI_SLAVE_ISR_IN_IRAM
help
Normally only the ISR of SPI slave is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
config SPI_SLAVE_ISR_IN_IRAM
bool "Place SPI slave ISR function into IRAM"
default y
select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_SLAVE_FUNC_IN_IRAM
help
Place the SPI slave ISR in to IRAM to avoid possible cache miss.
Also you can forbid the ISR being disabled during flash writing
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
endmenu # SPI Configuration
orsource "./twai/Kconfig.twai"
menu "Temperature sensor Configuration"

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -65,9 +65,9 @@ typedef struct {
gpio_num_t gpio_cd; ///< GPIO number of card detect signal
gpio_num_t gpio_wp; ///< GPIO number of write protect signal
gpio_num_t gpio_int; ///< GPIO number of interrupt line (input) for SDIO card.
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.
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. */
} sdspi_device_config_t;
#define SDSPI_SLOT_NO_CS GPIO_NUM_NC ///< indicates that card select line is not used

View File

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdspi_crc.h"
#include "sdkconfig.h"
#include "esp_rom_crc.h"
static const uint8_t crc7_table[256] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79,
};
// returns the CRC-7 for a message of "length" bytes
uint8_t sdspi_crc7(const uint8_t *data, size_t size)
{
uint8_t result = 0;
for (size_t i = 0; i < size; ++i) {
result = crc7_table[(result << 1) ^ data[i]];
}
return result;
}
/// Return CRC16 of data, in the on-the-wire format used by SD protocol
uint16_t sdspi_crc16(const uint8_t* data, size_t size)
{
return __builtin_bswap16(esp_rom_crc16_be(UINT16_MAX, data, size) ^ UINT16_MAX);
}

View File

@ -12,7 +12,6 @@ extern "C"
{
#endif
/**
* @brief Return CRC7 of data, in the format used by SD protocol
* @param data array of data used to compute CRC
@ -29,7 +28,6 @@ uint8_t sdspi_crc7(const uint8_t *data, size_t size);
*/
uint16_t sdspi_crc16(const uint8_t* data, size_t size);
#ifdef __cplusplus
}
#endif

View File

@ -22,7 +22,6 @@
#include "freertos/semphr.h"
#include "soc/soc_memory_layout.h"
/// Max number of transactions in flight (used in start_command_write_blocks)
#define SDSPI_TRANSACTION_COUNT 4
#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high
@ -67,13 +66,12 @@ static const char *TAG = "sdspi_host";
static const bool use_polling = true;
static const bool no_use_polling = true;
/// Functions to send out different kinds of commands
static esp_err_t start_command_read_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cmd,
uint8_t *data, uint32_t rx_length, bool need_stop_command);
uint8_t *data, uint32_t rx_length, bool need_stop_command);
static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cmd,
const uint8_t *data, uint32_t tx_length, bool multi_block, bool stop_trans);
const uint8_t *data, uint32_t tx_length, bool multi_block, bool stop_trans);
static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cmd_t *cmd);
@ -189,7 +187,7 @@ static void go_idle_clockout(slot_info_t *slot)
uint8_t data[12];
memset(data, 0xff, sizeof(data));
spi_transaction_t t = {
.length = 10*8,
.length = 10 * 8,
.tx_buffer = data,
.rx_buffer = data,
};
@ -276,17 +274,19 @@ esp_err_t sdspi_host_remove_device(sdspi_dev_handle_t handle)
return ESP_ERR_INVALID_ARG;
}
deinit_slot(slot);
deinit_slot(slot);
return ESP_OK;
}
//only the slots locally stored can be deinit in this function.
esp_err_t sdspi_host_deinit(void)
{
for (size_t i = 0; i < sizeof(s_slots)/sizeof(s_slots[0]); ++i) {
for (size_t i = 0; i < sizeof(s_slots) / sizeof(s_slots[0]); ++i) {
slot_info_t* slot = remove_slot_info(i);
//slot isn't used, skip
if (slot == NULL) continue;
if (slot == NULL) {
continue;
}
deinit_slot(slot);
}
@ -514,8 +514,8 @@ static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cm
{
size_t cmd_size = SDSPI_CMD_R1_SIZE;
if ((flags & SDSPI_CMD_FLAG_RSP_R1) ||
(flags & SDSPI_CMD_FLAG_NORSP) ||
(flags & SDSPI_CMD_FLAG_RSP_R1B )) {
(flags & SDSPI_CMD_FLAG_NORSP) ||
(flags & SDSPI_CMD_FLAG_RSP_R1B)) {
cmd_size = SDSPI_CMD_R1_SIZE;
} else if (flags & SDSPI_CMD_FLAG_RSP_R2) {
cmd_size = SDSPI_CMD_R2_SIZE;
@ -529,7 +529,7 @@ static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cm
cmd_size = SDSPI_CMD_R7_SIZE;
}
//add extra clocks to avoid polling
cmd_size += (SDSPI_NCR_MAX_SIZE-SDSPI_NCR_MIN_SIZE);
cmd_size += (SDSPI_NCR_MAX_SIZE - SDSPI_NCR_MIN_SIZE);
spi_transaction_t t = {
.flags = 0,
.length = cmd_size * 8,
@ -553,7 +553,9 @@ static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cm
// we have sent and received bytes with enough length.
// now shift the response to match the offset of sdspi_hw_cmd_t
ret = shift_cmd_response(cmd, cmd_size);
if (ret != ESP_OK) return ESP_ERR_TIMEOUT;
if (ret != ESP_OK) {
return ESP_ERR_TIMEOUT;
}
if (flags & SDSPI_CMD_FLAG_RSP_R1B) {
ret = poll_busy(slot, cmd->timeout_ms, no_use_polling);
@ -594,7 +596,7 @@ static esp_err_t poll_busy(slot_info_t *slot, int timeout_ms, bool polling)
return ESP_OK;
}
}
} while(esp_timer_get_time() < t_end);
} while (esp_timer_get_time() < t_end);
ESP_LOGD(TAG, "%s: timeout", __func__);
return ESP_ERR_TIMEOUT;
}
@ -629,7 +631,7 @@ static esp_err_t poll_data_token(slot_info_t *slot, uint8_t *extra_ptr, size_t *
}
if (rd_data != 0xff && rd_data != 0) {
ESP_LOGD(TAG, "%s: received 0x%02x while waiting for data",
__func__, rd_data);
__func__, rd_data);
return ESP_ERR_INVALID_RESPONSE;
}
}
@ -648,10 +650,14 @@ static esp_err_t shift_cmd_response(sdspi_hw_cmd_t* cmd, int sent_bytes)
{
uint8_t* pr1 = &cmd->r1;
int ncr_cnt = 1;
while(true) {
if ((*pr1 & SD_SPI_R1_NO_RESPONSE) == 0) break;
while (true) {
if ((*pr1 & SD_SPI_R1_NO_RESPONSE) == 0) {
break;
}
pr1++;
if (++ncr_cnt > 8) return ESP_ERR_NOT_FOUND;
if (++ncr_cnt > 8) {
return ESP_ERR_NOT_FOUND;
}
}
int copy_bytes = sent_bytes - SDSPI_CMD_SIZE - ncr_cnt;
@ -662,7 +668,6 @@ static esp_err_t shift_cmd_response(sdspi_hw_cmd_t* cmd, int sent_bytes)
return ESP_OK;
}
/**
* Receiving one or more blocks of data happens as follows:
* 1. send command + receive r1 response (SDSPI_CMD_R1_SIZE bytes total)
@ -705,7 +710,7 @@ static esp_err_t shift_cmd_response(sdspi_hw_cmd_t* cmd, int sent_bytes)
* expense of one extra temporary buffer.
*/
static esp_err_t start_command_read_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cmd,
uint8_t *data, uint32_t rx_length, bool need_stop_command)
uint8_t *data, uint32_t rx_length, bool need_stop_command)
{
spi_transaction_t t_command = {
.length = (SDSPI_CMD_R1_SIZE + SDSPI_RESPONSE_MAX_DELAY) * 8,
@ -838,7 +843,7 @@ static esp_err_t start_command_read_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cm
* It's also different that stop transmission token is not needed in the SDIO mode.
*/
static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cmd,
const uint8_t *data, uint32_t tx_length, bool multi_block, bool stop_trans)
const uint8_t *data, uint32_t tx_length, bool multi_block, bool stop_trans)
{
if (card_write_protected(slot)) {
ESP_LOGW(TAG, "%s: card write protected", __func__);
@ -846,7 +851,7 @@ static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *c
}
// Send the minimum length that is sure to get the complete response
// SD cards always return R1 (1bytes), SDIO returns R5 (2 bytes)
const int send_bytes = SDSPI_CMD_R5_SIZE+SDSPI_NCR_MAX_SIZE-SDSPI_NCR_MIN_SIZE;
const int send_bytes = SDSPI_CMD_R5_SIZE + SDSPI_NCR_MAX_SIZE - SDSPI_NCR_MIN_SIZE;
spi_transaction_t t_command = {
.length = send_bytes * 8,
@ -866,7 +871,7 @@ static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *c
}
uint8_t start_token = multi_block ?
TOKEN_BLOCK_START_WRITE_MULTI : TOKEN_BLOCK_START;
TOKEN_BLOCK_START_WRITE_MULTI : TOKEN_BLOCK_START;
while (tx_length > 0) {
// Write block start token
@ -909,7 +914,7 @@ static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *c
spi_transaction_t t_crc_rsp = {
.length = size_crc_response * 8,
.flags = SPI_TRANS_USE_TXDATA|SPI_TRANS_USE_RXDATA,
.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA,
};
memset(t_crc_rsp.tx_data, 0xff, 4);
memcpy(t_crc_rsp.tx_data, &crc, sizeof(crc));
@ -920,7 +925,9 @@ static esp_err_t start_command_write_blocks(slot_info_t *slot, sdspi_hw_cmd_t *c
}
uint8_t data_rsp = t_crc_rsp.rx_data[2];
if (!SD_SPI_DATA_RSP_VALID(data_rsp)) return ESP_ERR_INVALID_RESPONSE;
if (!SD_SPI_DATA_RSP_VALID(data_rsp)) {
return ESP_ERR_INVALID_RESPONSE;
}
switch (SD_SPI_DATA_RSP(data_rsp)) {
case SD_SPI_DATA_ACCEPTED:
break;
@ -976,7 +983,9 @@ esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_t
{
slot_info_t* slot = get_slot_info(handle);
//skip the interrupt and semaphore if the gpio is already low.
if (gpio_get_level(slot->gpio_int)==0) return ESP_OK;
if (gpio_get_level(slot->gpio_int) == 0) {
return ESP_OK;
}
//clear the semaphore before wait
xSemaphoreTake(slot->semphr_int, 0);

View File

@ -34,7 +34,6 @@
/// Data rejected due to write error
#define TOKEN_RSP_WRITE_ERR 0b01101
/// Data error tokens have format 0b0000xyzw where xyzw are signle bit flags.
/// MASK and VAL are used to check if a token is an error token
#define TOKEN_ERR_MASK 0b11110000
@ -49,7 +48,6 @@
/// Card is locked
#define TOKEN_ERR_LOCKED BIT(0)
/// Transfer format in SPI mode. See section 7.3.1.1 of SD simplified spec.
typedef struct {
// These fields form the command sent from host to the card (6 bytes)

View File

@ -22,7 +22,7 @@ static bool s_app_cmd;
static uint8_t sdspi_msg_crc7(sdspi_hw_cmd_t* hw_cmd)
{
const size_t bytes_to_crc = offsetof(sdspi_hw_cmd_t, arguments) +
sizeof(hw_cmd->arguments); /* can't take address of bit fields */
sizeof(hw_cmd->arguments); /* can't take address of bit fields */
return sdspi_crc7((const uint8_t *)hw_cmd, bytes_to_crc);
}
@ -128,7 +128,7 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
} else if (s_app_cmd && cmdinfo->opcode == SD_APP_SD_STATUS) {
flags |= SDSPI_CMD_FLAG_RSP_R2;
} else if (!s_app_cmd && cmdinfo->opcode == MMC_GO_IDLE_STATE &&
!(cmdinfo->flags & SCF_RSP_R1)) {
!(cmdinfo->flags & SCF_RSP_R1)) {
/* used to send CMD0 without expecting a response */
flags |= SDSPI_CMD_FLAG_NORSP;
} else if (!s_app_cmd && cmdinfo->opcode == SD_IO_SEND_OP_COND) {
@ -137,9 +137,13 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
flags |= SDSPI_CMD_FLAG_RSP_R5;
} else if (!s_app_cmd && cmdinfo->opcode == SD_IO_RW_EXTENDED) {
flags |= SDSPI_CMD_FLAG_RSP_R5 | SDSPI_CMD_FLAG_DATA;
if (cmdinfo->arg & SD_ARG_CMD53_WRITE) flags |= SDSPI_CMD_FLAG_WRITE;
if (cmdinfo->arg & SD_ARG_CMD53_WRITE) {
flags |= SDSPI_CMD_FLAG_WRITE;
}
// The CMD53 can assign block mode in the arg when the length is exactly 512 bytes
if (cmdinfo->arg & SD_ARG_CMD53_BLOCK_MODE) flags |= SDSPI_CMD_FLAG_MULTI_BLK;
if (cmdinfo->arg & SD_ARG_CMD53_BLOCK_MODE) {
flags |= SDSPI_CMD_FLAG_MULTI_BLK;
}
} else if (!s_app_cmd && (cmdinfo->opcode == MMC_ERASE || cmdinfo->opcode == MMC_STOP_TRANSMISSION)) {
flags |= SDSPI_CMD_FLAG_RSP_R1B;
} else {
@ -148,7 +152,7 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
// Send the command and get the response.
esp_err_t ret = sdspi_host_start_command(slot, &hw_cmd,
cmdinfo->data, cmdinfo->datalen, flags);
cmdinfo->data, cmdinfo->datalen, flags);
// Extract response bytes and store them into cmdinfo structure
if (ret == ESP_OK) {

View File

@ -1,46 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdspi_crc.h"
#include "sdkconfig.h"
#include "esp_rom_crc.h"
static const uint8_t crc7_table[256] =
{
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79,
};
// returns the CRC-7 for a message of "length" bytes
uint8_t sdspi_crc7(const uint8_t *data, size_t size)
{
uint8_t result = 0;
for (size_t i = 0; i < size; ++i) {
result = crc7_table[(result << 1) ^ data[i]];
}
return result;
}
/// Return CRC16 of data, in the on-the-wire format used by SD protocol
uint16_t sdspi_crc16(const uint8_t* data, size_t size)
{
return __builtin_bswap16(esp_rom_crc16_be(UINT16_MAX, data, size) ^ UINT16_MAX);
}

View File

@ -139,23 +139,6 @@ components/driver/test_apps/sigma_delta:
depends_components:
- esp_driver_gpio
components/driver/test_apps/spi/master:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
components/driver/test_apps/spi/param:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
components/driver/test_apps/spi/slave:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
components/driver/test_apps/spi/slave_hd:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
components/driver/test_apps/temperature_sensor:
disable:
- if: SOC_TEMP_SENSOR_SUPPORTED != 1

View File

@ -8,6 +8,6 @@ components/esp_adc/test_apps/adc:
- esp_adc
- esp_driver_gpio
- efuse
- esp_driver_spi # ADC continuous driver relies on SPI on ESP32S2
depends_filepatterns:
- components/driver/spi/**/* # ADC continuous driver relies on SPI on ESP32S2
- components/driver/i2s/**/* # ADC continuous driver relies on I2S on ESP32

View File

@ -0,0 +1,26 @@
idf_build_get_property(target IDF_TARGET)
if(${target} STREQUAL "linux")
return() # This component is not supported by the POSIX/Linux simulator
endif()
set(srcs "spi_bus_lock.c")
set(public_include "include")
if(CONFIG_SOC_GPSPI_SUPPORTED)
list(APPEND srcs "src/gpspi/spi_common.c"
"src/gpspi/spi_master.c"
"src/gpspi/spi_slave.c")
endif()
if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2)
list(APPEND srcs "src/gpspi/spi_slave_hd.c")
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${public_include}
REQUIRES esp_pm
PRIV_REQUIRES esp_timer esp_mm esp_driver_gpio esp_ringbuf
LDFRAGMENTS "linker.lf"
)

View File

@ -0,0 +1,61 @@
menu "ESP-Driver:SPI Configurations"
depends on SOC_GPSPI_SUPPORTED
config SPI_MASTER_IN_IRAM
bool "Place transmitting functions of SPI master into IRAM"
default n
depends on !FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
select SPI_MASTER_ISR_IN_IRAM
help
Normally only the ISR of SPI master is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
This configuration won't be available if `CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH` is enabled.
During unit test, this is enabled to measure the ideal case of api.
config SPI_MASTER_ISR_IN_IRAM
bool "Place SPI master ISR function into IRAM"
default y
depends on !HEAP_PLACE_FUNCTION_INTO_FLASH
select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_MASTER_FUNC_IN_IRAM
help
Place the SPI master ISR in to IRAM to avoid possible cache miss.
Enabling this configuration is possible only when HEAP_PLACE_FUNCTION_INTO_FLASH
is disabled since the spi master uses can allocate transactions buffers into DMA
memory section using the heap component API that ipso facto has to be placed in IRAM.
Also you can forbid the ISR being disabled during flash writing
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
config SPI_SLAVE_IN_IRAM
bool "Place transmitting functions of SPI slave into IRAM"
default n
select SPI_SLAVE_ISR_IN_IRAM
help
Normally only the ISR of SPI slave is placed in the IRAM, so that it
can work without the flash when interrupt is triggered.
For other functions, there's some possibility that the flash cache
miss when running inside and out of SPI functions, which may increase
the interval of SPI transactions.
Enable this to put ``queue_trans``, ``get_trans_result`` and
``transmit`` functions into the IRAM to avoid possible cache miss.
config SPI_SLAVE_ISR_IN_IRAM
bool "Place SPI slave ISR function into IRAM"
default y
select PERIPH_CTRL_FUNC_IN_IRAM
select HAL_SPI_SLAVE_FUNC_IN_IRAM
help
Place the SPI slave ISR in to IRAM to avoid possible cache miss.
Also you can forbid the ISR being disabled during flash writing
access, by add ESP_INTR_FLAG_IRAM when initializing the driver.
endmenu # SPI Configuration

View File

@ -69,12 +69,12 @@ extern "C"
* @brief SPI DMA channels
*/
typedef enum {
SPI_DMA_DISABLED = 0, ///< Do not enable DMA for SPI
SPI_DMA_DISABLED = 0, ///< Do not enable DMA for SPI
#if CONFIG_IDF_TARGET_ESP32
SPI_DMA_CH1 = 1, ///< Enable DMA, select DMA Channel 1
SPI_DMA_CH2 = 2, ///< Enable DMA, select DMA Channel 2
SPI_DMA_CH1 = 1, ///< Enable DMA, select DMA Channel 1
SPI_DMA_CH2 = 2, ///< Enable DMA, select DMA Channel 2
#endif
SPI_DMA_CH_AUTO = 3, ///< Enable DMA, channel is automatically selected by driver
SPI_DMA_CH_AUTO = 3, ///< Enable DMA, channel is automatically selected by driver
} spi_common_dma_t;
#if __cplusplus
@ -95,21 +95,21 @@ typedef spi_common_dma_t spi_dma_chan_t;
*/
typedef struct {
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.
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 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.
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.
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.
};
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.
@ -125,7 +125,6 @@ typedef struct {
*/
} spi_bus_config_t;
/**
* @brief Initialize a SPI bus
*

View File

@ -102,7 +102,6 @@ typedef struct {
*/
} spi_device_interface_config_t;
#define SPI_TRANS_MODE_DIO (1<<0) ///< Transmit/receive data in 2-bit mode
#define SPI_TRANS_MODE_QIO (1<<1) ///< Transmit/receive data in 4-bit mode
#define SPI_TRANS_USE_RXDATA (1<<2) ///< Receive into rx_data member of spi_transaction_t instead into memory at rx_buffer.
@ -158,7 +157,6 @@ typedef struct {
uint8_t dummy_bits; ///< The dummy length in this transaction, in bits.
} spi_transaction_ext_t ;
typedef struct spi_device_t *spi_device_handle_t; ///< Handle for a device on a SPI bus
/**
* @brief Allocate a device on a SPI bus
@ -183,7 +181,6 @@ typedef struct spi_device_t *spi_device_handle_t; ///< Handle for a device on a
*/
esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle);
/**
* @brief Remove a device from the SPI bus
*
@ -195,7 +192,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
*/
esp_err_t spi_bus_remove_device(spi_device_handle_t handle);
/**
* @brief Queue a SPI transaction for interrupt transaction execution. Get the result by ``spi_device_get_trans_result``.
*
@ -217,7 +213,6 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle);
*/
esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Get the result of a SPI transaction queued earlier by ``spi_device_queue_trans``.
*
@ -240,7 +235,6 @@ esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *
*/
esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait);
/**
* @brief Send a SPI transaction, wait for it to complete, and return the result
*
@ -259,7 +253,6 @@ esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transactio
*/
esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc);
/**
* @brief Immediately start a polling transaction.
*
@ -283,7 +276,6 @@ esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *tra
*/
esp_err_t spi_device_polling_start(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Poll until the polling transaction ends.
*
@ -301,7 +293,6 @@ esp_err_t spi_device_polling_start(spi_device_handle_t handle, spi_transaction_t
*/
esp_err_t spi_device_polling_end(spi_device_handle_t handle, TickType_t ticks_to_wait);
/**
* @brief Send a polling transaction, wait for it to complete, and return the result
*
@ -323,7 +314,6 @@ esp_err_t spi_device_polling_end(spi_device_handle_t handle, TickType_t ticks_to
*/
esp_err_t spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc);
/**
* @brief Occupy the SPI bus for a device to do continuous transactions.
*

View File

@ -4,7 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _DRIVER_SPI_SLAVE_H_
#define _DRIVER_SPI_SLAVE_H_
@ -13,13 +12,11 @@
#include "freertos/semphr.h"
#include "driver/spi_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define SPI_SLAVE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_SLAVE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
#define SPI_SLAVE_BIT_LSBFIRST (SPI_SLAVE_TXBIT_LSBFIRST|SPI_SLAVE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
@ -65,7 +62,6 @@ typedef struct {
*/
} spi_slave_interface_config_t;
#define SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO (1<<0) ///< Automatically re-malloc dma buffer if user buffer doesn't meet hardware alignment or dma_capable, this process may loss some memory and performance
/**
@ -123,7 +119,6 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
*/
esp_err_t spi_slave_free(spi_host_device_t host);
/**
* @brief Queue a SPI transaction for execution
*
@ -148,7 +143,6 @@ esp_err_t spi_slave_free(spi_host_device_t host);
*/
esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Get the result of a SPI transaction queued earlier
*
@ -171,7 +165,6 @@ esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transact
*/
esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait);
/**
* @brief Do a SPI transaction
*
@ -191,7 +184,6 @@ esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transacti
*/
esp_err_t spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait);
#ifdef __cplusplus
}
#endif

View File

@ -62,7 +62,6 @@ typedef struct {
void* arg; ///< Argument indicating this SPI Slave HD peripheral instance
} spi_slave_hd_callback_config_t;
//flags for ``spi_slave_hd_slot_config_t`` to use
#define SPI_SLAVE_HD_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_SLAVE_HD_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first

View File

@ -19,13 +19,11 @@
#include "esp_private/gdma.h"
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
#define SPI_MASTER_ISR_ATTR IRAM_ATTR
#else
@ -38,7 +36,6 @@ extern "C"
#define SPI_MASTER_ATTR
#endif
#define BUS_LOCK_DEBUG 0
#if BUS_LOCK_DEBUG
@ -88,7 +85,6 @@ typedef struct {
/// Destructor called when a bus is deinitialized.
typedef esp_err_t (*spi_destroy_func_t)(void*);
/**
* @brief Try to claim a SPI peripheral
*
@ -281,7 +277,6 @@ typedef void(*dmaworkaround_cb_t)(void *arg);
*/
bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg);
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
@ -289,7 +284,6 @@ bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void
*/
bool spicommon_dmaworkaround_reset_in_progress(void);
/**
* @brief Mark a DMA channel as idle.
*
@ -779,7 +773,6 @@ extern const spi_bus_lock_dev_handle_t g_spi_lock_main_flash_dev;
*/
esp_err_t spi_bus_lock_init_main_dev(void);
#ifdef __cplusplus
}
#endif

View File

@ -22,7 +22,6 @@
extern "C" {
#endif
/**
* @brief Reset the trans Queue of slave driver
* @note
@ -40,7 +39,6 @@ extern "C" {
*/
esp_err_t spi_slave_queue_reset(spi_host_device_t host);
/**
* @brief Reset the trans Queue from within ISR of slave driver
* @note
@ -55,7 +53,6 @@ esp_err_t spi_slave_queue_reset(spi_host_device_t host);
*/
esp_err_t spi_slave_queue_reset_isr(spi_host_device_t host);
/**
* @brief Queue a SPI transaction in ISR
* @note
@ -76,7 +73,6 @@ esp_err_t spi_slave_queue_reset_isr(spi_host_device_t host);
*/
esp_err_t spi_slave_queue_trans_isr(spi_host_device_t host, const spi_slave_transaction_t *trans_desc);
#ifdef __cplusplus
}
#endif

View File

View File

@ -17,7 +17,6 @@
#include <strings.h>
#include "esp_heap_caps.h"
/*
* This lock is designed to solve the conflicts between SPI devices (used in tasks) and
* the background operations (ISR or cache access).
@ -145,7 +144,6 @@ typedef struct spi_bus_lock_dev_t spi_bus_lock_dev_t;
typedef struct spi_bus_lock_t spi_bus_lock_t;
#define MAX_DEV_NUM 10
// Bit 29-20: lock bits, Bit 19-10: pending bits
@ -333,7 +331,7 @@ SPI_MASTER_ATTR static inline void req_core(spi_bus_lock_dev_t *dev_handle)
// Though `acquired_dev` is critical resource, `dev_handle == lock->acquired_dev`
// is a stable statement unless `acquire_start` or `acquire_end` is called by current
// device.
if (dev_handle == lock->acquiring_dev){
if (dev_handle == lock->acquiring_dev) {
// Set the REQ bit and check BG bits if we are the acquiring processor.
// If the BG bits were not active before, invoke the BG again.
@ -564,7 +562,9 @@ SPI_MASTER_ISR_ATTR static inline esp_err_t dev_wait(spi_bus_lock_dev_t *dev_han
{
BaseType_t ret = xSemaphoreTake(dev_handle->semphr, wait);
if (ret == pdFALSE) return ESP_ERR_TIMEOUT;
if (ret == pdFALSE) {
return ESP_ERR_TIMEOUT;
}
return ESP_OK;
}
@ -607,7 +607,7 @@ static int try_acquire_free_dev(spi_bus_lock_t *lock, bool cs_required)
break;
}
}
return ((i == lock->periph_cs_num)? -1: i);
return ((i == lock->periph_cs_num) ? -1 : i);
} else {
int i;
for (i = DEV_NUM_MAX - 1; i >= 0; i--) {
@ -624,9 +624,13 @@ static int try_acquire_free_dev(spi_bus_lock_t *lock, bool cs_required)
esp_err_t spi_bus_lock_register_dev(spi_bus_lock_handle_t lock, spi_bus_lock_dev_config_t *config,
spi_bus_lock_dev_handle_t *out_dev_handle)
{
if (lock == NULL) return ESP_ERR_INVALID_ARG;
if (lock == NULL) {
return ESP_ERR_INVALID_ARG;
}
int id = try_acquire_free_dev(lock, config->flags & SPI_BUS_LOCK_DEV_FLAG_CS_REQUIRED);
if (id == -1) return ESP_ERR_NOT_SUPPORTED;
if (id == -1) {
return ESP_ERR_NOT_SUPPORTED;
}
spi_bus_lock_dev_t* dev_lock = (spi_bus_lock_dev_t*)heap_caps_calloc(sizeof(spi_bus_lock_dev_t), 1, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (dev_lock == NULL) {
@ -654,7 +658,9 @@ void spi_bus_lock_unregister_dev(spi_bus_lock_dev_handle_t dev_handle)
spi_bus_lock_t* lock = dev_handle->parent;
BUS_LOCK_DEBUG_EXECUTE_CHECK(atomic_load(&lock->dev[id]) == (intptr_t)dev_handle);
if (lock->last_dev == dev_handle) lock->last_dev = NULL;
if (lock->last_dev == dev_handle) {
lock->last_dev = NULL;
}
atomic_store(&lock->dev[id], (intptr_t)NULL);
if (dev_handle->semphr) {
@ -683,7 +689,7 @@ void spi_bus_lock_set_bg_control(spi_bus_lock_handle_t lock, bg_ctrl_func_t bg_e
IRAM_ATTR int spi_bus_lock_get_dev_id(spi_bus_lock_dev_handle_t dev_handle)
{
return (dev_handle? dev_lock_get_id(dev_handle): -1);
return (dev_handle ? dev_lock_get_id(dev_handle) : -1);
}
//will be called when cache disabled
@ -692,9 +698,9 @@ IRAM_ATTR bool spi_bus_lock_touch(spi_bus_lock_dev_handle_t dev_handle)
spi_bus_lock_dev_t* last_dev = dev_handle->parent->last_dev;
dev_handle->parent->last_dev = dev_handle;
if (last_dev != dev_handle) {
int last_dev_id = (last_dev? dev_lock_get_id(last_dev): -1);
int last_dev_id = (last_dev ? dev_lock_get_id(last_dev) : -1);
ESP_DRAM_LOGV(TAG, "SPI dev changed from %d to %d",
last_dev_id, dev_lock_get_id(dev_handle));
last_dev_id, dev_lock_get_id(dev_handle));
}
return (dev_handle != last_dev);
}
@ -714,7 +720,9 @@ IRAM_ATTR esp_err_t spi_bus_lock_acquire_start(spi_bus_lock_dev_t *dev_handle, T
//block until becoming the acquiring processor (help by previous acquiring processor)
esp_err_t err = dev_wait(dev_handle, wait);
//TODO: add timeout handling here.
if (err != ESP_OK) return err;
if (err != ESP_OK) {
return err;
}
}
ESP_DRAM_LOGV(TAG, "dev %d acquired.", dev_lock_get_id(dev_handle));
@ -780,7 +788,9 @@ IRAM_ATTR esp_err_t spi_bus_lock_wait_bg_done(spi_bus_lock_dev_handle_t dev_hand
//block until becoming the acquiring processor (help by previous acquiring processor)
esp_err_t err = dev_wait(dev_handle, wait);
//TODO: add timeout handling here.
if (err != ESP_OK) return err;
if (err != ESP_OK) {
return err;
}
}
}

View File

@ -4,7 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
#include "stdatomic.h"
@ -57,7 +56,6 @@ static const char *SPI_TAG = "spi";
#define FUNC_GPIO PIN_FUNC_GPIO
typedef struct {
int host_id;
spi_destroy_func_t destroy_func;
@ -72,12 +70,12 @@ typedef struct {
//Periph 1 is 'claimed' by SPI flash code.
static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
#if (SOC_SPI_PERIPH_NUM >= 3)
ATOMIC_VAR_INIT(false),
ATOMIC_VAR_INIT(false),
#endif
#if (SOC_SPI_PERIPH_NUM >= 4)
ATOMIC_VAR_INIT(false),
ATOMIC_VAR_INIT(false),
#endif
};
};
static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT();
@ -89,7 +87,6 @@ static uint8_t spi_dma_chan_enabled = 0;
static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
#endif //#if !SOC_GDMA_SUPPORTED
static inline bool is_valid_host(spi_host_device_t host)
{
#if (SOC_SPI_PERIPH_NUM == 2)
@ -112,7 +109,7 @@ bool spicommon_periph_claim(spi_host_device_t host, const char* source)
spi_ll_reset_register(host);
}
} else {
ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]);
ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host + 1, spi_claiming_func[host]);
}
return ret;
}
@ -217,7 +214,7 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
if (dma_chan == SPI_DMA_CH_AUTO) {
#if CONFIG_IDF_TARGET_ESP32
for (int i = 1; i < SOC_SPI_DMA_CHAN_NUM+1; i++) {
for (int i = 1; i < SOC_SPI_DMA_CHAN_NUM + 1; i++) {
success = claim_dma_chan(i, &actual_dma_chan);
if (success) {
break;
@ -330,7 +327,6 @@ esp_err_t spicommon_gdma_get_handle(spi_host_device_t host_id, gdma_channel_hand
(gdma_direction == GDMA_CHANNEL_DIRECTION_RX), \
ESP_ERR_INVALID_ARG, SPI_TAG, "GDMA Direction not supported!");
if (gdma_direction == GDMA_CHANNEL_DIRECTION_TX) {
*gdma_handle = bus_ctx[host_id]->tx_channel;
}
@ -355,15 +351,15 @@ static esp_err_t dma_chan_free(spi_host_device_t host_id)
portENTER_CRITICAL(&spi_dma_spinlock);
spi_dma_chan_enabled &= ~BIT(dma_chan);
#if SPI_LL_DMA_SHARED
PERIPH_RCC_RELEASE_ATOMIC(get_dma_periph(dma_chan), ref_count) {
if (ref_count == 0) {
spi_dma_ll_enable_bus_clock(host_id, false);
}
}
#else
SPI_COMMON_RCC_CLOCK_ATOMIC() {
PERIPH_RCC_RELEASE_ATOMIC(get_dma_periph(dma_chan), ref_count) {
if (ref_count == 0) {
spi_dma_ll_enable_bus_clock(host_id, false);
}
}
#else
SPI_COMMON_RCC_CLOCK_ATOMIC() {
spi_dma_ll_enable_bus_clock(host_id, false);
}
#endif
portEXIT_CRITICAL(&spi_dma_spinlock);
@ -400,10 +396,12 @@ static bool check_iomux_pins_oct(spi_host_device_t host, const spi_bus_config_t*
return false;
}
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};
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++) {
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;
}
@ -414,24 +412,24 @@ static bool check_iomux_pins_oct(spi_host_device_t host, const spi_bus_config_t*
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) {
if (bus_config->sclk_io_num >= 0 &&
bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) {
return false;
}
if (bus_config->quadwp_io_num>=0 &&
bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
if (bus_config->quadwp_io_num >= 0 &&
bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
return false;
}
if (bus_config->quadhd_io_num>=0 &&
bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
if (bus_config->quadhd_io_num >= 0 &&
bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
return false;
}
if (bus_config->mosi_io_num >= 0 &&
bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
return false;
}
if (bus_config->miso_io_num>=0 &&
bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
if (bus_config->miso_io_num >= 0 &&
bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
return false;
}
return true;
@ -454,11 +452,13 @@ static void bus_iomux_pins_set_oct(spi_host_device_t host, const spi_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};
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++) {
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
@ -526,15 +526,15 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
bool miso_need_output;
bool mosi_need_output;
bool sclk_need_output;
if ((flags&SPICOMMON_BUSFLAG_MASTER) != 0) {
if ((flags & SPICOMMON_BUSFLAG_MASTER) != 0) {
//initial for master
miso_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
miso_need_output = ((flags & SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
mosi_need_output = true;
sclk_need_output = true;
} else {
//initial for slave
miso_need_output = true;
mosi_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
mosi_need_output = ((flags & SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
sclk_need_output = false;
}
@ -542,14 +542,14 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
const bool hd_need_output = true;
//check pin capabilities
if (bus_config->sclk_io_num>=0) {
if (bus_config->sclk_io_num >= 0) {
temp_flag |= SPICOMMON_BUSFLAG_SCLK;
SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", sclk_need_output);
}
if (bus_config->quadwp_io_num>=0) {
if (bus_config->quadwp_io_num >= 0) {
SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", wp_need_output);
}
if (bus_config->quadhd_io_num>=0) {
if (bus_config->quadhd_io_num >= 0) {
SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
}
#if SOC_SPI_SUPPORT_OCT
@ -576,7 +576,9 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
#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->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);
@ -586,8 +588,8 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
}
//set flags for DUAL mode according to output-capability of MOSI and MISO pins.
if ( (bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
(bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num)) ) {
if ((bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
(bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num))) {
temp_flag |= SPICOMMON_BUSFLAG_DUAL;
}
@ -603,7 +605,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
if (missing_flag != 0) {
//check pins existence
//check pins existence
if (missing_flag & SPICOMMON_BUSFLAG_SCLK) {
ESP_LOGE(SPI_TAG, "sclk pin required.");
}
@ -633,13 +635,13 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
if (use_iomux) {
//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);
ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host + 1);
bus_iomux_pins_set(host, bus_config);
} else {
//Use GPIO matrix
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host + 1);
if (bus_config->mosi_io_num >= 0) {
if (mosi_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
if (mosi_need_output || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) {
gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
esp_rom_gpio_connect_out_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_out, false, false);
} else {
@ -652,7 +654,7 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
}
if (bus_config->miso_io_num >= 0) {
if (miso_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
if (miso_need_output || (temp_flag & SPICOMMON_BUSFLAG_DUAL)) {
gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT);
esp_rom_gpio_connect_out_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_out, false, false);
} else {
@ -699,9 +701,10 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
if ((flags & SPICOMMON_BUSFLAG_OCTAL) == 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}};
{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);
@ -717,7 +720,9 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
#endif //SOC_SPI_SUPPORT_OCT
}
if (flags_o) *flags_o = temp_flag;
if (flags_o) {
*flags_o = temp_flag;
}
return ESP_OK;
}
@ -730,7 +735,7 @@ esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
bus_cfg->quadwp_io_num,
bus_cfg->quadhd_io_num,
};
for (int i = 0; i < sizeof(pin_array)/sizeof(int); i ++) {
for (int i = 0; i < sizeof(pin_array) / sizeof(int); i ++) {
const int io = pin_array[i];
if (GPIO_IS_VALID_GPIO(io)) {
gpio_reset_pin(io);
@ -753,7 +758,9 @@ void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num,
} else {
gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
}
if (cs_num == 0) esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
if (cs_num == 0) {
esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
}
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
}
@ -776,7 +783,6 @@ bool spicommon_bus_using_iomux(spi_host_device_t host)
return true;
}
void spi_bus_main_set_lock(spi_bus_lock_handle_t lock)
{
bus_ctx[0]->bus_attr.lock = lock;
@ -799,15 +805,15 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
#ifdef CONFIG_IDF_TARGET_ESP32
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
#elif CONFIG_IDF_TARGET_ESP32S2
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
#elif SOC_GDMA_SUPPORTED
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG);
#endif
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
#ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
#endif
bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
@ -835,7 +841,9 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
bus_attr->rx_dma_chan = actual_rx_dma_chan;
int dma_desc_ct = (bus_config->max_transfer_sz + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
if (dma_desc_ct == 0) {
dma_desc_ct = 1; //default to 4k when max is not given
}
bus_attr->max_transfer_sz = dma_desc_ct * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
bus_attr->dmadesc_tx = heap_caps_aligned_alloc(DMA_DESC_MEM_ALIGN_SIZE, sizeof(spi_dma_desc_t) * dma_desc_ct, MALLOC_CAP_DMA);
@ -867,7 +875,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *
#ifdef CONFIG_PM_ENABLE
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
&bus_attr->pm_lock);
&bus_attr->pm_lock);
if (err != ESP_OK) {
goto cleanup;
}
@ -904,7 +912,9 @@ cleanup:
const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id)
{
if (bus_ctx[host_id] == NULL) return NULL;
if (bus_ctx[host_id] == NULL) {
return NULL;
}
return &bus_ctx[host_id]->bus_attr;
}
@ -950,7 +960,6 @@ esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
return ESP_OK;
}
/*
Code for workaround for DMA issue in ESP32 v0/v1 silicon
*/
@ -967,7 +976,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t
int otherchan = (dmachan == 1) ? 2 : 1;
bool ret;
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
if (dmaworkaround_channels_busy[otherchan-1]) {
if (dmaworkaround_channels_busy[otherchan - 1]) {
//Other channel is busy. Call back when it's done.
dmaworkaround_cb = cb;
dmaworkaround_cb_arg = arg;
@ -975,7 +984,7 @@ bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t
ret = false;
} else {
//Reset DMA
periph_module_reset( PERIPH_SPI_DMA_MODULE );
periph_module_reset(PERIPH_SPI_DMA_MODULE);
ret = true;
}
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
@ -990,10 +999,10 @@ bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
{
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
dmaworkaround_channels_busy[dmachan-1] = 0;
dmaworkaround_channels_busy[dmachan - 1] = 0;
if (dmaworkaround_waiting_for_chan == dmachan) {
//Reset DMA
periph_module_reset( PERIPH_SPI_DMA_MODULE );
periph_module_reset(PERIPH_SPI_DMA_MODULE);
dmaworkaround_waiting_for_chan = 0;
//Call callback
dmaworkaround_cb(dmaworkaround_cb_arg);
@ -1005,7 +1014,7 @@ void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
{
portENTER_CRITICAL_ISR(&dmaworkaround_mux);
dmaworkaround_channels_busy[dmachan-1] = 1;
dmaworkaround_channels_busy[dmachan - 1] = 1;
portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
}
#endif //#if CONFIG_IDF_TARGET_ESP32

View File

@ -137,7 +137,7 @@ typedef struct spi_device_t spi_device_t;
typedef struct {
spi_transaction_t *trans;
const uint32_t *buffer_to_send; //equals to tx_data, if SPI_TRANS_USE_RXDATA is applied; otherwise if original buffer wasn't in DMA-capable memory, this gets the address of a temporary buffer that is;
//otherwise sets to the original buffer or NULL if no buffer is assigned.
//otherwise sets to the original buffer or NULL if no buffer is assigned.
uint32_t *buffer_to_rcv; // similar to buffer_to_send
} spi_trans_priv_t;
@ -305,7 +305,7 @@ static esp_err_t spi_master_deinit_driver(void* arg)
SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
int x;
for (x=0; x<DEV_NUM_MAX; x++) {
for (x = 0; x < DEV_NUM_MAX; x++) {
SPI_CHECK(host->device[x] == NULL, "not all CSses freed", ESP_ERR_INVALID_STATE);
}
@ -326,8 +326,12 @@ void spi_get_timing(bool gpio_is_used, int input_delay_ns, int eff_clk, int* dum
int timing_miso_delay;
spi_hal_cal_timing(APB_CLK_FREQ, eff_clk, gpio_is_used, input_delay_ns, &timing_dummy, &timing_miso_delay);
if (dummy_o) *dummy_o = timing_dummy;
if (cycles_remain_o) *cycles_remain_o = timing_miso_delay;
if (dummy_o) {
*dummy_o = timing_dummy;
}
if (cycles_remain_o) {
*cycles_remain_o = timing_miso_delay;
}
#else
//TODO: IDF-6578
ESP_LOGW(SPI_TAG, "This func temporary not supported for current target!");
@ -382,7 +386,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
//The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
//duplex mode does absolutely nothing on the ESP32.
SPI_CHECK(dev_config->cs_ena_pretrans <= 1 || (dev_config->address_bits == 0 && dev_config->command_bits == 0) ||
(dev_config->flags & SPI_DEVICE_HALFDUPLEX), "In full-duplex mode, only support cs pretrans delay = 1 and without address_bits and command_bits", ESP_ERR_INVALID_ARG);
(dev_config->flags & SPI_DEVICE_HALFDUPLEX), "In full-duplex mode, only support cs pretrans delay = 1 and without address_bits and command_bits", ESP_ERR_INVALID_ARG);
#endif
//Check post_cb status when `SPI_DEVICE_NO_RETURN_RESULT` flag is set.
@ -428,7 +432,9 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
//Allocate memory for device
dev = malloc(sizeof(spi_device_t));
if (dev == NULL) goto nomem;
if (dev == NULL) {
goto nomem;
}
memset(dev, 0, sizeof(spi_device_t));
dev->id = freecs;
@ -461,7 +467,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
//save a pointer to device in spi_host_t
host->device[freecs] = dev;
//save a pointer to host in spi_device_t
dev->host= host;
dev->host = host;
//initialise the device specific configuration
spi_hal_dev_config_t *hal_dev = &(dev->hal_dev);
@ -486,14 +492,18 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
hal_dev->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
*handle = dev;
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id+1, freecs, freq/1000);
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id + 1, freecs, freq / 1000);
return ESP_OK;
nomem:
if (dev) {
if (dev->trans_queue) vQueueDelete(dev->trans_queue);
if (dev->ret_queue) vQueueDelete(dev->ret_queue);
if (dev->trans_queue) {
vQueueDelete(dev->trans_queue);
}
if (dev->ret_queue) {
vQueueDelete(dev->ret_queue);
}
spi_bus_lock_unregister_dev(dev->dev_lock);
}
free(dev);
@ -502,13 +512,13 @@ nomem:
esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
{
SPI_CHECK(handle!=NULL, "invalid handle", ESP_ERR_INVALID_ARG);
SPI_CHECK(handle != NULL, "invalid handle", ESP_ERR_INVALID_ARG);
//These checks aren't exhaustive; another thread could sneak in a transaction inbetween. These are only here to
//catch design errors and aren't meant to be triggered during normal operation.
SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
SPI_CHECK(uxQueueMessagesWaiting(handle->trans_queue) == 0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
SPI_CHECK(handle->host->cur_cs == DEV_NUM_MAX || handle->host->device[handle->host->cur_cs] != handle, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
if (handle->ret_queue) {
SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue)==0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
SPI_CHECK(uxQueueMessagesWaiting(handle->ret_queue) == 0, "Have unfinished transactions", ESP_ERR_INVALID_STATE);
}
#if SOC_SPI_SUPPORT_CLK_RC_FAST
@ -519,11 +529,17 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
//return
int spics_io_num = handle->cfg.spics_io_num;
if (spics_io_num >= 0) spicommon_cs_free_io(spics_io_num);
if (spics_io_num >= 0) {
spicommon_cs_free_io(spics_io_num);
}
//Kill queues
if (handle->trans_queue) vQueueDelete(handle->trans_queue);
if (handle->ret_queue) vQueueDelete(handle->ret_queue);
if (handle->trans_queue) {
vQueueDelete(handle->trans_queue);
}
if (handle->ret_queue) {
vQueueDelete(handle->ret_queue);
}
spi_bus_lock_unregister_dev(handle->dev_lock);
assert(handle->host->device[handle->id] == handle);
@ -534,7 +550,7 @@ esp_err_t spi_bus_remove_device(spi_device_handle_t handle)
esp_err_t spi_device_get_actual_freq(spi_device_handle_t handle, int* freq_khz)
{
if ((spi_device_t*)handle == NULL || freq_khz == NULL) {
if ((spi_device_t *)handle == NULL || freq_khz == NULL) {
return ESP_ERR_INVALID_ARG;
}
@ -568,7 +584,9 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev)
static SPI_MASTER_ISR_ATTR spi_device_t *get_acquiring_dev(spi_host_t *host)
{
spi_bus_lock_dev_handle_t dev_lock = spi_bus_lock_get_acquiring_dev(host->bus_attr->lock);
if (!dev_lock) return NULL;
if (!dev_lock) {
return NULL;
}
return host->device[spi_bus_lock_get_dev_id(dev_lock)];
}
@ -623,7 +641,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
//Set up OIO/QIO/DIO if needed
hal_trans.line_mode.data_lines = (trans->flags & SPI_TRANS_MODE_DIO) ? 2 :
(trans->flags & SPI_TRANS_MODE_QIO) ? 4 : 1;
(trans->flags & SPI_TRANS_MODE_QIO) ? 4 : 1;
#if SOC_SPI_SUPPORT_OCT
if (trans->flags & SPI_TRANS_MODE_OCT) {
hal_trans.line_mode.data_lines = 8;
@ -652,7 +670,9 @@ static void SPI_MASTER_ISR_ATTR spi_new_trans(spi_device_t *dev, spi_trans_priv_
spi_hal_prepare_data(hal, hal_dev, &hal_trans);
//Call pre-transmission callback, if any
if (dev->cfg.pre_cb) dev->cfg.pre_cb(trans);
if (dev->cfg.pre_cb) {
dev->cfg.pre_cb(trans);
}
//Kick off transfer
spi_hal_user_start(hal);
}
@ -666,7 +686,9 @@ static void SPI_MASTER_ISR_ATTR spi_post_trans(spi_host_t *host)
spi_hal_fetch_result(&host->hal);
//Call post-transaction callback, if any
spi_device_t* dev = host->device[host->cur_cs];
if (dev->cfg.post_cb) dev->cfg.post_cb(cur_trans);
if (dev->cfg.post_cb) {
dev->cfg.post_cb(cur_trans);
}
host->cur_cs = DEV_NUM_MAX;
}
@ -734,7 +756,6 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
spi_bus_lock_handle_t lock = host->bus_attr->lock;
BaseType_t trans_found = pdFALSE;
// There should be remaining requests
BUS_LOCK_DEBUG_EXECUTE_CHECK(spi_bus_lock_bg_req_exist(lock));
@ -781,26 +802,28 @@ static void SPI_MASTER_ISR_ATTR spi_intr(void *arg)
// or resume acquiring device task (if quit due to bus acquiring).
} while (!spi_bus_lock_bg_exit(lock, trans_found, &do_yield));
if (do_yield) portYIELD_FROM_ISR();
if (do_yield) {
portYIELD_FROM_ISR();
}
}
static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handle, spi_transaction_t *trans_desc)
{
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
spi_host_t *host = handle->host;
const spi_bus_attr_t* bus_attr = host->bus_attr;
bool tx_enabled = (trans_desc->flags & SPI_TRANS_USE_TXDATA) || (trans_desc->tx_buffer);
bool rx_enabled = (trans_desc->flags & SPI_TRANS_USE_RXDATA) || (trans_desc->rx_buffer);
spi_transaction_ext_t *t_ext = (spi_transaction_ext_t *)trans_desc;
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY)? t_ext->dummy_bits: handle->cfg.dummy_bits) != 0);
bool dummy_enabled = (((trans_desc->flags & SPI_TRANS_VARIABLE_DUMMY) ? t_ext->dummy_bits : handle->cfg.dummy_bits) != 0);
bool extra_dummy_enabled = handle->hal_dev.timing_conf.timing_dummy;
bool is_half_duplex = ((handle->cfg.flags & SPI_DEVICE_HALFDUPLEX) != 0);
//check transmission length
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA)==0 || trans_desc->rxlength <= 32, "SPI_TRANS_USE_RXDATA only available for rxdata transfer <= 32 bits", ESP_ERR_INVALID_ARG);
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA)==0 || trans_desc->length <= 32, "SPI_TRANS_USE_TXDATA only available for txdata transfer <= 32 bits", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= bus_attr->max_transfer_sz*8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->rxlength <= bus_attr->max_transfer_sz*8, "rxdata transfer > host maximum", ESP_ERR_INVALID_ARG);
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_RXDATA) == 0 || trans_desc->rxlength <= 32, "SPI_TRANS_USE_RXDATA only available for rxdata transfer <= 32 bits", ESP_ERR_INVALID_ARG);
SPI_CHECK((trans_desc->flags & SPI_TRANS_USE_TXDATA) == 0 || trans_desc->length <= 32, "SPI_TRANS_USE_TXDATA only available for txdata transfer <= 32 bits", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= bus_attr->max_transfer_sz * 8, "txdata transfer > host maximum", ESP_ERR_INVALID_ARG);
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
#if SOC_SPI_SUPPORT_OCT
@ -808,10 +831,10 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "Incompatible when setting to both Octal mode and 3-wire-mode", ESP_ERR_INVALID_ARG);
SPI_CHECK(!((trans_desc->flags & SPI_TRANS_MODE_OCT) && !is_half_duplex), "Incompatible when setting to both Octal mode and half duplex mode", 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 when setting to both multi-line mode and 3-wire-mode", ESP_ERR_INVALID_ARG);
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO|SPI_TRANS_MODE_QIO)) && !is_half_duplex), "Incompatible when setting to both multi-line mode and half duplex mode", ESP_ERR_INVALID_ARG);
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO | SPI_TRANS_MODE_QIO)) && (handle->cfg.flags & SPI_DEVICE_3WIRE)), "Incompatible when setting to both multi-line mode and 3-wire-mode", ESP_ERR_INVALID_ARG);
SPI_CHECK(!((trans_desc->flags & (SPI_TRANS_MODE_DIO | SPI_TRANS_MODE_QIO)) && !is_half_duplex), "Incompatible when setting to both multi-line mode and half duplex mode", 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 );
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);
#endif
#if !SOC_SPI_HD_BOTH_INOUT_SUPPORTED
//On these chips, HW doesn't support using both TX and RX phases when in halfduplex mode
@ -825,8 +848,8 @@ static SPI_MASTER_ISR_ATTR esp_err_t check_trans_valid(spi_device_handle_t handl
SPI_CHECK(!is_half_duplex || trans_desc->rxlength != 0 || !rx_enabled, "trans rx_buffer should be NULL and SPI_TRANS_USE_RXDATA should be cleared to skip MISO phase.", ESP_ERR_INVALID_ARG);
//In Full duplex mode, default rxlength to be the same as length, if not filled in.
// set rxlength to length is ok, even when rx buffer=NULL
if (trans_desc->rxlength==0 && !is_half_duplex) {
trans_desc->rxlength=trans_desc->length;
if (trans_desc->rxlength == 0 && !is_half_duplex) {
trans_desc->rxlength = trans_desc->length;
}
//Dummy phase is not available when both data out and in are enabled, regardless of FD or HD mode.
SPI_CHECK(!tx_enabled || !rx_enabled || !dummy_enabled || !extra_dummy_enabled, "Dummy phase is not available when both data out and in are enabled", ESP_ERR_INVALID_ARG);
@ -846,7 +869,7 @@ static SPI_MASTER_ISR_ATTR void uninstall_priv_desc(spi_trans_priv_t* trans_buf)
{
spi_transaction_t *trans_desc = trans_buf->trans;
if ((void *)trans_buf->buffer_to_send != &trans_desc->tx_data[0] &&
trans_buf->buffer_to_send != trans_desc->tx_buffer) {
trans_buf->buffer_to_send != trans_desc->tx_buffer) {
free((void *)trans_buf->buffer_to_send); //force free, ignore const
}
// copy data from temporary DMA-capable buffer back to IRAM buffer and free the temporary one.
@ -868,7 +891,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
// rx memory assign
uint32_t* rcv_ptr;
if ( trans_desc->flags & SPI_TRANS_USE_RXDATA ) {
if (trans_desc->flags & SPI_TRANS_USE_RXDATA) {
rcv_ptr = (uint32_t *)&trans_desc->rx_data[0];
} else {
//if not use RXDATA neither rx_buffer, buffer_to_rcv assigned to NULL
@ -877,7 +900,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
// tx memory assign
const uint32_t *send_ptr;
if ( trans_desc->flags & SPI_TRANS_USE_TXDATA ) {
if (trans_desc->flags & SPI_TRANS_USE_TXDATA) {
send_ptr = (uint32_t *)&trans_desc->tx_data[0];
} else {
//if not use TXDATA neither tx_buffer, tx data assigned to NULL
@ -895,17 +918,17 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
#endif
if (send_ptr && bus_attr->dma_enabled) {
if ((!esp_ptr_dma_capable(send_ptr) || tx_unaligned )) {
if ((!esp_ptr_dma_capable(send_ptr) || tx_unaligned)) {
ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but TX buffer addr&len not align to %d, or not dma_capable", alignment);
//if txbuf in the desc not DMA-capable, or not bytes aligned to alignment, malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA" );
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA");
tx_byte_len = (tx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment
uint32_t *temp = heap_caps_aligned_alloc(alignment, tx_byte_len, MALLOC_CAP_DMA);
if (temp == NULL) {
goto clean_up;
}
memcpy( temp, send_ptr, (trans_desc->length + 7) / 8 );
memcpy(temp, send_ptr, (trans_desc->length + 7) / 8);
send_ptr = temp;
}
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
@ -914,10 +937,10 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_host_t *host, spi_trans
#endif
}
if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_unaligned )) {
if (rcv_ptr && bus_attr->dma_enabled && (!esp_ptr_dma_capable(rcv_ptr) || rx_unaligned)) {
ESP_RETURN_ON_FALSE(!(trans_desc->flags & SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL), ESP_ERR_INVALID_ARG, SPI_TAG, "Set flag SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL but RX buffer addr&len not align to %d, or not dma_capable", alignment);
//if rxbuf in the desc not DMA-capable, or not aligned to alignment, malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA" );
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA");
rx_byte_len = (rx_byte_len + alignment - 1) & (~(alignment - 1)); // up align alignment
rcv_ptr = heap_caps_aligned_alloc(alignment, rx_byte_len, MALLOC_CAP_DMA);
if (rcv_ptr == NULL) {
@ -936,11 +959,13 @@ clean_up:
esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait)
{
esp_err_t ret = check_trans_valid(handle, trans_desc);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
spi_host_t *host = handle->host;
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE );
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot queue new transaction while previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE);
/* Even when using interrupt transfer, the CS can only be kept activated if the bus has been
* acquired with `spi_device_acquire_bus()` first. */
@ -950,7 +975,9 @@ esp_err_t SPI_MASTER_ATTR spi_device_queue_trans(spi_device_handle_t handle, spi
spi_trans_priv_t trans_buf = { .trans = trans_desc, };
ret = setup_priv_desc(host, &trans_buf);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
#ifdef CONFIG_PM_ENABLE
// though clock source is selectable, read/write reg and mem of spi peripherial still use APB
@ -985,14 +1012,14 @@ esp_err_t SPI_MASTER_ATTR spi_device_get_trans_result(spi_device_handle_t handle
{
BaseType_t r;
spi_trans_priv_t trans_buf;
SPI_CHECK(handle!=NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
SPI_CHECK(handle != NULL, "invalid dev handle", ESP_ERR_INVALID_ARG);
bool use_dma = handle->host->bus_attr->dma_enabled;
//if SPI_DEVICE_NO_RETURN_RESULT is set, ret_queue will always be empty
SPI_CHECK(!(handle->cfg.flags & SPI_DEVICE_NO_RETURN_RESULT), "API not Supported!", ESP_ERR_NOT_SUPPORTED);
//use the interrupt, block until return
r=xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
r = xQueueReceive(handle->ret_queue, (void*)&trans_buf, ticks_to_wait);
if (!r) {
// The memory occupied by rx and tx DMA buffer destroyed only when receiving from the queue (transaction finished).
// If timeout, wait and retry.
@ -1015,10 +1042,14 @@ esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_tr
spi_transaction_t *ret_trans;
//ToDo: check if any spi transfers in flight
ret = spi_device_queue_trans(handle, trans_desc, portMAX_DELAY);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
ret = spi_device_get_trans_result(handle, &ret_trans, portMAX_DELAY);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
assert(ret_trans == trans_desc);
return ESP_OK;
@ -1027,8 +1058,8 @@ esp_err_t SPI_MASTER_ATTR spi_device_transmit(spi_device_handle_t handle, spi_tr
esp_err_t SPI_MASTER_ISR_ATTR spi_device_acquire_bus(spi_device_t *device, TickType_t wait)
{
spi_host_t *const host = device->host;
SPI_CHECK(wait==portMAX_DELAY, "acquire finite time not supported now.", ESP_ERR_INVALID_ARG);
SPI_CHECK(!spi_bus_device_is_polling(device), "Cannot acquire bus when a polling transaction is in progress.", ESP_ERR_INVALID_STATE );
SPI_CHECK(wait == portMAX_DELAY, "acquire finite time not supported now.", ESP_ERR_INVALID_ARG);
SPI_CHECK(!spi_bus_device_is_polling(device), "Cannot acquire bus when a polling transaction is in progress.", ESP_ERR_INVALID_STATE);
esp_err_t ret = spi_bus_lock_acquire_start(device->dev_lock, wait);
if (ret != ESP_OK) {
@ -1062,7 +1093,7 @@ void SPI_MASTER_ISR_ATTR spi_device_release_bus(spi_device_t *dev)
{
spi_host_t *host = dev->host;
if (spi_bus_device_is_polling(dev)){
if (spi_bus_device_is_polling(dev)) {
ESP_EARLY_LOGE(SPI_TAG, "Cannot release bus when a polling transaction is in progress.");
assert(0);
}
@ -1093,13 +1124,17 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_start(spi_device_handle_t handl
esp_err_t ret;
SPI_CHECK(ticks_to_wait == portMAX_DELAY, "currently timeout is not available for polling transactions", ESP_ERR_INVALID_ARG);
ret = check_trans_valid(handle, trans_desc);
if (ret!=ESP_OK) return ret;
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE );
if (ret != ESP_OK) {
return ret;
}
SPI_CHECK(!spi_bus_device_is_polling(handle), "Cannot send polling transaction while the previous polling transaction is not terminated.", ESP_ERR_INVALID_STATE);
spi_host_t *host = handle->host;
spi_trans_priv_t priv_polling_trans = { .trans = trans_desc, };
ret = setup_priv_desc(host, &priv_polling_trans);
if (ret!=ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
/* If device_acquiring_lock is set to handle, it means that the user has already
* acquired the bus thanks to the function `spi_device_acquire_bus()`.
@ -1182,7 +1217,9 @@ esp_err_t SPI_MASTER_ISR_ATTR spi_device_polling_transmit(spi_device_handle_t ha
{
esp_err_t ret;
ret = spi_device_polling_start(handle, trans_desc, portMAX_DELAY);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
return spi_device_polling_end(handle, portMAX_DELAY);
}

View File

@ -36,7 +36,6 @@ static const char *SPI_TAG = "spi_slave";
#define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str)
#ifdef CONFIG_SPI_SLAVE_ISR_IN_IRAM
#define SPI_SLAVE_ISR_ATTR IRAM_ATTR
#else
@ -98,7 +97,7 @@ static inline bool is_valid_host(spi_host_device_t host)
static inline bool SPI_SLAVE_ISR_ATTR bus_is_iomux(spi_slave_t *host)
{
return host->flags&SPICOMMON_BUSFLAG_IOMUX_PINS;
return host->flags & SPICOMMON_BUSFLAG_IOMUX_PINS;
}
static void SPI_SLAVE_ISR_ATTR freeze_cs(spi_slave_t *host)
@ -139,24 +138,24 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
esp_err_t err;
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
#ifdef CONFIG_IDF_TARGET_ESP32
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
#elif CONFIG_IDF_TARGET_ESP32S2
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG);
#elif SOC_GDMA_SUPPORTED
SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG);
#endif
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
#ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
#endif
SPI_CHECK(slave_config->spics_io_num < 0 || GPIO_IS_VALID_GPIO(slave_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG);
//Check post_trans_cb status when `SPI_SLAVE_NO_RETURN_RESULT` flag is set.
if(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT) {
if (slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT) {
SPI_CHECK(slave_config->post_trans_cb != NULL, "use feature flag 'SPI_SLAVE_NO_RETURN_RESULT' but no post_trans_cb function sets", ESP_ERR_INVALID_ARG);
}
spi_chan_claimed=spicommon_periph_claim(host, "spi slave");
spi_chan_claimed = spicommon_periph_claim(host, "spi slave");
SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE);
spihost[host] = malloc(sizeof(spi_slave_t));
@ -181,7 +180,9 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
//See how many dma descriptors we need and allocate them
int dma_desc_ct = (bus_config->max_transfer_sz + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN;
if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
if (dma_desc_ct == 0) {
dma_desc_ct = 1; //default to 4k when max is not given
}
spihost[host]->max_transfer_sz = dma_desc_ct * SPI_MAX_DMA_LEN;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
size_t alignment;
@ -203,8 +204,8 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
spihost[host]->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
}
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE|bus_config->flags, &spihost[host]->flags);
if (err!=ESP_OK) {
err = spicommon_bus_initialize_io(host, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, &spihost[host]->flags);
if (err != ESP_OK) {
ret = err;
goto cleanup;
}
@ -216,11 +217,13 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
}
// The slave DMA suffers from unexpected transactions. Forbid reading if DMA is enabled by disabling the CS line.
if (spihost[host]->dma_enabled) freeze_cs(spihost[host]);
if (spihost[host]->dma_enabled) {
freeze_cs(spihost[host]);
}
#ifdef CONFIG_PM_ENABLE
err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_slave",
&spihost[host]->pm_lock);
&spihost[host]->pm_lock);
if (err != ESP_OK) {
ret = err;
goto cleanup;
@ -235,7 +238,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
if(!(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT)) {
if (!(slave_config->flags & SPI_SLAVE_NO_RETURN_RESULT)) {
spihost[host]->ret_queue = xQueueCreate(slave_config->queue_size, sizeof(spi_slave_trans_priv_t));
if (!spihost[host]->ret_queue) {
ret = ESP_ERR_NO_MEM;
@ -282,8 +285,12 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b
cleanup:
if (spihost[host]) {
if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
if (spihost[host]->trans_queue) {
vQueueDelete(spihost[host]->trans_queue);
}
if (spihost[host]->ret_queue) {
vQueueDelete(spihost[host]->ret_queue);
}
#ifdef CONFIG_PM_ENABLE
if (spihost[host]->pm_lock) {
esp_pm_lock_release(spihost[host]->pm_lock);
@ -309,8 +316,12 @@ esp_err_t spi_slave_free(spi_host_device_t host)
{
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
if (spihost[host]->trans_queue) vQueueDelete(spihost[host]->trans_queue);
if (spihost[host]->ret_queue) vQueueDelete(spihost[host]->ret_queue);
if (spihost[host]->trans_queue) {
vQueueDelete(spihost[host]->trans_queue);
}
if (spihost[host]->ret_queue) {
vQueueDelete(spihost[host]->ret_queue);
}
if (spihost[host]->dma_enabled) {
spicommon_dma_chan_free(host);
free(spihost[host]->hal.dmadesc_tx);
@ -357,10 +368,10 @@ static esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_setup_priv_trans(spi_host_device_t
uint32_t buffer_byte_len = (trans->length + 7) / 8;
if (spihost[host]->dma_enabled && trans->tx_buffer) {
if ((!esp_ptr_dma_capable( trans->tx_buffer ) || ((((uint32_t)trans->tx_buffer) | buffer_byte_len) & (alignment - 1)))) {
if ((!esp_ptr_dma_capable(trans->tx_buffer) || ((((uint32_t)trans->tx_buffer) | buffer_byte_len) & (alignment - 1)))) {
ESP_RETURN_ON_FALSE_ISR(trans->flags & SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, SPI_TAG, "TX buffer addr&len not align to %d, or not dma_capable", alignment);
//if txbuf in the desc not DMA-capable, or not align to "alignment", malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA" );
ESP_EARLY_LOGD(SPI_TAG, "Allocate TX buffer for DMA");
buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1)); // up align to "alignment"
uint32_t *temp = heap_caps_aligned_alloc(alignment, buffer_byte_len, MALLOC_CAP_DMA);
if (temp == NULL) {
@ -376,11 +387,11 @@ static esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_setup_priv_trans(spi_host_device_t
if (spihost[host]->dma_enabled && trans->rx_buffer && (!esp_ptr_dma_capable(trans->rx_buffer) || ((((uint32_t)trans->rx_buffer) | (trans->length + 7) / 8) & (alignment - 1)))) {
ESP_RETURN_ON_FALSE_ISR(trans->flags & SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, SPI_TAG, "RX buffer addr&len not align to %d, or not dma_capable", alignment);
//if rxbuf in the desc not DMA-capable, or not align to "alignment", malloc a new one
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA" );
ESP_EARLY_LOGD(SPI_TAG, "Allocate RX buffer for DMA");
buffer_byte_len = (buffer_byte_len + alignment - 1) & (~(alignment - 1)); // up align to "alignment"
priv_trans->rx_buffer = heap_caps_aligned_alloc(alignment, buffer_byte_len, MALLOC_CAP_DMA);
if (priv_trans->rx_buffer == NULL) {
free (priv_trans->tx_buffer);
free(priv_trans->tx_buffer);
return ESP_ERR_NO_MEM;
}
}
@ -393,12 +404,12 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
BaseType_t r;
SPI_CHECK(is_valid_host(host), "invalid host", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host], "host not slave", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer==NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->rx_buffer==NULL ||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
(trans_desc->length%4==0)),
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->tx_buffer == NULL || esp_ptr_dma_capable(trans_desc->tx_buffer),
"txdata not in DMA-capable memory", ESP_ERR_INVALID_ARG);
SPI_CHECK(spihost[host]->dma_enabled == 0 || trans_desc->rx_buffer == NULL ||
(esp_ptr_dma_capable(trans_desc->rx_buffer) && esp_ptr_word_aligned(trans_desc->rx_buffer) &&
(trans_desc->length % 4 == 0)),
"rxdata not in DMA-capable memory or not WORD aligned", ESP_ERR_INVALID_ARG);
SPI_CHECK(trans_desc->length <= spihost[host]->max_transfer_sz * 8, "data transfer > host maximum", ESP_ERR_INVALID_ARG);
@ -406,7 +417,9 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_trans(spi_host_device_t host, const spi
SPI_CHECK(ESP_OK == spi_slave_setup_priv_trans(host, &priv_trans), "slave setup priv_trans failed", ESP_ERR_NO_MEM);
r = xQueueSend(spihost[host]->trans_queue, (void *)&priv_trans, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;
if (!r) {
return ESP_ERR_TIMEOUT;
}
esp_intr_enable(spihost[host]->intr);
return ESP_OK;
}
@ -434,7 +447,7 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_queue_reset(spi_host_device_t host)
spi_ll_set_int_stat(spihost[host]->hal.hw);
spi_slave_trans_priv_t trans;
while( uxQueueMessagesWaiting(spihost[host]->trans_queue)) {
while (uxQueueMessagesWaiting(spihost[host]->trans_queue)) {
xQueueReceive(spihost[host]->trans_queue, &trans, 0);
spi_slave_uninstall_priv_trans(host, &trans);
}
@ -455,17 +468,17 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_trans_isr(spi_host_device_t host, c
uint32_t buffer_byte_len = (trans_desc->length + 7) / 8;
ESP_RETURN_ON_FALSE_ISR(\
(trans_desc->tx_buffer && \
esp_ptr_dma_capable(trans_desc->tx_buffer) && \
((((uint32_t)trans_desc->tx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "txdata addr & len not align to %d bytes or not dma_capable", alignment\
);
(trans_desc->tx_buffer && \
esp_ptr_dma_capable(trans_desc->tx_buffer) && \
((((uint32_t)trans_desc->tx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "txdata addr & len not align to %d bytes or not dma_capable", alignment\
);
ESP_RETURN_ON_FALSE_ISR(\
(trans_desc->rx_buffer && \
esp_ptr_dma_capable(trans_desc->rx_buffer) && \
((((uint32_t)trans_desc->rx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "rxdata addr & len not align to %d bytes or not dma_capable", alignment\
);
(trans_desc->rx_buffer && \
esp_ptr_dma_capable(trans_desc->rx_buffer) && \
((((uint32_t)trans_desc->rx_buffer) | buffer_byte_len) & (alignment - 1)) == 0), \
ESP_ERR_INVALID_ARG, SPI_TAG, "rxdata addr & len not align to %d bytes or not dma_capable", alignment\
);
}
spi_slave_trans_priv_t priv_trans = {
@ -490,7 +503,7 @@ esp_err_t SPI_SLAVE_ISR_ATTR spi_slave_queue_reset_isr(spi_host_device_t host)
spi_slave_trans_priv_t trans;
BaseType_t do_yield = pdFALSE;
while( pdFALSE == xQueueIsQueueEmptyFromISR(spihost[host]->trans_queue)) {
while (pdFALSE == xQueueIsQueueEmptyFromISR(spihost[host]->trans_queue)) {
xQueueReceiveFromISR(spihost[host]->trans_queue, &trans, &do_yield);
spi_slave_uninstall_priv_trans(host, &trans);
}
@ -512,23 +525,28 @@ esp_err_t SPI_SLAVE_ATTR spi_slave_get_trans_result(spi_host_device_t host, spi_
spi_slave_trans_priv_t priv_trans;
r = xQueueReceive(spihost[host]->ret_queue, (void *)&priv_trans, ticks_to_wait);
if (!r) return ESP_ERR_TIMEOUT;
if (!r) {
return ESP_ERR_TIMEOUT;
}
spi_slave_uninstall_priv_trans(host, &priv_trans);
*trans_desc = priv_trans.trans;
return ESP_OK;
}
esp_err_t SPI_SLAVE_ATTR spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait)
{
esp_err_t ret;
spi_slave_transaction_t *ret_trans;
//ToDo: check if any spi transfers in flight
ret = spi_slave_queue_trans(host, trans_desc, ticks_to_wait);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
ret = spi_slave_get_trans_result(host, &ret_trans, ticks_to_wait);
if (ret != ESP_OK) return ret;
if (ret != ESP_OK) {
return ret;
}
assert(ret_trans == trans_desc);
return ESP_OK;
}
@ -556,7 +574,9 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
bool use_dma = host->dma_enabled;
if (host->cur_trans.trans) {
// When DMA is enabled, the slave rx dma suffers from unexpected transactions. Forbid reading until transaction ready.
if (use_dma) freeze_cs(host);
if (use_dma) {
freeze_cs(host);
}
spi_slave_hal_store_result(hal);
host->cur_trans.trans->trans_len = spi_slave_hal_get_rcv_bitlen(hal);
@ -579,9 +599,11 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
assert(ret == ESP_OK);
}
#endif
if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans.trans);
if (host->cfg.post_trans_cb) {
host->cfg.post_trans_cb(host->cur_trans.trans);
}
if(!(host->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT)) {
if (!(host->cfg.flags & SPI_SLAVE_NO_RETURN_RESULT)) {
xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
}
host->cur_trans.trans = NULL;
@ -595,7 +617,9 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
if (spicommon_dmaworkaround_reset_in_progress()) {
//We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
esp_intr_disable(host->intr);
if (do_yield) portYIELD_FROM_ISR();
if (do_yield) {
portYIELD_FROM_ISR();
}
return;
}
}
@ -637,7 +661,11 @@ static void SPI_SLAVE_ISR_ATTR spi_intr(void *arg)
//Kick off transfer
spi_slave_hal_user_start(hal);
if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(priv_trans.trans);
if (host->cfg.post_setup_cb) {
host->cfg.post_setup_cb(priv_trans.trans);
}
}
if (do_yield) {
portYIELD_FROM_ISR();
}
if (do_yield) portYIELD_FROM_ISR();
}

View File

@ -198,12 +198,12 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
if (!host->append_mode) {
//Seg mode
ret = esp_intr_alloc(spicommon_irqsource_for_host(host_id), 0, spi_slave_hd_intr_segment,
(void *)host, &host->intr);
(void *)host, &host->intr);
if (ret != ESP_OK) {
goto cleanup;
}
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, spi_slave_hd_intr_segment,
(void *)host, &host->intr_dma);
(void *)host, &host->intr_dma);
if (ret != ESP_OK) {
goto cleanup;
}
@ -212,7 +212,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
//On ESP32S2, `cmd7` and `cmd8` interrupts registered as spi rx & tx interrupt are from SPI DMA interrupt source.
//although the `cmd7` and `cmd8` interrupt on spi are registered independently here
ret = esp_intr_alloc(spicommon_irqsource_for_host(host_id), 0, spi_slave_hd_intr_append,
(void *)host, &host->intr);
(void *)host, &host->intr);
if (ret != ESP_OK) {
goto cleanup;
}
@ -225,7 +225,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
gdma_register_tx_event_callbacks(host->gdma_handle_tx, &tx_cbs, host);
#else
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(host_id), 0, spi_slave_hd_intr_append,
(void *)host, &host->intr_dma);
(void *)host, &host->intr_dma);
if (ret != ESP_OK) {
goto cleanup;
}
@ -234,10 +234,18 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
//Init callbacks
memcpy((uint8_t *)&host->callback, (uint8_t *)&config->cb_config, sizeof(spi_slave_hd_callback_config_t));
spi_event_t event = 0;
if (host->callback.cb_buffer_tx != NULL) event |= SPI_EV_BUF_TX;
if (host->callback.cb_buffer_rx != NULL) event |= SPI_EV_BUF_RX;
if (host->callback.cb_cmd9 != NULL) event |= SPI_EV_CMD9;
if (host->callback.cb_cmdA != NULL) event |= SPI_EV_CMDA;
if (host->callback.cb_buffer_tx != NULL) {
event |= SPI_EV_BUF_TX;
}
if (host->callback.cb_buffer_rx != NULL) {
event |= SPI_EV_BUF_RX;
}
if (host->callback.cb_cmd9 != NULL) {
event |= SPI_EV_CMD9;
}
if (host->callback.cb_cmdA != NULL) {
event |= SPI_EV_CMDA;
}
spi_slave_hd_hal_enable_event_intr(&host->hal, event);
return ESP_OK;
@ -251,14 +259,28 @@ cleanup:
esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
{
spi_slave_hd_slot_t *host = spihost[host_id];
if (host == NULL) return ESP_ERR_INVALID_ARG;
if (host == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (host->tx_trans_queue) vQueueDelete(host->tx_trans_queue);
if (host->tx_ret_queue) vQueueDelete(host->tx_ret_queue);
if (host->rx_trans_queue) vQueueDelete(host->rx_trans_queue);
if (host->rx_ret_queue) vQueueDelete(host->rx_ret_queue);
if (host->tx_cnting_sem) vSemaphoreDelete(host->tx_cnting_sem);
if (host->rx_cnting_sem) vSemaphoreDelete(host->rx_cnting_sem);
if (host->tx_trans_queue) {
vQueueDelete(host->tx_trans_queue);
}
if (host->tx_ret_queue) {
vQueueDelete(host->tx_ret_queue);
}
if (host->rx_trans_queue) {
vQueueDelete(host->rx_trans_queue);
}
if (host->rx_ret_queue) {
vQueueDelete(host->rx_ret_queue);
}
if (host->tx_cnting_sem) {
vSemaphoreDelete(host->tx_cnting_sem);
}
if (host->rx_cnting_sem) {
vSemaphoreDelete(host->rx_cnting_sem);
}
esp_intr_free(host->intr);
esp_intr_free(host->intr_dma);
#ifdef CONFIG_PM_ENABLE
@ -418,7 +440,9 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg)
}
portEXIT_CRITICAL_ISR(&host->int_spinlock);
if (awoken == pdTRUE) portYIELD_FROM_ISR();
if (awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static IRAM_ATTR void spi_slave_hd_append_tx_isr(void *arg)
@ -456,7 +480,9 @@ static IRAM_ATTR void spi_slave_hd_append_tx_isr(void *arg)
assert(ret == pdTRUE);
}
}
if (awoken==pdTRUE) portYIELD_FROM_ISR();
if (awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
@ -467,7 +493,6 @@ static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
spi_slave_hd_trans_priv_t ret_priv_trans;
size_t trans_len;
while (1) {
@ -502,7 +527,9 @@ static IRAM_ATTR void spi_slave_hd_append_rx_isr(void *arg)
assert(ret == pdTRUE);
}
}
if (awoken==pdTRUE) portYIELD_FROM_ISR();
if (awoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
#if SOC_GDMA_SUPPORTED
@ -569,7 +596,7 @@ static esp_err_t s_spi_slave_hd_setup_priv_trans(spi_host_device_t host, spi_sla
if (((uint32_t)orig_trans->data) | (byte_len & (alignment - 1))) {
ESP_RETURN_ON_FALSE(orig_trans->flags & SPI_SLAVE_HD_TRANS_DMA_BUFFER_ALIGN_AUTO, ESP_ERR_INVALID_ARG, TAG, "data buffer addr&len not align to %d, or not dma_capable", alignment);
byte_len = (byte_len + alignment - 1) & (~(alignment - 1)); // up align to alignment
ESP_LOGD(TAG, "Re-allocate %s buffer of len %ld for DMA", (chan == SPI_SLAVE_CHAN_TX)?"TX":"RX", byte_len);
ESP_LOGD(TAG, "Re-allocate %s buffer of len %ld for DMA", (chan == SPI_SLAVE_CHAN_TX) ? "TX" : "RX", byte_len);
priv_trans->aligned_buffer = heap_caps_aligned_alloc(64, byte_len, MALLOC_CAP_DMA);
if (priv_trans->aligned_buffer == NULL) {
return ESP_ERR_NO_MEM;
@ -615,7 +642,7 @@ esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t c
SPIHD_CHECK(chan == SPI_SLAVE_CHAN_TX || chan == SPI_SLAVE_CHAN_RX, "Invalid channel", ESP_ERR_INVALID_ARG);
spi_slave_hd_trans_priv_t hd_priv_trans = {.trans = trans};
SPIHD_CHECK( ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
SPIHD_CHECK(ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
if (chan == SPI_SLAVE_CHAN_TX) {
BaseType_t ret = xQueueSend(host->tx_trans_queue, &hd_priv_trans, timeout);
@ -669,7 +696,7 @@ esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t
SPIHD_CHECK(chan == SPI_SLAVE_CHAN_TX || chan == SPI_SLAVE_CHAN_RX, "Invalid channel", ESP_ERR_INVALID_ARG);
spi_slave_hd_trans_priv_t hd_priv_trans = {.trans = trans};
SPIHD_CHECK( ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
SPIHD_CHECK(ESP_OK == s_spi_slave_hd_setup_priv_trans(host_id, &hd_priv_trans, chan), "No mem to allocate new cache buffer", ESP_ERR_NO_MEM);
if (chan == SPI_SLAVE_CHAN_TX) {
BaseType_t ret = xSemaphoreTake(host->tx_cnting_sem, timeout);

View File

@ -0,0 +1,26 @@
.spi_depends_default: &spi_depends_default
depends_components:
- esp_mm # for cache
- esp_driver_spi
- esp_driver_gpio
components/esp_driver_spi/test_apps/spi/master:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
<<: *spi_depends_default
components/esp_driver_spi/test_apps/spi/param:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
<<: *spi_depends_default
components/esp_driver_spi/test_apps/spi/slave:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
<<: *spi_depends_default
components/esp_driver_spi/test_apps/spi/slave_hd:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
- if: SOC_SPI_SUPPORT_SLAVE_HD_VER2 != 1
<<: *spi_depends_default

View File

@ -15,7 +15,7 @@ project(spi_master_test)
if(CONFIG_COMPILER_DUMP_RTL_FILES)
add_custom_target(check_test_app_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/driver/,${CMAKE_BINARY_DIR}/esp-idf/hal/
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_driver_spi/,${CMAKE_BINARY_DIR}/esp-idf/hal/
--elf-file ${CMAKE_BINARY_DIR}/spi_master_test.elf
find-refs
--from-sections=.iram0.text

View File

@ -11,6 +11,6 @@ set(srcs
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(
SRCS ${srcs}
PRIV_REQUIRES test_utils driver test_driver_utils spi_flash
PRIV_REQUIRES test_utils esp_driver_spi test_driver_utils spi_flash
WHOLE_ARCHIVE
)

View File

@ -13,7 +13,6 @@
#include "spi_flash_mmap.h"
#include "unity.h"
#if CONFIG_IDF_TARGET_ESP32
// The VSPI pins on UT_T1_ESP_FLASH are connected to a external flash
#define TEST_BUS_PIN_NUM_MISO VSPI_IOMUX_PIN_NUM_MISO
@ -50,21 +49,21 @@ const static char TAG[] = "test_spi";
void spi_task1(void* arg)
{
//task1 send 50 polling transactions, acquire the bus and send another 50
int count=0;
int count = 0;
spi_transaction_t t = {
.flags = SPI_TRANS_USE_TXDATA,
.tx_data = { 0x80, 0x12, 0x34, 0x56 },
.length = 4*8,
.length = 4 * 8,
};
spi_device_handle_t handle = ((task_context_t*)arg)->handle;
for( int j = 0; j < 50; j ++ ) {
TEST_ESP_OK(spi_device_polling_transmit( handle, &t ));
ESP_LOGI(TAG, "task1:%d", count++ );
for (int j = 0; j < 50; j ++) {
TEST_ESP_OK(spi_device_polling_transmit(handle, &t));
ESP_LOGI(TAG, "task1:%d", count++);
}
TEST_ESP_OK(spi_device_acquire_bus( handle, portMAX_DELAY ));
for( int j = 0; j < 50; j ++ ) {
TEST_ESP_OK(spi_device_polling_transmit( handle, &t ));
ESP_LOGI(TAG, "task1:%d", count++ );
TEST_ESP_OK(spi_device_acquire_bus(handle, portMAX_DELAY));
for (int j = 0; j < 50; j ++) {
TEST_ESP_OK(spi_device_polling_transmit(handle, &t));
ESP_LOGI(TAG, "task1:%d", count++);
}
spi_device_release_bus(handle);
ESP_LOGI(TAG, "task1 terminates");
@ -74,29 +73,29 @@ void spi_task1(void* arg)
void spi_task2(void* arg)
{
int count=0;
int count = 0;
//task2 acquire the bus, send 50 polling transactions and then 50 non-polling
spi_transaction_t t = {
.flags = SPI_TRANS_USE_TXDATA,
.tx_data = { 0x80, 0x12, 0x34, 0x56 },
.length = 4*8,
.length = 4 * 8,
};
spi_transaction_t *ret_t;
spi_device_handle_t handle = ((task_context_t*)arg)->handle;
TEST_ESP_OK(spi_device_acquire_bus( handle, portMAX_DELAY ));
TEST_ESP_OK(spi_device_acquire_bus(handle, portMAX_DELAY));
for (int i = 0; i < 50; i ++) {
TEST_ESP_OK(spi_device_polling_transmit(handle, &t));
ESP_LOGI( TAG, "task2: %d", count++ );
ESP_LOGI(TAG, "task2: %d", count++);
}
for( int j = 0; j < 50; j ++ ) {
for (int j = 0; j < 50; j ++) {
TEST_ESP_OK(spi_device_queue_trans(handle, &t, portMAX_DELAY));
}
for( int j = 0; j < 50; j ++ ) {
for (int j = 0; j < 50; j ++) {
TEST_ESP_OK(spi_device_get_trans_result(handle, &ret_t, portMAX_DELAY));
assert(ret_t == &t);
ESP_LOGI( TAG, "task2: %d", count++ );
ESP_LOGI(TAG, "task2: %d", count++);
}
spi_device_release_bus(handle);
vTaskDelay(1);
@ -108,24 +107,24 @@ void spi_task2(void* arg)
void spi_task3(void* arg)
{
//task3 send 30 polling transactions, acquire the bus, send 20 polling transactions and then 50 non-polling
int count=0;
int count = 0;
spi_transaction_t t = {
.flags = SPI_TRANS_USE_TXDATA,
.tx_data = { 0x80, 0x12, 0x34, 0x56 },
.length = 4*8,
.length = 4 * 8,
};
spi_transaction_t *ret_t;
spi_device_handle_t handle = ((task_context_t*)arg)->handle;
for (int i = 0; i < 30; i ++) {
TEST_ESP_OK(spi_device_polling_transmit(handle, &t));
ESP_LOGI( TAG, "task3: %d", count++ );
ESP_LOGI(TAG, "task3: %d", count++);
}
TEST_ESP_OK(spi_device_acquire_bus( handle, portMAX_DELAY ));
TEST_ESP_OK(spi_device_acquire_bus(handle, portMAX_DELAY));
for (int i = 0; i < 20; i ++) {
TEST_ESP_OK(spi_device_polling_transmit(handle, &t));
ESP_LOGI( TAG, "task3: %d", count++ );
ESP_LOGI(TAG, "task3: %d", count++);
}
for (int j = 0; j < 50; j++) {
@ -147,11 +146,11 @@ static void write_large_buffer(esp_flash_t *chip, const esp_partition_t *part, c
{
printf("Erasing chip %p, %d bytes\n", chip, length);
TEST_ESP_OK(esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)) );
TEST_ESP_OK(esp_flash_erase_region(chip, part->address, (length + SPI_FLASH_SEC_SIZE) & ~(SPI_FLASH_SEC_SIZE - 1)));
printf("Writing chip %p, %d bytes from source %p\n", chip, length, source);
// note writing to unaligned address
TEST_ESP_OK(esp_flash_write(chip, source, part->address + 1, length) );
TEST_ESP_OK(esp_flash_write(chip, source, part->address + 1, length));
printf("Write done.\n");
}
@ -161,18 +160,18 @@ static void read_and_check(esp_flash_t *chip, const esp_partition_t *part, const
printf("Checking chip %p, %d bytes\n", chip, length);
uint8_t *buf = malloc(length);
TEST_ASSERT_NOT_NULL(buf);
TEST_ESP_OK(esp_flash_read(chip, buf, part->address + 1, length) );
TEST_ESP_OK(esp_flash_read(chip, buf, part->address + 1, length));
TEST_ASSERT_EQUAL_HEX8_ARRAY(source, buf, length);
free(buf);
// check nothing was written at beginning or end
uint8_t ends[8];
TEST_ESP_OK(esp_flash_read(chip, ends, part->address, sizeof(ends)) );
TEST_ESP_OK(esp_flash_read(chip, ends, part->address, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[0]);
TEST_ASSERT_EQUAL_HEX8(source[0], ends[1]);
TEST_ESP_OK(esp_flash_read(chip, ends, part->address + length, sizeof(ends)) );
TEST_ESP_OK(esp_flash_read(chip, ends, part->address + length, sizeof(ends)));
TEST_ASSERT_EQUAL_HEX8(source[length - 1], ends[0]);
TEST_ASSERT_EQUAL_HEX8(0xFF, ends[1]);
@ -210,18 +209,18 @@ void spi_task4(void* arg)
static void test_bus_lock(bool test_flash)
{
task_context_t context1={};
task_context_t context2={};
task_context_t context3={};
task_context_t context4={};
task_context_t context1 = {};
task_context_t context2 = {};
task_context_t context3 = {};
task_context_t context4 = {};
TaskHandle_t task1, task2, task3, task4;
esp_err_t ret;
spi_bus_config_t buscfg=SPI_BUS_TEST_DEFAULT_CONFIG();
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
buscfg.miso_io_num = TEST_BUS_PIN_NUM_MISO;
buscfg.mosi_io_num = TEST_BUS_PIN_NUM_MOSI;
buscfg.sclk_io_num = TEST_BUS_PIN_NUM_CLK;
spi_device_interface_config_t devcfg=SPI_DEVICE_TEST_DEFAULT_CONFIG();
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
devcfg.queue_size = 100;
//Initialize the SPI bus and 3 devices
@ -258,18 +257,20 @@ static void test_bus_lock(bool test_flash)
}
ESP_LOGI(TAG, "Start testing...");
xTaskCreate( spi_task1, "task1", 4096, &context1, 0, &task1 );
xTaskCreate( spi_task2, "task2", 4096, &context2, 0, &task2 );
xTaskCreate( spi_task3, "task3", 4096, &context3, 0, &task3 );
xTaskCreate(spi_task1, "task1", 4096, &context1, 0, &task1);
xTaskCreate(spi_task2, "task2", 4096, &context2, 0, &task2);
xTaskCreate(spi_task3, "task3", 4096, &context3, 0, &task3);
if (test_flash) {
xTaskCreate( spi_task4, "task4", 2048, &context4, 0, &task4 );
xTaskCreate(spi_task4, "task4", 2048, &context4, 0, &task4);
} else {
context4.finished = true;
}
for(;;){
for (;;) {
vTaskDelay(10);
if (context1.finished && context2.finished && context3.finished && context4.finished) break;
if (context1.finished && context2.finished && context3.finished && context4.finished) {
break;
}
}
TEST_ESP_OK(spi_bus_remove_device(context1.handle));
@ -278,19 +279,18 @@ static void test_bus_lock(bool test_flash)
if (test_flash) {
TEST_ESP_OK(spi_bus_remove_flash_device(chip));
}
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST) );
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
}
#if CONFIG_IDF_TARGET_ESP32
// no need this case in other target, only esp32 need buslock to split MSPI and GPSPI2 action
TEST_CASE("spi bus lock, with flash","[spi][test_env=external_flash]")
TEST_CASE("spi bus lock, with flash", "[spi][test_env=external_flash]")
{
test_bus_lock(true);
}
#endif //CONFIG_IDF_TARGET_ESP32
TEST_CASE("spi bus lock","[spi]")
TEST_CASE("spi bus lock", "[spi]")
{
test_bus_lock(false);
}
@ -327,7 +327,7 @@ TEST_CASE("spi master can be used on SPI1", "[spi]")
{
spi_device_interface_config_t dev_cfg = {
.mode = 1,
.clock_speed_hz = 1*1000*1000,
.clock_speed_hz = 1 * 1000 * 1000,
.spics_io_num = -1,
.queue_size = 1,
};

View File

@ -7,7 +7,6 @@
Tests for the spi_master device driver
*/
#include "sdkconfig.h"
#include "driver/spi_master.h"
#include "driver/spi_slave.h"
@ -24,7 +23,6 @@
#include "test_utils.h"
#include "test_spi_utils.h"
const static char TAG[] = "test_spi";
// There is no input-only pin except on esp32 and esp32s2
@ -75,8 +73,7 @@ static void check_spi_pre_n_for(spi_clock_source_t clock_source, int clk, int pr
* {freq, pre, n}
*/
#define TEST_CLK_TIMES 8
struct test_clk_param_group_t
{
struct test_clk_param_group_t {
uint32_t clk_param_80m[TEST_CLK_TIMES][3];
uint32_t clk_param_48m[TEST_CLK_TIMES][3];
uint32_t clk_param_40m[TEST_CLK_TIMES][3];
@ -92,7 +89,6 @@ struct test_clk_param_group_t
{{1, SOC_SPI_MAX_PRE_DIVIDER, 64}, {100000, 2, 35}, {333333, 1, 21}, {800000, 1, 9}, {900000, 1, 8}, {1100000, 1, 6}, {4000000, 1, 2,}, {7000000, 1, 1} },
};
TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
{
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
@ -148,12 +144,12 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
#if SOC_SPI_SUPPORT_CLK_XTAL
esp_clk_tree_src_get_freq_hz(SPI_CLK_SRC_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz);
printf("\nTest clock source XTAL = %ld\n", clock_source_hz);
if((40 * 1000 * 1000) == clock_source_hz){
if ((40 * 1000 * 1000) == clock_source_hz) {
for (int i = 0; i < TEST_CLK_TIMES; i++) {
check_spi_pre_n_for(SPI_CLK_SRC_XTAL, test_clk_param.clk_param_40m[i][0], test_clk_param.clk_param_40m[i][1], test_clk_param.clk_param_40m[i][2]);
}
}
if((32 * 1000 * 1000) == clock_source_hz){
if ((32 * 1000 * 1000) == clock_source_hz) {
for (int i = 0; i < TEST_CLK_TIMES; i++) {
check_spi_pre_n_for(SPI_CLK_SRC_XTAL, test_clk_param.clk_param_32m[i][0], test_clk_param.clk_param_32m[i][1], test_clk_param.clk_param_32m[i][2]);
}
@ -164,12 +160,12 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
#if SOC_SPI_SUPPORT_CLK_RC_FAST
esp_clk_tree_src_get_freq_hz(SPI_CLK_SRC_RC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz);
printf("\nTest clock source RC_FAST = %ld\n", clock_source_hz);
if((17500000) == clock_source_hz){
if ((17500000) == clock_source_hz) {
for (int i = 0; i < TEST_CLK_TIMES; i++) {
check_spi_pre_n_for(SPI_CLK_SRC_RC_FAST, test_clk_param.clk_param_17m[i][0], test_clk_param.clk_param_17m[i][1], test_clk_param.clk_param_17m[i][2]);
}
}
if((7000000) == clock_source_hz){
if ((7000000) == clock_source_hz) {
for (int i = 0; i < TEST_CLK_TIMES; i++) {
check_spi_pre_n_for(SPI_CLK_SRC_RC_FAST, test_clk_param.clk_param_7m[i][0], test_clk_param.clk_param_7m[i][1], test_clk_param.clk_param_7m[i][2]);
}
@ -317,7 +313,6 @@ TEST_CASE("SPI Master test", "[spi]")
TEST_ASSERT(success);
}
TEST_CASE("SPI Master test, interaction of multiple devs", "[spi]")
{
esp_err_t ret;
@ -355,7 +350,6 @@ TEST_CASE("SPI Master test, interaction of multiple devs", "[spi]")
printf("Sending to dev 2\n");
success &= spi_test(handle2, 5000);
ret = spi_bus_remove_device(handle2);
TEST_ASSERT(ret == ESP_OK);
master_free_device_bus(handle1);
@ -440,9 +434,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test 4 iomux output pins...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_IOMUX_PINS | SPICOMMON_BUSFLAG_DUAL;
@ -451,9 +445,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test 6 output pins...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_QUAD | SPICOMMON_BUSFLAG_GPIO_PINS;
@ -463,9 +457,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test 4 output pins...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_DUAL | SPICOMMON_BUSFLAG_GPIO_PINS;
@ -475,9 +469,9 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
#if TEST_SOC_HAS_INPUT_ONLY_PINS //There is no input-only pin on esp32c3 and esp32s3, so this test could be ignored.
ESP_LOGI(TAG, "test master 5 output pins and MOSI on input-only pin...");
@ -487,7 +481,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test slave 5 output pins and MISO on input-only pin...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_WPHD | SPICOMMON_BUSFLAG_GPIO_PINS;
@ -496,7 +490,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test master 3 output pins and MOSI on input-only pin...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_GPIO_PINS;
@ -506,7 +500,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_MASTER, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
ESP_LOGI(TAG, "test slave 3 output pins and MISO on input-only pin...");
flags_expected = SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_GPIO_PINS;
@ -515,7 +509,7 @@ TEST_CASE("spi bus setting with different pin configs", "[spi]")
.max_transfer_sz = 8, .flags = flags_expected
};
TEST_ESP_OK(spicommon_bus_initialize_io(TEST_SPI_HOST, &cfg, flags_expected | SPICOMMON_BUSFLAG_SLAVE, &flags_o));
TEST_ASSERT_EQUAL_HEX32( flags_expected, flags_o );
TEST_ASSERT_EQUAL_HEX32(flags_expected, flags_o);
//There is no input-only pin on esp32c3 and esp32s3, so this test could be ignored.
#endif //#if TEST_SOC_HAS_INPUT_ONLY_PINS
@ -673,7 +667,6 @@ TEST_CASE("SPI Master no response when switch from host1 (SPI2) to host2 (SPI3)"
TEST_ESP_OK(spi_bus_free(host));
}
DRAM_ATTR static uint32_t data_dram[80] = {0};
//force to place in code area.
static const uint8_t data_drom[320 + 3] = {
@ -789,36 +782,36 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
//connect MOSI to two devices breaks the output, fix it.
spitest_gpio_output_sel(buscfg.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
for ( int i = 0; i < 8; i ++ ) {
memset( rx_buf, 0x66, sizeof(rx_buf));
for (int i = 0; i < 8; i ++) {
memset(rx_buf, 0x66, sizeof(rx_buf));
spi_transaction_t t = {};
t.length = 8 * (i + 1);
t.rxlength = 0;
t.tx_buffer = tx_buf + 2 * i;
t.rx_buffer = rx_buf + i;
if ( i == 1 ) {
if (i == 1) {
//test set no start
t.rx_buffer = NULL;
} else if ( i == 2 ) {
} else if (i == 2) {
//test rx length != tx_length
t.rxlength = t.length - 8;
}
spi_device_transmit( spi, &t );
spi_device_transmit(spi, &t);
for ( int i = 0; i < 16; i ++ ) {
for (int i = 0; i < 16; i ++) {
printf("%02X ", rx_buf[i]);
}
printf("\n");
if ( i == 1 ) {
if (i == 1) {
// no rx, skip check
} else if ( i == 2 ) {
} else if (i == 2) {
//test rx length = tx length-1
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, t.rx_buffer, t.length / 8 - 1 );
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, t.rx_buffer, t.length / 8 - 1);
} else {
//normal check
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, t.rx_buffer, t.length / 8);
}
}
@ -826,7 +819,6 @@ TEST_CASE("SPI Master DMA test: length, start, not aligned", "[spi]")
TEST_ASSERT(spi_bus_free(TEST_SPI_HOST) == ESP_OK);
}
#if (TEST_SPI_PERIPH_NUM >= 2)
//These will only be enabled on chips with 2 or more SPI peripherals
@ -881,7 +873,7 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
#ifdef CONFIG_IDF_TARGET_ESP32
addr_bits = 56 - 8 * i;
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
//ESP32S2 only supportes up to 32 bits address
//ESP32S2 only supportes up to 32 bits address
addr_bits = 28 - 4 * i;
#endif
int round_up = (cmd_bits + addr_bits + 7) / 8 * 8;
@ -897,7 +889,7 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
.address_bits = addr_bits,
};
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
ESP_LOGI(MASTER_TAG, "===== test%d =====", i);
ESP_LOGI(MASTER_TAG, "cmd_bits: %d, addr_bits: %d", cmd_bits, addr_bits);
TEST_ESP_OK(spi_device_transmit(spi, (spi_transaction_t *)&trans));
//wait for both master and slave end
@ -964,10 +956,10 @@ void test_cmd_addr(spi_slave_task_context_t *slave_context, bool lsb_first)
TEST_CASE("SPI master variable cmd & addr test", "[spi]")
{
spi_slave_task_context_t slave_context = {};
esp_err_t err = init_slave_context( &slave_context, TEST_SLAVE_HOST );
TEST_ASSERT( err == ESP_OK );
esp_err_t err = init_slave_context(&slave_context, TEST_SLAVE_HOST);
TEST_ASSERT(err == ESP_OK);
TaskHandle_t handle_slave;
xTaskCreate( spitest_slave_task, "spi_slave", 4096, &slave_context, 0, &handle_slave);
xTaskCreate(spitest_slave_task, "spi_slave", 4096, &slave_context, 0, &handle_slave);
//initial slave, mode 0, no dma
int dma_chan = 0;
@ -976,12 +968,12 @@ TEST_CASE("SPI master variable cmd & addr test", "[spi]")
spi_slave_interface_config_t slvcfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
slvcfg.mode = slave_mode;
//Initialize SPI slave interface
TEST_ESP_OK( spi_slave_initialize(TEST_SLAVE_HOST, &slv_buscfg, &slvcfg, dma_chan) );
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &slv_buscfg, &slvcfg, dma_chan));
test_cmd_addr(&slave_context, false);
test_cmd_addr(&slave_context, true);
vTaskDelete( handle_slave );
vTaskDelete(handle_slave);
handle_slave = 0;
deinit_slave_context(&slave_context);
@ -1225,12 +1217,12 @@ static void fd_master(void)
//Master FD DMA, RX without TX Test
for (int i = 0; i < TEST_NUM; i++) {
// 1. Master FD DMA, only receive, with NULL tx_buffer
get_tx_buffer(FD_SEED1+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED1 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(mst_recv_buf, 0x0, FD_TEST_BUF_SIZE);
master_only_rx_trans(spi, mst_recv_buf, slv_send_buf, FD_TEST_BUF_SIZE);
//2. Master FD DMA with TX and RX
get_tx_buffer(FD_SEED2+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED2 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(mst_recv_buf, 0x0, FD_TEST_BUF_SIZE);
master_both_trans(spi, mst_send_buf, mst_recv_buf, slv_send_buf, FD_TEST_BUF_SIZE);
}
@ -1238,11 +1230,11 @@ static void fd_master(void)
//Master FD DMA, TX without RX Test
for (int i = 0; i < TEST_NUM; i++) {
// 1. Master FD DMA, only send, with NULL rx_buffer
get_tx_buffer(FD_SEED3+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED3 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
master_only_tx_trans(spi, mst_send_buf, FD_TEST_BUF_SIZE);
//2. Master FD DMA with TX and RX
get_tx_buffer(FD_SEED4+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED4 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(mst_recv_buf, 0x0, FD_TEST_BUF_SIZE);
master_both_trans(spi, mst_send_buf, mst_recv_buf, slv_send_buf, FD_TEST_BUF_SIZE);
}
@ -1307,23 +1299,23 @@ static void fd_slave(void)
for (int i = 0; i < TEST_NUM; i++) {
//1. Slave TX without RX (rx_buffer == NULL)
get_tx_buffer(FD_SEED1+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED1 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
slave_only_tx_trans(slv_send_buf, FD_TEST_BUF_SIZE);
//2. Slave both TX and RX
get_tx_buffer(FD_SEED2+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED2 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(slv_recv_buf, 0x0, FD_TEST_BUF_SIZE);
slave_both_trans(slv_send_buf, slv_recv_buf, mst_send_buf, FD_TEST_BUF_SIZE);
}
for (int i = 0; i < TEST_NUM; i++) {
// 1. Slave RX without TX (tx_buffer == NULL)
get_tx_buffer(FD_SEED3+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED3 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(slv_recv_buf, 0x0, FD_TEST_BUF_SIZE);
slave_only_rx_trans(slv_recv_buf, mst_send_buf, FD_TEST_BUF_SIZE);
//2. Slave both TX and RX
get_tx_buffer(FD_SEED4+i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
get_tx_buffer(FD_SEED4 + i, mst_send_buf, slv_send_buf, FD_TEST_BUF_SIZE);
memset(slv_recv_buf, 0x0, FD_TEST_BUF_SIZE);
slave_both_trans(slv_send_buf, slv_recv_buf, mst_send_buf, FD_TEST_BUF_SIZE);
}
@ -1337,7 +1329,6 @@ static void fd_slave(void)
TEST_CASE_MULTIPLE_DEVICES("SPI Master: FD, DMA, Master Single Direction Test", "[spi_ms][test_env=generic_multi_device]", fd_master, fd_slave);
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32) //TODO: IDF-3494
//NOTE: Explained in IDF-1445 | MR !14996
#if !(CONFIG_SPIRAM) || (CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL >= 16384)
/********************************************************************************
@ -1600,15 +1591,15 @@ void test_add_device_slave(void)
TEST_CASE_MULTIPLE_DEVICES("SPI_Master:Test multiple devices", "[spi_ms]", test_add_device_master, test_add_device_slave);
#if (SOC_CPU_CORES_NUM > 1) && (!CONFIG_FREERTOS_UNICORE)
#define TEST_ISR_CNT 100
static void test_master_isr_core_post_trans_cbk(spi_transaction_t *curr_trans){
static void test_master_isr_core_post_trans_cbk(spi_transaction_t *curr_trans)
{
*((int *)curr_trans->user) += esp_cpu_get_core_id();
}
TEST_CASE("test_master_isr_pin_to_core","[spi]")
TEST_CASE("test_master_isr_pin_to_core", "[spi]")
{
spi_device_handle_t dev0;
uint32_t master_send;
@ -1640,7 +1631,6 @@ TEST_CASE("test_master_isr_pin_to_core","[spi]")
// by default the esp_intr_alloc is called on ESP_MAIN_TASK_AFFINITY_CPU0 now
TEST_ASSERT_EQUAL_UINT32(0, master_expect);
//-------------------------------------CPU1---------------------------------------
buscfg.isr_cpu_id = ESP_INTR_CPU_AFFINITY_1;
@ -1696,7 +1686,7 @@ static IRAM_ATTR void test_master_iram(void)
spi_flash_disable_interrupts_caches_and_other_cpu();
flag_trans_done = false;
spi_device_queue_trans(dev_handle, &trans_cfg, portMAX_DELAY);
while(!flag_trans_done) {
while (!flag_trans_done) {
// waitting for transaction done and return from ISR
}
spi_device_get_trans_result(dev_handle, &ret_trans, portMAX_DELAY);

View File

@ -49,7 +49,6 @@ static void inner_connect(spi_bus_config_t bus)
//Slave MOSI(spid_in) input to `mosi_num`
spitest_gpio_input_sel(bus.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spid_in);
//Master MOSI input(spid_in) to `miso_num`, due to SIO mode, we use Master's `spid_in` to receive data
spitest_gpio_input_sel(bus.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_in);
//Slave MISO output(spiq_out)
@ -76,11 +75,9 @@ TEST_CASE("SPI Single Board Test SIO", "[spi]")
spi_slave_interface_config_t slv_cfg = SPI_SLAVE_TEST_DEFAULT_CONFIG();
TEST_ESP_OK(spi_slave_initialize(TEST_SLAVE_HOST, &bus_cfg, &slv_cfg, SPI_DMA_DISABLED));
same_pin_func_sel(bus_cfg, dev_cfg, 0);
inner_connect(bus_cfg);
WORD_ALIGNED_ATTR uint8_t master_rx_buffer[320];
WORD_ALIGNED_ATTR uint8_t slave_rx_buffer[320];
@ -114,7 +111,6 @@ TEST_CASE("SPI Single Board Test SIO", "[spi]")
ESP_LOG_BUFFER_HEXDUMP("slave rx", slv_trans.rx_buffer, tlen, ESP_LOG_INFO);
TEST_ASSERT_EQUAL_HEX8_ARRAY(mst_trans.tx_buffer, slv_trans.rx_buffer, tlen);
ESP_LOGI("spi", "=========== TEST(%d) Master RX, Slave TX ==========", i);
//Slave TX
memset(&slv_trans, 0x0, sizeof(spi_slave_transaction_t));

View File

@ -50,7 +50,7 @@ static void local_test_init(void **arg)
spitest_context_t *context = (spitest_context_t *)*arg;
TEST_ASSERT(context != NULL);
context->slave_context = (spi_slave_task_context_t) {};
esp_err_t err = init_slave_context( &context->slave_context, TEST_SLAVE_HOST);
esp_err_t err = init_slave_context(&context->slave_context, TEST_SLAVE_HOST);
TEST_ASSERT(err == ESP_OK);
xTaskCreate(spitest_slave_task, "spi_slave", 4096, &context->slave_context, 0, &context->handle_slave);
@ -213,16 +213,16 @@ static void local_test_loop(const void *arg1, void *arg2)
bool failed = false;
//check master data
if (check_master_data && memcmp(slave_trans.tx_buffer, t->rx_buffer, (len + 7) / 8) != 0 ) {
if (check_master_data && memcmp(slave_trans.tx_buffer, t->rx_buffer, (len + 7) / 8) != 0) {
failed = true;
}
//check slave data and length
//currently the rcv_len can be in range of [t->length-1, t->length+3]
if ( rcv_len < len - 1 || rcv_len > len + 4) {
if (rcv_len < len - 1 || rcv_len > len + 4) {
failed = true;
}
if (check_slave_data && memcmp(t->tx_buffer, slave_trans.rx_buffer, (len + 7) / 8) != 0 ) {
if (check_slave_data && memcmp(t->tx_buffer, slave_trans.rx_buffer, (len + 7) / 8) != 0) {
failed = true;
}
@ -378,7 +378,6 @@ static int test_freq_mode_local[] = {
#define SLAVE_EXTRA_DELAY_DMA 0
#endif
static spitest_param_set_t mode_pgroup[] = {
{
.pset_name = "Mode 0",
@ -795,7 +794,7 @@ static void test_master_loop(const void *arg1, void *arg2)
const int *timing_speed_array = test_cfg->freq_list;
ESP_LOGI(MASTER_TAG, "****************** %s ***************", test_cfg->pset_name);
for (int i = 0; ; i++ ) {
for (int i = 0; ; i++) {
const int freq = timing_speed_array[i];
if (freq == 0) {
break;
@ -809,21 +808,21 @@ static void test_master_loop(const void *arg1, void *arg2)
unity_wait_for_signal("Slave ready");
for ( int j = 0; j < test_cfg->test_size; j ++ ) {
for (int j = 0; j < test_cfg->test_size; j ++) {
//wait for both master and slave end
ESP_LOGI( MASTER_TAG, "=> test%d", j );
ESP_LOGI(MASTER_TAG, "=> test%d", j);
//send master tx data
vTaskDelay(20);
spi_transaction_t *t = &context->master_trans[j];
TEST_ESP_OK (spi_device_transmit(spi, t) );
TEST_ESP_OK(spi_device_transmit(spi, t));
int len = get_trans_len(test_cfg->dup, t);
if (TEST_LOG_DBUG) {
spitest_master_print_data(t, len);
}
size_t rcv_len;
slave_rxdata_t *rcv_data = xRingbufferReceive( context->slave_context.data_received, &rcv_len, portMAX_DELAY );
slave_rxdata_t *rcv_data = xRingbufferReceive(context->slave_context.data_received, &rcv_len, portMAX_DELAY);
if (TEST_LOG_DBUG) {
spitest_slave_print_data(rcv_data, false);
}
@ -840,7 +839,7 @@ static void test_master_loop(const void *arg1, void *arg2)
check_len, check_slave_data));
}
//clean
vRingbufferReturnItem( context->slave_context.data_received, rcv_data );
vRingbufferReturnItem(context->slave_context.data_received, rcv_data);
}
master_free_device_bus(spi);
}
@ -854,17 +853,17 @@ static void test_slave_init(void **arg)
spitest_context_t *context = (spitest_context_t *)*arg;
TEST_ASSERT(context != NULL);
context->slave_context = (spi_slave_task_context_t) {};
esp_err_t err = init_slave_context( &context->slave_context, TEST_SPI_HOST);
TEST_ASSERT( err == ESP_OK );
esp_err_t err = init_slave_context(&context->slave_context, TEST_SPI_HOST);
TEST_ASSERT(err == ESP_OK);
unity_wait_for_signal("Master ready");
xTaskCreate( spitest_slave_task, "spi_slave", 4096, &context->slave_context, 0, &context->handle_slave);
xTaskCreate(spitest_slave_task, "spi_slave", 4096, &context->slave_context, 0, &context->handle_slave);
}
static void test_slave_deinit(void *arg)
{
spitest_context_t *context = (spitest_context_t *)arg;
vTaskDelete( context->handle_slave );
vTaskDelete(context->handle_slave);
context->handle_slave = 0;
deinit_slave_context(&context->slave_context);
@ -905,7 +904,7 @@ static void test_slave_loop(const void *arg1, void *arg2)
spitest_init_transactions(pset, context);
const int *timing_speed_array = pset->freq_list;
for (int i = 0; ; i++ ) {
for (int i = 0; ; i++) {
const int freq = timing_speed_array[i];
if (freq == 0) {
break;
@ -920,16 +919,16 @@ static void test_slave_loop(const void *arg1, void *arg2)
//prepare slave tx data
for (int i = 0; i < pset->test_size; i ++) {
xQueueSend( context->slave_context.data_to_send, &context->slave_trans[i], portMAX_DELAY );
xQueueSend(context->slave_context.data_to_send, &context->slave_trans[i], portMAX_DELAY);
//memcpy(context->master_trans[i].rx_buffer, context->slave_trans[i].start, (context->master_trans[i].length+7)/8);
}
vTaskDelay(50 / portTICK_PERIOD_MS);
unity_send_signal("Slave ready");
for ( int i = 0; i < pset->test_size; i ++ ) {
for (int i = 0; i < pset->test_size; i ++) {
//wait for both master and slave end
ESP_LOGI( MASTER_TAG, "===== test%d =====", i );
ESP_LOGI(MASTER_TAG, "===== test%d =====", i);
//send master tx data
vTaskDelay(20);
@ -940,7 +939,7 @@ static void test_slave_loop(const void *arg1, void *arg2)
}
size_t rcv_len;
slave_rxdata_t *rcv_data = xRingbufferReceive( context->slave_context.data_received, &rcv_len, portMAX_DELAY );
slave_rxdata_t *rcv_data = xRingbufferReceive(context->slave_context.data_received, &rcv_len, portMAX_DELAY);
if (TEST_LOG_DBUG) {
spitest_slave_print_data(rcv_data, true);
}
@ -951,7 +950,7 @@ static void test_slave_loop(const void *arg1, void *arg2)
const bool check_len = true;
TEST_ESP_OK(spitest_check_data(len, t, rcv_data, check_master_data, check_len, check_slave_data));
//clean
vRingbufferReturnItem( context->slave_context.data_received, rcv_data );
vRingbufferReturnItem(context->slave_context.data_received, rcv_data);
}
TEST_ASSERT(spi_slave_free(TEST_SPI_HOST) == ESP_OK);
}
@ -1269,7 +1268,6 @@ TEST_SPI_MASTER_SLAVE(MODE, mode_conf, "")
#endif // #if (TEST_SPI_PERIPH_NUM >= 2)
#define TEST_STEP_LEN 96
#define TEST_STEP 2
static int s_spi_bus_freq[] = {
@ -1395,7 +1393,6 @@ static void test_slave_fd_dma(void)
TEST_CASE_MULTIPLE_DEVICES("TEST_SPI_Freq_FD_DMA", "[spi_ms][timeout=30]", test_master_fd_dma, test_slave_fd_dma);
//------------------------------------------- Full Duplex no DMA Freq test --------------------------------------
static void test_master_fd_no_dma(void)
{
@ -1511,7 +1508,6 @@ static void test_slave_fd_no_dma(void)
TEST_CASE_MULTIPLE_DEVICES("TEST_SPI_Freq_FD_no_DMA", "[spi_ms][timeout=30]", test_master_fd_no_dma, test_slave_fd_no_dma);
#if SOC_SPI_SUPPORT_SLAVE_HD_VER2
//------------------------------------------- Half Duplex with DMA Freq test --------------------------------------
static void test_master_hd_dma(void)
@ -1614,7 +1610,6 @@ static void test_slave_hd_dma(void)
TEST_CASE_MULTIPLE_DEVICES("TEST_SPI_Freq_HD_DMA", "[spi_ms][timeout=30]", test_master_hd_dma, test_slave_hd_dma);
//------------------------------------------- Half Duplex no DMA Freq test --------------------------------------
static void test_master_hd_no_dma(void)
{
@ -1717,7 +1712,6 @@ static void test_slave_hd_no_dma(void)
TEST_CASE_MULTIPLE_DEVICES("TEST_SPI_Freq_HD_no_DMA", "[spi_ms][timeout=30]", test_master_hd_no_dma, test_slave_hd_no_dma);
#endif // SOC_SPI_SUPPORT_SLAVE_HD_VER2
#if CONFIG_IDF_TARGET_ESP32
// item num should same as `s_spi_bus_freq`
static int s_master_input_delay[] = {12.5, 12.5 * 2, 12.5 * 2, 12.5 * 5, 12.5 * 5};
@ -1853,7 +1847,6 @@ static void test_slave_sio_dma(void)
TEST_CASE_MULTIPLE_DEVICES("TEST_SPI_Freq_SIO_DMA", "[spi_ms][timeout=30]", test_master_sio_dma, test_slave_sio_dma);
//------------------------------------------- SIO no DMA Freq test --------------------------------------
static void test_master_sio_no_dma(void)
{

View File

@ -15,7 +15,7 @@ project(spi_slave_test)
if(CONFIG_COMPILER_DUMP_RTL_FILES)
add_custom_target(check_test_app_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/driver/,${CMAKE_BINARY_DIR}/esp-idf/hal/
--rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_driver_spi/,${CMAKE_BINARY_DIR}/esp-idf/hal/
--elf-file ${CMAKE_BINARY_DIR}/spi_slave_test.elf
find-refs
--from-sections=.iram0.text

View File

@ -36,13 +36,13 @@ static WORD_ALIGNED_ATTR uint8_t slave_rxbuf[320];
static const uint8_t master_send[] = { 0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43 };
static const uint8_t slave_send[] = { 0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0 };
static inline void int_connect( uint32_t gpio, uint32_t sigo, uint32_t sigi )
static inline void int_connect(uint32_t gpio, uint32_t sigo, uint32_t sigi)
{
esp_rom_gpio_connect_out_signal( gpio, sigo, false, false );
esp_rom_gpio_connect_in_signal( gpio, sigi, false );
esp_rom_gpio_connect_out_signal(gpio, sigo, false, false);
esp_rom_gpio_connect_in_signal(gpio, sigi, false);
}
static void master_init( spi_device_handle_t *spi)
static void master_init(spi_device_handle_t *spi)
{
esp_err_t ret;
spi_bus_config_t buscfg = {
@ -101,15 +101,15 @@ static void custom_setup(void)
memset(slave_rxbuf, 0, sizeof(slave_rxbuf));
//Initialize SPI Master
master_init( &spi );
master_init(&spi);
//Initialize SPI Slave
slave_init();
//Do internal connections
int_connect( PIN_NUM_MOSI, spi_periph_signal[TEST_SPI_HOST].spid_out, spi_periph_signal[TEST_SLAVE_HOST].spiq_in );
int_connect( PIN_NUM_MISO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out, spi_periph_signal[TEST_SPI_HOST].spid_in );
int_connect( PIN_NUM_CS, spi_periph_signal[TEST_SPI_HOST].spics_out[0], spi_periph_signal[TEST_SLAVE_HOST].spics_in );
int_connect( PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in );
int_connect(PIN_NUM_MOSI, spi_periph_signal[TEST_SPI_HOST].spid_out, spi_periph_signal[TEST_SLAVE_HOST].spiq_in);
int_connect(PIN_NUM_MISO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out, spi_periph_signal[TEST_SPI_HOST].spid_in);
int_connect(PIN_NUM_CS, spi_periph_signal[TEST_SPI_HOST].spics_out[0], spi_periph_signal[TEST_SLAVE_HOST].spics_in);
int_connect(PIN_NUM_CLK, spi_periph_signal[TEST_SPI_HOST].spiclk_out, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in);
}
static void custom_teardown(void)
@ -125,7 +125,7 @@ TEST_CASE("test fullduplex slave with only RX direction", "[spi]")
memcpy(master_txbuf, master_send, sizeof(master_send));
for ( int i = 0; i < 4; i ++ ) {
for (int i = 0; i < 4; i ++) {
//slave send
spi_slave_transaction_t slave_t;
spi_slave_transaction_t *out;
@ -136,29 +136,29 @@ TEST_CASE("test fullduplex slave with only RX direction", "[spi]")
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffer with known pattern
memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf));
memset(slave_rxbuf, 0x66, sizeof(slave_rxbuf));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_t, portMAX_DELAY));
//send
spi_transaction_t t = {};
t.length = 32 * (i + 1);
if ( t.length != 0 ) {
if (t.length != 0) {
t.tx_buffer = master_txbuf;
t.rx_buffer = NULL;
}
spi_device_transmit( spi, (spi_transaction_t *)&t );
spi_device_transmit(spi, (spi_transaction_t *)&t);
//wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX("master tx", t.tx_buffer, t.length / 8);
ESP_LOG_BUFFER_HEX("slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, slave_t.rx_buffer, t.length / 8);
TEST_ASSERT_EQUAL(t.length, slave_t.trans_len);
}
custom_teardown();
@ -172,7 +172,7 @@ TEST_CASE("test fullduplex slave with only TX direction", "[spi]")
memcpy(slave_txbuf, slave_send, sizeof(slave_send));
for ( int i = 0; i < 4; i ++ ) {
for (int i = 0; i < 4; i ++) {
//slave send
spi_slave_transaction_t slave_t;
spi_slave_transaction_t *out;
@ -183,29 +183,29 @@ TEST_CASE("test fullduplex slave with only TX direction", "[spi]")
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffer with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
memset(master_rxbuf, 0x66, sizeof(master_rxbuf));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_t, portMAX_DELAY));
//send
spi_transaction_t t = {};
t.length = 32 * (i + 1);
if ( t.length != 0 ) {
if (t.length != 0) {
t.tx_buffer = NULL;
t.rx_buffer = master_rxbuf;
}
spi_device_transmit( spi, (spi_transaction_t *)&t );
spi_device_transmit(spi, (spi_transaction_t *)&t);
//wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX("master rx", t.rx_buffer, t.length / 8);
ESP_LOG_BUFFER_HEX("slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_t.tx_buffer, t.rx_buffer, t.length / 8);
TEST_ASSERT_EQUAL(t.length, slave_t.trans_len);
}
custom_teardown();
@ -220,7 +220,7 @@ TEST_CASE("test slave send unaligned", "[spi]")
memcpy(master_txbuf, master_send, sizeof(master_send));
memcpy(slave_txbuf, slave_send, sizeof(slave_send));
for ( int i = 0; i < 4; i ++ ) {
for (int i = 0; i < 4; i ++) {
//slave send
spi_slave_transaction_t slave_t;
spi_slave_transaction_t *out;
@ -231,33 +231,33 @@ TEST_CASE("test slave send unaligned", "[spi]")
slave_t.flags |= SPI_SLAVE_TRANS_DMA_BUFFER_ALIGN_AUTO;
// Colorize RX buffers with known pattern
memset( master_rxbuf, 0x66, sizeof(master_rxbuf));
memset( slave_rxbuf, 0x66, sizeof(slave_rxbuf));
memset(master_rxbuf, 0x66, sizeof(master_rxbuf));
memset(slave_rxbuf, 0x66, sizeof(slave_rxbuf));
TEST_ESP_OK(spi_slave_queue_trans(TEST_SLAVE_HOST, &slave_t, portMAX_DELAY));
//send
spi_transaction_t t = {};
t.length = 32 * (i + 1);
if ( t.length != 0 ) {
if (t.length != 0) {
t.tx_buffer = master_txbuf + i;
t.rx_buffer = master_rxbuf + i;
}
spi_device_transmit( spi, (spi_transaction_t *)&t );
spi_device_transmit(spi, (spi_transaction_t *)&t);
//wait for end
TEST_ESP_OK(spi_slave_get_trans_result(TEST_SLAVE_HOST, &out, portMAX_DELAY));
//show result
ESP_LOGI(SLAVE_TAG, "trans_len: %d", slave_t.trans_len);
ESP_LOG_BUFFER_HEX( "master tx", t.tx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "master rx", t.rx_buffer, t.length / 8 );
ESP_LOG_BUFFER_HEX( "slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX( "slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX("master tx", t.tx_buffer, t.length / 8);
ESP_LOG_BUFFER_HEX("master rx", t.rx_buffer, t.length / 8);
ESP_LOG_BUFFER_HEX("slave tx", slave_t.tx_buffer, (slave_t.trans_len + 7) / 8);
ESP_LOG_BUFFER_HEX("slave rx", slave_t.rx_buffer, (slave_t.trans_len + 7) / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY( t.tx_buffer, slave_t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL_HEX8_ARRAY( slave_t.tx_buffer, t.rx_buffer, t.length / 8 );
TEST_ASSERT_EQUAL( t.length, slave_t.trans_len );
TEST_ASSERT_EQUAL_HEX8_ARRAY(t.tx_buffer, slave_t.rx_buffer, t.length / 8);
TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_t.tx_buffer, t.rx_buffer, t.length / 8);
TEST_ASSERT_EQUAL(t.length, slave_t.trans_len);
}
custom_teardown();
@ -652,7 +652,7 @@ static IRAM_ATTR void spi_queue_reset_in_isr(void)
uint8_t *slave_isr_send = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_recv = heap_caps_aligned_alloc(64, TEST_BUFFER_SZ, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *dummy_data = heap_caps_aligned_alloc(64, 64*2, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *dummy_data = heap_caps_aligned_alloc(64, 64 * 2, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
uint8_t *slave_isr_exp = heap_caps_malloc(TEST_BUFFER_SZ, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
get_tx_buffer(1001, slave_isr_exp, slave_isr_send, TEST_BUFFER_SZ);
get_tx_buffer(1001, dummy_data, dummy_data + 64, 64);

View File

@ -48,16 +48,16 @@ static uint32_t get_hd_flags(void)
ESP_LOGI("io mode", "%d", flag_id);
switch (flag_id) {
case 1:
return SPI_TRANS_MODE_DIO;
case 2:
return SPI_TRANS_MODE_DIO | SPI_TRANS_MODE_DIOQIO_ADDR;
case 3:
return SPI_TRANS_MODE_QIO;
case 4:
return SPI_TRANS_MODE_QIO | SPI_TRANS_MODE_DIOQIO_ADDR;
default:
return 0;
case 1:
return SPI_TRANS_MODE_DIO;
case 2:
return SPI_TRANS_MODE_DIO | SPI_TRANS_MODE_DIOQIO_ADDR;
case 3:
return SPI_TRANS_MODE_QIO;
case 4:
return SPI_TRANS_MODE_QIO | SPI_TRANS_MODE_DIOQIO_ADDR;
default:
return 0;
}
}
@ -79,7 +79,7 @@ void config_single_board_test_pin(void)
static void init_master_hd(spi_device_handle_t* spi, const spitest_param_set_t* config, int freq)
{
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
bus_cfg.max_transfer_sz = TEST_DMA_MAX_SIZE*30;
bus_cfg.max_transfer_sz = TEST_DMA_MAX_SIZE * 30;
bus_cfg.quadhd_io_num = PIN_NUM_HD;
bus_cfg.quadwp_io_num = PIN_NUM_WP;
#if defined(TEST_MASTER_GPIO_MATRIX) && CONFIG_IDF_TARGET_ESP32S2
@ -101,7 +101,7 @@ static void init_master_hd(spi_device_handle_t* spi, const spitest_param_set_t*
static void init_slave_hd(int mode, bool append_mode, const spi_slave_hd_callback_config_t* callback)
{
spi_bus_config_t bus_cfg = SPI_BUS_TEST_DEFAULT_CONFIG();
bus_cfg.max_transfer_sz = TEST_DMA_MAX_SIZE*30;
bus_cfg.max_transfer_sz = TEST_DMA_MAX_SIZE * 30;
bus_cfg.quadwp_io_num = -1;
bus_cfg.quadhd_io_num = -1;
#ifdef TEST_SLAVE_GPIO_MATRIX
@ -116,18 +116,18 @@ static void init_slave_hd(int mode, bool append_mode, const spi_slave_hd_callbac
if (callback) {
slave_hd_cfg.cb_config = *callback;
} else {
slave_hd_cfg.cb_config = (spi_slave_hd_callback_config_t){};
slave_hd_cfg.cb_config = (spi_slave_hd_callback_config_t) {};
}
TEST_ESP_OK(spi_slave_hd_init(TEST_SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
}
static void test_hd_init(void** arg)
{
TEST_ASSERT(*arg==NULL);
TEST_ASSERT(*arg == NULL);
*arg = heap_caps_malloc(sizeof(testhd_context_t), MALLOC_CAP_DMA);
assert(((int)arg%4)==0);
assert(((int)arg % 4) == 0);
testhd_context_t* context = (testhd_context_t*)*arg;
TEST_ASSERT(context!=NULL);
TEST_ASSERT(context != NULL);
context->ev_rdbuf = xSemaphoreCreateBinary();
context->ev_wrbuf = xSemaphoreCreateBinary();
@ -143,7 +143,7 @@ static void test_hd_deinit(void* arg)
esp_err_t wait_wrbuf_sig(testhd_context_t* context, TickType_t wait)
{
BaseType_t r = xSemaphoreTake(context->ev_wrbuf, wait);
if (r==pdTRUE) {
if (r == pdTRUE) {
return ESP_OK;
} else {
return ESP_ERR_TIMEOUT;
@ -153,7 +153,7 @@ esp_err_t wait_wrbuf_sig(testhd_context_t* context, TickType_t wait)
esp_err_t wait_rdbuf_sig(testhd_context_t* context, TickType_t wait)
{
BaseType_t r = xSemaphoreTake(context->ev_rdbuf, wait);
if (r==pdTRUE) {
if (r == pdTRUE) {
return ESP_OK;
} else {
return ESP_ERR_TIMEOUT;
@ -211,14 +211,19 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para
check_no_rx(ctx);
check_no_tx(ctx);
srand(9322);
for (int i = 0; i < TEST_DMA_MAX_SIZE; i++) ctx->slave_rddma_buf[i] = rand();
for (int i = 0; i < TEST_DMA_MAX_SIZE; i++) ctx->master_wrdma_buf[i] = rand();
for (int i = 0; i < TEST_DMA_MAX_SIZE; i++) {
ctx->slave_rddma_buf[i] = rand();
}
for (int i = 0; i < TEST_DMA_MAX_SIZE; i++) {
ctx->master_wrdma_buf[i] = rand();
}
int pos = rand() % TEST_DMA_MAX_SIZE;
int len = rand() % TEST_DMA_MAX_SIZE + 1;
if (pos + len > TEST_DMA_MAX_SIZE) len = TEST_DMA_MAX_SIZE - pos;
if (pos + len > TEST_DMA_MAX_SIZE) {
len = TEST_DMA_MAX_SIZE - pos;
}
ESP_LOGI("rddma_load_len", "%d", len);
ctx->tx_data = (spi_slave_hd_data_t) {
@ -238,7 +243,6 @@ static void test_hd_start(spi_device_handle_t *spi, int freq, const spitest_para
TEST_ESP_OK(err);
}
#define REG_REGION_SIZE SOC_SPI_MAXIMUM_BUFFER_SIZE
void check_no_signal(testhd_context_t* context)
@ -253,8 +257,10 @@ void check_no_signal(testhd_context_t* context)
void test_wrdma(testhd_context_t* ctx, const spitest_param_set_t *cfg, spi_device_handle_t spi)
{
int pos = rand() % TEST_DMA_MAX_SIZE;
int len = rand() % TEST_DMA_MAX_SIZE+1;
if (pos+len > TEST_DMA_MAX_SIZE) len = TEST_DMA_MAX_SIZE - pos;
int len = rand() % TEST_DMA_MAX_SIZE + 1;
if (pos + len > TEST_DMA_MAX_SIZE) {
len = TEST_DMA_MAX_SIZE - pos;
}
int test_seg_size = len;//TEST_SEG_SIZE;
ESP_LOGW("test_wrdma", "len: %d, seg_size: %d", len, test_seg_size);
@ -283,7 +289,6 @@ void test_rddma(testhd_context_t* ctx, const spitest_param_set_t* cfg, spi_devic
int len;
int test_seg_size;
len = ctx->tx_data.len;
test_seg_size = TEST_SEG_SIZE;
@ -299,8 +304,10 @@ void test_rddma(testhd_context_t* ctx, const spitest_param_set_t* cfg, spi_devic
spitest_cmp_or_dump(data_expected, ctx->master_rddma_buf, len);
int pos = rand() % TEST_DMA_MAX_SIZE;
len = rand() % TEST_DMA_MAX_SIZE+1;
if (pos + len > TEST_DMA_MAX_SIZE) len = TEST_DMA_MAX_SIZE - pos;
len = rand() % TEST_DMA_MAX_SIZE + 1;
if (pos + len > TEST_DMA_MAX_SIZE) {
len = TEST_DMA_MAX_SIZE - pos;
}
ctx->tx_data = (spi_slave_hd_data_t) {
.data = &ctx->slave_rddma_buf[pos],
@ -321,8 +328,12 @@ static void test_hd_loop(const void* arg1, void* arg2)
for (int j = 0; ; j++) {
spi_device_handle_t spi;
const int freq = timing_speed_array[j];
if (freq==0) break;
if (test_cfg->freq_limit && freq > test_cfg->freq_limit) break;
if (freq == 0) {
break;
}
if (test_cfg->freq_limit && freq > test_cfg->freq_limit) {
break;
}
ESP_LOGI(MASTER_TAG, "======> %dk", freq / 1000);
@ -333,8 +344,8 @@ static void test_hd_loop(const void* arg1, void* arg2)
uint8_t recv_buffer[REG_REGION_SIZE];
srand(123);
uint32_t mem[(REG_REGION_SIZE/4)];
for (int i = 0; i < (REG_REGION_SIZE/4); i++) {
uint32_t mem[(REG_REGION_SIZE / 4)];
for (int i = 0; i < (REG_REGION_SIZE / 4); i++) {
mem[i] = rand();
}
mem_ptr = (uint8_t*)mem;
@ -344,16 +355,18 @@ static void test_hd_loop(const void* arg1, void* arg2)
spi_slave_hd_write_buffer(TEST_SLAVE_HOST, 0, (uint8_t *) mem, SOC_SPI_MAXIMUM_BUFFER_SIZE);
srand(123);
for (int i = 0; i < (REG_REGION_SIZE/4); i++) {
for (int i = 0; i < (REG_REGION_SIZE / 4); i++) {
TEST_ASSERT(mem[i] == rand());
}
check_no_signal(context);
test_rddma(context, test_cfg, spi);
for (int i = 0; i < 128; i ++) {
int pos = rand()%REG_REGION_SIZE;
int len = rand()%REG_REGION_SIZE+1;
if (len+pos>REG_REGION_SIZE) len = REG_REGION_SIZE-pos;
int pos = rand() % REG_REGION_SIZE;
int len = rand() % REG_REGION_SIZE + 1;
if (len + pos > REG_REGION_SIZE) {
len = REG_REGION_SIZE - pos;
}
memset(recv_buffer, 0xcc, sizeof(recv_buffer));
@ -389,13 +402,15 @@ static void test_hd_loop(const void* arg1, void* arg2)
srand(466);
for (int i = 0; i < 64; i ++) {
ESP_LOGI("temp_i", "^^^^^^^^^^^^^^^^ %d ^^^^^^^^^^", i);
for (int j = 0; j < (REG_REGION_SIZE/4); j++) {
for (int j = 0; j < (REG_REGION_SIZE / 4); j++) {
mem[j] = rand();
}
for (int k = 0; k < 2; k++) {
int pos = rand() % REG_REGION_SIZE;
int len = rand() % REG_REGION_SIZE + 1;
if (len + pos > REG_REGION_SIZE) len = REG_REGION_SIZE - pos;
if (len + pos > REG_REGION_SIZE) {
len = REG_REGION_SIZE - pos;
}
printf("pos: %d, len: %d\n", pos, len);
@ -454,37 +469,41 @@ static int test_freq_hd[] = {
#define TEST_HD_IN_CONTINUOUS_MODE true
static spitest_param_set_t hd_conf[] = {
{ .pset_name = "MODE0",
{
.pset_name = "MODE0",
.freq_list = test_freq_hd,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 0,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 0,
},
{ .pset_name = "MODE1",
{
.pset_name = "MODE1",
.freq_list = test_freq_hd,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 1,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 1,
},
{ .pset_name = "MODE2",
{
.pset_name = "MODE2",
.freq_list = test_freq_hd,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 2,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 2,
},
{ .pset_name = "MODE3",
{
.pset_name = "MODE3",
.freq_list = test_freq_hd,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 3,
.dup = FULL_DUPLEX,
.master_iomux = false,
.slave_iomux = false,
.slave_tv_ns = TV_WITH_ESP_SLAVE,
.mode = 3,
},
};
TEST_SPI_HD(HD, hd_conf);
@ -500,7 +519,7 @@ TEST_CASE("test spi slave hd segment mode, master too long", "[spi][spi_slv_hd]"
{
spi_device_handle_t spi;
spitest_param_set_t *cfg = &hd_conf[0];
int freq = 100*1000; // the frequency should be small enough for the slave to prepare new trans
int freq = 100 * 1000; // the frequency should be small enough for the slave to prepare new trans
init_master_hd(&spi, cfg, freq);
@ -519,8 +538,8 @@ TEST_CASE("test spi slave hd segment mode, master too long", "[spi][spi_slv_hd]"
memset(slave_recv_buf, 0xcc, send_buf_size * 2);
memset(master_recv_buf, 0xcc, send_buf_size * 2);
srand (939);
for (int i = 0; i< send_buf_size * 2; i++) {
srand(939);
for (int i = 0; i < send_buf_size * 2; i++) {
master_send_buf[i] = rand();
slave_send_buf[i] = rand();
}
@ -642,7 +661,6 @@ static void hd_master(void)
unity_wait_for_signal("slave ready");
essl_spi_wrdma(spi, master_send_buf + send_buf_size, send_buf_size, 5, 0);
unity_wait_for_signal("slave ready");
essl_spi_rddma(spi, master_recv_buf, send_buf_size, -1, 0);
spitest_cmp_or_dump(slave_send_buf, master_recv_buf, trans_len[0]);
@ -651,7 +669,6 @@ static void hd_master(void)
essl_spi_rddma(spi, master_recv_buf + send_buf_size, send_buf_size, 5, 0);
spitest_cmp_or_dump(slave_send_buf + send_buf_size, master_recv_buf + send_buf_size, trans_len[1]);
free(master_recv_buf);
free(master_send_buf);
free(slave_send_buf);
@ -750,7 +767,8 @@ TEST_CASE_MULTIPLE_DEVICES("SPI Slave HD: segment mode, master sends too long",
#define BUF_SIZE 256
static void hd_master_quad(void){
static void hd_master_quad(void)
{
spi_bus_config_t bus_cfg = {
.miso_io_num = PIN_NUM_MISO,
.mosi_io_num = PIN_NUM_MOSI,
@ -788,7 +806,7 @@ static void hd_master_quad(void){
essl_spi_rddma(spi, master_recv_buf, BUF_SIZE / 2, -1, SPI_TRANS_MODE_QIO);
unity_wait_for_signal("slave ready");
essl_spi_rddma(spi, master_recv_buf+ BUF_SIZE / 2, BUF_SIZE / 2, -1, SPI_TRANS_MODE_QIO);
essl_spi_rddma(spi, master_recv_buf + BUF_SIZE / 2, BUF_SIZE / 2, -1, SPI_TRANS_MODE_QIO);
ESP_LOG_BUFFER_HEX("slave send", slave_send_buf, BUF_SIZE);
ESP_LOG_BUFFER_HEX("master recv", master_recv_buf, BUF_SIZE);
@ -802,7 +820,8 @@ static void hd_master_quad(void){
master_free_device_bus(spi);
}
static void hd_slave_quad(void){
static void hd_slave_quad(void)
{
spi_bus_config_t bus_cfg = {
.miso_io_num = PIN_NUM_MISO,
@ -839,7 +858,7 @@ static void hd_slave_quad(void){
.len = (trans_len + 3) & (~3),
},
{
.data = slave_recv_buf+BUF_SIZE/2,
.data = slave_recv_buf + BUF_SIZE / 2,
.len = (trans_len + 3) & (~3),
},
//send
@ -847,8 +866,8 @@ static void hd_slave_quad(void){
.data = slave_send_buf,
.len = (trans_len + 3) & (~3),
},
{
.data = slave_send_buf+BUF_SIZE/2,
{
.data = slave_send_buf + BUF_SIZE / 2,
.len = (trans_len + 3) & (~3),
},
};
@ -887,15 +906,14 @@ TEST_CASE_MULTIPLE_DEVICES("SPI quad hd test ", "[spi_ms][test_env=generic_multi
#endif // #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
//***************************************TEST FOR APPEND MODE******************************************//
#define TEST_APPEND_CACHE_SIZE 4
#define TEST_TRANS_LEN TEST_DMA_MAX_SIZE
void prepare_data(uint8_t *buff, uint32_t len, int8_t diff){
void prepare_data(uint8_t *buff, uint32_t len, int8_t diff)
{
buff[0] = random();
for (int line_index=1; line_index<len; line_index ++) {
for (int line_index = 1; line_index < len; line_index ++) {
buff[line_index] = buff[0] + line_index * diff;
}
}
@ -916,7 +934,7 @@ void slave_run_append(void)
// append some data first
for (uint32_t cache_instans = 0; cache_instans < TEST_APPEND_CACHE_SIZE; cache_instans++) {
int trans_len = 16 << (cache_instans+1);
int trans_len = 16 << (cache_instans + 1);
if (trans_len > TEST_TRANS_LEN) {
trans_len = TEST_TRANS_LEN;
}
@ -959,7 +977,7 @@ void slave_run_append(void)
//------------------------------------tx direction------------------------------
spi_slave_hd_data_t slave_tx_trans[TEST_APPEND_CACHE_SIZE] = {};
for (uint32_t cache_instans = 0; cache_instans < TEST_APPEND_CACHE_SIZE; cache_instans ++) {
int trans_len = 16 << (cache_instans+1);
int trans_len = 16 << (cache_instans + 1);
if (trans_len >= TEST_TRANS_LEN) {
trans_len = TEST_TRANS_LEN;
}
@ -989,7 +1007,9 @@ void slave_run_append(void)
}
}
printf("================Master Rx Done==================\n");
for (int i = 0; i < TEST_APPEND_CACHE_SIZE; i++) free(slave_tx_trans[i].data);
for (int i = 0; i < TEST_APPEND_CACHE_SIZE; i++) {
free(slave_tx_trans[i].data);
}
spi_slave_hd_deinit(TEST_SPI_HOST);
}

View File

@ -27,5 +27,5 @@ endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_REQUIRES ${priv_requires}
REQUIRES driver esp_driver_gpio
REQUIRES driver esp_driver_gpio esp_driver_spi
LDFRAGMENTS linker.lf)

View File

@ -41,7 +41,6 @@ components/esp_lcd/test_apps/rgb_lcd:
components/esp_lcd/test_apps/spi_lcd:
depends_components:
- esp_lcd
depends_filepatterns:
- components/driver/spi/**/*
- esp_driver_spi
disable:
- if: SOC_GPSPI_SUPPORTED != 1

View File

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

View File

@ -6,13 +6,13 @@ components/spi_flash/test_apps/esp_flash:
temporary: true
reason: target esp32p4 is not supported yet # TODO: IDF-7499
depends_filepatterns:
- components/driver/spi/**/*
- components/bootloader_support/bootloader_flash/**/*
depends_components:
- esp_mm
- esp_psram
- spi_flash
- esp_driver_gpio
- esp_driver_spi
- esptool_py # Some flash related kconfigs are listed here.
components/spi_flash/test_apps/flash_encryption:
@ -53,11 +53,11 @@ components/spi_flash/test_apps/mspi_test:
temporary: true
reason: not supported yet #TODO: IDF-7556 for p4
depends_filepatterns:
- components/driver/spi/**/*
- components/bootloader_support/bootloader_flash/**/*
depends_components:
- esp_mm
- esp_psram
- spi_flash
- esp_driver_gpio
- esp_driver_spi
- esptool_py # Some flash related kconfigs are listed here.

View File

@ -110,11 +110,11 @@ INPUT = \
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_default_configs.h \
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_host.h \
$(PROJECT_PATH)/components/driver/sdmmc/include/driver/sdmmc_types.h \
$(PROJECT_PATH)/components/driver/spi/include/driver/sdspi_host.h \
$(PROJECT_PATH)/components/driver/spi/include/driver/spi_common.h \
$(PROJECT_PATH)/components/driver/spi/include/driver/spi_master.h \
$(PROJECT_PATH)/components/driver/spi/include/driver/spi_slave_hd.h \
$(PROJECT_PATH)/components/driver/spi/include/driver/spi_slave.h \
$(PROJECT_PATH)/components/driver/sdspi/include/driver/sdspi_host.h \
$(PROJECT_PATH)/components/esp_driver_spi/include/driver/spi_common.h \
$(PROJECT_PATH)/components/esp_driver_spi/include/driver/spi_master.h \
$(PROJECT_PATH)/components/esp_driver_spi/include/driver/spi_slave_hd.h \
$(PROJECT_PATH)/components/esp_driver_spi/include/driver/spi_slave.h \
$(PROJECT_PATH)/components/driver/temperature_sensor/include/driver/temperature_sensor.h \
$(PROJECT_PATH)/components/driver/touch_sensor/include/driver/touch_sensor_common.h \
$(PROJECT_PATH)/components/driver/twai/include/driver/twai.h \

View File

@ -8,7 +8,7 @@ Overview
The SD/SDIO/MMC driver currently supports SD memory, SDIO cards, and eMMC chips. This is a protocol level driver built on top of SDMMC and SD SPI host drivers.
SDMMC and SD SPI host drivers (:component_file:`driver/sdmmc/include/driver/sdmmc_host.h` and :component_file:`driver/spi/include/driver/sdspi_host.h`) provide API functions for:
SDMMC and SD SPI host drivers (:component_file:`driver/sdmmc/include/driver/sdmmc_host.h` and :component_file:`driver/sdspi/include/driver/sdspi_host.h`) provide API functions for:
- Sending commands to slave devices
- Sending and receiving data

View File

@ -8,6 +8,7 @@ In order to control the dependence of other components on drivers at a smaller g
- `esp_driver_gptimer` - Driver for general purpose timers
- `esp_driver_pcnt` - Driver for pulse counter
- `esp_driver_gpio` - Driver for GPIO
- `esp_driver_spi` - Driver for GPSPI
For compatibility, the original `driver`` component is still treated as an all-in-one component by registering these `esp_driver_xyz`` components as its public dependencies. In other words, you do not need to modify the CMake file of an existing project, but you now have a way to specify the specific peripheral driver that your project depends on.

View File

@ -8,7 +8,7 @@ SD/SDIO/MMC 驱动程序
SD/SDIO/MMC 驱动是一种基于 SDMMC 和 SD SPI 主机驱动的协议级驱动程序,目前已支持 SD 存储器、SDIO 卡和 eMMC 芯片。
SDMMC 主机驱动和 SD SPI 主机驱动(:component_file:`driver/sdmmc/include/driver/sdmmc_host.h` 和 :component_file:`driver/spi/include/driver/sdspi_host.h`)为以下功能提供 API
SDMMC 主机驱动和 SD SPI 主机驱动(:component_file:`driver/sdmmc/include/driver/sdmmc_host.h` 和 :component_file:`driver/sdspi/include/driver/sdspi_host.h`)为以下功能提供 API
- 发送命令至从设备
- 接收和发送数据

View File

@ -8,6 +8,7 @@
- `esp_driver_gptimer` - 通用定时器驱动
- `esp_driver_pcnt` - 脉冲计数器驱动
- `esp_driver_gpio` - GPIO 驱动
- `esp_driver_spi` - 通用 SPI 驱动
为了兼容性,原来的 `driver` 组件仍然存在,并作为一个 “all-in-one" 的组件,将以上这些 `esp_driver_xyz` 组件注册成自己的公共依赖。换句话说,你无需修改既有项目的 CMake 文件,但是你现在多了一个途径去指定你项目依赖的具体的外设驱动。

View File

@ -9,8 +9,7 @@ examples/ethernet/basic:
- lwip
- esp_event
- esp_driver_gpio
depends_filepatterns:
- components/driver/spi/**/*
- esp_driver_spi
examples/ethernet/enc28j60:
disable:
@ -23,8 +22,7 @@ examples/ethernet/enc28j60:
- lwip
- esp_event
- esp_driver_gpio
depends_filepatterns:
- components/driver/spi/**/*
- esp_driver_spi
examples/ethernet/iperf:
disable_test:
@ -38,8 +36,8 @@ examples/ethernet/iperf:
- esp_event
- console
- esp_driver_gpio
- esp_driver_spi
depends_filepatterns:
- components/driver/spi/**/*
- examples/common_components/iperf/**/*
- examples/common_components/protocol_examples_common/**/*
- examples/system/console/advanced/components/cmd_system/**/*

View File

@ -4,8 +4,8 @@ examples/network/bridge:
disable_test:
- if: IDF_TARGET != "esp32"
reason: Generic functionality, no need to be run on specific targets
depends_filepatterns:
- components/driver/spi/**/*
depends_components:
- esp_driver_spi
examples/network/eth2ap:
disable:

View File

@ -131,16 +131,14 @@ examples/peripherals/lcd/spi_lcd_touch:
- if: SOC_GPSPI_SUPPORTED != 1
depends_components:
- esp_lcd
depends_filepatterns:
- components/driver/spi/**/*
- esp_driver_spi
examples/peripherals/lcd/tjpgd:
disable:
- if: SOC_GPSPI_SUPPORTED != 1
depends_components:
- esp_lcd
depends_filepatterns:
- components/driver/spi/**/*
- esp_driver_spi
examples/peripherals/ledc:
disable:

View File

@ -7,12 +7,12 @@ idf_component_get_property(original_driver_dir driver COMPONENT_OVERRIDEN_DIR)
set(include_dirs
"${IDF_PATH}/components/esp_driver_gpio/include/driver"
"${IDF_PATH}/components/esp_driver_gpio/include"
"${IDF_PATH}/components/esp_driver_spi/include/driver"
"${IDF_PATH}/components/esp_driver_spi/include"
"${original_driver_dir}/i2c/include/driver"
"${original_driver_dir}/spi/include/driver"
"${original_driver_dir}/rmt/include/driver"
"${original_driver_dir}/usb_serial_jtag/include/driver"
"${original_driver_dir}/i2c/include"
"${original_driver_dir}/spi/include"
"${original_driver_dir}/rmt/include"
"${original_driver_dir}/usb_serial_jtag/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../hal/include")
@ -21,8 +21,8 @@ idf_component_mock(INCLUDE_DIRS ${include_dirs}
REQUIRES freertos
MOCK_HEADER_FILES
${IDF_PATH}/components/esp_driver_gpio/include/driver/gpio.h
${original_driver_dir}/spi/include/driver/spi_master.h
${original_driver_dir}/spi/include/driver/spi_common.h
${IDF_PATH}/components/esp_driver_spi/include/driver/spi_master.h
${IDF_PATH}/components/esp_driver_spi/include/driver/spi_common.h
${original_driver_dir}/i2c/include/driver/i2c.h
${original_driver_dir}/rmt/include/driver/rmt_rx.h
${original_driver_dir}/rmt/include/driver/rmt_tx.h

View File

@ -35,7 +35,7 @@ set(extra_components_which_shouldnt_be_included
cxx
# [refactor-todo]: driver is a dependency of esp_pm, spi_flash, vfs, esp_wifi
# all of these should be removed from G1 except for spi_flash.
driver esp_driver_gpio esp_driver_pcnt esp_driver_gptimer
driver esp_driver_gpio esp_driver_pcnt esp_driver_gptimer esp_driver_spi
# esp_app_format is dependency of bootloader_support, app_update
esp_app_format
# esp_bootloader_format is dependency of bootloader_support, app_update