mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-03 22:08:28 +00:00 
			
		
		
		
	spi_slave_hd: add segment mode example
This commit is contained in:
		
							
								
								
									
										106
									
								
								examples/peripherals/spi_slave_hd/segment_mode/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								examples/peripherals/spi_slave_hd/segment_mode/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
# SPI Slave Halfduplex: Segment Mode Examples
 | 
			
		||||
 | 
			
		||||
(See the README.md file in the 'examples' directory for more information about IDF examples.)
 | 
			
		||||
 | 
			
		||||
These two projects illustrate the SPI Slave Halfduplex Segment Mode.
 | 
			
		||||
* ``seg_slave`` shows one of the ways to use the SPI Slave Halfduplex driver. There are 2 tasks repeating to receive/send transactions from/to SPI Master respectively.
 | 
			
		||||
* ``seg_master`` shows how to use the ESP Serial Slave Link APIs to communicate with SPI Slave Halfduplex driver. It receives/sends transactions from/to slave a few times.
 | 
			
		||||
 | 
			
		||||
## How to use example
 | 
			
		||||
 | 
			
		||||
### Hardware Required
 | 
			
		||||
 | 
			
		||||
These two projects are supposed to be flashed onto two seperate boards and jumped together via correctly connected SPI pins defined in both of the ``app_main.c`` files. For the ``seg_master`` project, it could be flashed onto all the ESP Chips. Whereas the ``seg_slave`` currently could be flashed onto ESP32-S2. Once they are connected and flashed, they will use the SPI Master and SPI Slave Halfduplex drivers to communicate with each other.
 | 
			
		||||
 | 
			
		||||
Following is the connection between 2 ESP32S2 boards:
 | 
			
		||||
 | 
			
		||||
| Signal    | Master | Slave  |
 | 
			
		||||
|-----------|--------|--------|
 | 
			
		||||
| MOSI      | GPIO11 | GPIO11 |
 | 
			
		||||
| MISO      | GPIO13 | GPIO13 |
 | 
			
		||||
| SCLK      | GPIO12 | GPIO12 |
 | 
			
		||||
| CS        | GPIO10 | GPIO10 |
 | 
			
		||||
 | 
			
		||||
(Feel free to change the GPIO settings by editing the macro definations at the top of ``app_main.c`` files.)
 | 
			
		||||
 | 
			
		||||
### Build and Flash
 | 
			
		||||
 | 
			
		||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
 | 
			
		||||
 | 
			
		||||
(To exit the serial monitor, type ``Ctrl-]``.)
 | 
			
		||||
 | 
			
		||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to build, flash and monitor projects.
 | 
			
		||||
 | 
			
		||||
## Example Output
 | 
			
		||||
 | 
			
		||||
``seg_master``
 | 
			
		||||
```
 | 
			
		||||
---------SLAVE INFO---------
 | 
			
		||||
 | 
			
		||||
Slave MAX Send Buffer Size:       5000
 | 
			
		||||
Slave MAX Receive Buffer Size:    120
 | 
			
		||||
I (328) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.0 from slave, length: 4640
 | 
			
		||||
I (338) SEG_MASTER: SENDING......
 | 
			
		||||
I (348) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.1 from slave, length: 3299
 | 
			
		||||
I (348) SEG_MASTER: SENDING......
 | 
			
		||||
I (358) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.2 from slave, length: 4836
 | 
			
		||||
I (368) SEG_MASTER: SENDING......
 | 
			
		||||
I (368) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.3 from slave, length: 3333
 | 
			
		||||
I (378) SEG_MASTER: SENDING......
 | 
			
		||||
I (378) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.4 from slave, length: 4965
 | 
			
		||||
I (388) SEG_MASTER: SENDING......
 | 
			
		||||
I (388) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.5 from slave, length: 3042
 | 
			
		||||
I (398) SEG_MASTER: SENDING......
 | 
			
		||||
I (408) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.6 from slave, length: 4892
 | 
			
		||||
I (408) SEG_MASTER: SENDING......
 | 
			
		||||
I (418) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.7 from slave, length: 3585
 | 
			
		||||
I (428) SEG_MASTER: SENDING......
 | 
			
		||||
I (428) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.8 from slave, length: 3348
 | 
			
		||||
I (438) SEG_MASTER: SENDING......
 | 
			
		||||
I (438) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.9 from slave, length: 4985
 | 
			
		||||
I (448) SEG_MASTER: SENDING......
 | 
			
		||||
I (448) SEG_MASTER: RECEIVING......
 | 
			
		||||
Transaction No.10 from slave, length: 3710
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
``seg_slave``
 | 
			
		||||
```
 | 
			
		||||
77 bytes are received:
 | 
			
		||||
this is master's transaction 0
 | 
			
		||||
109 bytes are received:
 | 
			
		||||
this is master's transaction 1
 | 
			
		||||
83 bytes are received:
 | 
			
		||||
this is master's transaction 2
 | 
			
		||||
97 bytes are received:
 | 
			
		||||
this is master's transaction 3
 | 
			
		||||
47 bytes are received:
 | 
			
		||||
this is master's transaction 4
 | 
			
		||||
89 bytes are received:
 | 
			
		||||
this is master's transaction 5
 | 
			
		||||
80 bytes are received:
 | 
			
		||||
this is master's transaction 6
 | 
			
		||||
96 bytes are received:
 | 
			
		||||
