-
Notifications
You must be signed in to change notification settings - Fork 7k
/
test_spi_utils.h
325 lines (272 loc) · 11.3 KB
/
test_spi_utils.h
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
316
317
318
319
320
321
322
323
324
325
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _TEST_COMMON_SPI_H_
#define _TEST_COMMON_SPI_H_
#include <esp_types.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/ringbuf.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "unity.h"
#include "param_test.h"
#include "soc/io_mux_reg.h"
#include "sdkconfig.h"
#include "soc/spi_periph.h"
#include "driver/spi_master.h"
// All the tests using the header should use this definition as much as possible,
// so that the working host can be changed easily in the future.
#define TEST_SPI_PERIPH_NUM (SOC_SPI_PERIPH_NUM - 1)
#if CONFIG_IDF_TARGET_ESP32
#define TEST_SPI_HOST SPI2_HOST
#define TEST_SLAVE_HOST SPI3_HOST
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define MASTER_IOMUX_PIN_WP SPI2_IOMUX_PIN_NUM_WP
#define MASTER_IOMUX_PIN_HD SPI2_IOMUX_PIN_NUM_HD
#define SLAVE_IOMUX_PIN_MISO SPI3_IOMUX_PIN_NUM_MISO
#define SLAVE_IOMUX_PIN_MOSI SPI3_IOMUX_PIN_NUM_MOSI
#define SLAVE_IOMUX_PIN_SCLK SPI3_IOMUX_PIN_NUM_CLK
#define SLAVE_IOMUX_PIN_CS SPI3_IOMUX_PIN_NUM_CS
#define SLAVE_IOMUX_PIN_WP SPI3_IOMUX_PIN_NUM_WP
#define SLAVE_IOMUX_PIN_HD SPI3_IOMUX_PIN_NUM_HD
#define UNCONNECTED_PIN 27
#define INPUT_ONLY_PIN 34
#define GPIO_DELAY (12.5*2)
#define ESP_SPI_SLAVE_TV (12.5*3.5)
#define WIRE_DELAY 12.5
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define TEST_SPI_HOST SPI2_HOST
#define TEST_SLAVE_HOST SPI3_HOST
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define MASTER_IOMUX_PIN_WP SPI2_IOMUX_PIN_NUM_WP
#define MASTER_IOMUX_PIN_HD SPI2_IOMUX_PIN_NUM_HD
#define SLAVE_IOMUX_PIN_MISO -1
#define SLAVE_IOMUX_PIN_MOSI -1
#define SLAVE_IOMUX_PIN_SCLK -1
#define SLAVE_IOMUX_PIN_CS -1
#define SLAVE_IOMUX_PIN_NUM_WP -1
#define SLAVE_IOMUX_PIN_NUM_HD -1
#define UNCONNECTED_PIN 41
#define INPUT_ONLY_PIN 46
#define GPIO_DELAY 0
#define ESP_SPI_SLAVE_TV 0
#define WIRE_DELAY 12.5
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H4
//NOTE: On these chips, there is only 1 GPSPI controller, so master-slave test on single board should be disabled
#define TEST_SPI_HOST SPI2_HOST
#define TEST_SLAVE_HOST SPI2_HOST
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_NUM_CS SPI2_IOMUX_PIN_NUM_CS
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
#define SLAVE_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define SLAVE_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define SLAVE_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
#define SLAVE_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define MASTER_IOMUX_PIN_MISO SPI2_IOMUX_PIN_NUM_MISO
#define MASTER_IOMUX_PIN_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define MASTER_IOMUX_PIN_SCLK SPI2_IOMUX_PIN_NUM_CLK
#define MASTER_IOMUX_PIN_CS SPI2_IOMUX_PIN_NUM_CS
#define GPIO_DELAY 0
#define ESP_SPI_SLAVE_TV 0
#define WIRE_DELAY 12.5
#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
#define TEST_SPI_HOST SPI2_HOST
#define TEST_SLAVE_HOST SPI2_HOST
#define PIN_NUM_MISO SPI2_IOMUX_PIN_NUM_MISO
#define PIN_NUM_MOSI SPI2_IOMUX_PIN_NUM_MOSI
#define PIN_NUM_CLK SPI2_IOMUX_PIN_NUM_CLK
#define PIN_NUM_CS 10 //the IOMUX pin of SPI2 CS0&CS1 is Pin_16&17 which is same from UART Tx&Rx Pin
#define PIN_NUM_WP SPI2_IOMUX_PIN_NUM_WP
#define PIN_NUM_HD SPI2_IOMUX_PIN_NUM_HD
#endif
#define GET_DMA_CHAN(HOST) (HOST)
#define TEST_DMA_CHAN_MASTER GET_DMA_CHAN(TEST_SPI_HOST)
#define TEST_DMA_CHAN_SLAVE GET_DMA_CHAN(TEST_SLAVE_HOST)
#define FUNC_SPI 1
#define FUNC_GPIO PIN_FUNC_GPIO
//Delay information
#define TV_INT_CONNECT_GPIO (ESP_SPI_SLAVE_TV+GPIO_DELAY)
#define TV_INT_CONNECT (ESP_SPI_SLAVE_TV)
//when connecting to another board, the delay is usually increased by 12.5ns
#define TV_WITH_ESP_SLAVE_GPIO (TV_INT_CONNECT_GPIO+WIRE_DELAY)
#define TV_WITH_ESP_SLAVE (TV_INT_CONNECT+WIRE_DELAY)
//currently ESP32 slave only supports up to 20MHz, but 40MHz on the same board
#define ESP_SPI_SLAVE_MAX_FREQ 20 * 1000 * 1000
#define ESP_SPI_SLAVE_MAX_FREQ_SYNC 40 * 1000 * 1000
#define MAX_TEST_SIZE 16 ///< in this test we run several transactions, this is the maximum trans that can be run
#define PSET_NAME_LEN 30 ///< length of each param set name
//test low frequency, high frequency until freq limit for worst case (both GPIO)
#define TEST_FREQ_DEFAULT(){ \
1 * 1000 * 1000, \
8 * 1000 * 1000, \
9 * 1000 * 1000, \
10 * 1000 * 1000, \
11 * 1000 * 1000, \
13 * 1000 * 1000, \
16 * 1000 * 1000, \
20 * 1000 * 1000, \
26 * 1000 * 1000, \
40 * 1000 * 1000, \
80 * 1000 * 1000, \
0,\
}
//default bus config for tests
#define SPI_BUS_TEST_DEFAULT_CONFIG() {\
.miso_io_num=PIN_NUM_MISO, \
.mosi_io_num=PIN_NUM_MOSI,\
.sclk_io_num=PIN_NUM_CLK,\
.quadwp_io_num=-1,\
.quadhd_io_num=-1\
}
//default device config for master devices
#define SPI_DEVICE_TEST_DEFAULT_CONFIG() {\
.clock_speed_hz=10*1000*1000,\
.mode=0,\
.spics_io_num=PIN_NUM_CS,\
.queue_size=16,\
.pre_cb=NULL, \
.cs_ena_pretrans = 0,\
.cs_ena_posttrans = 0,\
.input_delay_ns = 62.5,\
}
//default device config for slave devices
#define SPI_SLAVE_TEST_DEFAULT_CONFIG() {\
.mode=0,\
.spics_io_num=PIN_NUM_CS,\
.queue_size=3,\
.flags=0,\
}
typedef enum {
FULL_DUPLEX = 0,
HALF_DUPLEX_MISO = 1,
HALF_DUPLEX_MOSI = 2,
} spi_dup_t;
/*-------- slave task related stuff -----------*/
typedef struct {
uint32_t len;
uint8_t* tx_start;
uint8_t data[1];
} slave_rxdata_t;
typedef struct {
uint32_t len;
const uint8_t *start;
} slave_txdata_t;
typedef struct {
spi_host_device_t spi;
RingbufHandle_t data_received;
QueueHandle_t data_to_send;
} spi_slave_task_context_t;
// test data for master and slave
extern uint8_t spitest_master_send[];
extern uint8_t spitest_slave_send[];
//tags for master and slave app
extern const char MASTER_TAG[];
extern const char SLAVE_TAG[];
//parameter set definition
typedef struct {
const char pset_name[PSET_NAME_LEN];
/*The test work till the frequency below,
*set the frequency to higher and remove checks in the driver to know how fast the system can run.
*/
const int *freq_list; // list of tested frequency, terminated by 0
int freq_limit; //freq larger (not equal) than this will be ignored
spi_dup_t dup;
int mode;
bool length_aligned;
int test_size;
int master_limit; // the master disable dummy bits and discard readings over this freq
bool master_iomux;
int master_dma_chan;
bool slave_iomux;
int slave_dma_chan;
int slave_tv_ns;
bool slave_unaligned_addr;
} spitest_param_set_t;
//context definition for the parameterized test
typedef struct {
uint8_t master_rxbuf[480];
spi_transaction_t master_trans[MAX_TEST_SIZE];
TaskHandle_t handle_slave;
spi_slave_task_context_t slave_context;
slave_txdata_t slave_trans[MAX_TEST_SIZE];
} spitest_context_t;
// fill default value of spitest_param_set_t
void spitest_def_param(void* arg);
// functions for slave task
esp_err_t init_slave_context(spi_slave_task_context_t *context, spi_host_device_t host);
void deinit_slave_context(spi_slave_task_context_t *context);
void spitest_slave_task(void* arg);
//called by slave, pull-up all pins used by slave
void slave_pull_up(const spi_bus_config_t* cfg, int spics_io_num);
// to access data of pre-defined transactions.
void spitest_init_transactions(const spitest_param_set_t *cfg, spitest_context_t* context);
// print data from a transaction
void spitest_master_print_data(spi_transaction_t *t, int rxlength);
void spitest_slave_print_data(slave_rxdata_t *t, bool print_rxdata);
// Check whether master and slave data match
esp_err_t spitest_check_data(int len, spi_transaction_t *master_t, slave_rxdata_t *slave_t, bool check_master_data, bool check_slave_len, bool check_slave_data);
#define spitest_cmp_or_dump(expected, actual, len) ({\
int r = memcmp(expected, actual, len);\
if (r != 0) {\
ESP_LOG_BUFFER_HEXDUMP("expected", expected, len, ESP_LOG_INFO);\
ESP_LOG_BUFFER_HEXDUMP("actual", actual, len, ESP_LOG_WARN);\
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, len);\
}\
r;\
})
static inline int get_trans_len(spi_dup_t dup, spi_transaction_t *master_t)
{
if (dup!=HALF_DUPLEX_MISO) {
return master_t->length;
} else {
return master_t->rxlength;
}
}
//remove device from bus and free the bus
void master_free_device_bus(spi_device_handle_t spi);
//use this function to fix the output source when assign multiple funcitons to a same pin
void spitest_gpio_output_sel(uint32_t gpio_num, int func, uint32_t signal_idx);
//use this function to fix the input source when assign multiple funcitons to a same pin
void spitest_gpio_input_sel(uint32_t gpio_num, int func, uint32_t signal_idx);
//Note this cs_num is the ID of the connected devices' ID, e.g. if 2 devices are connected to the bus,
//then the cs_num of the 1st and 2nd devices are 0 and 1 respectively.
void same_pin_func_sel(spi_bus_config_t bus, spi_device_interface_config_t dev, uint8_t cs_num);
/**
* This function is used to get tx_buffer used in dual-board test
* `master_send_buf` and `slave_send_buf` will be fulfilled with same random numbers with the seed of `seed`.
*
* @param seed Random number seed
* @param master_send_buf Master TX buffer
* @param slave_send_buf Slave TX buffer
* @param send_buf_size Buffer size
*/
void get_tx_buffer(uint32_t seed, uint8_t *master_send_buf, uint8_t *slave_send_buf, int send_buf_size);
#endif //_TEST_COMMON_SPI_H_