SDIO 卡从机驱动程序

[English]

概述

如下表所示,ESP32 SDIO 卡的主机与从机外设共享两组管脚。SPI0 总线通常会占用第一组管脚,该总线负责运行代码,与 SPI flash 相连。因此,在 SDIO 主机不使用第二组管脚时,SDIO 从机驱动程序只能在第二组管脚上运行。

SDIO 从机支持以下三种运行模式:SPI、1 位 SD 和 4 位 SD。从机设备可以根据接口上的信号确定当前模式,并相应地配置自身以适配该模式。随后,从机驱动程序可以与从机设备进行通信,正确处理命令和数据传输。根据 SDIO 规范,无论是在 1 位 SD、4 位 SD 还是 SPI 模式下,CMD 和 DAT0-3 信号线都应设置为高电平。

连接方式

管脚名称

SPI 模式的对应管脚

GPIO 编号(卡槽 1)

GPIO 编号(卡槽 2)

CLK

SCLK

6

14

CMD

MOSI

11

15

DAT0

MISO

7

2

DAT1

中断

8

4

DAT2

N.C.(拉高)

9

12

DAT3

#CS

10

13

  • 1 位 SD 模式:连接 CLK、CMD、DAT0 和 DAT1 管脚并接地。

  • 4 位 SD 模式:连接所有管脚并接地。

  • SPI 模式:连接 SCLK、MOSI、MISO、中断、#CS 管脚并接地。

备注

请确保使用 10 KOhm - 90 KOhm 的上拉电阻将 SDIO 卡的 CMD 和数据线 DAT0-DAT3 配置为上拉,包括在 1 位模式或 SPI 模式下。大多数官方模组内部并未提供此类上拉电阻,使用官方开发板时,请参阅 Overview of Compatibility,确认所用开发板是否配置此类上拉电阻。

备注

多数官方模组的 strapping 管脚与 SDIO 从机功能配置存在冲突。若在内置 3.3 V flash 的 ESP32 模组上进行首次开发,需要在开发之前进行 eFuse 烧录,以调整模组的管脚配置,使其与 SDIO 功能兼容。请参阅 Overview of Compatibility,了解具体配置方法。

以下是内置 3.3 V flash 的模组/开发板列表:

  • 模组:除 ESP32-WROVER、ESP32-WROVER-I、ESP32-S3-WROOM-2 外的所有模组,模组列表见 模组概览

  • 开发板:ESP32-PICO-KIT、ESP32-DevKitC(最高版本为 v4)、ESP32-WROVER-KIT(v4.1 [也称 ESP32-WROVER-KIT-VB]、v2、v1 [也称 DevKitJ v1])

通过开发板上模组的型号可以判断 ESP32-WROVER-KIT 的版本:v4.1 使用 ESP32-WROVER-B 模组,v3 使用 ESP32-WROVER 模组,v2 和 v1 使用 ESP32-WROOM-32 模组。

要了解有关上拉电阻的更多技术细节,请参阅 SD Pull-up Requirements

主机可以配置 DAT3 管脚为高电平并发送 CMD0 命令,将从机初始化为 SD 模式;或配置 CS 管脚为低电平并发送 CMD0 命令,将从机初始化为 SPI 模式。CS 管脚与 DAT3 管脚相同。

初始化完成后,主机可以发送 CMD52 命令,将数据写入 CCCR 寄存器 0x07,启用 4 位 SD 模式。所有总线检测均由从机外设处理。

主机与从机的通信必须通过 ESP 从机特定协议进行。

通过 CMD52 和 CMD53 命令,从机驱动程序基于 Function 1 提供了以下三种服务:

  1. 发送和接收 FIFO

  2. 主机和从机共享的 52 个 8 位 读写寄存器

  3. 16 个中断源(8 个从主机到从机,8 个从从机到主机)

术语

SDIO 从机驱动程序的相关术语如下:

  • 传输 (transfer):传输始终由主机发出的命令符启动,可能包含一个响应和多个数据块。ESP32 SDIO 从机驱动程序的核心机制是通过传输进行数据交换和通信。

  • 发送 (sending):从从机到主机的传输。

  • 接收 (receiving):从主机到从机的传输。