this is master's transaction 7
 | 
			
		||||
83 bytes are received:
 | 
			
		||||
this is master's transaction 8
 | 
			
		||||
110 bytes are received:
 | 
			
		||||
this is master's transaction 9
 | 
			
		||||
113 bytes are received:
 | 
			
		||||
this is master's transaction 10
 | 
			
		||||
...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Troubleshooting
 | 
			
		||||
 | 
			
		||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you.
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
# The following lines of boilerplate have to be in your project's CMakeLists
 | 
			
		||||
# in this exact order for cmake to work correctly
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 | 
			
		||||
project(seg-master)
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
#
 | 
			
		||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
 | 
			
		||||
# project subdirectory.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
PROJECT_NAME := spi-slave-hd-seg-master
 | 
			
		||||
 | 
			
		||||
include $(IDF_PATH)/make/project.mk
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
See README.md in the parent directory
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
idf_component_register(SRCS "app_main.c"
 | 
			
		||||
                    INCLUDE_DIRS ".")
 | 
			
		||||
@@ -0,0 +1,294 @@
 | 
			
		||||
/* SPI Slave Halfduplex example
 | 
			
		||||
 | 
			
		||||
   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 <string.h>
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
#include "esp_err.h"
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "freertos/task.h"
 | 
			
		||||
#include "driver/spi_master.h"
 | 
			
		||||
#include "esp_serial_slave_link/essl_spi.h"
 | 
			
		||||
 | 
			
		||||
//Pin setting
 | 
			
		||||
#if !CONFIG_IDF_TARGET_ESP32C3
 | 
			
		||||
#define GPIO_MOSI    11
 | 
			
		||||
#define GPIO_MISO    13
 | 
			
		||||
#define GPIO_SCLK    12
 | 
			
		||||
#define GPIO_CS      10
 | 
			
		||||
#else
 | 
			
		||||
#define GPIO_MOSI    7
 | 
			
		||||
#define GPIO_MISO    2
 | 
			
		||||
#define GPIO_SCLK    6
 | 
			
		||||
#define GPIO_CS      10
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MASTER_HOST SPI2_HOST
 | 
			
		||||
#define DMA_CHAN     SPI_DMA_CH_AUTO
 | 
			
		||||
 | 
			
		||||
#define TX_SIZE_MIN  40
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper Macros for Master-Slave synchronization, each setting is 4-byte-width
 | 
			
		||||
 *
 | 
			
		||||
 * The address and value should be negotiated with Master beforehand
 | 
			
		||||
 */
 | 
			
		||||
//----------------------General Settings---------------------//
 | 
			
		||||
//Indicate Slave General Settings are ready
 | 
			
		||||
#define SLAVE_READY_FLAG_REG            0
 | 
			
		||||
#define SLAVE_READY_FLAG                0xEE
 | 
			
		||||
//Value in these 4 registers (Byte 4, 5, 6, 7) indicates the MAX Slave TX buffer length
 | 
			
		||||
#define SLAVE_MAX_TX_BUF_LEN_REG        4
 | 
			
		||||
//Value in these 4 registers indicates the MAX Slave RX buffer length
 | 
			
		||||
#define SLAVE_MAX_RX_BUF_LEN_REG        8
 | 
			
		||||
 | 
			
		||||
//----------------------Updating Info------------------------//
 | 
			
		||||
//Value in these 4 registers indicates size of the TX buffer that Slave has loaded to the DMA
 | 
			
		||||
#define SLAVE_TX_READY_BUF_SIZE_REG     12
 | 
			
		||||
//Value in these 4 registers indicates number of the RX buffer that Slave has loaded to the DMA
 | 
			
		||||
#define SLAVE_RX_READY_BUF_NUM_REG      16
 | 
			
		||||
 | 
			
		||||
