| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /* SDIO example, slave (uses sdio slave driver)
- This example code is in the Public Domain (or CC0 licensed, at your option.)
- Unless required by applicable law or agreed to in writing, this
- software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied.
- */
- #include "driver/sdio_slave.h"
- #include "esp_log.h"
- #include "sys/queue.h"
- #include "soc/soc.h"
- #include "freertos/task.h"
- #include "freertos/ringbuf.h"
- #include "sdkconfig.h"
- /*
- sdio slave example.
- This example is supposed to work together with the sdio host example. It uses the pins as follows:
- * Host Slave
- * IO14 CLK
- * IO15 CMD
- * IO2 D0
- * IO4 D1
- * IO12 D2
- * IO13 D3
- This is the only pins that can be used in standard ESP modules. The other set of pins (6, 11, 7, 8, 9, 10)
- are occupied by the spi bus communicating with the flash.
- Protocol Above the ESP slave service:
- - Interrupts:
- 0 is used to notify the slave to read the register 0.
- - Registers:
- - 0 is the register to hold tasks. Bits:
- - 0: the slave should reset.
- - 1: the slave should send interrupts.
- - 2: the slave should write the shared registers acoording to the value in register 1.
- - 1 is the register to hold test value.
- - other registers will be written by the slave for testing.
- - FIFO:
- The receving FIFO is size of 256 bytes.
- When the host writes something to slave recv FIFO, the slave should return it as is to the sending FIFO.
- The host works as following process:
- 1. reset the slave.
- 2. tell the slave to write registers and read them back.
- 3. tell the slave to send interrupts to the host.
- 4. send data to slave FIFO and read them back.
- 5. loop step 4.
- */
- #define SDIO_SLAVE_QUEUE_SIZE 11
- #define BUFFER_SIZE 128
- #define BUFFER_NUM 16
- #define EV_STR(s) "================ "s" ================"
- typedef enum {
- JOB_IDLE = 0,
- JOB_RESET = 1,
- JOB_SEND_INT = 2,
- JOB_WRITE_REG = 4,
- } example_job_t;
- static const char TAG[] = "example_slave";
- static int s_job = JOB_IDLE;
- DMA_ATTR uint8_t data_to_send[BUFFER_SIZE] = {0x97, 0x84, 0x43, 0x67, 0xc1, 0xdd, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x56, 0x55, 0x44, 0x33 ,0x22, 0x11, 0x00 };
- DMA_ATTR uint8_t data_to_recv[BUFFER_SIZE] = {0x97, 0x84, 0x43, 0x67, 0xc1, 0xdd, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x56, 0x55, 0x44, 0x33 ,0x22, 0x11, 0x00 };
- static const char job_desc[][32] = {
- "JOB_IDLE",
- "JOB_RESET",
- "JOB_SEND_INT",
- "JOB_WRITE_REG",
- };
- //reset counters of the slave hardware, and clean the receive buffer (normally they should be sent back to the host)
- static esp_err_t slave_reset(void)
- {
- esp_err_t ret;
- sdio_slave_stop();
- ret = sdio_slave_reset();
- if (ret != ESP_OK) return ret;
- ret = sdio_slave_start();
- if (ret != ESP_OK) return ret;
- //Since the buffer will not be sent any more, we return them back to receving driver
- while(1) {
- sdio_slave_buf_handle_t handle;
- ret = sdio_slave_send_get_finished(&handle, 0);
- if (ret != ESP_OK) break;
- ret = sdio_slave_recv_load_buf(handle);
- ESP_ERROR_CHECK(ret);
- }
- return ESP_OK;
- }
- //sent interrupts to the host in turns
- static esp_err_t task_hostint(void)
- {
- for(int i = 0; i < 8; i++) {
- ESP_LOGV(TAG, "send intr: %d", i);
- sdio_slave_send_host_int(i);
- //check reset for quick response to RESET signal
- if (s_job & JOB_RESET) break;
- vTaskDelay(500/portTICK_RATE_MS);
- }
- return ESP_OK;
- }
- //read the value in a specified register set by the host, and set other register according to this.
- //the host will read these registers later
- static esp_err_t task_write_reg(void)
- {
- //the host write REG1, the slave should write its registers according to value of REG1
- uint8_t read = sdio_slave_read_reg(1);
- for (int i = 0; i < 64; i++) {
- //skip interrupt regs.
- if (i >= 28 && i <= 31) continue;
- sdio_slave_write_reg(i, read+3*i);
- }
- uint8_t reg[64] = {0};
- for (int i = 0; i < 64; i++) {
- //skip interrupt regs.
- if (i >= 28 && i <= 31) continue;
- reg[i] = sdio_slave_read_reg(i);
- }
- ESP_LOGI(TAG, "write regs:");
- ESP_LOG_BUFFER_HEXDUMP(TAG, reg, 64, ESP_LOG_INFO);
- return ESP_OK;
- }
- //we use the event callback (in ISR) in this example to get higer responding speed
- //note you can't do delay in the ISR
- //``sdio_slave_wait_int`` is another way to handle interrupts
- static void event_cb(uint8_t pos)
- {
- ESP_EARLY_LOGD(TAG, "event: %d", pos);
- switch(pos) {
- case 0:
- s_job = sdio_slave_read_reg(0);
- sdio_slave_write_reg(0, JOB_IDLE);
- break;
- }
- }
- DMA_ATTR uint8_t buffer[BUFFER_NUM][BUFFER_SIZE] = {};
- //Main application
- void app_main(void)
- {
- esp_err_t ret;
- sdio_slave_config_t config = {
- .sending_mode = SDIO_SLAVE_SEND_PACKET,
- .send_queue_size = SDIO_SLAVE_QUEUE_SIZE,
- .recv_buffer_size = BUFFER_SIZE,
- .event_cb = event_cb,
- /* Note: For small devkits there may be no pullups on the board.
- This enables the internal pullups to help evaluate the driver
- quickly. However the internal pullups are not sufficient and not
- reliable, please make sure external pullups are connected to the
- bus in your real design.
- */
- //.flags = SDIO_SLAVE_FLAG_INTERNAL_PULLUP,
- };
- #ifdef CONFIG_SDIO_DAT2_DISABLED
- /* For slave chips with 3.3V flash, DAT2 pullup conflicts with the pulldown
- required by strapping pin (MTDI). We can either burn the EFUSE for the
- strapping or just disable the DAT2 and work in 1-bit mode.
- */
- config.flags |= SDIO_SLAVE_FLAG_DAT2_DISABLED;
- #endif
- ret = sdio_slave_initialize(&config);
- ESP_ERROR_CHECK(ret);
- sdio_slave_write_reg(0, JOB_IDLE);
- sdio_slave_buf_handle_t handle;
- for(int i = 0; i < BUFFER_NUM; i++) {
- handle = sdio_slave_recv_register_buf(buffer[i]);
- assert(handle != NULL);
- ret = sdio_slave_recv_load_buf(handle);
- ESP_ERROR_CHECK(ret);
- }
- sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET |
- SDIO_SLAVE_HOSTINT_BIT0 |
- SDIO_SLAVE_HOSTINT_BIT1 |
- SDIO_SLAVE_HOSTINT_BIT2 |
- SDIO_SLAVE_HOSTINT_BIT3 |
- SDIO_SLAVE_HOSTINT_BIT4 |
- SDIO_SLAVE_HOSTINT_BIT5 |
- SDIO_SLAVE_HOSTINT_BIT6 |
- SDIO_SLAVE_HOSTINT_BIT7
- );
- sdio_slave_start();
- ESP_LOGI(TAG, EV_STR("slave ready"));
- for(;;) {
- //receive data and send back to host.
- size_t length;
- uint8_t *ptr;
- const TickType_t non_blocking = 0;
- ret = sdio_slave_recv(&handle, &ptr, &length, non_blocking);
- if (ret == ESP_OK) {
- ESP_LOGI(TAG, "handle: %p, recv len: %d, data:", handle, length);
- ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, length, ESP_LOG_INFO);
- /* If buffer is no longer used, call sdio_slave_recv_load_buf to return it here. Since we wants to show how
- * to share large buffers between drivers here (we share between sending and receiving), keep the buffer
- * until the buffer is sent by sending driver.
- */
- //send the received buffer to host, with the handle as the argument
- ret = sdio_slave_send_queue(ptr, length, handle, non_blocking);
- if (ret == ESP_ERR_TIMEOUT) {
- // send failed, direct return the buffer to rx
- ESP_LOGE(TAG, "send_queue full, discard received.");
- ret = sdio_slave_recv_load_buf(handle);
- }
- ESP_ERROR_CHECK(ret);
- }
- // if there's finished sending desc, return the buffer to receiving driver
- for(;;){
- sdio_slave_buf_handle_t handle;
- ret = sdio_slave_send_get_finished(&handle, 0);
- if (ret == ESP_ERR_TIMEOUT) break;
- ESP_ERROR_CHECK(ret);
- ret = sdio_slave_recv_load_buf(handle);
- ESP_ERROR_CHECK(ret);
- }
- if (s_job != 0) {
- for(int i = 0; i < 8; i++) {
- if (s_job & BIT(i)) {
- ESP_LOGI(TAG, EV_STR("%s"), job_desc[i+1]);
- s_job &= ~BIT(i);
- switch(BIT(i)) {
- case JOB_SEND_INT:
- ret = task_hostint();
- ESP_ERROR_CHECK(ret);
- break;
- case JOB_RESET:
- ret = slave_reset();
- ESP_ERROR_CHECK(ret);
- break;
- case JOB_WRITE_REG:
- ret = task_write_reg();
- ESP_ERROR_CHECK(ret);
- break;
- }
- }
- }
- }
- vTaskDelay(1);
- }
- }
|