sdio_example: use the new esp_ser component and new evboard

pull/4494/head
Michael (XIAO Xufeng) 2019-09-19 22:51:22 +08:00
rodzic d158fa3f5c
commit 17b7c9036f
6 zmienionych plików z 54 dodań i 659 usunięć

Wyświetl plik

@ -84,7 +84,7 @@ better or disabling the HS mode in menuconfig.
to pull down DAT2 line to set proper flash voltage. This conflicts with SDIO
pullup requirements. Currently devkits using PICO-D4 and Wroom-32 series
modules have this problem. You can either:
- Use Wrover Kit v3 which integrates a Wrover module
- Still use PICO-D4 or Wroom-32 Series modules as the slave, however:
- Don't connect the DAT2 pin and leave it floating. This means
@ -101,13 +101,8 @@ and ``api_reference/peripherals/sd_pullup_requirements`` to see more
descriptions about pullups and MTDI requirements and solutions of official
modules and devkits.
## About esp_slave component in this example
## About `esp_serial_slave_link` component used in this example
The component in this example shows how to communicate with esp32 sdio slave
correctly. However, currently it is for example purpose only.
The example shows how to talk with the slave, but doesn't show how to handle
exceptions. Assertion fails if any of the preconditions (connections,
grounding, slave data preparation, etc.) is not met.
Please do check and handle the return value in your real product.
`esp_serial_slave_link` component in the IDF is used to communicate to a ESP slave device.
When the `esp_serial_slave_link` device is initialized with an `essl_sdio_config_t` structure,
the `esp_serial_slave_link` can be used to communicate with an ESP32 SDIO slave.

Wyświetl plik

@ -1,3 +0,0 @@
idf_component_register(SRCS "esp_slave.c"
INCLUDE_DIRS "include"
REQUIRES driver sdmmc)

Wyświetl plik