static const char TAG[] = "SEG_MASTER";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void get_spi_bus_default_config(spi_bus_config_t *bus_cfg)
 | 
			
		||||
{
 | 
			
		||||
    memset(bus_cfg, 0x0, sizeof(spi_bus_config_t));
 | 
			
		||||
    bus_cfg->mosi_io_num = GPIO_MOSI;
 | 
			
		||||
    bus_cfg->miso_io_num = GPIO_MISO;
 | 
			
		||||
    bus_cfg->sclk_io_num = GPIO_SCLK;
 | 
			
		||||
    bus_cfg->quadwp_io_num = -1;
 | 
			
		||||
    bus_cfg->quadhd_io_num = -1;
 | 
			
		||||
    bus_cfg->max_transfer_sz = 14000;
 | 
			
		||||
    bus_cfg->flags = 0;
 | 
			
		||||
    bus_cfg->intr_flags = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_spi_device_default_config(spi_device_interface_config_t *dev_cfg)
 | 
			
		||||
{
 | 
			
		||||
    memset(dev_cfg, 0x0, sizeof(spi_device_interface_config_t));
 | 
			
		||||
    dev_cfg->clock_speed_hz = 10*1000*1000;
 | 
			
		||||
    dev_cfg->mode = 0;
 | 
			
		||||
    dev_cfg->spics_io_num = GPIO_CS;
 | 
			
		||||
    dev_cfg->cs_ena_pretrans = 0;
 | 
			
		||||
    dev_cfg->cs_ena_posttrans = 0;
 | 
			
		||||
    dev_cfg->command_bits = 8;
 | 
			
		||||
    dev_cfg->address_bits = 8;
 | 
			
		||||
    dev_cfg->dummy_bits = 8;
 | 
			
		||||
    dev_cfg->queue_size = 16;
 | 
			
		||||
    dev_cfg->flags = SPI_DEVICE_HALFDUPLEX;
 | 
			
		||||
    dev_cfg->duty_cycle_pos = 0;
 | 
			
		||||
    dev_cfg->input_delay_ns = 0;
 | 
			
		||||
    dev_cfg->pre_cb = NULL;
 | 
			
		||||
    dev_cfg->post_cb = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_master_hd(spi_device_handle_t* out_spi)
 | 
			
		||||
{
 | 
			
		||||
    //init bus
 | 
			
		||||
    spi_bus_config_t bus_cfg = {};
 | 
			
		||||
    get_spi_bus_default_config(&bus_cfg);
 | 
			
		||||
    ESP_ERROR_CHECK(spi_bus_initialize(MASTER_HOST, &bus_cfg, DMA_CHAN));
 | 
			
		||||
 | 
			
		||||
    //add device
 | 
			
		||||
    spi_device_interface_config_t dev_cfg = {};
 | 
			
		||||
    get_spi_device_default_config(&dev_cfg);
 | 
			
		||||
    ESP_ERROR_CHECK(spi_bus_add_device(MASTER_HOST, &dev_cfg, out_spi));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//-------------------------------Function used for Master-Slave Synchronization---------------------------//
 | 
			
		||||
//Wait for Slave to init the shared registers for its configurations, see the Helper Macros above
 | 
			
		||||
static esp_err_t wait_for_slave_ready(spi_device_handle_t spi)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
    uint32_t slave_ready_flag;
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        //Master sends CMD2 to get slave configuration
 | 
			
		||||
        //The first byte is a flag assigned by slave as a start signal, here it's 0xee
 | 
			
		||||
        ret = essl_spi_rdbuf(spi, (uint8_t *)&slave_ready_flag, SLAVE_READY_FLAG_REG, 4, 0);
 | 
			
		||||
        if (ret != ESP_OK) {
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (slave_ready_flag != SLAVE_READY_FLAG) {
 | 
			
		||||
            printf("Waiting for Slave to be ready...\n");
 | 
			
		||||
            vTaskDelay(1000 / portTICK_PERIOD_MS);
 | 
			
		||||
        } else if (slave_ready_flag == SLAVE_READY_FLAG) {
 | 
			
		||||
            return ESP_OK;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Get the MAX length of Slave's TX/RX buffer
 | 
			
		||||
static esp_err_t get_slave_max_buf_size(spi_device_handle_t spi, uint32_t *out_send_size, uint32_t *out_recv_size)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t ret;
 | 
			
		||||
 | 
			
		||||
    ret = essl_spi_rdbuf(spi, (uint8_t *)out_send_size, SLAVE_MAX_TX_BUF_LEN_REG, 4, 0);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    ret = essl_spi_rdbuf(spi, (uint8_t *)out_recv_size, SLAVE_MAX_RX_BUF_LEN_REG, 4, 0);
 | 
			
		||||
    if (ret != ESP_OK) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * To get the size of the ready Slave TX buffer
 | 
			
		||||
 * This size can be read from the pre-negotiated shared register (here `SLAVE_TX_READY_BUF_SIZE_REG`)
 | 
			
		||||
 */
 | 
			
		||||
static uint32_t get_slave_tx_buf_size(spi_device_handle_t spi)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t updated_size;
 | 
			
		||||
    uint32_t temp;
 | 
			
		||||
 | 
			
		||||
    ESP_ERROR_CHECK(essl_spi_rdbuf_polling(spi, (uint8_t *)&temp, SLAVE_TX_READY_BUF_SIZE_REG, 4, 0));
 | 
			
		||||
    /**
 | 
			
		||||
     * Read until the last 2 reading result are same. Reason:
 | 
			
		||||
     * SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the
 | 
			
		||||
     * value is changed by Slave at this time, Master may get wrong data.
 | 
			
		||||
     */
 | 
			
		||||
    while (1) {
 | 
			
		||||
        ESP_ERROR_CHECK(essl_spi_rdbuf_polling(spi, (uint8_t *)&updated_size, SLAVE_TX_READY_BUF_SIZE_REG, 4, 0));
 | 
			
		||||
        if (updated_size == temp) {
 | 
			
		||||
            return updated_size;
 | 
			
		||||
        }
 | 
			
		||||
        temp = updated_size;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * To get the number of the ready Slave RX buffers
 | 
			
		||||
 * This number can be read from the pre-negotiated shared register (here `SLAVE_RX_READY_BUF_NUM_REG`)
 | 
			
		||||
 */
 | 
			
		||||
static uint32_t get_slave_rx_buf_num(spi_device_handle_t spi)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t updated_num;
 | 
			
		||||
    uint32_t temp;
 | 
			
		||||
 | 
			
		||||
    ESP_ERROR_CHECK(essl_spi_rdbuf_polling(spi, (uint8_t *)&temp, SLAVE_RX_READY_BUF_NUM_REG, 4, 0));
 | 
			
		||||
    /**
 | 
			
		||||
     * Read until the last 2 reading result are same. Reason:
 | 
			
		||||
     * SPI transaction is carried on per 1 Byte. So when Master is reading the shared register, if the
 | 
			
		||||
     * value is changed by Slave at this time, Master may get wrong data.
 | 
			
		||||
     */
 | 
			
		||||
    while (1) {
 | 
			
		||||
        ESP_ERROR_CHECK(essl_spi_rdbuf_polling(spi, (uint8_t *)&updated_num, SLAVE_RX_READY_BUF_NUM_REG, 4, 0));
 | 
			
		||||
        if (updated_num == temp) {
 | 
			
		||||
            return updated_num;
 | 
			
		||||
        }
 | 
			
		||||
        temp = updated_num;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void app_main(void)
 | 
			
		||||
{
 | 
			
		||||
    spi_device_handle_t spi;
 | 
			
		||||
    init_master_hd(&spi);
 | 
			
		||||
 | 
			
		||||
    ESP_ERROR_CHECK(wait_for_slave_ready(spi));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Here we let the Slave to claim its transaction size. You can modify it in your own way,
 | 
			
		||||
     * e.g. let the Senders to claim its MAX length, or let the Master/Slave determine the length themselves, without considering
 | 
			
		||||
     * throughputs in the opposite side.
 | 
			
		||||
     */
 | 
			
		||||
    uint32_t slave_max_tx_buf_size;
 | 
			
		||||
    uint32_t slave_max_rx_buf_size;
 | 
			
		||||
    ESP_ERROR_CHECK(get_slave_max_buf_size(spi, &slave_max_tx_buf_size, &slave_max_rx_buf_size));
 | 
			
		||||
    uint32_t rx_buf_size = slave_max_tx_buf_size;
 | 
			
		||||
    printf("\n\n---------SLAVE INFO---------\n\n");
 | 
			
		||||
    printf("Slave MAX Send Buffer Size:       %d\n", slave_max_tx_buf_size);
 | 
			
		||||
    printf("Slave MAX Receive Buffer Size:    %d\n", slave_max_rx_buf_size);
 | 
			
		||||
 | 
			
		||||
    uint8_t *recv_buf = heap_caps_calloc(1, rx_buf_size, MALLOC_CAP_DMA);
 | 
			
		||||
    if (!recv_buf) {
 | 
			
		||||
        ESP_LOGE(TAG, "No enough memory!");
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t *send_buf = heap_caps_calloc(1, slave_max_rx_buf_size, MALLOC_CAP_DMA);
 | 
			
		||||
    if (!send_buf) {
 | 
			
		||||
        ESP_LOGE(TAG, "No enough memory!");
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t size_has_read = 0;    //Counter of the size that Master has received.
 | 
			
		||||
    uint32_t size_to_read = 0;
 | 
			
		||||
 | 
			
		||||
    uint32_t num_has_sent = 0;     //Counter of the buffer number that Master has sent.
 | 
			
		||||
    uint32_t tx_trans_id = 0;
 | 
			
		||||
    srand(30);
 | 
			
		||||
    while (1) {
 | 
			
		||||
        //RECV
 | 
			
		||||
        ESP_LOGI(TAG, "RECEIVING......");
 | 
			
		||||
        /**
 | 
			
		||||
         * This (`size_has_read`) is the counter mentioned in examples/peripherals/spi_slave_hd/segment_mode/seg_slave/app_main.c.
 | 
			
		||||
         * See its Note for Function used for Master-Slave Synchronization.
 | 
			
		||||
         *
 | 
			
		||||
         * Condition when this counter overflows:
 | 
			
		||||
         * If the Slave increases its counter with the value smaller than 2^32, then the calculation is still safe. For example:
 | 
			
		||||
         * 1. Initially, Slave's counter is (2^32 - 1 - 10), Master's counter is (2^32 - 1 - 20). So the difference would be 10B initially.
 | 
			
		||||
         * 2. Slave loads 20 bytes to the DMA, and increase its counter. So the value would be ((2^32 - 1 - 10) + 20) = 9;
 | 
			
		||||
         * 3. The difference (`size_can_be_read`) would be (9 - (2^32 - 1 - 20)) = 30;
 | 
			
		||||
         *
 | 
			
		||||
         * If this is 0, it means Slave didn't load new TX buffer to the bus yet.
 | 
			
		||||
         */
 | 
			
		||||
        uint32_t size_can_be_read = get_slave_tx_buf_size(spi) - size_has_read;
 | 
			
		||||
 | 
			
		||||
        if (size_can_be_read > rx_buf_size) {
 | 
			
		||||
            ESP_LOGW(TAG, "Slave is going to send buffer(%d Bytes) larger than pre-negotiated MAX size", size_can_be_read);
 | 
			
		||||
            /**
 | 
			
		||||
             * NOTE:
 | 
			
		||||
             * In this condition, Master should still increase its counter (``size_has_read``) by the size that Slave has loaded,
 | 
			
		||||
             * because Master RX buffer is not large enough, and it should read as large as it can, then send the CMD8. The extra
 | 
			
		||||
             * bits will be missed by Master.
 | 
			
		||||
             */
 | 
			
		||||
            size_to_read = rx_buf_size;
 | 
			
		||||
        } else {
 | 
			
		||||
            size_to_read = size_can_be_read;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (size_to_read) {
 | 
			
		||||
            ESP_ERROR_CHECK(essl_spi_rddma(spi, recv_buf, size_to_read, -1, 0));
 | 
			
		||||
            size_has_read += size_can_be_read;  //See NOTE above
 | 
			
		||||
 | 
			
		||||
            //Process the data. Here we just print it out.
 | 
			
		||||
            printf("%s\n", recv_buf);
 | 
			
		||||
            memset(recv_buf, 0x0, rx_buf_size);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //SEND
 | 
			
		||||
        ESP_LOGI(TAG, "SENDING......");
 | 
			
		||||
        /**
 | 
			
		||||
         * Similar logic, see the comment for `size_can_be_read` above.
 | 
			
		||||
         * If this is 0, it means Slave didn't load RX buffer to the bus yet.
 | 
			
		||||
         */
 | 
			
		||||
        uint32_t num_to_send = get_slave_rx_buf_num(spi) - num_has_sent;
 | 
			
		||||
 | 
			
		||||
        //Prepare your TX transaction in your own way. Here is an example.
 | 
			
		||||
        //You can set any size to send (shorter, longer or equal to the Slave Max RX buf size), Slave can get the actual length by ``trans_len`` member of ``spi_slave_hd_data_t``
 | 
			
		||||
        uint32_t actual_tx_size = (rand() % (slave_max_rx_buf_size - TX_SIZE_MIN + 1)) + TX_SIZE_MIN;
 | 
			
		||||
        snprintf((char *)send_buf, slave_max_rx_buf_size, "this is master's transaction %d", tx_trans_id);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < num_to_send; i++) {
 | 
			
		||||
            ESP_ERROR_CHECK(essl_spi_wrdma(spi, send_buf, actual_tx_size, -1, 0));
 | 
			
		||||
            num_has_sent++;
 | 
			
		||||
            tx_trans_id++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(recv_buf);
 | 
			
		||||
    free(send_buf);
 | 
			
		||||
 | 
			
		||||
    spi_bus_remove_device(spi);
 | 
			
		||||
    spi_bus_free(MASTER_HOST);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
#
 | 
			
		||||
# Main component makefile.
 | 
			
		||||
#
 | 
			
		||||
# This Makefile can be left empty. By default, it will take the sources in the
 | 
			
		||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
 | 
			
		||||
# in the build directory. This behaviour is entirely configurable,
 | 
			
		||||
# please read the ESP-IDF documents if you need to do this.
 | 
			
		||||
#
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
# The following lines of boilerplate have to be in your project's CMakeLists
 | 
			
		||||
# in this exact order for cmake to work correctly
 | 
			
		||||
cmake_minimum_required(VERSION 3.5)
 | 
			
		||||
 | 
			
		||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
 | 
			
		||||
project(seg-slave)
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
| Supported Targets | ESP32-S2 |
 | 
			
		||||
| ----------------- | -------- |
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
idf_component_register(SRCS "app_main.c"
 | 
			
		||||
                    INCLUDE_DIRS ".")
 | 
			
		||||
@@ -0,0 +1,304 @@
 | 
			
		||||
/* SPI Slave Halfduplex example
 | 
			
		||||
 | 
			
		||||
   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 <string.h>
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
#include "esp_err.h"
 | 
			
		||||
#include "freertos/FreeRTOS.h"
 | 
			
		||||
#include "freertos/task.h"
 | 
			
		||||
#include "driver/spi_slave_hd.h"
 | 
			
		||||
 | 
			
		||||
#define TIME_IS_OUT(start, end, timeout)     (timeout) > ((end)-(start)) ? 0 : 1
 | 
			
		||||
 | 
			
		||||
//Pin setting
 | 
			
		||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
 | 
			
		||||
#define GPIO_MOSI 11
 | 
			
		||||
#define GPIO_MISO 13
 | 
			
		||||
#define GPIO_SCLK 12
 | 
			
		||||
#define GPIO_CS   10
 | 
			
		||||
 | 
			
		||||
#define SLAVE_HOST SPI2_HOST
 | 
			
		||||
#define DMA_CHAN   SPI_DMA_CH_AUTO
 | 
			
		||||
#define QUEUE_SIZE 4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper Macros for Master-Slave synchronization, each setting is 4-byte-width
 | 
			
		||||
 *
 | 
			
		||||
 * The address and value should be negotiated with Master beforehand
 | 
			
		||||
 */
 | 
			
		||||
//----------------------General Settings---------------------//
 | 
			
		||||
//Indicate Slave General Settings are ready
 | 
			
		||||
#define SLAVE_READY_FLAG_REG            0
 | 
			
		||||
#define SLAVE_READY_FLAG                0xEE
 | 
			
		||||
//Value in these 4 registers (Byte 4, 5, 6, 7) indicates the MAX Slave TX buffer length
 | 
			
		||||
#define SLAVE_MAX_TX_BUF_LEN_REG        4
 | 
			
		||||
//Value in these 4 registers indicates the MAX Slave RX buffer length
 | 
			
		||||
#define SLAVE_MAX_RX_BUF_LEN_REG        8
 | 
			
		||||
 | 
			
		||||
//----------------------Updating Info------------------------//
 | 
			
		||||
//Value in these 4 registers indicates size of the TX buffer that Slave has loaded to the DMA
 | 
			
		||||
#define SLAVE_TX_READY_BUF_SIZE_REG     12
 | 
			
		||||
//Value in these 4 registers indicates number of the RX buffer that Slave has loaded to the DMA
 | 
			
		||||
#define SLAVE_RX_READY_BUF_NUM_REG      16
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const char TAG[] = "SEG_SLAVE";
 | 
			
		||||
 | 
			
		||||
/* Used for Master-Slave synchronization */
 | 
			
		||||
static uint32_t s_tx_ready_buf_size;  //See ``cb_set_tx_ready_buf_size()``
 | 
			
		||||
static uint32_t s_rx_ready_buf_num;   //See ``cb_set_rx_ready_buf_num()``
 | 
			
		||||
 | 
			
		||||
static uint32_t s_tx_data_id;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//-------------------------------Function used for Master-Slave Synchronization---------------------------//
 | 
			
		||||
/**
 | 
			
		||||
 * NOTE: Only if all the counters are in same size (here uint32_t), the calculation is safe (when the shared register overflows).
 | 
			
		||||
 * NOTE: If Slave resets the counters, Master needs to reset its counter accordingly.
 | 
			
		||||
 * NOTE: You can also implement your own synchronization method, BUT DO MIND the parallelled issue.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * To write the size of the TX buffer that is loaded to the hardware (DMA)
 | 
			
		||||
 *
 | 
			
		||||
 * This callback function will be called when each TX buffer is loaded to the DMA.
 | 
			
		||||
 * - For Slave, ``s_tx_ready_buf_size`` is a counter of the loaded buffer size and will be written to the pre-negotiated shared register.
 | 
			
		||||
 * - For Master, it also needs a counter for the size of buffers that have been received.
 | 
			
		||||
 * - The difference between these 2 counters will be the number that Master can read, without concern of reading meaningless data.
 | 
			
		||||
 *
 | 
			
		||||
 * There are 3 conditions:
 | 
			
		||||
 * 1. Master reads same length as Slave loaded size.
 | 
			
		||||
 * 2. If Master reads longer than the Slave loaded size, the extra bits that Master reads from the bus would be meaningless.
 | 
			
		||||
 * 3. If Master reads shorter than the Slave loaded size, Master should still increase its counter by the Slave loaded size (here ``event->trans->len``),
 | 
			
		||||
 *    because the extra bits that Slave sends to the bus would be missed by the Master.
 | 
			
		||||
 */
 | 
			
		||||
static bool cb_set_tx_ready_buf_size(void *arg, spi_slave_hd_event_t *event, BaseType_t *awoken)
 | 
			
		||||
{
 | 
			
		||||
    s_tx_ready_buf_size += event->trans->len;
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, SLAVE_TX_READY_BUF_SIZE_REG, (uint8_t *)&s_tx_ready_buf_size, 4);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * To write the number of the RX buffers that are loaded to the hardware (DMA)
 | 
			
		||||
 *
 | 
			
		||||
 * This callback function will be called when each RX buffer is loaded to the DMA.
 | 
			
		||||
 * - For Slave, ``s_rx_ready_buf_num`` is a counter for the loaded buffer and will be written to the pre-negotiated shared register
 | 
			
		||||
 * - For Master, it also needs a counter for the number of buffers that have been sent out.
 | 
			
		||||
 * - The difference between these 2 counters will be the number that Master can send.
 | 
			
		||||
 */
 | 
			
		||||
static bool cb_set_rx_ready_buf_num(void *arg, spi_slave_hd_event_t *event, BaseType_t *awoken)
 | 
			
		||||
{
 | 
			
		||||
    s_rx_ready_buf_num ++;
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, SLAVE_RX_READY_BUF_NUM_REG, (uint8_t *)&s_rx_ready_buf_num, 4);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_spi_bus_default_config(spi_bus_config_t *bus_cfg)
 | 
			
		||||
{
 | 
			
		||||
    memset(bus_cfg, 0x0, sizeof(spi_bus_config_t));
 | 
			
		||||
    bus_cfg->mosi_io_num = GPIO_MOSI;
 | 
			
		||||
    bus_cfg->miso_io_num = GPIO_MISO;
 | 
			
		||||
    bus_cfg->sclk_io_num = GPIO_SCLK;
 | 
			
		||||
    bus_cfg->quadwp_io_num = -1;
 | 
			
		||||
    bus_cfg->quadhd_io_num = -1;
 | 
			
		||||
    bus_cfg->max_transfer_sz = 14000;
 | 
			
		||||
    bus_cfg->flags = 0;
 | 
			
		||||
    bus_cfg->intr_flags = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_spi_slot_default_config(spi_slave_hd_slot_config_t *slave_hd_cfg)
 | 
			
		||||
{
 | 
			
		||||
    memset(slave_hd_cfg, 0x0, sizeof(spi_slave_hd_slot_config_t));
 | 
			
		||||
    slave_hd_cfg->spics_io_num = GPIO_CS;
 | 
			
		||||
    slave_hd_cfg->flags = 0;
 | 
			
		||||
    slave_hd_cfg->mode = 0;
 | 
			
		||||
    slave_hd_cfg->command_bits = 8;
 | 
			
		||||
    slave_hd_cfg->address_bits = 8;
 | 
			
		||||
    slave_hd_cfg->dummy_bits = 8;
 | 
			
		||||
    slave_hd_cfg->queue_size = QUEUE_SIZE;
 | 
			
		||||
    slave_hd_cfg->dma_chan = DMA_CHAN;
 | 
			
		||||
    slave_hd_cfg->cb_config = (spi_slave_hd_callback_config_t) {
 | 
			
		||||
        .cb_send_dma_ready = cb_set_tx_ready_buf_size,
 | 
			
		||||
        .cb_recv_dma_ready = cb_set_rx_ready_buf_num
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_slave_hd(void)
 | 
			
		||||
{
 | 
			
		||||
    spi_bus_config_t bus_cfg = {};
 | 
			
		||||
    get_spi_bus_default_config(&bus_cfg);
 | 
			
		||||
 | 
			
		||||
    spi_slave_hd_slot_config_t slave_hd_cfg = {};
 | 
			
		||||
    get_spi_slot_default_config(&slave_hd_cfg);
 | 
			
		||||
 | 
			
		||||
    ESP_ERROR_CHECK(spi_slave_hd_init(SLAVE_HOST, &bus_cfg, &slave_hd_cfg));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Example code for data to send. Use your own code for TX data here.
 | 
			
		||||
static bool get_tx_data(uint8_t *data, uint32_t max_len, uint32_t *out_len)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t min_len = 0;
 | 
			
		||||
    *out_len = (rand() % (max_len - min_len + 1)) + min_len;
 | 
			
		||||
    if (*out_len < (max_len - min_len) / 2) {
 | 
			
		||||
        *out_len = 0;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    snprintf((char *)data, *out_len, "Transaction No.%d from slave, length: %d", s_tx_data_id, *out_len);
 | 
			
		||||
    s_tx_data_id++;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sender(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t err = ESP_OK;
 | 
			
		||||
    uint32_t send_buf_size = *(uint32_t *)arg;      //Tx buffer max size
 | 
			
		||||
    uint8_t *send_buf[QUEUE_SIZE];                  //TX buffer
 | 
			
		||||
    spi_slave_hd_data_t slave_trans[QUEUE_SIZE];    //Transaction descriptor
 | 
			
		||||
    spi_slave_hd_data_t *ret_trans;                 //Pointer to the descriptor of return result
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < QUEUE_SIZE; i++) {
 | 
			
		||||
        // slave_trans
 | 
			
		||||
        send_buf[i] = heap_caps_calloc(1, send_buf_size, MALLOC_CAP_DMA);
 | 
			
		||||
        if (!send_buf[i]) {
 | 
			
		||||
            ESP_LOGE(TAG, "No enough memory!");
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * These 2 counters are used to maintain the driver internal queue.
 | 
			
		||||
     * internal queue item number = queue_sent_cnt - queue_recv_cnt
 | 
			
		||||
     */
 | 
			
		||||
    uint32_t queue_sent_cnt = 0;
 | 
			
		||||
    uint32_t queue_recv_cnt = 0;
 | 
			
		||||
 | 
			
		||||
    uint32_t descriptor_id = 0;
 | 
			
		||||
    uint32_t ready_data_size = 0;
 | 
			
		||||
    bool data_ready = false;
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        /**
 | 
			
		||||
         * Start TX transaction
 | 
			
		||||
         * If the internal queue number is equal to the QUEUE_SIZE you set when initialisation,
 | 
			
		||||
         * - you should not call ``spi_slave_hd_queue_trans``.
 | 
			
		||||
         * - you should call ``spi_slave_hd_get_trans_res`` instead.
 | 
			
		||||
         */
 | 
			
		||||
        if (queue_sent_cnt - queue_recv_cnt < QUEUE_SIZE) {
 | 
			
		||||
            /**
 | 
			
		||||
             * Here we simply get some random data.
 | 
			
		||||
             * In your own code, you could prepare some buffers, and create a FreeRTOS task to generate/get data, and give a
 | 
			
		||||
             * Semaphore to unblock this `sender()` Task.
 | 
			
		||||
             */
 | 
			
		||||
            data_ready = get_tx_data(send_buf[descriptor_id], send_buf_size, &ready_data_size);
 | 
			
		||||
            if (data_ready) {
 | 
			
		||||
                slave_trans[descriptor_id].data = send_buf[descriptor_id];
 | 
			
		||||
                slave_trans[descriptor_id].len = ready_data_size;
 | 
			
		||||
                //Due to the `queue_sent_cnt` and `queue_recv_cnt` logic above, we are sure there is space to send data, this will return ESP_OK immediately
 | 
			
		||||
                ESP_ERROR_CHECK(spi_slave_hd_queue_trans(SLAVE_HOST, SPI_SLAVE_CHAN_TX, &slave_trans[descriptor_id], portMAX_DELAY));
 | 
			
		||||
                descriptor_id = (descriptor_id + 1) % QUEUE_SIZE;   //descriptor_id will be: 0, 1, 2, ..., QUEUE_SIZE, 0, 1, ....
 | 
			
		||||
                queue_sent_cnt++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //Normally the task would be blocked when there is no data to send, here we use a delay to yield to other tasks
 | 
			
		||||
        vTaskDelay(1);
 | 
			
		||||
 | 
			
		||||
        //Recycle the transaction
 | 
			
		||||
        while (1) {
 | 
			
		||||
            /**
 | 
			
		||||
             * Get the TX transaction result
 | 
			
		||||
             *
 | 
			
		||||
             * The ``ret_trans`` will exactly point to the transaction descriptor passed to the driver before (here ``slave_trans``).
 | 
			
		||||
             * For TX, the ``ret_trans->trans_len`` is meaningless. But you do need this API to maintain the internal queue.
 | 
			
		||||
             */
 | 
			
		||||
            err = spi_slave_hd_get_trans_res(SLAVE_HOST, SPI_SLAVE_CHAN_TX, &ret_trans, 0);
 | 
			
		||||
            if (err != ESP_OK) {
 | 
			
		||||
                assert(err == ESP_ERR_TIMEOUT);
 | 
			
		||||
                //Recycle all the used descriptors until there is no in-the-flight descriptor
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            queue_recv_cnt++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void receiver(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    spi_slave_hd_data_t *ret_trans;
 | 
			
		||||
    uint32_t recv_buf_size = *(uint32_t *)arg;
 | 
			
		||||
    uint8_t *recv_buf[QUEUE_SIZE];
 | 
			
		||||
    spi_slave_hd_data_t slave_trans[QUEUE_SIZE];
 | 
			
		||||
    for (int i = 0; i < QUEUE_SIZE; i++) {
 | 
			
		||||
        recv_buf[i] = heap_caps_calloc(1, recv_buf_size, MALLOC_CAP_DMA);
 | 
			
		||||
        if (!recv_buf[i]) {
 | 
			
		||||
            ESP_LOGE(TAG, "No enough memory!");
 | 
			
		||||
            abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * - For SPI Slave, you can use this way (making use of the internal queue) to pre-load transactions to driver. Thus if
 | 
			
		||||
     *   Master's speed is slower than Slave, Slave won't need to wait until Master finishes.
 | 
			
		||||
     */
 | 
			
		||||
    uint32_t descriptor_id = 0;
 | 
			
		||||
    for (int i = 0; i < QUEUE_SIZE; i++) {
 | 
			
		||||
        slave_trans[descriptor_id].data = recv_buf[descriptor_id];
 | 
			
		||||
        slave_trans[descriptor_id].len = recv_buf_size;
 | 
			
		||||
        ESP_ERROR_CHECK(spi_slave_hd_queue_trans(SLAVE_HOST, SPI_SLAVE_CHAN_RX, &slave_trans[descriptor_id], portMAX_DELAY));
 | 
			
		||||
        descriptor_id = (descriptor_id + 1) % QUEUE_SIZE;   //descriptor_id will be: 0, 1, 2, ..., QUEUE_SIZE, 0, 1, ....
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (1) {
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the RX transaction result
 | 
			
		||||
         *
 | 
			
		||||
         * The actual used (by master) buffer size could be derived by ``ret_trans->trans_len``:
 | 
			
		||||
         * For example, when Master sends 4bytes, whereas slave prepares 512 bytes buffer. When master finish sending its
 | 
			
		||||
         * 4 bytes, it will send CMD7, which will force stopping the transaction. Slave will get the actual received length
 | 
			
		||||
         * from `ret_trans->trans_len`` member (here 4 bytes). The ``ret_trans`` will exactly point to the transaction descriptor
 | 
			
		||||
         * passed to the driver before (here ``slave_trans``). If the master sends longer than slave recv buffer,
 | 
			
		||||
         * slave will lose the extra bits.
 | 
			
		||||
         */
 | 
			
		||||
        ESP_ERROR_CHECK(spi_slave_hd_get_trans_res(SLAVE_HOST, SPI_SLAVE_CHAN_RX, &ret_trans, portMAX_DELAY));
 | 
			
		||||
        //Process the received data in your own code. Here we just print it out.
 | 
			
		||||
        printf("%d bytes are received: \n%s\n", ret_trans->trans_len, ret_trans->data);
 | 
			
		||||
        memset(ret_trans->data, 0x0, recv_buf_size);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Prepared data for new transaction
 | 
			
		||||
         */
 | 
			
		||||
        slave_trans[descriptor_id].data = recv_buf[descriptor_id];
 | 
			
		||||
        slave_trans[descriptor_id].len = recv_buf_size;
 | 
			
		||||
        //Start new transaction
 | 
			
		||||
        ESP_ERROR_CHECK(spi_slave_hd_queue_trans(SLAVE_HOST, SPI_SLAVE_CHAN_RX, &slave_trans[descriptor_id], portMAX_DELAY));
 | 
			
		||||
        descriptor_id = (descriptor_id + 1) % QUEUE_SIZE;   //descriptor_id will be: 0, 1, 2, ..., QUEUE_SIZE, 0, 1, ....
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void app_main(void)
 | 
			
		||||
{
 | 
			
		||||
    init_slave_hd();
 | 
			
		||||
 | 
			
		||||
    //Reset the shared register to 0
 | 
			
		||||
    uint8_t init_value[SOC_SPI_MAXIMUM_BUFFER_SIZE] = {0x0};
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, 0, init_value, SOC_SPI_MAXIMUM_BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
    uint32_t send_buf_size = 5000;
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, SLAVE_MAX_TX_BUF_LEN_REG, (uint8_t *)&send_buf_size, 4);
 | 
			
		||||
 | 
			
		||||
    uint32_t recv_buf_size = 120;
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, SLAVE_MAX_RX_BUF_LEN_REG, (uint8_t *)&recv_buf_size, 4);
 | 
			
		||||
 | 
			
		||||
    uint32_t slave_ready_flag = SLAVE_READY_FLAG;
 | 
			
		||||
    spi_slave_hd_write_buffer(SLAVE_HOST, SLAVE_READY_FLAG_REG, (uint8_t *)&slave_ready_flag, 4);
 | 
			
		||||
 | 
			
		||||
    xTaskCreate(sender, "sendTask", 4096, &send_buf_size, 1, NULL);
 | 
			
		||||
    xTaskCreate(receiver, "recvTask", 4096, &recv_buf_size, 1, NULL);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user