备注

ESP32 技术参考手册 > SDIO 从机控制器 [PDF] 中,寄存器从主机的角度进行命名和定义。即,RX 寄存器指的是发送寄存器,TX 寄存器指的是接收寄存器。 我们在驱动程序中不再使用 TXRX,以避免产生歧义。

  • FIFO:在 Function 1 内的特定地址,可以通过使用 CMD53 命令读写大量数据。该地址与在单个传输中请求从从机读取或写入的长度相关:请求长度 = 0x1F800 – 地址。

  • 所有权 (ownership):拥有缓冲区的所有权时,驱动程序可以随机读写该缓冲区(通常通过 DMA 实现)。在所有权返回给应用程序前,应用程序不应读取/写入该缓冲区。如果应用程序从缓冲区中读取数据时,接收驱动程序拥有缓冲区的所有权,可能会读取到随机数据;如果应用程序向缓冲区写入数据时,发送驱动程序拥有缓冲区的所有权,发送的数据可能会损坏。

  • 请求长度 (requested length):一次传输中的请求长度,由 FIFO 地址确定。

  • 传输长度 (transfer length):一次传输中的请求长度,由 CMD53 字节/块计数字段确定。

备注

请求长度不同于传输长度。在 ESP32 SDIO DMA 中,操作基于 请求长度 而非 传输长度,即 DMA 控制器会根据 请求长度 处理数据传输,确保只传输 请求长度 范围内的数据。传输长度 必须等于或长于 请求长度,并将剩余部分在发送时填充为 0,或在接受时丢弃。

  • 接收缓冲区大小 (receiving buffer size):通信开始前,主机与从机间会预先定义缓冲区大小。初始化过程中,从机应用程序必须通过结构体 sdio_slave_config_t 中的 recv_buffer_size 设置缓冲区大小。

  • 中断 (interrupts):ESP32 SDIO 从机支持两个方向的中断,即由主机到从机(以下称从机中断)以及由从机到主机(以下称主机中断)。更多详情,请参阅 中断

  • 寄存器 (registers):通过 CMD52 或 CMD53 命令在 Function 1 中访问的特定地址。

与 ESP SDIO 从机通信

在使用主机初始化 SDIO 从机时,应遵循标准 SDIO 初始化流程(请参阅 SDIO 简化规范 的第 3.1.2 节),简化版流程可参考 初始化 ESP SDIO 从机

此外,在通过 CMD52/CMD53 访问到 Function 1 这一机制的基础上,还存在一个仅适用于 ESP32 的上层通信协议。该特定通信协议中,主机和从机通过 CMD52/CMD53 命令进行数据交换和通信。更多详情,请参阅 ESP SDIO 从机协议

组件 ESP 串行从机链路 也支持 ESP32 主机与 ESP32 SDIO 从机通信。在开发主机应用程序时,请参阅 peripherals/sdio 中的示例。

中断

为了方便通信,SDIO 从机驱动程序中既存在由主机到从机的中断信号,也存在由从机到主机的中断信号。

从机中断

主机可以通过在寄存器 0x08D 中写入任意一个位来向从机发起中断。一旦置位了寄存器中的任意一位,就会产生一个中断,促使 SDIO 从机驱动调用特定回调函数,该回调函数由 sdio_slave_config_t 结构体中的 slave_intr_cb 定义。

备注

该回调函数在中断服务例程中调用,请勿在其中使用任何延迟、循环或可能阻塞的函数,如互斥锁。

类似前述情况,还有一组备选函数可供使用。可以调用 sdio_slave_wait_int 在一定时间内等待中断,或调用 sdio_slave_clear_int 清除来自主机的中断。回调函数可以与等待函数完美配合。

主机中断

从机可以在特定时间通过中断线向主机发起中断,这个中断是电平触发的。主机检测到中断线电平拉低时,它可以读取从机中断状态寄存器,以查看中断源。主机可以清除特定的中断位,或选择禁用中断源。在清除或禁用所有中断源前,中断线会保持激活状态。