@ -1,357 +0,0 @@
// Copyright 2015-2018 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 "esp_slave.h"
#include "esp_log.h"
#include "freertos/task.h"
#include "soc/sdio_slave_periph.h"
static const char TAG[] = "esp_slave";
#define ESP_SLAVE_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))
esp_err_t esp_slave_init_io(esp_slave_context_t *context)
{
esp_err_t err;
uint8_t ioe;
sdmmc_card_t* card = context->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_LOGI(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_LOGI(TAG, "Function 0 BS: %04x", (int) bs_read);
// Set block sizes for functions 1 to given value (default value = 512).
if (context->block_size > 0 || context->block_size <= 2048) {
bs = context->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_LOGI(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_LOGI(TAG, "Function 1 BS: %04x", (int) bs_read);
if (bs_read != context->block_size) {
ESP_LOGW(TAG, "Function1 block size %d different than set value %d", bs_read, context->block_size);
context->block_size = bs_read;
}
return ESP_OK;
}
esp_err_t esp_slave_wait_for_ioready(esp_slave_context_t *context)
{
ESP_LOGV(TAG, "wait_for_ioready");
esp_err_t err;
sdmmc_card_t *card = context->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_LOGI(TAG, "IOR: 0x%02x", ior);
}
return ESP_OK;
}
static inline esp_err_t esp_slave_write_byte(esp_slave_context_t *context, uint32_t addr, uint8_t val, uint8_t *val_o)
{
return sdmmc_io_write_byte(context->card, 1, addr&0x3FF, val, val_o);
}
static inline esp_err_t esp_slave_write_bytes(esp_slave_context_t *context, uint32_t addr, uint8_t *val, int len)
{
return sdmmc_io_write_bytes(context->card, 1, addr&0x3FF, val, len);
}
static inline esp_err_t esp_slave_read_byte(esp_slave_context_t *context, uint32_t addr, uint8_t *val_o)
{
return sdmmc_io_read_byte(context->card, 1, addr&0x3FF, val_o);
}
static inline esp_err_t esp_slave_read_bytes(esp_slave_context_t *context, uint32_t addr, uint8_t *val_o, int len)
{
return sdmmc_io_read_bytes(context->card, 1, addr&0x3FF, val_o, len);
}
esp_err_t esp_slave_send_packet(esp_slave_context_t *context, const void* start, size_t length, uint32_t wait_ms)
{
sdmmc_card_t *card = context->card;
uint16_t buffer_size = context->buffer_size;
int buffer_used = (length + buffer_size - 1)/buffer_size;
esp_err_t err;
const uint32_t wait_ticks = wait_ms/portTICK_PERIOD_MS;
uint32_t pre = xTaskGetTickCount();
assert(length>0);
for(;;) {
uint32_t num = 0;
err = esp_slave_get_tx_buffer_num(context, &num);
if (err == ESP_OK && num * buffer_size >= length) break;
if (err != ESP_OK && err != ESP_ERR_TIMEOUT) return err;
//not error and buffer not enough, retry ``timeout_cnt`` times
uint32_t now = xTaskGetTickCount();
if (now-pre >= wait_ticks) {
ESP_LOGD(TAG, "buffer is not enough: %d, %d required.", num, buffer_used);
return ESP_ERR_TIMEOUT;
} else {
ESP_LOGV(TAG, "buffer is not enough: %d, %d required. Retry...", num, buffer_used);
}
vTaskDelay(1);
}
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(card, 1, ESP_SLAVE_CMD53_END_ADDR - len_remain, start_ptr, len_to_send);
} else {
len_to_send = len_remain;
err = sdmmc_io_write_bytes(card, 1, ESP_SLAVE_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);
context->tx_sent_buffers += buffer_used;
return ESP_OK;
}
esp_err_t esp_slave_get_packet(esp_slave_context_t *context, void* out_data, size_t size, size_t *out_length, uint32_t wait_ms)
{
sdmmc_card_t *card = context->card;
esp_err_t err;
esp_err_t ret = ESP_OK;
uint32_t len;
const uint32_t wait_ticks = wait_ms/portTICK_PERIOD_MS;
uint32_t pre = xTaskGetTickCount();
assert (size>0);
for (;;) {
err = esp_slave_get_rx_data_size(context, &len);
if (err == ESP_OK && len > 0) break;
if (err != ESP_OK && err != ESP_ERR_TIMEOUT) return err;
//not error and no data, retry ``timeout_cnt`` times.
uint32_t now = xTaskGetTickCount();
if (now-pre >= wait_ticks) return ESP_ERR_NOT_FOUND;
vTaskDelay(1);
}
ESP_LOGV(TAG, "get_packet: slave len=%d, max read size=%d", len, size);
if (len > size) {
len = size;
ret = ESP_ERR_NOT_FINISHED;
}
uint8_t *start = out_data;
uint32_t len_remain = len;
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(card, 1, ESP_SLAVE_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(card, 1, ESP_SLAVE_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;
} while(len_remain!=0);
context->rx_got_bytes += len;
*out_length = len;
return ret;
}
esp_err_t esp_slave_get_tx_buffer_num(esp_slave_context_t *context, uint32_t* tx_num)
{
uint32_t len;
esp_err_t err;
ESP_LOGV(TAG, "get_tx_buffer_num");
err = esp_slave_read_bytes(context, HOST_SLC0HOST_TOKEN_RDATA_REG, (uint8_t*)&len, 4);
if (err != ESP_OK) return err;
len = (len>>16)&TX_BUFFER_MASK;
len = (len + TX_BUFFER_MAX - context->tx_sent_buffers)%TX_BUFFER_MAX;
*tx_num = len;
return ESP_OK;
}
esp_err_t esp_slave_get_rx_data_size(esp_slave_context_t *context, uint32_t* rx_size)
{
uint32_t len;
esp_err_t err;
ESP_LOGV(TAG, "get_rx_data_size: got_bytes: %d", context->rx_got_bytes);
err = esp_slave_read_bytes(context, HOST_SLCHOST_PKT_LEN_REG, (uint8_t*)&len, 4);
if (err != ESP_OK) return err;
len &= RX_BYTE_MASK;
len = (len + RX_BYTE_MAX - context->rx_got_bytes)%RX_BYTE_MAX;
*rx_size = len;
return ESP_OK;
}
esp_err_t esp_slave_clear_intr(esp_slave_context_t *context, uint32_t intr_mask)
{
ESP_LOGV(TAG, "clear_intr: %08X", intr_mask);
return esp_slave_write_bytes(context, HOST_SLC0HOST_INT_CLR_REG, (uint8_t*)&intr_mask, 4);
}
esp_err_t esp_slave_get_intr(esp_slave_context_t *context, uint32_t *intr_raw, uint32_t *intr_st)
{
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= esp_slave_read_bytes(context, HOST_SLC0HOST_INT_RAW_REG, (uint8_t*)intr_raw, 4);
if (r != ESP_OK) return r;
}
if (intr_st != NULL) {
r = esp_slave_read_bytes(context, HOST_SLC0HOST_INT_ST_REG, (uint8_t*)intr_st, 4);
if (r != ESP_OK) return r;
}
return ESP_OK;
}
esp_err_t esp_slave_set_intr_ena(esp_slave_context_t *context, uint32_t ena_mask)
{
ESP_LOGV(TAG, "set_intr_ena: %08X", ena_mask);
return esp_slave_write_bytes(context, HOST_SLC0HOST_INT_ENA_REG, (uint8_t*)&ena_mask, 4);
}
esp_err_t esp_slave_get_intr_ena(esp_slave_context_t *context, uint32_t *ena_mask_o)
{
ESP_LOGV(TAG, "get_intr_ena");
esp_err_t ret = esp_slave_read_bytes(context, HOST_SLC0HOST_INT_ENA_REG, (uint8_t*)ena_mask_o, 4);
ESP_LOGV(TAG, "ena: %08X", *ena_mask_o);
return ret;
}
esp_err_t esp_slave_write_reg(esp_slave_context_t *context, uint8_t addr, uint8_t value, uint8_t* value_o)
{
ESP_LOGV(TAG, "write_reg: %08X", value);
// addrress over range
if (addr >= 64) return ESP_ERR_INVALID_ARG;
// reserved for interrupts
if (addr >= 28 && addr <= 31) return ESP_ERR_INVALID_ARG;
return esp_slave_write_byte(context, HOST_SLCHOST_CONF_W_REG(addr), value, value_o);
}
esp_err_t esp_slave_read_reg(esp_slave_context_t *context, uint8_t add, uint8_t *value_o)
{
ESP_LOGV(TAG, "read_reg");
// address over range
if (add >= 64) return ESP_ERR_INVALID_ARG;
esp_err_t ret = esp_slave_read_byte(context, HOST_SLCHOST_CONF_W_REG(add), value_o);
ESP_LOGV(TAG, "reg: %08X", *value_o);
return ret;
}
esp_err_t esp_slave_send_slave_intr(esp_slave_context_t *context, uint8_t intr_mask)
{
ESP_LOGV(TAG, "send_slave_intr: %02x", intr_mask);
return esp_slave_write_byte(context, HOST_SLCHOST_CONF_W7_REG+0, intr_mask, NULL);
}

Wyświetl plik

@ -1,233 +0,0 @@
// Copyright 2015-2018 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 "sdmmc_cmd.h"
#include "driver/sdmmc_defs.h"
#include "soc/sdio_slave_periph.h"
/*
* NOTE: This component is for example purpose only. Assertion fails if any of
* the preconditions (connections, grounding, slave data preparation, etc.) is
* not met.
* Please do check and handle the return value in your real product.
*/
#define ESP_ERR_NOT_FINISHED 0x201
/** Context used by the ``esp_slave`` component.
*/
typedef struct {
sdmmc_card_t* card; ///< Initialized sdmmc_cmd card
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.
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.
size_t tx_sent_buffers; ///< Counter hold the amount of buffers already sent to ESP32 slave. Should be set to 0 when initialization.
size_t rx_got_bytes; ///< Counter hold the amount of bytes already received from ESP32 slave. Should be set to 0 when initialization.
} esp_slave_context_t;
/** Initialize ``esp_slave_context_t`` by this macro.
*/
#define ESP_SLAVE_DEFAULT_CONTEXT(card) (esp_slave_context_t){\
.card = card, \
.block_size = 0x200, \
.buffer_size = 128, \
.tx_sent_buffers = 0, \
.rx_got_bytes = 0, \
}
/** SDIO Initialize process of a ESP32 slave device.
*
* @param context Context of the ``esp_slave`` component. Send to other functions later.
*
* @return
* - ESP_OK if success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_init_io(esp_slave_context_t *context);
/** Wait for interrupt of a ESP32 slave device.
*
* @param context Context of the ``esp_slave`` component.
*
* @return
* - ESP_OK if success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_wait_for_ioready(esp_slave_context_t *context);
/** Get buffer num for the host to send data to the slave. The buffers are size of ``buffer_size``.
*
* @param context Context of the component.
* @param tx_num Output of buffer num that host can send data to ESP32 slave.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_get_tx_buffer_num(esp_slave_context_t *context, uint32_t* tx_num);
/** Get amount of data the ESP32 slave preparing to send to host.
*
* @param context Context of the component.
* @param rx_size Output of data size to read from slave.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_get_rx_data_size(esp_slave_context_t *context, uint32_t* rx_size);
/** Reset the counters of this component. Usually you don't need to do this unless you know the slave is reset.
*
* @param context Context of the component.
*/
inline static void esp_slave_reset_cnt(esp_slave_context_t *context)
{
context->rx_got_bytes = 0;
context->tx_sent_buffers = 0;
}
/** Send a packet to the ESP32 slave. The slave receive the packet into buffers whose size is ``buffer_size`` in the context.
*
* @param context 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 esp_slave_send_packet(esp_slave_context_t *context, const void* start, size_t length, uint32_t wait_ms);
/** Get a packet from ESP32 slave.
*
* @param context 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[out] out_length Output of length the data actually received from slave.
* @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 esp_slave_get_packet(esp_slave_context_t *context, void* out_data, size_t size, size_t *out_length, uint32_t wait_ms);
/** wait for an interrupt of the slave
*
* @param context Context of the component.
* @param wait Ticks to wait.
*
* @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.
*/
inline static esp_err_t esp_slave_wait_int(esp_slave_context_t *context, TickType_t wait)
{
return sdmmc_io_wait_int(context->card, wait);
}
/** Clear interrupt bits of ESP32 slave. All the bits set in the mask will be cleared, while other bits will stay the same.
*
* @param context Context of the component.
* @param intr_mask Mask of interrupt bits to clear.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_clear_intr(esp_slave_context_t *context, uint32_t intr_mask);
/** Get interrupt bits of ESP32 slave.
*
* @param context 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.
*
* @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 esp_slave_get_intr(esp_slave_context_t *context, uint32_t *intr_raw, uint32_t *intr_st);
/** 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 context Context of the component.
* @param ena_mask Mask of the interrupt bits to enable.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_set_intr_ena(esp_slave_context_t *context, uint32_t ena_mask);
/** Get interrupt enable bits of ESP32 slave.
*
* @param context Context of the component.
* @param ena_mask_o Output of interrupt bit enable mask.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_get_intr_ena(esp_slave_context_t *context, uint32_t *ena_mask_o);
/** Write general purpose R/W registers (8-bit) of ESP32 slave.
*
* @param context 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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Address not valid.
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_write_reg(esp_slave_context_t *context, uint8_t addr, uint8_t value, uint8_t* value_o);
/** Read general purpose R/W registers (8-bit) of ESP32 slave.
*
* @param context 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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Address not valid.
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_read_reg(esp_slave_context_t *context, uint8_t add, uint8_t *value_o);
/** Send interrupts to slave. Each bit of the interrupt will be triggered.
*
* @param context Context of the component.
* @param intr_mask Mask of interrupt bits to send to slave.
*
* @return
* - ESP_OK Success
* - One of the error codes from SDMMC host controller
*/
esp_err_t esp_slave_send_slave_intr(esp_slave_context_t *context, uint8_t intr_mask);

Wyświetl plik

@ -33,25 +33,21 @@ menu "Example Configuration"
If the example does not work, please try disabling the HS mode.
choice EXAMPLE_SLAVE
prompt "Id of Slave used in Espressif master-slave board."
prompt "GPIO to control slave EN in Espressif master-slave board."
default EXAMPLE_SLAVE_NONE
help
If Espressif master-slave board is used, select which slave is used.
If Espressif master-slave board is used, select the correct GPIO to control slave's EN.
config EXAMPLE_SLAVE_NONE
bool "Not using Espressif master-slave board."
config EXAMPLE_SLAVE_B1
bool "Using slave B1"
config EXAMPLE_SLAVE_B2
bool "Using slave B2"
config EXAMPLE_SLAVE_B3
bool "Using slave B3"
endchoice
config EXAMPLE_SLAVE_PWR_NEGTIVE_ACTIVE
bool "Slave power control pin is negtive active, otherwise postive active"
depends on !EXAMPLE_SLAVE_NONE
default y
default n
help
Slave power control pin is negtive active, otherwise postive active

Wyświetl plik

@ -1,4 +1,4 @@
/* SDIO example, host (uses sdmmc host driver)
/* SDIO example, host (uses sdmmc_host/sdspi_host driver)
This example code is in the Public Domain (or CC0 licensed, at your option.)
@ -20,26 +20,18 @@
#include "soc/sdio_slave_periph.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_slave.h"
#include "esp_serial_slave_link/essl_sdio.h"
#include "sdkconfig.h"
#include "driver/sdmmc_host.h"
#include "driver/sdspi_host.h"
#define TIMEOUT_MAX UINT32_MAX
/*
* For SDIO master-slave board, we have 3 pins controlling power of 3 different
* slaves individially. We only enable one at a time.
*/
#define GPIO_B1 5
#define GPIO_B2 18
#define GPIO_B3 19
#define GPIO_B1 21
#if CONFIG_EXAMPLE_SLAVE_B1
#define SLAVE_PWR_GPIO GPIO_B1
#elif CONFIG_EXAMPLE_SLAVE_B2
#define SLAVE_PWR_GPIO GPIO_B2
#elif CONFIG_EXAMPLE_SLAVE_B3
#define SLAVE_PWR_GPIO GPIO_B3
#endif
/*
@ -85,6 +77,7 @@
#define WRITE_BUFFER_LEN 4096
#define READ_BUFFER_LEN 4096
#define SLAVE_BUFFER_SIZE 128
static const char TAG[] = "example_host";
@ -103,21 +96,21 @@ typedef enum {
} example_job_t;
//host use this to inform the slave it should reset its counters
esp_err_t slave_reset(esp_slave_context_t *context)
esp_err_t slave_reset(essl_handle_t handle)
{
esp_err_t ret;
ESP_LOGI(TAG, "send reset to slave...");
ret = esp_slave_write_reg(context, 0, JOB_RESET, NULL);
ret = essl_write_reg(handle, 0, JOB_RESET, NULL, TIMEOUT_MAX);
if (ret != ESP_OK) {
return ret;
}
ret = esp_slave_send_slave_intr(context, BIT(SLAVE_INTR_NOTIFY));
ret = essl_send_slave_intr(handle, BIT(SLAVE_INTR_NOTIFY), TIMEOUT_MAX);
if (ret != ESP_OK) {
return ret;
}
vTaskDelay(500 / portTICK_RATE_MS);
ret = esp_slave_wait_for_ioready(context);
ret = essl_wait_for_ready(handle, TIMEOUT_MAX);
ESP_LOGI(TAG, "slave io ready");
return ret;
}
@ -166,7 +159,7 @@ static esp_err_t print_sdio_cis_information(sdmmc_card_t* card)
}
//host use this to initialize the slave card as well as SDIO registers
esp_err_t slave_init(esp_slave_context_t *context)
esp_err_t slave_init(essl_handle_t* handle)
{
esp_err_t err;
/* Probe */
@ -247,8 +240,14 @@ esp_err_t slave_init(esp_slave_context_t *context)
gpio_pullup_en(13);
gpio_pulldown_dis(13);
*context = ESP_SLAVE_DEFAULT_CONTEXT(card);
esp_err_t ret = esp_slave_init_io(context);
essl_sdio_config_t ser_config = {
.card = card,
.recv_buffer_size = SLAVE_BUFFER_SIZE,
};
err = essl_sdio_init_dev(handle, &ser_config);
ESP_ERROR_CHECK(err);
esp_err_t ret = essl_init(*handle, TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
ret = print_sdio_cis_information(card);
@ -267,7 +266,7 @@ void slave_power_on(void)
level_active = 1;
#endif
gpio_config_t cfg = {
.pin_bit_mask = BIT64(GPIO_B1) | BIT64(GPIO_B2) | BIT64(GPIO_B3),
.pin_bit_mask = BIT64(GPIO_B1),
.mode = GPIO_MODE_DEF_OUTPUT,
.pull_up_en = false,
.pull_down_en = false,
@ -275,8 +274,6 @@ void slave_power_on(void)
};
gpio_config(&cfg);
gpio_set_level(GPIO_B1, !level_active);
gpio_set_level(GPIO_B2, !level_active);
gpio_set_level(GPIO_B3, !level_active);
vTaskDelay(100);
gpio_set_level(SLAVE_PWR_GPIO, level_active);
@ -288,18 +285,18 @@ void slave_power_on(void)
DMA_ATTR uint8_t rcv_buffer[READ_BUFFER_LEN];
//try to get an interrupt from the slave and handle it, return if none.
esp_err_t process_event(esp_slave_context_t *context)
esp_err_t process_event(essl_handle_t handle)
{
esp_err_t ret = esp_slave_wait_int(context, 0);
esp_err_t ret = essl_wait_int(handle, 0);
if (ret == ESP_ERR_TIMEOUT) {
return ret;
}
ESP_ERROR_CHECK(ret);
uint32_t intr_raw, intr_st;
ret = esp_slave_get_intr(context, &intr_raw, &intr_st);
ret = essl_get_intr(handle, &intr_raw, &intr_st, TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
ret = esp_slave_clear_intr(context, intr_raw);
ret = essl_clear_intr(handle, intr_raw, TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
ESP_LOGD(TAG, "intr: %08X", intr_raw);
@ -314,7 +311,7 @@ esp_err_t process_event(esp_slave_context_t *context)
ESP_LOGD(TAG, "new packet coming");
while (1) {
size_t size_read = READ_BUFFER_LEN;
ret = esp_slave_get_packet(context, rcv_buffer, READ_BUFFER_LEN, &size_read, wait_ms);
ret = essl_get_packet(handle, rcv_buffer, READ_BUFFER_LEN, &size_read, wait_ms);
if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "interrupt but no data can be read");
break;
@ -334,32 +331,32 @@ esp_err_t process_event(esp_slave_context_t *context)
}
//tell the slave to do a job
static inline esp_err_t slave_inform_job(esp_slave_context_t *context, example_job_t job)
static inline esp_err_t slave_inform_job(essl_handle_t handle, example_job_t job)
{
esp_err_t ret;
ret = esp_slave_write_reg(context, SLAVE_REG_JOB, job, NULL);
ret = essl_write_reg(handle, SLAVE_REG_JOB, job, NULL, TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
ret = esp_slave_send_slave_intr(context, BIT(SLAVE_INTR_NOTIFY));
ret = essl_send_slave_intr(handle, BIT(SLAVE_INTR_NOTIFY), TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
return ret;
}
//tell the slave to write registers by write one of them, and read them back
void job_write_reg(esp_slave_context_t *context, int value)
void job_write_reg(essl_handle_t handle, int value)
{
esp_err_t ret;
uint8_t reg_read[64];
uint8_t reg_read[60];
ESP_LOGI(TAG, "========JOB: write slave reg========");
ret = esp_slave_write_reg(context, SLAVE_REG_VALUE, value, NULL);
ret = essl_write_reg(handle, SLAVE_REG_VALUE, value, NULL, TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
ret = slave_inform_job(context, JOB_WRITE_REG);
ret = slave_inform_job(handle, JOB_WRITE_REG);
ESP_ERROR_CHECK(ret);
vTaskDelay(10);
for (int i = 0; i < 64; i++) {
for (int i = 0; i < 60; i++) {
ESP_LOGD(TAG, "reading register %d", i);
ret = esp_slave_read_reg(context, i, &reg_read[i]);
ret = essl_read_reg(handle, i, &reg_read[i], TIMEOUT_MAX);
ESP_ERROR_CHECK(ret);
}
@ -374,7 +371,7 @@ int packet_len[] = {6, 12, 1024, 512, 3, 513, 517};
DMA_ATTR uint8_t send_buffer[READ_BUFFER_LEN];
//send packets to the slave (they will return and be handled by the interrupt handler)
void job_fifo(esp_slave_context_t *context)
void job_fifo(essl_handle_t handle)
{
for (int i = 0; i < READ_BUFFER_LEN; i++) {
send_buffer[i] = 0x46 + i * 5;
@ -392,7 +389,7 @@ void job_fifo(esp_slave_context_t *context)
for (int i = 0; i < sizeof(packet_len) / sizeof(int); i++) {
const int wait_ms = 50;
int length = packet_len[i];
ret = esp_slave_send_packet(context, send_buffer + pointer, length, wait_ms);
ret = essl_send_packet(handle, send_buffer + pointer, length, wait_ms);
if (ret == ESP_ERR_TIMEOUT) {
ESP_LOGD(TAG, "several packets are expected to timeout.");
} else {
@ -404,15 +401,15 @@ void job_fifo(esp_slave_context_t *context)
}
//inform the slave to send interrupts to host (the interrupts will be handled in the interrupt handler)
void job_getint(esp_slave_context_t *context)
void job_getint(essl_handle_t handle)
{
ESP_LOGI(TAG, "========JOB: get interrupts from slave========");
slave_inform_job(context, JOB_SEND_INT);
slave_inform_job(handle, JOB_SEND_INT);
}
void app_main(void)
{
esp_slave_context_t context;
essl_handle_t handle;
esp_err_t err;
//enable the power if on espressif SDIO master-slave board
@ -420,23 +417,23 @@ void app_main(void)
ESP_LOGI(TAG, "host ready, start initializing slave...");
err = slave_init(&context);
err = slave_init(&handle);
ESP_ERROR_CHECK(err);
err = slave_reset(&context);
err = slave_reset(handle);
ESP_ERROR_CHECK(err);
uint32_t start, end;
job_write_reg(&context, 10);
job_write_reg(handle, 10);
int times = 2;
while (1) {
job_getint(&context);
job_getint(handle);
start = xTaskGetTickCount();
while (1) {
process_event(&context);
process_event(handle);
vTaskDelay(1);
end = xTaskGetTickCount();
if ((end - start) * 1000 / CONFIG_FREERTOS_HZ > 5000) {
@ -449,11 +446,11 @@ void app_main(void)
};
while (1) {
job_fifo(&context);
job_fifo(handle);
start = xTaskGetTickCount();
while (1) {
process_event(&context);
process_event(handle);
vTaskDelay(1);
end = xTaskGetTickCount();
if ((end - start) * 1000 / CONFIG_FREERTOS_HZ > 2000) {