mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
essl: new component to communicate with esp serial slave devices
This commit is contained in:
parent
7c8139734d
commit
087c8f6065
@ -35,6 +35,9 @@
|
||||
#if __has_include("esp_ping.h")
|
||||
#include "esp_ping.h"
|
||||
#endif
|
||||
#if __has_include("esp_serial_slave_link/essl.h")
|
||||
#include "esp_serial_slave_link/essl.h"
|
||||
#endif
|
||||
#if __has_include("esp_spi_flash.h")
|
||||
#include "esp_spi_flash.h"
|
||||
#endif
|
||||
@ -105,6 +108,10 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
||||
# endif
|
||||
# ifdef ESP_ERR_INVALID_MAC
|
||||
ERR_TBL_IT(ESP_ERR_INVALID_MAC), /* 267 0x10b MAC address was invalid */
|
||||
# endif
|
||||
// components/esp_serial_slave_link/include/esp_serial_slave_link/essl.h
|
||||
# ifdef ESP_ERR_NOT_FINISHED
|
||||
ERR_TBL_IT(ESP_ERR_NOT_FINISHED), /* 513 0x201 */
|
||||
# endif
|
||||
// components/nvs_flash/include/nvs.h
|
||||
# ifdef ESP_ERR_NVS_BASE
|
||||
|
9
components/esp_serial_slave_link/CMakeLists.txt
Normal file
9
components/esp_serial_slave_link/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
idf_component_register(SRCS "essl.c"
|
||||
"essl_sdio.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES "sdmmc"
|
||||
"driver"
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
"include/esp_serial_slave_link"
|
||||
)
|
||||
|
@ -3,4 +3,5 @@
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := . include/esp_serial_slave_link
|
||||
|
244
components/esp_serial_slave_link/essl.c
Normal file
244
components/esp_serial_slave_link/essl.c
Normal file
@ -0,0 +1,244 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "essl.h"
|
||||
#include "essl_internal.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define TIME_EXPIRED_SINCE_CORE(start, end, timeout, max) (bool)((end)>=(start)? \
|
||||
((end)-(start)>(timeout)) :\
|
||||
((max)-(timeout)>(start)-(end)))
|
||||
|
||||
#define TIME_EXPIRED_SINCE(start, end, timeout) TIME_EXPIRED_SINCE_CORE(start, end, timeout, UINT32_MAX)
|
||||
|
||||
#define MINUS_UNTIL_ZERO(a, b) ( ((a) > (b)) ? ((a)-(b)): 0)
|
||||
|
||||
#define TIME_REMAIN_CORE(start, end, timeout, max) ((end)>=(start)?\
|
||||
MINUS_UNTIL_ZERO(timeout, (end)-(start)):\
|
||||
MINUS_UNTIL_ZERO((start)-(end), (max)-(timeout)))
|
||||
|
||||
#define TIME_REMAIN(start, end, timeout) TIME_REMAIN_CORE(start, end, timeout, UINT32_MAX)
|
||||
|
||||
|
||||
#define ESSL_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
__attribute__((unused)) static const char TAG[] = "esp_serial_slave_link";
|
||||
|
||||
#define _CHECK_EXECUTE_CMD(DEV, CMD, STR, ...) do{ \
|
||||
if ((DEV) == NULL) { \
|
||||
return ESP_ERR_INVALID_ARG; \
|
||||
} \
|
||||
if ((DEV)->CMD) { \
|
||||
return (DEV)->CMD((DEV)->args,##__VA_ARGS__); \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, STR); \
|
||||
return ESP_ERR_NOT_SUPPORTED; \
|
||||
} } while(0)
|
||||
|
||||
#define CHECK_EXECUTE_CMD(DEV, CMD, ...) _CHECK_EXECUTE_CMD(DEV, CMD, #CMD" not supported for the current device.",##__VA_ARGS__)
|
||||
|
||||
|
||||
esp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, init, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, wait_for_ready, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (start == NULL || length == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->send_packet == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
esp_err_t err;
|
||||
const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);
|
||||
|
||||
uint32_t pre = xTaskGetTickCount();
|
||||
uint32_t now;
|
||||
uint32_t remain_wait_ms = 0;
|
||||
|
||||
do {
|
||||
now = xTaskGetTickCount();
|
||||
remain_wait_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->send_packet(handle->args, start, length, remain_wait_ms);
|
||||
if (err == ESP_OK) {
|
||||
break;
|
||||
} else if (err != ESP_ERR_NOT_FOUND) {
|
||||
return err;
|
||||
} // else ESP_ERR_NOT_FOUND
|
||||
//the slave has no enough memory, retry
|
||||
} while (remain_wait_ms > 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (out_data == NULL || size == 0 || out_length == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->get_packet == NULL || handle->update_rx_data_size == NULL || handle->get_rx_data_size == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
esp_err_t err;
|
||||
const uint32_t timeout_ticks = pdMS_TO_TICKS(wait_ms);
|
||||
|
||||
uint32_t pre = xTaskGetTickCount();
|
||||
uint32_t now = 3;
|
||||
uint32_t wait_remain_ms = 0;
|
||||
int data_available = handle->get_rx_data_size(handle->args);
|
||||
|
||||
// if there is already enough data to read, skip the length update.
|
||||
if (data_available < size) {
|
||||
//loop until timeout, or there is at least one byte
|
||||
do {
|
||||
now = xTaskGetTickCount();
|
||||
wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->update_rx_data_size(handle->args, wait_remain_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
data_available = handle->get_rx_data_size(handle->args);
|
||||
if (data_available > 0) {
|
||||
break;
|
||||
}
|
||||
} while (wait_remain_ms > 0);
|
||||
}
|
||||
|
||||
if (data_available == 0) {
|
||||
//the slave has no data to send
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int len = ESSL_MIN(data_available, size);
|
||||
now = xTaskGetTickCount();
|
||||
wait_remain_ms = pdTICKS_TO_MS(TIME_REMAIN(pre, now, timeout_ticks));
|
||||
err = handle->get_packet(handle->args, out_data, len, wait_remain_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_length = len;
|
||||
if (len < data_available) {
|
||||
return ESP_ERR_NOT_FINISHED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL || out_tx_num == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->update_tx_buffer_num == NULL|| handle->get_tx_buffer_num == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = handle->update_tx_buffer_num(handle->args, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_tx_num = handle->get_tx_buffer_num(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms)
|
||||
{
|
||||
if (handle == NULL || out_rx_size == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->update_rx_data_size == NULL|| handle->get_rx_data_size == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = handle->update_rx_data_size(handle->args, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*out_rx_size = handle->get_rx_data_size(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, write_reg, addr, value, value_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, read_reg, add, value_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_wait_int(essl_handle_t handle, TickType_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, wait_int, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_reset_cnt(essl_handle_t handle)
|
||||
{
|
||||
if (handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (handle->reset_cnt == NULL) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
handle->reset_cnt(handle->args);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, clear_intr, intr_mask, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)
|
||||
{
|
||||
if (intr_raw == NULL && intr_st == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
CHECK_EXECUTE_CMD(handle, get_intr, intr_raw, intr_st, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, set_intr_ena, ena_mask, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms)
|
||||
{
|
||||
if (ena_mask_o == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
CHECK_EXECUTE_CMD(handle, get_intr_ena, ena_mask_o, wait_ms);
|
||||
}
|
||||
|
||||
esp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
CHECK_EXECUTE_CMD(handle, send_slave_intr, intr_mask, wait_ms);
|
||||
}
|
||||
|
45
components/esp_serial_slave_link/essl_internal.h
Normal file
45
components/esp_serial_slave_link/essl_internal.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <esp_types.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
/** Context used by the ``esp_serial_slave_link`` component.
|
||||
*/
|
||||
struct essl_dev_t {
|
||||
void* args;
|
||||
|
||||
esp_err_t (*init)(void* ctx, uint32_t wait_ms);
|
||||
|
||||
esp_err_t (*wait_for_ready)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*update_tx_buffer_num)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*update_rx_data_size)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*send_packet)(void *ctx, const void* start, size_t length, uint32_t wait_ms);
|
||||
esp_err_t (*get_packet)(void *ctx, void* out_data, size_t size, uint32_t wait_ms);
|
||||
esp_err_t (*write_reg)(void *ctx, uint8_t addr, uint8_t value, uint8_t* value_o, uint32_t wait_ms);
|
||||
esp_err_t (*read_reg)(void *ctx, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
esp_err_t (*wait_int)(void *ctx, uint32_t wait_ms);
|
||||
esp_err_t (*clear_intr)(void* ctx, uint32_t intr_mask, uint32_t wait_ms);
|
||||
esp_err_t (*get_intr)(void* ctx, uint32_t* intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
esp_err_t (*set_intr_ena)(void* ctx, uint32_t ena_mask, uint32_t wait_ms);
|
||||
esp_err_t (*get_intr_ena)(void* ctx, uint32_t* ena_mask_o, uint32_t wait_ms);
|
||||
esp_err_t (*send_slave_intr)(void* ctx, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
uint32_t (*get_tx_buffer_num)(void *ctx);
|
||||
uint32_t (*get_rx_data_size)(void *ctx);
|
||||
void (*reset_cnt)(void *ctx);
|
||||
};
|
||||
|
||||
typedef struct essl_dev_t essl_dev_t;
|
455
components/esp_serial_slave_link/essl_sdio.c
Normal file
455
components/esp_serial_slave_link/essl_sdio.c
Normal file
@ -0,0 +1,455 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "essl_sdio.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/host_reg.h"
|
||||
#include "freertos/task.h"
|
||||
#include "essl_internal.h"
|
||||
|
||||
static const char TAG[] = "essl_sdio";
|
||||
|
||||
#define ESSL_CMD53_END_ADDR 0x1f800
|
||||
|
||||
#define TX_BUFFER_MAX 0x1000
|
||||
#define TX_BUFFER_MASK 0xFFF
|
||||
#define RX_BYTE_MAX 0x100000
|
||||
#define RX_BYTE_MASK 0xFFFFF
|
||||
|
||||
#define FUNC1_EN_MASK (BIT(1))
|
||||
|
||||
/**
|
||||
* Initialize ``void`` over SDIO by this macro.
|
||||
*/
|
||||
#define ESSL_SDIO_DEFAULT_CONTEXT() (essl_dev_t){\
|
||||
.init = essl_sdio_init, \
|
||||
.wait_for_ready = essl_sdio_wait_for_ready, \
|
||||
.get_tx_buffer_num = essl_sdio_get_tx_buffer_num,\
|
||||
.update_tx_buffer_num = essl_sdio_update_tx_buffer_num,\
|
||||
.get_rx_data_size = essl_sdio_get_rx_data_size,\
|
||||
.update_rx_data_size = essl_sdio_update_rx_data_size,\
|
||||
.send_packet = essl_sdio_send_packet,\
|
||||
.get_packet = essl_sdio_get_packet,\
|
||||
.write_reg = essl_sdio_write_reg,\
|
||||
.read_reg = essl_sdio_read_reg,\
|
||||
.wait_int = essl_sdio_wait_int,\
|
||||
.send_slave_intr = essl_sdio_send_slave_intr, \
|
||||
.get_intr = essl_sdio_get_intr, \
|
||||
.clear_intr = essl_sdio_clear_intr, \
|
||||
.set_intr_ena = essl_sdio_set_intr_ena, \
|
||||
.reset_cnt = essl_sdio_reset_cnt, \
|
||||
}
|
||||
|
||||
typedef struct{
|
||||
//common part
|
||||
uint16_t buffer_size;
|
||||
///< All data that do not fully fill a buffer is still counted as one buffer. E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer.
|
||||
///< Buffer size of the slave pre-defined between host and slave before communication.
|
||||
size_t tx_sent_buffers; ///< Counter holding the amount of buffers already sent to ESP32 slave. Should be set to 0 when initialization.
|
||||
size_t tx_sent_buffers_latest; ///< The latest reading (from the slave) of counter holding the amount of buffers loaded. Should be set to 0 when initialization.
|
||||
size_t rx_got_bytes; ///< Counter holding the amount of bytes already received from ESP32 slave. Should be set to 0 when initialization.
|
||||
size_t rx_got_bytes_latest; ///< The latest reading (from the slave) of counter holding the amount of bytes to send. Should be set to 0 when initialization.
|
||||
|
||||
sdmmc_card_t* card; ///< Initialized sdmmc_cmd card
|
||||
uint16_t block_size;
|
||||
///< If this is too large, it takes time to send stuff bits; while if too small, intervals between blocks cost much.
|
||||
///< Should be set according to length of data, and larger than ``TRANS_LEN_MAX/511``.
|
||||
///< Block size of the SDIO function 1. After the initialization this will hold the value the slave really do. Valid value is 1-2048.
|
||||
} essl_sdio_context_t;
|
||||
|
||||
|
||||
esp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms);
|
||||
esp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms);
|
||||
|
||||
static inline esp_err_t essl_sdio_write_byte(sdmmc_card_t *card, uint32_t addr, uint8_t val, uint8_t *val_o)
|
||||
{
|
||||
return sdmmc_io_write_byte(card, 1, addr&0x3FF, val, val_o);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_write_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val, int len)
|
||||
{
|
||||
return sdmmc_io_write_bytes(card, 1, addr&0x3FF, val, len);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_read_byte(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o)
|
||||
{
|
||||
return sdmmc_io_read_byte(card, 1, addr&0x3FF, val_o);
|
||||
}
|
||||
|
||||
static inline esp_err_t essl_sdio_read_bytes(sdmmc_card_t *card, uint32_t addr, uint8_t *val_o, int len)
|
||||
{
|
||||
return sdmmc_io_read_bytes(card, 1, addr&0x3FF, val_o, len);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
essl_sdio_context_t* arg = NULL;
|
||||
essl_dev_t* dev = NULL;
|
||||
arg = (essl_sdio_context_t*)heap_caps_malloc(sizeof(essl_sdio_context_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
dev = (essl_dev_t*)heap_caps_malloc(sizeof(essl_dev_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
|
||||
if (arg == NULL || dev == NULL) {
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*dev = ESSL_SDIO_DEFAULT_CONTEXT();
|
||||
dev->args = arg;
|
||||
|
||||
*arg = (essl_sdio_context_t) {
|
||||
.card = config->card,
|
||||
.block_size = 0x200,
|
||||
.buffer_size = config->recv_buffer_size,
|
||||
.tx_sent_buffers = 0,
|
||||
.rx_got_bytes = 0,
|
||||
};
|
||||
|
||||
*out_handle = dev;
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
free(arg);
|
||||
free(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_deinit_dev(essl_handle_t handle)
|
||||
{
|
||||
if (handle) free (handle->args);
|
||||
free(handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_init(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
esp_err_t err;
|
||||
uint8_t ioe;
|
||||
sdmmc_card_t* card = ctx->card;
|
||||
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_ENABLE, &ioe);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IOE: 0x%02x", ioe);
|
||||
|
||||
uint8_t ior = 0;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IOR: 0x%02x", ior);
|
||||
|
||||
// enable function 1
|
||||
ioe |= FUNC1_EN_MASK;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_FN_ENABLE, ioe, &ioe);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IOE: 0x%02x", ioe);
|
||||
|
||||
// wait for the card to become ready
|
||||
while ((ior & FUNC1_EN_MASK) == 0) {
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IOR: 0x%02x", ior);
|
||||
}
|
||||
|
||||
// get interrupt status
|
||||
uint8_t ie;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_INT_ENABLE, &ie);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG,"IE: 0x%02x", ie);
|
||||
|
||||
// enable interrupts for function 1&2 and master enable
|
||||
ie |= BIT(0) | FUNC1_EN_MASK;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_INT_ENABLE, ie, &ie);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IE: 0x%02x", ie);
|
||||
|
||||
// get bus width register
|
||||
uint8_t bus_width;
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, &bus_width);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG,"BUS_WIDTH: 0x%02x", bus_width);
|
||||
|
||||
// enable continuous SPI interrupts
|
||||
bus_width |= CCCR_BUS_WIDTH_ECSI;
|
||||
err = sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BUS_WIDTH, bus_width, &bus_width);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "BUS_WIDTH: 0x%02x", bus_width);
|
||||
|
||||
uint16_t bs = 512;
|
||||
const uint8_t* bs_u8 = (const uint8_t*) &bs;
|
||||
uint16_t bs_read = 0;
|
||||
uint8_t* bs_read_u8 = (uint8_t*) &bs_read;
|
||||
// Set block sizes for functions 0 to 512 bytes
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 0 BS: %04x", (int) bs_read);
|
||||
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 0 BS: %04x", (int) bs_read);
|
||||
|
||||
// Set block sizes for functions 1 to given value (default value = 512).
|
||||
if (ctx->block_size > 0 || ctx->block_size <= 2048) {
|
||||
bs = ctx->block_size;
|
||||
} else {
|
||||
bs = 512;
|
||||
}
|
||||
size_t offset = SD_IO_FBR_START * 1;
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 1 BS: %04x", (int) bs_read);
|
||||
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, bs_u8[0], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_write_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, bs_u8[1], NULL));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEL, &bs_read_u8[0]));
|
||||
ESP_ERROR_CHECK(sdmmc_io_read_byte(card, 0, offset + SD_IO_CCCR_BLKSIZEH, &bs_read_u8[1]));
|
||||
ESP_LOGD(TAG, "Function 1 BS: %04x", (int) bs_read);
|
||||
|
||||
if (bs_read != ctx->block_size) {
|
||||
ESP_LOGW(TAG, "Function1 block size %d different than set value %d", bs_read, ctx->block_size);
|
||||
ctx->block_size = bs_read;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "wait_for_ioready");
|
||||
esp_err_t err;
|
||||
sdmmc_card_t *card = ((essl_sdio_context_t*)arg)->card;
|
||||
// wait for the card to become ready
|
||||
uint8_t ior = 0;
|
||||
while ((ior & FUNC1_EN_MASK) == 0) {
|
||||
err = sdmmc_io_read_byte(card, 0, SD_IO_CCCR_FN_READY, &ior);
|
||||
if (err != ESP_OK) return err;
|
||||
ESP_LOGD(TAG, "IOR: 0x%02x", ior);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
uint16_t buffer_size = ctx->buffer_size;
|
||||
int buffer_used = (length + buffer_size - 1)/buffer_size;
|
||||
esp_err_t err;
|
||||
|
||||
if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {
|
||||
//slave has no enough buffer, try update for once
|
||||
esp_err_t err = essl_sdio_update_tx_buffer_num(arg, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (essl_sdio_get_tx_buffer_num(arg) < buffer_used) {
|
||||
ESP_LOGV(TAG, "buffer is not enough: %d, %d required.", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers + buffer_used);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "send_packet: len: %d", length);
|
||||
|
||||
uint8_t *start_ptr = (uint8_t*)start;
|
||||
uint32_t len_remain = length;
|
||||
do {
|
||||
const int block_size = 512;
|
||||
/* Though the driver supports to split packet of unaligned size into
|
||||
* length of 4x and 1~3, we still send aligned size of data to get
|
||||
* higher effeciency. The length is determined by the SDIO address, and
|
||||
* the remainning will be discard by the slave hardware.
|
||||
*/
|
||||
int block_n = len_remain/block_size;
|
||||
int len_to_send;
|
||||
if (block_n) {
|
||||
len_to_send = block_n * block_size;
|
||||
err = sdmmc_io_write_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, len_to_send);
|
||||
} else {
|
||||
len_to_send = len_remain;
|
||||
err = sdmmc_io_write_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start_ptr, (len_to_send + 3) & (~3));
|
||||
}
|
||||
if (err != ESP_OK) return err;
|
||||
start_ptr += len_to_send;
|
||||
len_remain -= len_to_send;
|
||||
} while (len_remain);
|
||||
|
||||
ctx->tx_sent_buffers += buffer_used;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGV(TAG, "get_packet: read size=%d", size);
|
||||
if (essl_sdio_get_rx_data_size(arg) < size) {
|
||||
err = essl_sdio_update_rx_data_size(arg, wait_ms);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (essl_sdio_get_rx_data_size(arg) < size) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *start = out_data;
|
||||
uint32_t len_remain = size;
|
||||
do {
|
||||
const int block_size = 512; //currently our driver don't support block size other than 512
|
||||
int len_to_send;
|
||||
|
||||
int block_n = len_remain/block_size;
|
||||
if (block_n != 0) {
|
||||
len_to_send = block_n * block_size;
|
||||
err = sdmmc_io_read_blocks(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, len_to_send);
|
||||
} else {
|
||||
len_to_send = len_remain;
|
||||
/* though the driver supports to split packet of unaligned size into length
|
||||
* of 4x and 1~3, we still get aligned size of data to get higher
|
||||
* effeciency. The length is determined by the SDIO address, and the
|
||||
* remainning will be ignored by the slave hardware.
|
||||
*/
|
||||
err = sdmmc_io_read_bytes(ctx->card, 1, ESSL_CMD53_END_ADDR - len_remain, start, (len_to_send + 3) & (~3));
|
||||
}
|
||||
if (err != ESP_OK) return err;
|
||||
start += len_to_send;
|
||||
len_remain -= len_to_send;
|
||||
ctx->rx_got_bytes += len_to_send;
|
||||
} while(len_remain!=0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t essl_sdio_get_tx_buffer_num(void *arg)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
ESP_LOGV(TAG, "tx latest: %d, sent: %d", ctx->tx_sent_buffers_latest, ctx->tx_sent_buffers);
|
||||
return (ctx->tx_sent_buffers_latest + TX_BUFFER_MAX - ctx->tx_sent_buffers)%TX_BUFFER_MAX;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_update_tx_buffer_num(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
uint32_t len;
|
||||
esp_err_t err;
|
||||
|
||||
err = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_TOKEN_RDATA_REG, (uint8_t *) &len, 4);
|
||||
if (err != ESP_OK) return err;
|
||||
len = (len>>16)&TX_BUFFER_MASK;
|
||||
ctx->tx_sent_buffers_latest = len;
|
||||
ESP_LOGV(TAG, "update_tx_buffer_num: %d", len);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
uint32_t essl_sdio_get_rx_data_size(void *arg)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
ESP_LOGV(TAG, "rx latest: %d, read: %d", ctx->rx_got_bytes_latest, ctx->rx_got_bytes);
|
||||
return (ctx->rx_got_bytes_latest + RX_BYTE_MAX - ctx->rx_got_bytes)%RX_BYTE_MAX;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_update_rx_data_size(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
uint32_t len;
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGV(TAG, "get_rx_data_size: got_bytes: %d", ctx->rx_got_bytes);
|
||||
err = essl_sdio_read_bytes(ctx->card, HOST_SLCHOST_PKT_LEN_REG, (uint8_t *) &len, 4);
|
||||
if (err != ESP_OK) return err;
|
||||
len &= RX_BYTE_MASK;
|
||||
ctx->rx_got_bytes_latest = len;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "write_reg: %08X", value);
|
||||
// addrress over range
|
||||
if (addr >= 60) return ESP_ERR_INVALID_ARG;
|
||||
//W7 is reserved for interrupts
|
||||
if (addr >= 28) addr += 4;
|
||||
return essl_sdio_write_byte(((essl_sdio_context_t*)arg)->card, HOST_SLCHOST_CONF_W_REG(addr), value, value_o);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "read_reg");
|
||||
// address over range
|
||||
if (add >= 60) return ESP_ERR_INVALID_ARG;
|
||||
//W7 is reserved for interrupts
|
||||
if (add >= 28) add += 4;
|
||||
esp_err_t ret = essl_sdio_read_byte(((essl_sdio_context_t*)arg)->card, HOST_SLCHOST_CONF_W_REG(add), value_o);
|
||||
ESP_LOGV(TAG, "reg: %08X", *value_o);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "clear_intr: %08X", intr_mask);
|
||||
return essl_sdio_write_bytes(((essl_sdio_context_t *) arg)->card, HOST_SLC0HOST_INT_CLR_REG, (uint8_t *) &intr_mask, 4);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
esp_err_t r;
|
||||
ESP_LOGV(TAG, "get_intr");
|
||||
if (intr_raw == NULL && intr_st == NULL) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
if (intr_raw != NULL) {
|
||||
r= essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_RAW_REG, (uint8_t *) intr_raw, 4);
|
||||
if (r != ESP_OK) return r;
|
||||
}
|
||||
if (intr_st != NULL) {
|
||||
r = essl_sdio_read_bytes(ctx->card, HOST_SLC0HOST_INT_ST_REG, (uint8_t *) intr_st, 4);
|
||||
if (r != ESP_OK) return r;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "set_intr_ena: %08X", ena_mask);
|
||||
return essl_sdio_write_bytes(((essl_sdio_context_t*)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,
|
||||
(uint8_t *) &ena_mask, 4);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "get_intr_ena");
|
||||
esp_err_t ret = essl_sdio_read_bytes(((essl_sdio_context_t*)arg)->card, HOST_SLC0HOST_FUNC1_INT_ENA_REG,
|
||||
(uint8_t *) ena_mask_o, 4);
|
||||
ESP_LOGV(TAG, "ena: %08X", *ena_mask_o);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms)
|
||||
{
|
||||
ESP_LOGV(TAG, "send_slave_intr: %02x", intr_mask);
|
||||
return essl_sdio_write_byte(((essl_sdio_context_t*)arg)->card, HOST_SLCHOST_CONF_W7_REG + 0, intr_mask, NULL);
|
||||
}
|
||||
|
||||
esp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms)
|
||||
{
|
||||
return sdmmc_io_wait_int(((essl_sdio_context_t*)arg)->card, wait_ms);
|
||||
}
|
||||
|
||||
void essl_sdio_reset_cnt(void *arg)
|
||||
{
|
||||
essl_sdio_context_t* ctx = arg;
|
||||
ctx->rx_got_bytes = 0;
|
||||
ctx->tx_sent_buffers = 0;
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
|
||||
#define ESP_ERR_NOT_FINISHED 0x201 ///< There is still remaining data.
|
||||
|
||||
struct essl_dev_t;
|
||||
/// Handle of an ESSL device
|
||||
typedef struct essl_dev_t* essl_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
* @return ESP_OK if success, or other value returned from lower layer `init`.
|
||||
*/
|
||||
esp_err_t essl_init(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Wait for interrupt of a ESP32 slave device.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_wait_for_ready(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param out_tx_num Output of buffer num that host can send data to ESP32 slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_tx_buffer_num(essl_handle_t handle, uint32_t *out_tx_num, uint32_t wait_ms);
|
||||
|
||||
/** Get amount of data the ESP32 slave preparing to send to host.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param out_rx_size Output of data size to read from slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_rx_data_size(essl_handle_t handle, uint32_t *out_rx_size, uint32_t wait_ms);
|
||||
|
||||
|
||||
/** Reset the counters of this component. Usually you don't need to do this unless you know the slave is reset.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
*/
|
||||
esp_err_t essl_reset_cnt(essl_handle_t handle);
|
||||
|
||||
/** Send a packet to the ESP32 slave. The slave receive the packet into buffers whose size is ``buffer_size`` (configured during initialization).
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param start Start address of the packet to send
|
||||
* @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_TIMEOUT No buffer to use, or error ftrom SDMMC host controller
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_send_packet(essl_handle_t handle, const void *start, size_t length, uint32_t wait_ms);
|
||||
|
||||
/** Get a packet from ESP32 slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param[out] out_data Data output address
|
||||
* @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``
|
||||
* @param[out] out_length Output of length the data actually received from slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success, all the data are read from the slave.
|
||||
* - ESP_ERR_NOT_FINISHED Read success, while there're data remaining.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_packet(essl_handle_t handle, void *out_data, size_t size, size_t *out_length, uint32_t wait_ms);
|
||||
|
||||
/** Write general purpose R/W registers (8-bit) of ESP32 slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param addr Address of register to write. Valid address: 0-59.
|
||||
* @param value Value to write to the register.
|
||||
* @param value_o Output of the returned written value.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @note sdio 28-31 are reserved, the lower API helps to skip.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_write_reg(essl_handle_t handle, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/** Read general purpose R/W registers (8-bit) of ESP32 slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param add Address of register to read. Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read).
|
||||
* @param value_o Output value read from the register.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_read_reg(essl_handle_t handle, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/** wait for an interrupt of the slave
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_NOT_SUPPORTED Currently our driver doesnot support SDIO with SPI interface.
|
||||
* - ESP_OK If interrupt triggered.
|
||||
* - ESP_ERR_TIMEOUT No interrupts before timeout.
|
||||
*/
|
||||
esp_err_t essl_wait_int(essl_handle_t handle, uint32_t wait_ms);
|
||||
|
||||
/** Clear interrupt bits of ESP32 slave. All the bits set in the mask will be cleared, while other bits will stay the same.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param intr_mask Mask of interrupt bits to clear.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_clear_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/** Get interrupt bits of ESP32 slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.
|
||||
* @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_INVALID_ARG if both ``intr_raw`` and ``intr_st`` are NULL.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_intr(essl_handle_t handle, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
|
||||
/** Set interrupt enable bits of ESP32 slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param ena_mask Mask of the interrupt bits to enable.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_set_intr_ena(essl_handle_t handle, uint32_t ena_mask, uint32_t wait_ms);
|
||||
|
||||
/** Get interrupt enable bits of ESP32 slave.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param ena_mask_o Output of interrupt bit enable mask.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_get_intr_ena(essl_handle_t handle, uint32_t *ena_mask_o, uint32_t wait_ms);
|
||||
|
||||
/** Send interrupts to slave. Each bit of the interrupt will be triggered.
|
||||
*
|
||||
* @param handle Handle of a ``essl`` device.
|
||||
* @param intr_mask Mask of interrupt bits to send to slave.
|
||||
* @param wait_ms Millisecond to wait before timeout, will not wait at all if set to 0-9.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_send_slave_intr(essl_handle_t handle, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
|
@ -0,0 +1,248 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// ESP SDIO slave link used by the ESP host to communicate with ESP32 SDIO slave.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_serial_slave_link/essl.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/sdmmc_defs.h"
|
||||
|
||||
/// Configuration for the essl SDIO device
|
||||
typedef struct {
|
||||
sdmmc_card_t *card; ///< The initialized sdmmc card pointer of the slave.
|
||||
int recv_buffer_size; ///< The pre-negotiated recv buffer size used by both the host and the slave.
|
||||
} essl_sdio_config_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the ESSL SDIO device and get its handle.
|
||||
*
|
||||
* @param out_handle Output of the handle.
|
||||
* @param config Configuration for the ESSL SDIO device.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_NO_MEM: memory exhausted.
|
||||
*/
|
||||
esp_err_t essl_sdio_init_dev(essl_handle_t *out_handle, const essl_sdio_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free the space used by the ESSL SDIO device.
|
||||
*
|
||||
* @param handle Handle of the ESSL SDIO device to deinit.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_INVALID_ARG: wrong handle passed
|
||||
*/
|
||||
esp_err_t essl_sdio_deinit_dev(essl_handle_t handle);
|
||||
|
||||
//Please call `essl_` functions witout `sdio` instead of calling these functions directly.
|
||||
/** @cond */
|
||||
/**
|
||||
* SDIO Initialize process of a ESP32 slave device.
|
||||
*
|
||||
* @param arg Context of the ``essl`` component. Send to other functions later.
|
||||
* @param wait_ms Time to wait before operation is done, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_init(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Wait for interrupt of a ESP32 slave device.
|
||||
*
|
||||
* @param arg Context of the ``essl`` component.
|
||||
* @param wait_ms Time to wait before operation is done, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_wait_for_ready(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
uint32_t essl_sdio_get_tx_buffer_num(void *arg);
|
||||
|
||||
/** Get amount of data the ESP32 slave preparing to send to host.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
uint32_t essl_sdio_get_rx_data_size(void *arg);
|
||||
|
||||
/**
|
||||
* Send a packet to the ESP32 slave. The slave receive the packet into buffers whose size is ``buffer_size`` in the arg.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param start Start address of the packet to send
|
||||
* @param length Length of data to send, if the packet is over-size, the it will be divided into blocks and hold into different buffers automatically.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_TIMEOUT No buffer to use, or error ftrom SDMMC host controller
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_send_packet(void *arg, const void *start, size_t length, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get a packet from ESP32 slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param[out] out_data Data output address
|
||||
* @param size The size of the output buffer, if the buffer is smaller than the size of data to receive from slave, the driver returns ``ESP_ERR_NOT_FINISHED``
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success, all the data are read from the slave.
|
||||
* - ESP_ERR_NOT_FINISHED Read success, while there're data remaining.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_packet(void *arg, void *out_data, size_t size, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Wait for the interrupt from the SDIO slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
* @return
|
||||
* - ESP_ERR_NOT_SUPPORTED: if the interrupt line is not initialized properly.
|
||||
* - ESP_OK: if interrupt happened
|
||||
* - ESP_ERR_TIMEOUT: if timeout before interrupt happened.
|
||||
* - or other values returned from the `io_int_wait` member of the `card->host` structure.
|
||||
*/
|
||||
esp_err_t essl_sdio_wait_int(void *arg, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Clear interrupt bits of ESP32 slave. All the bits set in the mask will be cleared, while other bits will stay the same.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_mask Mask of interrupt bits to clear.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_clear_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get interrupt bits of ESP32 slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_raw Output of the raw interrupt bits. Set to NULL if only masked bits are read.
|
||||
* @param intr_st Output of the masked interrupt bits. set to NULL if only raw bits are read.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_INVALID_ARG if both ``intr_raw`` and ``intr_st`` are NULL.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_intr(void *arg, uint32_t *intr_raw, uint32_t *intr_st, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Set interrupt enable bits of ESP32 slave. The slave only sends interrupt on the line when there is a bit both the raw status and the enable are set.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param ena_mask Mask of the interrupt bits to enable.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_set_intr_ena(void *arg, uint32_t ena_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Get interrupt enable bits of ESP32 slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param ena_mask_o Output of interrupt bit enable mask.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_get_intr_ena(void *arg, uint32_t *ena_mask_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Write general purpose R/W registers (8-bit) of ESP32 slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param addr Address of register to write. Valid address: 0-27, 32-63 (28-31 reserved).
|
||||
* @param value Value to write to the register.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_write_reg(void *arg, uint8_t addr, uint8_t value, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Read general purpose R/W registers (8-bit) of ESP32 slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param add Address of register to read. Valid address: 0-27, 32-63 (28-31 reserved, return interrupt bits on read).
|
||||
* @param value Output value read from the register.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Address not valid.
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_read_reg(void *arg, uint8_t add, uint8_t *value_o, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* Send interrupts to slave. Each bit of the interrupt will be triggered.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
* @param intr_mask Mask of interrupt bits to send to slave.
|
||||
* @param wait_ms Time to wait before timeout, in ms.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - One of the error codes from SDMMC host controller
|
||||
*/
|
||||
esp_err_t essl_sdio_send_slave_intr(void *arg, uint32_t intr_mask, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* @brief Reset the counter on the host side.
|
||||
*
|
||||
* @note Only call when you know the slave has reset its counter, or there will be inconsistent between the master and the slave.
|
||||
*
|
||||
* @param arg Context of the component.
|
||||
*/
|
||||
void essl_sdio_reset_cnt(void *arg);
|
||||
|
||||
/** @endcond */
|
@ -78,6 +78,7 @@ typedef void (*TaskFunction_t)( void * );
|
||||
|
||||
/* Converts a time in milliseconds to a time in ticks. */
|
||||
#define pdMS_TO_TICKS( xTimeInMs ) ( ( ( TickType_t ) ( xTimeInMs ) * configTICK_RATE_HZ ) / ( TickType_t ) 1000 )
|
||||
#define pdTICKS_TO_MS( xTicks ) ( ( uint32_t ) ( xTicks ) * 1000 / configTICK_RATE_HZ )
|
||||
|
||||
#define pdFALSE ( ( BaseType_t ) 0 )
|
||||
#define pdTRUE ( ( BaseType_t ) 1 )
|
||||
|
@ -145,6 +145,9 @@ INPUT = \
|
||||
../../components/esp_https_server/include/esp_https_server.h \
|
||||
## ESP Local Ctrl
|
||||
../../components/esp_local_ctrl/include/esp_local_ctrl.h \
|
||||
## ESP Serial Slave Link
|
||||
../../components/esp_serial_slave_link/include/esp_serial_slave_link/essl.h \
|
||||
../../components/esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio.h \
|
||||
##
|
||||
## Provisioning - API Reference
|
||||
##
|
||||
|
@ -76,7 +76,10 @@ ESP SDIO slave protocol
|
||||
-----------------------
|
||||
|
||||
The protocol is based on Function 1 access by CMD52 and CMD53, offering 3 services: (1) sending and receiving FIFO, (2) 52 8-bit R/W
|
||||
register shared by host and slave, (3) 8 general purpose interrupt sources from host to slave and 8 in the oppsite direction.
|
||||
register shared by host and slave, (3) 8 general purpose interrupt sources from host to slave and 8 in the opposite direction.
|
||||
|
||||
There is a component `esp_serial_slave_link` implementing the logic of this protocol for
|
||||
ESP32 master to communicate with the ESP32 slave. See :doc:`/api-reference/protocols/esp_serial_slave_link`.
|
||||
|
||||
The host should access the registers below as described to communicate with slave.
|
||||
|
||||
@ -154,7 +157,7 @@ To write the receiving FIFO in the slave, host should work in the following step
|
||||
|
||||
1. Read the TOKEN1 field (bits 27-16) of TOKEN_RDATA (0x044) register. The buffer number remaining is TOKEN1 minus
|
||||
the number of buffers used by host.
|
||||
2. Make sure the buffer number is sufficient (*buffer_size* * *buffer_num* is greater than data to write, *buffer_size*
|
||||
2. Make sure the buffer number is sufficient (*recv_buffer_size* * *buffer_num* is greater than data to write, *recv_buffer_size*
|
||||
is pre-defined between the host and the slave before the communication starts). Or go back to step 1 until the buffer
|
||||
is enough.
|
||||
3. Write to the FIFO address with CMD53. Note that the *requested length* should not be larger than calculated in step 2,
|
||||
|
@ -127,9 +127,11 @@ SDIO initialization process (Sector 3.1.2 of `SDIO Simplified
|
||||
Specification <https://www.sdcard.org/downloads/pls/>`_), which is described
|
||||
briefly in :ref:`esp_slave_init`.
|
||||
|
||||
Furthermore, there's an ESP32-specific upper-level communication protocol upon
|
||||
the CMD52/CMD53 to Func 1. Please refer to :ref:`esp_slave_protocol_layer`,
|
||||
or example :example:`peripherals/sdio` when programming your host.
|
||||
Furthermore, there's an ESP32-specific upper-level communication protocol upon the CMD52/CMD53 to
|
||||
Func 1. Please refer to :ref:`esp_slave_protocol_layer`. There is also a component
|
||||
:doc:`ESP Serial Slave Link </api-reference/protocols/esp_serial_slave_link>`
|
||||
for ESP32 master to communicate with ESP32 SDIO slave, see example :example:`peripherals/sdio`
|
||||
when programming your host.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
154
docs/en/api-reference/protocols/esp_serial_slave_link.rst
Normal file
154
docs/en/api-reference/protocols/esp_serial_slave_link.rst
Normal file
@ -0,0 +1,154 @@
|
||||
ESP Serial Slave Link
|
||||
=====================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Espressif provides several chips that can work as slaves. These slave devices rely on some
|
||||
common buses, and have their own communication protocols over those buses. The `esp_serial_slave_link` component is
|
||||
designed for the master to communicate with ESP slave devices through those protocols over the
|
||||
bus drivers.
|
||||
|
||||
After an `esp_serial_slave_link` device is initialized properly, the application can use it to communicate with the ESP
|
||||
slave devices conveniently.
|
||||
|
||||
For more details about ESP32 SDIO slave protocol, see document :doc:`/api-reference/peripherals/esp_slave_protocol`.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
|
||||
- ESSL: Abbreviation for ESP Serial Slave Link, the component described by this document.
|
||||
|
||||
- Master: The device running the `esp_serial_slave_link` component.
|
||||
|
||||
- ESSL device: a virtual device on the master associated with an ESP slave device. The device
|
||||
context has the knowledge of the slave protocol above the bus, relying on some bus drivers to
|
||||
communicate with the slave.
|
||||
|
||||
- ESSL device handle: a handle to ESSL device context containing the configuration, status and
|
||||
data required by the ESSL component. The context stores the driver configurations,
|
||||
communication state, data shared by master and slave, etc.
|
||||
|
||||
The context should be initialized before it is used, and get deinitialized if not used any more. The
|
||||
master application operates on the ESSL device through this handle.
|
||||
|
||||
- ESP slave: the slave device connected to the bus, which ESSL component is designed to
|
||||
communicate with.
|
||||
|
||||
- Bus: The bus over which the master and the slave communicate with each other.
|
||||
|
||||
- Slave protocol: The special communication protocol specified by Espressif HW/SW over the bus.
|
||||
|
||||
- TX buffer num: a counter, which is on the slave and can be read by the master, indicates the
|
||||
accumulated buffer numbers that the slave has loaded to the hardware to receive data from the
|
||||
master.
|
||||
|
||||
- RX data size: a counter, which is on the slave and can be read by the master, indicates the
|
||||
accumulated data size that the slave has loaded to the hardware to send to the master.
|
||||
|
||||
Services provided by ESP slave
|
||||
------------------------------
|
||||
|
||||
There are some common services provided by the Espressif slaves:
|
||||
|
||||
1. Tohost Interrupts: The slave can inform the master about certain events by the interrupt line.
|
||||
|
||||
2. Frhost Interrupts: The master can inform the slave about certain events.
|
||||
|
||||
3. Tx FIFO (master to slave): the slave can send data in stream to the master. The SDIO slave can
|
||||
also indicate it has new data to send to master by the interrupt line.
|
||||
|
||||
The slave updates the TX buffer num to inform the master how much data it can receive, and the
|
||||
master then read the TX buffer num, and take off the used buffer number to know how many buffers are remaining.
|
||||
|
||||
4. Rx FIFO (slave to master): the slave can receive data from the master in units of receiving
|
||||
buffers.
|
||||
|
||||
The slave updates the RX data size to inform the master how much data it has prepared to
|
||||
send, and then the master read the data size, and take off the data length it has already received to know how many
|
||||
data is remaining.
|
||||
|
||||
5. Shared registers: the master can read some part of the registers on the slave, and also write
|
||||
these registers to let the slave read.
|
||||
|
||||
|
||||
Initialization of ESP SDIO Slave Link
|
||||
-------------------------------------
|
||||
|
||||
The ESP SDIO slave link (ESSL SDIO) devices relies on the sdmmc component. The ESSL device should
|
||||
be initialized as below:
|
||||
|
||||
1. Initialize a sdmmc card (see :doc:` Document of SDMMC driver </api-reference/storage/sdmmc>`)
|
||||
structure.
|
||||
|
||||
2. Call :cpp:func:`sdmmc_card_init` to initialize the card.
|
||||
|
||||
3. Initialize the ESSL device with :cpp:type:`essl_sdio_config_t`. The `card` member should be
|
||||
the :cpp:type:`sdmmc_card_t` got in step 2, and the `recv_buffer_size` member should be filled
|
||||
correctly according to pre-negotiated value.
|
||||
|
||||
4. Call :cpp:func:`essl_init` to do initialization of the SDIO part.
|
||||
|
||||
5. Call :cpp:func:`essl_wait_for_ready` to wait for the slave to be ready.
|
||||
|
||||
APIs
|
||||
----
|
||||
|
||||
After the initialization process above is performed, you can call the APIs below to make use of
|
||||
the services provided by the slave:
|
||||
|
||||
Interrupts
|
||||
^^^^^^^^^^
|
||||
|
||||
1. Call :cpp:func:`essl_get_intr_ena` to know which events will trigger the interrupts to the master.
|
||||
|
||||
2. Call :cpp:func:`essl_set_intr_ena` to set the events that will trigger interrupts to the master.
|
||||
|
||||
3. Call :cpp:func:`essl_wait_int` to wait until interrupt from the slave, or timeout.
|
||||
|
||||
4. When interrupt is triggered, call :cpp:func:`essl_get_intr` to know which events are active,
|
||||
and call :cpp:func:`essl_clear_intr` to clear them.
|
||||
|
||||
5. Call :cpp:func:`essl_send_slave_intr` to trigger general purpose interrupt of the slave.
|
||||
|
||||
TX FIFO
|
||||
^^^^^^^
|
||||
|
||||
1. Call :cpp:func:`essl_get_tx_buffer_num` to know how many buffers the slave has prepared to
|
||||
receive data from the master. This is optional. The master will poll `tx_buffer_num` when it try
|
||||
to send packets to the slave, until the slave has enough buffer or timeout.
|
||||
|
||||
2. Call :cpp:func:`essl_send_paket` to send data to the slave.
|
||||
|
||||
RX FIFO
|
||||
^^^^^^^
|
||||
|
||||
1. Call :cpp:func:`essl_get_rx_data_size` to know how many data the slave has prepared to send to
|
||||
the master. This is optional. When the master tries to receive data from the slave, it will update
|
||||
the `rx_data_size` for once, if the current `rx_data_size` is shorter than the buffer size the
|
||||
master prepared to receive. And it may poll the `rx_data_size` if the `rx_dat_size` keeps 0,
|
||||
until timeout.
|
||||
|
||||
2. Call :cpp:func:`essl_get_packet` to receive data from the slave.
|
||||
|
||||
Reset counters (Optional)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Call :cpp:func:`essl_reset_cnt` to reset the internal counter if you find the slave has reset its
|
||||
counter.
|
||||
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
The example below shows how ESP32 SDIO host and slave communicate with each other. The host use the ESSL SDIO.
|
||||
|
||||
:example:`peripherals/sdio`.
|
||||
|
||||
Please refer to the specific example README.md for details.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/essl.inc
|
||||
.. include:: /_build/inc/essl_sdio.inc
|
@ -16,6 +16,7 @@ Application Protocols
|
||||
mDNS <mdns>
|
||||
Modbus <modbus>
|
||||
Websocket Client <esp_websocket_client>
|
||||
ESP Serial Slave Link <esp_serial_slave_link>
|
||||
|
||||
Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples.
|
||||
|
||||
|
@ -71,7 +71,7 @@ In particular, the driver does not set any bits in (1) I/O Enable and Int Enable
|
||||
For card configuration and data transfer, choose the pair of functions relevant to your case from the table below.
|
||||
|
||||
========================================================================= ================================= =================================
|
||||
Action Read Function Write Function
|
||||
Action Read Function Write Function
|
||||
========================================================================= ================================= =================================
|
||||
Read and write a single byte using IO_RW_DIRECT (CMD52) :cpp:func:`sdmmc_io_read_byte` :cpp:func:`sdmmc_io_write_byte`
|
||||
Read and write multiple bytes using IO_RW_EXTENDED (CMD53) in byte mode :cpp:func:`sdmmc_io_read_bytes` :cpp:func:`sdmmc_io_write_bytes`
|
||||
@ -82,6 +82,8 @@ SDIO interrupts can be enabled by the application using the function :cpp:func:`
|
||||
|
||||
If you want the application to wait until the SDIO interrupt occurs, use :cpp:func:`sdmmc_io_wait_int`.
|
||||
|
||||
There is a component ESSL (ESP Serial Slave Link) to use if you are communicating with an ESP32
|
||||
SDIO slave. See :doc:`/api-reference/protocols/esp_serial_slave_link` and example :example:`peripherals/sdio/host`.
|
||||
|
||||
Combo (memory + IO) cards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -0,0 +1 @@
|
||||
.. include:: ../../../en/api-reference/protocols/esp_serial_slave_link.rst
|
@ -3,19 +3,20 @@
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:maxdepth: 1
|
||||
|
||||
mDNS <mdns>
|
||||
ESP-TLS <esp_tls>
|
||||
HTTP Client <esp_http_client>
|
||||
Websocket Client <esp_websocket_client>
|
||||
HTTP 服务器 <esp_http_server>
|
||||
HTTPS Server <esp_https_server>
|
||||
ICMP Echo <icmp_echo>
|
||||
ASIO <asio>
|
||||
ESP-MQTT <mqtt>
|
||||
Modbus slave <modbus>
|
||||
Local Control <esp_local_ctrl>
|
||||
mDNS <mdns>
|
||||
ESP-TLS <esp_tls>
|
||||
HTTP Client <esp_http_client>
|
||||
Websocket Client <esp_websocket_client>
|
||||
HTTP 服务器 <esp_http_server>
|
||||
HTTPS Server <esp_https_server>
|
||||
ICMP Echo <icmp_echo>
|
||||
ASIO <asio>
|
||||
ESP-MQTT <mqtt>
|
||||
Modbus slave <modbus>
|
||||
Local Control <esp_local_ctrl>
|
||||
ESP Serial Slave Link <esp_serial_slave_link>
|
||||
|
||||
此 API 部分的示例代码在 ESP-IDF 示例工程的 :example:`protocols` 目录下提供。
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user