在 SDIO 从机驱动程序中,还存在一些专用中断源和通用中断源,详情请参阅 sdio_slave_hostint_t

共享寄存器

在主机与从机之间共有 52 个共享的 8 位读写寄存器,用于在主机和从机之间共享信息。通过 sdio_slave_read_regsdio_slave_write_reg,从机可以随时读取或写入寄存器。主机可以通过 CMD52 或 CMD53 访问(读写)这些寄存器。

接收 FIFO

准备向从机发送数据包时,主机需要读取从机的缓冲区数据数量,判定从机是否准备好接收数据。

为了支持接收来自主机的数据,应用程序需按照以下步骤,将缓冲区加载到从机驱动程序中:

  1. 调用 sdio_slave_recv_register_buf 注册缓冲区,并获取已注册缓冲区的句柄。驱动程序会为链接到硬件的链表描述符所需的缓冲区分配内存。这些缓冲区的大小应与接收缓冲区大小相等。

  2. 将缓冲区句柄传递给 sdio_slave_recv_load_buf,将缓冲区加载到驱动程序中。

  3. 调用 sdio_slave_recvsdio_slave_recv_packet 获取接收到的数据。如果需要采取非阻塞式调用,可以设置 wait 为 0。

    这两个 API 的区别在于,sdio_slave_recv_packet 会提供更多有关数据包的信息,数据包可以由多个缓冲区组成。

    当此 API 返回 ESP_ERR_NOT_FINISHED 时,应循环调用此 API,直到返回值为 ESP_OK。此时,在主机发送的数据包中,包含了所有与 ESP_ERR_NOT_FINISHED 一起返回的连续缓冲区,以及与 ESP_OK 一起返回的最后一个缓冲区。

    调用 sdio_slave_recv_get_buf 获取所接收数据的地址,以及每个缓冲区实际接收到的长度。数据包的长度是数据包中所有缓冲区接收长度的总和。

    如果主机发送的数据始终小于接收缓冲区的大小,或者数据包的边界(例如,数据只是一个字节流)无关紧要,则可以使用更简单的 sdio_slave_recv

  4. 调用 sdio_recv_load_buf,将经过处理的缓冲区句柄再次传递给驱动程序。

备注

为减少复制数据的开销,驱动程序本身不具有任何内部缓冲区;应用程序有责任及时提供新的缓冲区,DMA 会自动将接收到的数据存储到缓冲区中。

发送 FIFO

每当从机要发送数据时,它会触发一个中断,并由主机请求数据包长度。发送模式有两种:

  • 数据流模式 (stream mode):在此模式下,当缓冲区加载到驱动程序中时,无论之前的数据包是否已经发送,该缓冲区的长度会计入主机在传入通信中请求的数据包长度中。换句话说,即使之前还有未发送的数据包,新加载的缓冲区长度也会包括在主机请求的数据包长度中。这样,主机可以在一次传输中获取多个缓冲区的数据。

  • 数据包模式 (packet mode):在此模式下,数据包长度逐个更新,且仅在前一个数据包发送时更新。此时,主机在一次传输中只能获取一个缓冲区的数据。

备注

为减少复制数据的开销,驱动程序本身没有内部缓冲区,DMA 直接从应用程序提供的缓冲区中获取数据。发送完成前,应用程序不应该访问缓冲区,以确保数据传输的正确性。

结构体 sdio_slave_config_t 中的 sending_mode 可以设置发送模式,send_queue_size 可以设置缓冲区数量。缓冲区大小均限制在 4092 字节内。尽管在流模式下,一次传输可以发送多个缓冲区,但每个缓冲区在队列中仍然计为一个。

