Select one of the symbols to view example projects that use it.
 
Outline
#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"
#define SDIO_SLAVE_QUEUE_SIZE
#define BUFFER_SIZE
#define BUFFER_NUM
#define EV_STR
#define SLAVE_ADDR
example_job_t
TAG
s_job
data_to_send
data_to_recv
job_desc
slave_reset()
task_hostint()
task_write_reg()
event_cb(uint8_t)
buffer
app_main()
Files
loading...
SourceVuESP-IDF Framework and Examplesslave samplemain/app_main.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* 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"7 includes /* 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" ================" //skip interrupt regs. #define SLAVE_ADDR(i) ((i) >= 28? (i) + 4: (i))5 defines 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_PERIOD_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 < 60; i++) { sdio_slave_write_reg(SLAVE_ADDR(i), read + 3 * i); }{...} uint8_t reg[60] = {0}; for (int i = 0; i < 60; i++) { reg[i] = sdio_slave_read_reg(SLAVE_ADDR(i)); }{...} ESP_LOGI(TAG, "write regs:"); ESP_LOG_BUFFER_HEXDUMP(TAG, reg, 60, 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); for (int i = 0; i < BUFFER_NUM; i++) { sdio_slave_buf_handle_t 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 (;;) { const TickType_t non_blocking = 0, blocking = portMAX_DELAY; sdio_slave_buf_handle_t recv_queue[BUFFER_NUM]; int packet_size = 0; sdio_slave_buf_handle_t handle; ret = sdio_slave_recv_packet(&handle, non_blocking); if (ret != ESP_ERR_TIMEOUT) { recv_queue[packet_size++] = handle; //Receive following buffers in the same packet in blocking mode. //You can also skip this step and handle the data buffer by buffer, if the data is a stream or you don't care about the packet boundary. while (ret == ESP_ERR_NOT_FINISHED) { //The return value must be ESP_OK or ESP_ERR_NOT_FINISHED. ret = sdio_slave_recv_packet(&handle, blocking); recv_queue[packet_size++] = handle; }{...} ESP_ERROR_CHECK(ret); int packet_len = 0; for (int i = 0; i < packet_size; i++) { size_t buf_len; sdio_slave_recv_get_buf(recv_queue[i], &buf_len); packet_len += buf_len; }{...} ESP_LOGI(TAG, "Packet received, len: %d", packet_len); for (int i = 0; i < packet_size; i++) { handle = recv_queue[i]; //handle data in the buffer, here we print them and send the same buffer back to the host //receive data and send back to host. size_t length; uint8_t *ptr = sdio_slave_recv_get_buf(handle, &length); ESP_LOGI(TAG, "Buffer %d, len: %d", i, length); ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, length, ESP_LOG_INFO); /* If buffer is no longer used, we can call sdio_slave_recv_load_buf to use it to receive data again. * But here we wants to show how to share large buffers between drivers here (we share the buffer * between sending and receiving), the buffer is kept until the buffer is sent by sending driver. *//* ... */ //the recv_buf_handle is used as the argument, so that we can easily load the same buffer to recv driver, // after it's sent void* send_args = handle; ret = sdio_slave_send_queue(ptr, length, send_args, 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 (;;) { void* send_args = NULL; ret = sdio_slave_send_get_finished(&send_args, 0); //extract the buffer handle from the sending args sdio_slave_buf_handle_t handle = (sdio_slave_buf_handle_t)send_args; 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); }{...} }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.