1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "test/test_common_spi.h"
7 #include "driver/spi_slave.h"
8 #include "esp_log.h"
9 #include "driver/gpio.h"
10 #include "hal/gpio_hal.h"
11 
12 int test_freq_default[]=TEST_FREQ_DEFAULT();
13 
14 const char MASTER_TAG[] = "test_master";
15 const char SLAVE_TAG[] = "test_slave";
16 
17 DRAM_ATTR uint8_t spitest_master_send[] = {
18     0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
19     0x74,
20     0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
21     0x74,
22     0x93, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xaa, 0xcc, 0xff, 0xee, 0x55, 0x77, 0x88, 0x43,
23     0x74,
24     };
25 DRAM_ATTR uint8_t spitest_slave_send[] = {
26     0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
27     0xda,
28     0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
29     0xda,
30     0xaa, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x13, 0x57, 0x9b, 0xdf, 0x24, 0x68, 0xac, 0xe0,
31     0xda,
32     };
33 
spitest_def_param(void * arg)34 void spitest_def_param(void* arg)
35 {
36     spitest_param_set_t *param_set=(spitest_param_set_t*)arg;
37     param_set->test_size = 8;
38     if (param_set->freq_list==NULL) param_set->freq_list = test_freq_default;
39 }
40 
41 /**********************************************************************************
42  * functions for slave task
43  *********************************************************************************/
init_slave_context(spi_slave_task_context_t * context)44 esp_err_t init_slave_context(spi_slave_task_context_t *context)
45 {
46     context->data_to_send = xQueueCreate( 16, sizeof( slave_txdata_t ));
47     if ( context->data_to_send == NULL ) {
48         return ESP_ERR_NO_MEM;
49     }
50     context->data_received = xRingbufferCreate( 1024, RINGBUF_TYPE_NOSPLIT );
51     if ( context->data_received == NULL ) {
52         return ESP_ERR_NO_MEM;
53     }
54     context->spi=TEST_SLAVE_HOST;
55     return ESP_OK;
56 }
57 
deinit_slave_context(spi_slave_task_context_t * context)58 void deinit_slave_context(spi_slave_task_context_t *context)
59 {
60     TEST_ASSERT( context->data_to_send != NULL );
61     vQueueDelete( context->data_to_send );
62     context->data_to_send = NULL;
63     TEST_ASSERT( context->data_received != NULL );
64     vRingbufferDelete( context->data_received );
65     context->data_received = NULL;
66 }
67 
68 /* The task requires a queue and a ringbuf, which should be initialized before task starts.
69    Send ``slave_txdata_t`` to the queue to make the task send data;
70    the task returns data got to the ringbuf, which should have sufficient size.
71 */
spitest_slave_task(void * arg)72 void spitest_slave_task(void* arg)
73 {
74     spi_slave_task_context_t* context = (spi_slave_task_context_t*) arg;
75     QueueHandle_t queue = context->data_to_send;
76     RingbufHandle_t ringbuf = context->data_received;
77     uint8_t recvbuf[320+8];
78     slave_txdata_t txdata;
79 
80     ESP_LOGI( SLAVE_TAG, "slave up" );
81     //never quit, but blocked by the queue, waiting to be killed, when no more send from main task.
82     while( 1 ) {
83         BaseType_t ret = xQueueReceive( queue, &txdata, portMAX_DELAY );
84         assert(ret);
85 
86         spi_slave_transaction_t t = {};
87         t.length = txdata.len;
88         t.tx_buffer = txdata.start;
89         t.rx_buffer = recvbuf+8;
90         //loop until trans_len != 0 to skip glitches
91         do {
92             TEST_ESP_OK( spi_slave_transmit( context->spi, &t, portMAX_DELAY ) );
93         } while ( t.trans_len <= 2 );
94         memcpy(recvbuf, &t.trans_len, sizeof(uint32_t));
95         *(uint8_t**)(recvbuf+4) = (uint8_t*)txdata.start;
96         ESP_LOGD( SLAVE_TAG, "received: %d", t.trans_len );
97         xRingbufferSend( ringbuf, recvbuf, 8+(t.trans_len+7)/8, portMAX_DELAY );
98     }
99 }
100 
slave_pull_up(const spi_bus_config_t * cfg,int spics_io_num)101 void slave_pull_up(const spi_bus_config_t* cfg, int spics_io_num)
102 {
103     gpio_set_pull_mode(cfg->mosi_io_num, GPIO_PULLUP_ONLY);
104     gpio_set_pull_mode(cfg->sclk_io_num, GPIO_PULLUP_ONLY);
105     gpio_set_pull_mode(spics_io_num, GPIO_PULLUP_ONLY);
106 }
107 
108 /**********************************************************************************
109  * functions for slave task
110  *********************************************************************************/
111 
112 static int test_len[] = {1, 3, 5, 7, 9, 11, 33, 64};
113 
spitest_init_transactions(const spitest_param_set_t * cfg,spitest_context_t * context)114 void spitest_init_transactions(const spitest_param_set_t *cfg, spitest_context_t* context)
115 {
116     spi_transaction_t* trans = context->master_trans;
117     uint8_t *rx_buf_ptr = context->master_rxbuf;
118     const spi_dup_t dup = cfg->dup;
119 
120     for (int i = 0; i < cfg->test_size; i++) {
121         const void* tx_buffer = spitest_master_send + i%8;
122         int length = 8*test_len[i];
123         if (cfg->length_aligned) length = (length+31)&(~31);
124 
125         if (dup == HALF_DUPLEX_MISO) {
126             trans[i] = (spi_transaction_t) {
127                 .rx_buffer = rx_buf_ptr,
128                 .rxlength = length,
129             };
130         } else if (dup == HALF_DUPLEX_MOSI) {
131             trans[i] = (spi_transaction_t) {
132                 .tx_buffer = tx_buffer,
133                 .length = length,
134             };
135         } else {
136             trans[i] = (spi_transaction_t) {
137                 .tx_buffer = tx_buffer,
138                 .length = length,
139                 .rx_buffer = rx_buf_ptr,
140             };
141         }
142         rx_buf_ptr = (uint8_t*)( (uint32_t)(rx_buf_ptr + (length+7)/8 + 3) & (~3));
143 
144         const void* slave_tx = spitest_slave_send + (cfg->slave_unaligned_addr? i%3: (i%3)*4);
145         //prepare slave tx data
146         context->slave_trans[i] = (slave_txdata_t) {
147             .start = slave_tx,
148             .len = 512,
149         };
150         if (cfg->slave_dma_chan != 0) context->slave_trans[i].len = 1024;
151     }
152 }
153 
spitest_master_print_data(spi_transaction_t * t,int rxlength)154 void spitest_master_print_data(spi_transaction_t *t, int rxlength)
155 {
156     if (t->tx_buffer) ESP_LOG_BUFFER_HEX( "master tx", t->tx_buffer, t->length/8 );
157     if (t->rx_buffer) ESP_LOG_BUFFER_HEX( "master rx", t->rx_buffer, rxlength/8 );
158 }
159 
spitest_slave_print_data(slave_rxdata_t * t,bool print_rxdata)160 void spitest_slave_print_data(slave_rxdata_t *t, bool print_rxdata)
161 {
162     int rcv_len = (t->len+7)/8;
163     ESP_LOGI(SLAVE_TAG, "trans_len: %d", t->len);
164     ESP_LOG_BUFFER_HEX("slave tx", t->tx_start, rcv_len);
165     if (print_rxdata) ESP_LOG_BUFFER_HEX("slave rx", t->data, rcv_len);
166 }
167 
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)168 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)
169 {
170     esp_err_t ret = ESP_OK;
171     uint32_t rcv_len = slave_t->len;
172     //currently the rcv_len can be in range of [t->length-1, t->length+3]
173     if (check_slave_len &&
174         (rcv_len < len - 1 || rcv_len > len + 4)) {
175             ret = ESP_FAIL;
176     }
177 
178     if (check_master_data &&
179         memcmp(slave_t->tx_start, master_t->rx_buffer, (len + 7) / 8) != 0 ) {
180             ret = ESP_FAIL;
181     }
182 
183     if (check_slave_data &&
184         memcmp(master_t->tx_buffer, slave_t->data, (len + 7) / 8) != 0 ) {
185             ret = ESP_FAIL;
186     }
187     if (ret != ESP_OK) {
188         ESP_LOGI(SLAVE_TAG, "slave_recv_len: %d", rcv_len);
189         spitest_master_print_data(master_t, len);
190         spitest_slave_print_data(slave_t, true);
191         //already failed, try to use the TEST_ASSERT to output the reason...
192         if (check_slave_len) {
193             TEST_ASSERT(rcv_len >= len - 1 && rcv_len <= len + 4);
194         }
195         TEST_ASSERT_EQUAL_HEX8_ARRAY(slave_t->tx_start, master_t->rx_buffer, (len + 7) / 8);
196         TEST_ASSERT_EQUAL_HEX8_ARRAY(master_t->tx_buffer, slave_t->data, (len + 7) / 8);
197     }
198 
199     return ESP_OK;
200 }
201 
202 
master_free_device_bus(spi_device_handle_t spi)203 void master_free_device_bus(spi_device_handle_t spi)
204 {
205     TEST_ESP_OK( spi_bus_remove_device(spi) );
206     TEST_ESP_OK( spi_bus_free(TEST_SPI_HOST) );
207 }
208 
spitest_gpio_output_sel(uint32_t gpio_num,int func,uint32_t signal_idx)209 void spitest_gpio_output_sel(uint32_t gpio_num, int func, uint32_t signal_idx)
210 {
211     gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func);
212     GPIO.func_out_sel_cfg[gpio_num].func_sel = signal_idx;
213 }
214 
spitest_gpio_input_sel(uint32_t gpio_num,int func,uint32_t signal_idx)215 void spitest_gpio_input_sel(uint32_t gpio_num, int func, uint32_t signal_idx)
216 {
217     gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func);
218     GPIO.func_in_sel_cfg[signal_idx].func_sel = gpio_num;
219 }
220 
221 //Note this cs_num is the ID of the connected devices' ID, e.g. if 2 devices are connected to the bus,
222 //then the cs_num of the 1st and 2nd devices are 0 and 1 respectively.
same_pin_func_sel(spi_bus_config_t bus,spi_device_interface_config_t dev,uint8_t cs_num)223 void same_pin_func_sel(spi_bus_config_t bus, spi_device_interface_config_t dev, uint8_t cs_num)
224 {
225     spitest_gpio_output_sel(bus.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spid_out);
226     spitest_gpio_input_sel(bus.mosi_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spid_in);
227 
228     spitest_gpio_output_sel(bus.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiq_out);
229     spitest_gpio_input_sel(bus.miso_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spiq_in);
230 
231     spitest_gpio_output_sel(dev.spics_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spics_out[cs_num]);
232     spitest_gpio_input_sel(dev.spics_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spics_in);
233 
234     spitest_gpio_output_sel(bus.sclk_io_num, FUNC_GPIO, spi_periph_signal[TEST_SPI_HOST].spiclk_out);
235     spitest_gpio_input_sel(bus.sclk_io_num, FUNC_GPIO, spi_periph_signal[TEST_SLAVE_HOST].spiclk_in);
236 
237 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
238     GPIO.func_in_sel_cfg[FSPIQ_IN_IDX].sig_in_sel = 1;
239 #endif
240 }
241 
get_tx_buffer(uint32_t seed,uint8_t * master_send_buf,uint8_t * slave_send_buf,int send_buf_size)242 void get_tx_buffer(uint32_t seed, uint8_t *master_send_buf, uint8_t *slave_send_buf, int send_buf_size)
243 {
244     srand(seed);
245     for (int i = 0; i < send_buf_size; i++) {
246         slave_send_buf[i] = rand();
247         master_send_buf[i] = rand();
248     }
249 }
250