refactor(sdspi): place sdspi driver into a new component
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return CRC7 of data, in the format used by SD protocol
|
||||
* @param data array of data used to compute CRC
|
||||
* @param size size of data in bytes
|
||||
* @return CRC7 value
|
||||
*/
|
||||
uint8_t sdspi_crc7(const uint8_t *data, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Return CRC16 of data, in the format used by SD protocol
|
||||
* @param data array of data used to compute CRC
|
||||
* @param size size of data in bytes
|
||||
* @return CRC16 value
|
||||
*/
|
||||
uint16_t sdspi_crc16(const uint8_t* data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/sdspi_host.h"
|
||||
|
||||
/// Control tokens used to frame data transfers
|
||||
/// (see section 7.3.3 of SD simplified spec)
|
||||
|
||||
/// Token sent before single/multi block reads and single block writes
|
||||
#define TOKEN_BLOCK_START 0b11111110
|
||||
/// Token sent before multi block writes
|
||||
#define TOKEN_BLOCK_START_WRITE_MULTI 0b11111100
|
||||
/// Token used to stop multi block write (for reads, CMD12 is used instead)
|
||||
#define TOKEN_BLOCK_STOP_WRITE_MULTI 0b11111101
|
||||
|
||||
/// Data response tokens
|
||||
|
||||
/// Mask (high 3 bits are undefined for data response tokens)
|
||||
#define TOKEN_RSP_MASK 0b11111
|
||||
/// Data accepted
|
||||
#define TOKEN_RSP_OK 0b00101
|
||||
/// Data rejected due to CRC error
|
||||
#define TOKEN_RSP_CRC_ERR 0b01011
|
||||
/// 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
|
||||
#define TOKEN_ERR_VAL 0b00000000
|
||||
|
||||
/// Argument is out of range
|
||||
#define TOKEN_ERR_RANGE BIT(3)
|
||||
/// Card internal ECC error
|
||||
#define TOKEN_ERR_CARD_ECC BIT(2)
|
||||
/// Card controller error
|
||||
#define TOKEN_ERR_INTERNAL BIT(1)
|
||||
/// 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)
|
||||
uint8_t cmd_index : 6;
|
||||
uint8_t transmission_bit : 1;
|
||||
uint8_t start_bit : 1;
|
||||
uint8_t arguments[4];
|
||||
uint8_t stop_bit : 1;
|
||||
uint8_t crc7 : 7;
|
||||
/// Ncr is the dead time between command and response; should be 0xff
|
||||
uint8_t ncr;
|
||||
/// Response data, should be set by host to 0xff for read operations
|
||||
uint8_t r1;
|
||||
/// Up to 16 bytes of response. Luckily, this is aligned on 4 byte boundary.
|
||||
uint32_t response[4];
|
||||
/// response timeout, in milliseconds
|
||||
int timeout_ms;
|
||||
} sdspi_hw_cmd_t;
|
||||
|
||||
#define SDSPI_CMD_SIZE 6
|
||||
#define SDSPI_NCR_MIN_SIZE 1
|
||||
#define SDSPI_NCR_MAX_SIZE 8
|
||||
|
||||
//the size here contains 6 bytes of CMD, 1 bytes of dummy and the actual response
|
||||
#define SDSPI_CMD_NORESP_SIZE (SDSPI_CMD_SIZE+0) //!< Size of the command without any response
|
||||
#define SDSPI_CMD_R1_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+1) //!< Size of the command with R1 response
|
||||
#define SDSPI_CMD_R2_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+2) //!< Size of the command with R1b response
|
||||
#define SDSPI_CMD_R3_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+5) //!< Size of the command with R3 response
|
||||
#define SDSPI_CMD_R4_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+5) //!< Size of the command with R4 response
|
||||
#define SDSPI_CMD_R5_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+2) //!< Size of the command with R5 response
|
||||
#define SDSPI_CMD_R7_SIZE (SDSPI_CMD_SIZE+SDSPI_NCR_MIN_SIZE+5) //!< Size of the command with R7 response
|
||||
|
||||
#define SDSPI_CMD_FLAG_DATA BIT(0) //!< Command has data transfer
|
||||
#define SDSPI_CMD_FLAG_WRITE BIT(1) //!< Data is written to the card
|
||||
#define SDSPI_CMD_FLAG_RSP_R1 BIT(2) //!< Response format R1 (1 byte)
|
||||
#define SDSPI_CMD_FLAG_RSP_R1B BIT(3) //!< Response format R1 (1 byte), with busy polling
|
||||
#define SDSPI_CMD_FLAG_RSP_R2 BIT(4) //!< Response format R2 (2 bytes)
|
||||
#define SDSPI_CMD_FLAG_RSP_R3 BIT(5) //!< Response format R3 (5 bytes)
|
||||
#define SDSPI_CMD_FLAG_RSP_R4 BIT(6) //!< Response format R4 (5 bytes)
|
||||
#define SDSPI_CMD_FLAG_RSP_R5 BIT(7) //!< Response format R5 (2 bytes)
|
||||
#define SDSPI_CMD_FLAG_RSP_R7 BIT(8) //!< Response format R7 (5 bytes)
|
||||
#define SDSPI_CMD_FLAG_NORSP BIT(9) //!< Don't expect response (used when sending CMD0 first time).
|
||||
#define SDSPI_CMD_FLAG_MULTI_BLK BIT(10) //!< For the write multiblock commands, the start token should be different
|
||||
|
||||
#define SDSPI_MAX_DATA_LEN 512 //!< Max size of single block transfer
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd);
|
||||
|
||||
esp_err_t sdspi_host_start_command(sdspi_dev_handle_t handle, sdspi_hw_cmd_t *cmd,
|
||||
void *data, uint32_t data_size, int flags);
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "sys/lock.h"
|
||||
#include "sd_protocol_defs.h"
|
||||
#include "sd_protocol_types.h"
|
||||
#include "sdspi_private.h"
|
||||
#include "sdspi_crc.h"
|
||||
|
||||
static const char* TAG = "sdspi_transaction";
|
||||
|
||||
static _lock_t s_lock;
|
||||
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 */
|
||||
return sdspi_crc7((const uint8_t *)hw_cmd, bytes_to_crc);
|
||||
}
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd)
|
||||
{
|
||||
hw_cmd->start_bit = 0;
|
||||
hw_cmd->transmission_bit = 1;
|
||||
hw_cmd->cmd_index = opcode;
|
||||
hw_cmd->stop_bit = 1;
|
||||
hw_cmd->r1 = 0xff;
|
||||
memset(hw_cmd->response, 0xff, sizeof(hw_cmd->response));
|
||||
hw_cmd->ncr = 0xff;
|
||||
uint32_t arg_s = __builtin_bswap32(arg);
|
||||
memcpy(hw_cmd->arguments, &arg_s, sizeof(arg_s));
|
||||
hw_cmd->crc7 = sdspi_msg_crc7(hw_cmd);
|
||||
hw_cmd->timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
static void r1_response_to_err(uint8_t r1, int cmd, esp_err_t *out_err)
|
||||
{
|
||||
if (r1 & SD_SPI_R1_NO_RESPONSE) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response not found", cmd);
|
||||
*out_err = ESP_ERR_TIMEOUT;
|
||||
} else if (r1 & SD_SPI_R1_CMD_CRC_ERR) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response: command CRC error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_CRC;
|
||||
} else if (r1 & SD_SPI_R1_ILLEGAL_CMD) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response: command not supported", cmd);
|
||||
*out_err = ESP_ERR_NOT_SUPPORTED;
|
||||
} else if (r1 & SD_SPI_R1_ADDR_ERR) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response: alignment error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_ARG;
|
||||
} else if (r1 & SD_SPI_R1_PARAM_ERR) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response: size error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_SIZE;
|
||||
} else if ((r1 & SD_SPI_R1_ERASE_RST) ||
|
||||
(r1 & SD_SPI_R1_ERASE_SEQ_ERR)) {
|
||||
*out_err = ESP_ERR_INVALID_STATE;
|
||||
} else if (r1 & SD_SPI_R1_IDLE_STATE) {
|
||||
// Idle state is handled at command layer
|
||||
} else if (r1 != 0) {
|
||||
ESP_LOGD(TAG, "cmd=%d, R1 response: unexpected value 0x%02x", cmd, r1);
|
||||
*out_err = ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void r1_sdio_response_to_err(uint8_t r1, int cmd, esp_err_t *out_err)
|
||||
{
|
||||
if (r1 & SD_SPI_R1_NO_RESPONSE) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response not found", cmd);
|
||||
*out_err = ESP_ERR_TIMEOUT;
|
||||
} else if (r1 & SD_SPI_R1_CMD_CRC_ERR) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response: command CRC error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_CRC;
|
||||
} else if (r1 & SD_SPI_R1_ILLEGAL_CMD) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response: command not supported", cmd);
|
||||
*out_err = ESP_ERR_NOT_SUPPORTED;
|
||||
} else if (r1 & SD_SPI_R1_PARAM_ERR) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response: size error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_SIZE;
|
||||
} else if (r1 & SDIO_R1_FUNC_NUM_ERR) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response: function number error", cmd);
|
||||
*out_err = ESP_ERR_INVALID_ARG;
|
||||
} else if (r1 & SD_SPI_R1_IDLE_STATE) {
|
||||
// Idle state is handled at command layer
|
||||
} else if (r1 != 0) {
|
||||
ESP_LOGI(TAG, "cmd=%d, R1 response: unexpected value 0x%02x", cmd, r1);
|
||||
*out_err = ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
|
||||
{
|
||||
_lock_acquire(&s_lock);
|
||||
// Convert the command to wire format
|
||||
WORD_ALIGNED_ATTR sdspi_hw_cmd_t hw_cmd;
|
||||
make_hw_cmd(cmdinfo->opcode, cmdinfo->arg, cmdinfo->timeout_ms, &hw_cmd);
|
||||
|
||||
// Flags indicate which of the transfer types should be used
|
||||
int flags = 0;
|
||||
if (SCF_CMD(cmdinfo->flags) == SCF_CMD_ADTC) {
|
||||
flags = SDSPI_CMD_FLAG_DATA | SDSPI_CMD_FLAG_WRITE;
|
||||
} else if (SCF_CMD(cmdinfo->flags) == (SCF_CMD_ADTC | SCF_CMD_READ)) {
|
||||
flags = SDSPI_CMD_FLAG_DATA;
|
||||
}
|
||||
|
||||
// The block size is 512, when larger than 512, the data must send in multi blocks
|
||||
if (cmdinfo->datalen > SDSPI_MAX_DATA_LEN) {
|
||||
flags |= SDSPI_CMD_FLAG_MULTI_BLK;
|
||||
}
|
||||
|
||||
// In SD host, response format is encoded using SCF_RSP_* flags which come
|
||||
// as part of sdmmc_command_t from the upper layer (sdmmc_cmd.c).
|
||||
// SPI mode uses different command formats. In fact, most of the commands
|
||||
// use R1 response. Therefore, instead of adding another parallel set of
|
||||
// response flags for the SPI mode, response format is determined here:
|
||||
if (!s_app_cmd && cmdinfo->opcode == SD_SEND_IF_COND) {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R7;
|
||||
} else if (!s_app_cmd && cmdinfo->opcode == MMC_SEND_STATUS) {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R2;
|
||||
} else if (!s_app_cmd && cmdinfo->opcode == SD_READ_OCR) {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R3;
|
||||
} 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)) {
|
||||
/* 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) {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R4;
|
||||
} else if (!s_app_cmd && cmdinfo->opcode == SD_IO_RW_DIRECT) {
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
} else if (!s_app_cmd && (cmdinfo->opcode == MMC_ERASE || cmdinfo->opcode == MMC_STOP_TRANSMISSION)) {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R1B;
|
||||
} else {
|
||||
flags |= SDSPI_CMD_FLAG_RSP_R1;
|
||||
}
|
||||
|
||||
// Send the command and get the response.
|
||||
esp_err_t ret = sdspi_host_start_command(slot, &hw_cmd,
|
||||
cmdinfo->data, cmdinfo->datalen, flags);
|
||||
|
||||
// Extract response bytes and store them into cmdinfo structure
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGV(TAG, "r1 = 0x%02x hw_cmd.r[0]=0x%08"PRIx32, hw_cmd.r1, hw_cmd.response[0]);
|
||||
// Some errors should be reported using return code
|
||||
if (flags & (SDSPI_CMD_FLAG_RSP_R1 | SDSPI_CMD_FLAG_RSP_R1B)) {
|
||||
cmdinfo->response[0] = hw_cmd.r1;
|
||||
r1_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret);
|
||||
} else if (flags & SDSPI_CMD_FLAG_RSP_R2) {
|
||||
cmdinfo->response[0] = ((uint32_t)hw_cmd.r1) | ((hw_cmd.response[0] & 0xff) << 8);
|
||||
} else if (flags & (SDSPI_CMD_FLAG_RSP_R3 | SDSPI_CMD_FLAG_RSP_R7)) {
|
||||
r1_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret);
|
||||
cmdinfo->response[0] = __builtin_bswap32(hw_cmd.response[0]);
|
||||
} else if (flags & SDSPI_CMD_FLAG_RSP_R4) {
|
||||
r1_sdio_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret);
|
||||
cmdinfo->response[0] = __builtin_bswap32(hw_cmd.response[0]);
|
||||
} else if (flags & SDSPI_CMD_FLAG_RSP_R5) {
|
||||
r1_sdio_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret);
|
||||
cmdinfo->response[0] = hw_cmd.response[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Save a flag whether the next command is expected to be an app command
|
||||
if (ret == ESP_OK) {
|
||||
s_app_cmd = (cmdinfo->opcode == MMC_APP_CMD);
|
||||
} else {
|
||||
s_app_cmd = false;
|
||||
}
|
||||
_lock_release(&s_lock);
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user