应用程序可以调用 sdio_slave_transmit 函数发送数据包。此时,函数在传输完成后返回,因此队列并未完全占用。若需要更高效率,应用程序可以改用以下函数:

  1. 将缓冲区信息(地址、长度以及表示缓冲区的 arg 参数)传递给 sdio_slave_send_queue

    • 如果需要采用非阻塞调用,请设置 wait 为 0。

    • 如果 wait 并未设置为 portMAX_DELAY (等待直到缓冲区传输完成),应用程序应检查返回结果,确认数据是否已放入队列中,或是否已丢弃。

  2. 调用 sdio_slave_send_get_finished 来获取并处理已完成的传输。在缓冲区 sdio_slave_send_get_finished 返回前不应修改缓冲区。这意味着缓冲区实际上发送给了主机,而非在队列中等待。

要使用队列参数中 arg ,可以采用以下几种方法:

  1. 直接将 arg 指向一个动态分配的缓冲区,并在传输完成后使用 arg 释放该缓冲区。

  2. 在传输结构体中封装传输信息,并将 arg 指向该结构体。使用该结构体还可以执行更多操作,例如:

    typedef struct {
        uint8_t* buffer;
        size_t   size;
        int      id;
    }sdio_transfer_t;
    
    //发送传输:
    sdio_transfer_t trans = {
        .buffer = ADDRESS_TO_SEND,
        .size = 8,
        .id = 3,  //第 3 个传输
    };
    sdio_slave_send_queue(trans.buffer, trans.size, &trans, portMAX_DELAY);
    
    //… 在此还可能发送更多传输
    
    //处理完成的传输:
    sdio_transfer_t* arg = NULL;
    sdio_slave_send_get_finished((void**)&arg, portMAX_DELAY);
    ESP_LOGI("tag", "(%d) successfully send %d bytes of %p", arg->id, arg->size, arg->buffer);
    some_post_callback(arg); //执行更多操作
    
  3. 用于该驱动程序的接收部分,将 arg 指向该缓冲区的接收缓冲区句柄。这样,可以在发送数据时直接使用该缓冲区来接收数据:

    uint8_t buffer[256]={1,2,3,4,5,6,7,8};
    sdio_slave_buf_handle_t handle = sdio_slave_recv_register_buf(buffer);
    sdio_slave_send_queue(buffer, 8, handle, portMAX_DELAY);
    
    //… 在此还可能发送更多传输
    
    //加载已完成的传输,准备接收
    sdio_slave_buf_handle_t handle = NULL;
    sdio_slave_send_get_finished((void**)&handle, portMAX_DELAY);
    sdio_slave_recv_load_buf(handle);
    

    更多详情,请参阅 peripherals/sdio

应用示例

从机/主机通信的相关应用示例请参阅 peripherals/sdio

API 参考

Header File

Enumerations

enum sdio_slave_hostint_t

Mask of interrupts sending to the host.

Values:

enumerator SDIO_SLAVE_HOSTINT_BIT0

General purpose interrupt bit 0.

enumerator SDIO_SLAVE_HOSTINT_BIT1
enumerator SDIO_SLAVE_HOSTINT_BIT2
enumerator SDIO_SLAVE_HOSTINT_BIT3
enumerator SDIO_SLAVE_HOSTINT_BIT4
enumerator SDIO_SLAVE_HOSTINT_BIT5
enumerator SDIO_SLAVE_HOSTINT_BIT6
enumerator SDIO_SLAVE_HOSTINT_BIT7
enumerator SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET

New packet available.

enum sdio_slave_timing_t

Timing of SDIO slave.

Values:

enumerator SDIO_SLAVE_TIMING_PSEND_PSAMPLE

Send at posedge, and sample at posedge. Default value for HS mode. If :c:macro:SDIO_SLAVE_FLAG_HIGH_SPEED is specified in :cpp:class:sdio_slave_config_t, this should be selected. Normally there's no problem using this to work in DS mode.

enumerator SDIO_SLAVE_TIMING_NSEND_PSAMPLE

Send at negedge, and sample at posedge. Default value for DS mode and below. If :c:macro:SDIO_SLAVE_FLAG_DEFAULT_SPEED is specified in :cpp:class:sdio_slave_config_t, this should be selected.

enumerator SDIO_SLAVE_TIMING_PSEND_NSAMPLE

Send at posedge, and sample at negedge.

