2021-05-24 01:50:04 +02:00
/*
2022-01-05 16:17:12 +08:00
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
2021-05-24 01:50:04 +02:00
*
* SPDX-License-Identifier: Apache-2.0
*/
2017-11-29 13:33:07 +08:00
2021-05-10 23:24:20 +08:00
# pragma once
2017-11-29 13:33:07 +08:00
# include "esp_err.h"
2022-01-05 16:17:12 +08:00
# include "freertos/FreeRTOS.h" // for TickType_t
2019-10-10 12:35:13 +08:00
# include "hal/sdio_slave_types.h"
2017-11-29 13:33:07 +08:00
# ifdef __cplusplus
extern " C " {
# endif
# define SDIO_SLAVE_RECV_MAX_BUFFER (4096-4)
typedef void ( * sdio_event_cb_t ) ( uint8_t event ) ;
/// Configuration of SDIO slave
typedef struct {
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 ;
2023-11-14 17:06:40 +08:00
///< 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.
2017-11-29 13:33:07 +08:00
sdio_event_cb_t event_cb ; ///< when the host interrupts slave, this callback will be called with interrupt number (0-7).
2018-05-25 19:44:53 +08:00
uint32_t flags ; ///< Features to be enabled for the slave, combinations of ``SDIO_SLAVE_FLAG_*``.
2018-07-06 16:02:32 +08:00
# define SDIO_SLAVE_FLAG_DAT2_DISABLED BIT(0) /**< 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
2018-05-25 19:44:53 +08:00
support 4-bit mode anymore, please do this at your own risk.
*/
2018-07-06 16:02:32 +08:00
# define SDIO_SLAVE_FLAG_HOST_INTR_DISABLED BIT(1) /**< 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
2018-05-25 19:44:53 +08:00
mode. Note that the host has to do polling to the interrupt registers to know whether there are interrupts from
2018-07-06 16:02:32 +08:00
the slave. And it cannot read CCCR registers to know we don't support 4-bit mode anymore, please do this at
2018-05-25 19:44:53 +08:00
your own risk.
*/
2018-07-06 16:02:32 +08:00
# define SDIO_SLAVE_FLAG_INTERNAL_PULLUP BIT(2) /**< 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
2018-05-25 19:44:53 +08:00
bus. This is only for example and debug use.
*/
2022-09-23 15:51:43 +08:00
# define SDIO_SLAVE_FLAG_DEFAULT_SPEED BIT(3) /**< Disable the highspeed support of the hardware. */
# define SDIO_SLAVE_FLAG_HIGH_SPEED 0 /**< 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. */
2017-11-29 13:33:07 +08:00
} sdio_slave_config_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.
*/
typedef void * sdio_slave_buf_handle_t ;
/** Initialize the sdio slave driver
*
* @param config Configuration of the sdio slave driver.
*
* @return
* - 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
*/
esp_err_t sdio_slave_initialize ( sdio_slave_config_t * config ) ;
/** De-initialize the sdio slave driver to release the resources.
*/
2019-07-16 16:33:30 +07:00
void sdio_slave_deinit ( void ) ;
2017-11-29 13:33:07 +08:00
/** Start hardware for sending and receiving, as well as set the IOREADY1 to 1.
*
* @note 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``.
*
* @return
* - ESP_ERR_INVALID_STATE if already started.
* - ESP_OK otherwise.
*/
2019-07-16 16:33:30 +07:00
esp_err_t sdio_slave_start ( void ) ;
2017-11-29 13:33:07 +08:00
/** Stop hardware from sending and receiving, also set IOREADY1 to 0.
*
* @note 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.
*/
2019-07-16 16:33:30 +07:00
void sdio_slave_stop ( void ) ;
2017-11-29 13:33:07 +08:00
/** Clear the data still in the driver, as well as reset the PKT_LEN and TOKEN1 counting.
*
* @return always return ESP_OK.
*/
2019-07-16 16:33:30 +07:00
esp_err_t sdio_slave_reset ( void ) ;
2017-11-29 13:33:07 +08:00
/*---------------------------------------------------------------------------
* Receive
*--------------------------------------------------------------------------*/
/** 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.
*
* @param start The start address of the buffer.
*
* @note 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.
*
* @return The buffer handle if success, otherwise NULL.
*/
sdio_slave_buf_handle_t sdio_slave_recv_register_buf ( uint8_t * start ) ;
/** Unregister buffer from driver, and free the space used by the descriptor pointing to the buffer.
*
* @param handle Handle to the buffer to release.
*
* @return 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_unregister_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.
*
* @param handle Handle to the buffer ready to receive data.
*
* @return
* - 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_load_buf ( sdio_slave_buf_handle_t handle ) ;
2021-05-10 23:24:20 +08:00
/** 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).
*
* @param 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.
* @param wait Time to wait before data received.
*
* @note 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`.
*
* @return
* - 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_packet ( sdio_slave_buf_handle_t * handle_ret , TickType_t wait ) ;
2017-11-29 13:33:07 +08:00
/** Get received data if exist. The driver returns the ownership of the buffer to the app.
*
* @param 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.
2018-06-07 20:11:08 +08:00
* @param[out] out_addr Output of the start address, set to NULL if not needed.
* @param[out] out_len Actual length of the data in the buffer, set to NULL if not needed.
2017-11-29 13:33:07 +08:00
* @param wait Time to wait before data received.
*
* @note 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`.
*
* @return
* - ESP_ERR_INVALID_ARG if handle_ret is NULL
* - ESP_ERR_TIMEOUT if timeout before receiving new data
* - ESP_OK if success
*/
2018-06-07 20:11:08 +08:00
esp_err_t sdio_slave_recv ( sdio_slave_buf_handle_t * handle_ret , uint8_t * * out_addr , size_t * out_len , TickType_t wait ) ;
2017-11-29 13:33:07 +08:00
/** Retrieve the buffer corresponding to a handle.
*
* @param handle Handle to get the buffer.
* @param len_o Output of buffer length
*
* @return buffer address if success, otherwise NULL.
*/
2018-06-07 20:11:08 +08:00
uint8_t * sdio_slave_recv_get_buf ( sdio_slave_buf_handle_t handle , size_t * len_o ) ;
2017-11-29 13:33:07 +08:00
/*---------------------------------------------------------------------------
* Send
*--------------------------------------------------------------------------*/
/** 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.
*
* @param addr Address for data to be sent. The buffer should be DMA capable and 32-bit aligned.
* @param len Length of the data, should not be longer than 4092 bytes (may support longer in the future).
* @param 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.
* @param wait Time to wait if the buffer is full.
*
* @return
* - 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_queue ( uint8_t * addr , size_t len , void * arg , TickType_t wait ) ;
/** Return the ownership of a finished transaction.
2018-07-06 16:02:32 +08:00
* @param out_arg Argument of the finished transaction. Set to NULL if unused.
2017-11-29 13:33:07 +08:00
* @param wait Time to wait if there's no finished sending transaction.
*
* @return ESP_ERR_TIMEOUT if no transaction finished, or ESP_OK if succeed.
*/
2018-07-06 16:02:32 +08:00
esp_err_t sdio_slave_send_get_finished ( void * * out_arg , TickType_t wait ) ;
2017-11-29 13:33:07 +08:00
/** Start a new sending transfer, and wait for it (blocked) to be finished.
*
* @param addr Start address of the buffer to send
* @param len Length of buffer to send.
*
* @return
* - 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.
*/
esp_err_t sdio_slave_transmit ( uint8_t * addr , size_t len ) ;
/*---------------------------------------------------------------------------
* Host
*--------------------------------------------------------------------------*/
/** Read the spi slave register shared with host.
*
* @param pos register address, 0-27 or 32-63.
*
* @note register 28 to 31 are reserved for interrupt vector.
*
* @return value of the register.
*/
uint8_t sdio_slave_read_reg ( int pos ) ;
/** Write the spi slave register shared with host.
*
* @param pos register address, 0-11, 14-15, 18-19, 24-27 and 32-63, other address are reserved.
* @param reg the value to write.
*
* @note register 29 and 31 are used for interrupt vector.
*
* @return ESP_ERR_INVALID_ARG if address wrong, otherwise ESP_OK.
*/
esp_err_t sdio_slave_write_reg ( int pos , uint8_t reg ) ;
/** Get the interrupt enable for host.
*
* @return the interrupt mask.
*/
2019-07-16 16:33:30 +07:00
sdio_slave_hostint_t sdio_slave_get_host_intena ( void ) ;
2017-11-29 13:33:07 +08:00
/** Set the interrupt enable for host.
*
2019-10-10 12:35:13 +08:00
* @param mask Enable mask for host interrupt.
2017-11-29 13:33:07 +08:00
*/
2019-10-10 12:35:13 +08:00
void sdio_slave_set_host_intena ( sdio_slave_hostint_t mask ) ;
2017-11-29 13:33:07 +08:00
/** Interrupt the host by general purpose interrupt.
*
* @param pos Interrupt num, 0-7.
*
* @return
* - ESP_ERR_INVALID_ARG if interrupt num error
* - ESP_OK otherwise
*/
2018-06-07 20:11:08 +08:00
esp_err_t sdio_slave_send_host_int ( uint8_t pos ) ;
2017-11-29 13:33:07 +08:00
/** Clear general purpose interrupt to host.
*
* @param mask Interrupt bits to clear, by bit mask.
*/
2019-10-10 12:35:13 +08:00
void sdio_slave_clear_host_int ( sdio_slave_hostint_t mask ) ;
2017-11-29 13:33:07 +08:00
/** Wait for general purpose interrupt from host.
*
* @param pos Interrupt source number to wait for.
* is set.
* @param wait Time to wait before interrupt triggered.
*
* @note this clears the interrupt at the same time.
*
* @return ESP_OK if success, ESP_ERR_TIMEOUT if timeout.
*/
esp_err_t sdio_slave_wait_int ( int pos , TickType_t wait ) ;
# ifdef __cplusplus
}
# endif