enumerator SDIO_SLAVE_TIMING_NSEND_NSAMPLE

Send at negedge, and sample at negedge.

enum sdio_slave_sending_mode_t

Configuration of SDIO slave mode.

Values:

enumerator SDIO_SLAVE_SEND_STREAM

Stream mode, all packets to send will be combined as one if possible.

enumerator SDIO_SLAVE_SEND_PACKET

Packet mode, one packets will be sent one after another (only increase packet_len if last packet sent).

Header File

  • components/esp_driver_sdio/include/driver/sdio_slave.h

  • This header file can be included with:

    #include "driver/sdio_slave.h"
    
  • This header file is a part of the API provided by the esp_driver_sdio component. To declare that your component depends on esp_driver_sdio, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_sdio
    

    or

    PRIV_REQUIRES esp_driver_sdio
    

Functions

esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)

Initialize the sdio slave driver

参数

config -- Configuration of the sdio slave driver.

返回

  • ESP_ERR_NOT_FOUND if no free interrupt found.

  • ESP_ERR_INVALID_STATE if already initialized.

  • ESP_ERR_NO_MEM if fail due to memory allocation failed.

  • ESP_OK if success

void sdio_slave_deinit(void)

De-initialize the sdio slave driver to release the resources.

esp_err_t sdio_slave_start(void)

Start hardware for sending and receiving, as well as set the IOREADY1 to 1.

备注

The driver will continue sending from previous data and PKT_LEN counting, keep data received as well as start receiving from current TOKEN1 counting. See sdio_slave_reset.

返回

  • ESP_ERR_INVALID_STATE if already started.

  • ESP_OK otherwise.

void sdio_slave_stop(void)

Stop hardware from sending and receiving, also set IOREADY1 to 0.

备注

this will not clear the data already in the driver, and also not reset the PKT_LEN and TOKEN1 counting. Call sdio_slave_reset to do that.

esp_err_t sdio_slave_reset(void)

Clear the data still in the driver, as well as reset the PKT_LEN and TOKEN1 counting.

返回

always return ESP_OK.

sdio_slave_buf_handle_t sdio_slave_recv_register_buf(uint8_t *start)

Register buffer used for receiving. All buffers should be registered before used, and then can be used (again) in the driver by the handle returned.

备注

The driver will use and only use the amount of space specified in the recv_buffer_size member set in the sdio_slave_config_t. All buffers should be larger than that. The buffer is used by the DMA, so it should be DMA capable and 32-bit aligned.

参数

start -- The start address of the buffer.

返回

The buffer handle if success, otherwise NULL.

esp_err_t sdio_slave_recv_unregister_buf(sdio_slave_buf_handle_t handle)

Unregister buffer from driver, and free the space used by the descriptor pointing to the buffer.

参数

handle -- Handle to the buffer to release.

返回

ESP_OK if success, ESP_ERR_INVALID_ARG if the handle is NULL or the buffer is being used.

esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle)

Load buffer to the queue waiting to receive data. The driver takes ownership of the buffer until the buffer is returned by sdio_slave_send_get_finished after the transaction is finished.

参数

handle -- Handle to the buffer ready to receive data.

返回

  • ESP_ERR_INVALID_ARG if invalid handle or the buffer is already in the queue. Only after the buffer is returened by sdio_slave_recv can you load it again.

  • ESP_OK if success

esp_err_t sdio_slave_recv_packet(sdio_slave_buf_handle_t *handle_ret, TickType_t wait)

Get buffer of received data if exist with packet information. The driver returns the ownership of the buffer to the app.

When you see return value is ESP_ERR_NOT_FINISHED, you should call this API iteratively until the return value is ESP_OK. All the continuous buffers returned with ESP_ERR_NOT_FINISHED, together with the last buffer returned with ESP_OK, belong to one packet from the host.

You can call simpler sdio_slave_recv instead, if the host never send data longer than the Receiving buffer size, or you don't care about the packet boundary (e.g. the data is only a byte stream).

备注

Call sdio_slave_load_buf with the handle to re-load the buffer onto the link list, and receive with the same buffer again. The address and length of the buffer got here is the same as got from sdio_slave_get_buffer.

参数
  • handle_ret -- Handle of the buffer holding received data. Use this handle in sdio_slave_recv_load_buf() to receive in the same buffer again.

  • wait -- Time to wait before data received.

返回

  • ESP_ERR_INVALID_ARG if handle_ret is NULL

  • ESP_ERR_TIMEOUT if timeout before receiving new data

  • ESP_ERR_NOT_FINISHED if returned buffer is not the end of a packet from the host, should call this API again until the end of a packet

  • ESP_OK if success

esp_err_t sdio_slave_recv(sdio_slave_buf_handle_t *handle_ret, uint8_t **out_addr, size_t *out_len, TickType_t wait)

Get received data if exist. The driver returns the ownership of the buffer to the app.

备注

Call sdio_slave_load_buf with the handle to re-load the buffer onto the link list, and receive with the same buffer again. The address and length of the buffer got here is the same as got from sdio_slave_get_buffer.

参数
  • handle_ret -- Handle to the buffer holding received data. Use this handle in sdio_slave_recv_load_buf to receive in the same buffer again.

  • out_addr -- [out] Output of the start address, set to NULL if not needed.

  • out_len -- [out] Actual length of the data in the buffer, set to NULL if not needed.

  • wait -- Time to wait before data received.

返回

  • ESP_ERR_INVALID_ARG if handle_ret is NULL

  • ESP_ERR_TIMEOUT if timeout before receiving new data

  • ESP_OK if success

uint8_t *sdio_slave_recv_get_buf(sdio_slave_buf_handle_t handle, size_t *len_o)

Retrieve the buffer corresponding to a handle.

参数
  • handle -- Handle to get the buffer.

  • len_o -- Output of buffer length

返回

buffer address if success, otherwise NULL.

esp_err_t sdio_slave_send_queue(uint8_t *addr, size_t len, void *arg, TickType_t wait)

Put a new sending transfer into the send queue. The driver takes ownership of the buffer until the buffer is returned by sdio_slave_send_get_finished after the transaction is finished.

参数
  • addr -- Address for data to be sent. The buffer should be DMA capable and 32-bit aligned.

  • len -- Length of the data, should not be longer than 4092 bytes (may support longer in the future).

  • arg -- Argument to returned in sdio_slave_send_get_finished. The argument can be used to indicate which transaction is done, or as a parameter for a callback. Set to NULL if not needed.

  • wait -- Time to wait if the buffer is full.

返回

  • ESP_ERR_INVALID_ARG if the length is not greater than 0.

  • ESP_ERR_TIMEOUT if the queue is still full until timeout.

  • ESP_OK if success.

esp_err_t sdio_slave_send_get_finished(void **out_arg, TickType_t wait)

Return the ownership of a finished transaction.

参数
  • out_arg -- Argument of the finished transaction. Set to NULL if unused.

  • wait -- Time to wait if there's no finished sending transaction.

返回

ESP_ERR_TIMEOUT if no transaction finished, or ESP_OK if succeed.

esp_err_t sdio_slave_transmit(uint8_t *addr, size_t len)

Start a new sending transfer, and wait for it (blocked) to be finished.

参数
  • addr -- Start address of the buffer to send

  • len -- Length of buffer to send.

返回

  • ESP_ERR_INVALID_ARG if the length of descriptor is not greater than 0.

  • ESP_ERR_TIMEOUT if the queue is full or host do not start a transfer before timeout.

  • ESP_OK if success.

uint8_t sdio_slave_read_reg(int pos)

Read the spi slave register shared with host.

备注

register 28 to 31 are reserved for interrupt vector.

参数

pos -- register address, 0-27 or 32-63.

返回

value of the register.

esp_err_t sdio_slave_write_reg(int pos, uint8_t reg)

Write the spi slave register shared with host.

备注

register 29 and 31 are used for interrupt vector.

参数
  • pos -- register address, 0-11, 14-15, 18-19, 24-27 and 32-63, other address are reserved.

  • reg -- the value to write.

返回

ESP_ERR_INVALID_ARG if address wrong, otherwise ESP_OK.

sdio_slave_hostint_t sdio_slave_get_host_intena(void)

Get the interrupt enable for host.

返回

the interrupt mask.

void sdio_slave_set_host_intena(sdio_slave_hostint_t mask)

Set the interrupt enable for host.

参数

mask -- Enable mask for host interrupt.

esp_err_t sdio_slave_send_host_int(uint8_t pos)

Interrupt the host by general purpose interrupt.

参数

pos -- Interrupt num, 0-7.

返回

  • ESP_ERR_INVALID_ARG if interrupt num error

  • ESP_OK otherwise

void sdio_slave_clear_host_int(sdio_slave_hostint_t mask)

Clear general purpose interrupt to host.

参数

mask -- Interrupt bits to clear, by bit mask.

esp_err_t sdio_slave_wait_int(int pos, TickType_t wait)

Wait for general purpose interrupt from host.

备注

this clears the interrupt at the same time.

参数
  • pos -- Interrupt source number to wait for. is set.

  • wait -- Time to wait before interrupt triggered.

返回

ESP_OK if success, ESP_ERR_TIMEOUT if timeout.

Structures

struct sdio_slave_config_t

Configuration of SDIO slave.

Public Members

sdio_slave_timing_t timing

timing of sdio_slave. see sdio_slave_timing_t.

sdio_slave_sending_mode_t sending_mode

mode of sdio_slave. SDIO_SLAVE_MODE_STREAM if the data needs to be sent as much as possible; SDIO_SLAVE_MODE_PACKET if the data should be sent in packets.

int send_queue_size

max buffers that can be queued before sending.

size_t recv_buffer_size

If buffer_size is too small, it costs more CPU time to handle larger number of buffers. If buffer_size is too large, the space larger than the transaction length is left blank but still counts a buffer, and the buffers are easily run out. Should be set according to length of data really transferred. 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. All receive buffer given to the driver should be larger than this.

sdio_event_cb_t event_cb

when the host interrupts slave, this callback will be called with interrupt number (0-7).

uint32_t flags

Features to be enabled for the slave, combinations of SDIO_SLAVE_FLAG_*.

Macros

SDIO_SLAVE_RECV_MAX_BUFFER
SDIO_SLAVE_FLAG_DAT2_DISABLED

It is required by the SD specification that all 4 data lines should be used and pulled up even in 1-bit mode or SPI mode. However, as a feature, the user can specify this flag to make use of DAT2 pin in 1-bit mode. Note that the host cannot read CCCR registers to know we don't support 4-bit mode anymore, please do this at your own risk.

SDIO_SLAVE_FLAG_HOST_INTR_DISABLED

The DAT1 line is used as the interrupt line in SDIO protocol. However, as a feature, the user can specify this flag to make use of DAT1 pin of the slave in 1-bit mode. Note that the host has to do polling to the interrupt registers to know whether there are interrupts from the slave. And it cannot read CCCR registers to know we don't support 4-bit mode anymore, please do this at your own risk.

SDIO_SLAVE_FLAG_INTERNAL_PULLUP

Enable internal pullups for enabled pins. It is required by the SD specification that all the 4 data lines should be pulled up even in 1-bit mode or SPI mode. Note that the internal pull-ups are not sufficient for stable communication, please do connect external pull-ups on the bus. This is only for example and debug use.

SDIO_SLAVE_FLAG_DEFAULT_SPEED

Disable the highspeed support of the hardware.

SDIO_SLAVE_FLAG_HIGH_SPEED

Enable the highspeed support of the hardware. This is the default option. The host will see highspeed capability, but the mode actually used is determined by the host.

Type Definitions

typedef void (*sdio_event_cb_t)(uint8_t event)
typedef void *sdio_slave_buf_handle_t

Handle of a receive buffer, register a handle by calling sdio_slave_recv_register_buf. Use the handle to load the buffer to the driver, or call sdio_slave_recv_unregister_buf if it is no longer used.