Skip to content

Commit 9d21b17

Browse files
committed
Merge branch 'feat/spi_slave_hd_esp32s2' into 'master'
spi_slave_hd: new driver for spi slave in half duplex mode Closes IDF-1589 See merge request espressif/esp-idf!8386
2 parents 9a71a74 + 48aa582 commit 9d21b17

38 files changed

+2692
-131
lines changed

components/driver/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ if(IDF_TARGET STREQUAL "esp32s2")
4040
list(APPEND srcs "esp32s2/rtc_tempsensor.c"
4141
"esp32s2/touch_sensor.c"
4242
"esp32s2/adc.c"
43-
"esp32s2/adc2_init_cal.c")
43+
"esp32s2/adc2_init_cal.c"
44+
"spi_slave_hd.c"
45+
)
4446
# currently only S2 beta has its own target-specific includes
4547
list(APPEND includes "esp32s2/include")
4648
endif()

components/driver/component.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Component Makefile
33
#
44
COMPONENT_SRCDIRS := . $(IDF_TARGET)
5+
COMPONENT_OBJEXCLUDE += spi_slave_hd.o
56

67
COMPONENT_ADD_INCLUDEDIRS := include $(IDF_TARGET)/include $(IDF_TARGET)/include/driver
78

components/driver/include/driver/spi_common.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ extern "C"
6262
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
6363
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
6464
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
65-
#define SPICOMMON_BUSFLAG_SCLK (1<<2) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
66-
#define SPICOMMON_BUSFLAG_MISO (1<<3) ///< Check existing of MISO pin. Or indicates MISO line initialized.
67-
#define SPICOMMON_BUSFLAG_MOSI (1<<4) ///< Check existing of MOSI pin. Or indicates CLK line initialized.
68-
#define SPICOMMON_BUSFLAG_DUAL (1<<5) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
69-
#define SPICOMMON_BUSFLAG_WPHD (1<<6) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
65+
#define SPICOMMON_BUSFLAG_GPIO_PINS (1<<2) ///< Force the signals to be routed through GPIO matrix. Or indicates the pins are routed through the GPIO matrix.
66+
#define SPICOMMON_BUSFLAG_SCLK (1<<3) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
67+
#define SPICOMMON_BUSFLAG_MISO (1<<4) ///< Check existing of MISO pin. Or indicates MISO line initialized.
68+
#define SPICOMMON_BUSFLAG_MOSI (1<<5) ///< Check existing of MOSI pin. Or indicates MOSI line initialized.
69+
#define SPICOMMON_BUSFLAG_DUAL (1<<6) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
70+
#define SPICOMMON_BUSFLAG_WPHD (1<<7) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
7071
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
7172

7273
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include "esp_types.h"
18+
#include "soc/spi_caps.h"
19+
#include "freertos/FreeRTOS.h"
20+
21+
#include "hal/spi_types.h"
22+
#include "driver/spi_common.h"
23+
#include "sdkconfig.h"
24+
25+
#ifdef __cplusplus
26+
extern "C"
27+
{
28+
#endif
29+
30+
#if !SOC_SPI_SUPPORT_SLAVE_HD_VER2 && !CI_HEADER_CHECK
31+
#error The SPI peripheral does not support this feature
32+
#endif
33+
34+
/// Descriptor of data to send/receive
35+
typedef struct {
36+
uint8_t* data; ///< Buffer to send, must be DMA capable
37+
size_t len; ///< Len of data to send/receive. For receiving the buffer length should be multiples of 4 bytes, otherwise the extra part will be truncated.
38+
size_t trans_len; ///< Data actually received
39+
void* arg; ///< Extra argument indiciating this data
40+
} spi_slave_hd_data_t;
41+
42+
/// Information of SPI Slave HD event
43+
typedef struct {
44+
spi_event_t event; ///< Event type
45+
spi_slave_hd_data_t* trans; ///< Corresponding transaction for SPI_EV_SEND and SPI_EV_RECV events
46+
} spi_slave_hd_event_t;
47+
48+
/// Callback for SPI Slave HD
49+
typedef bool (*slave_cb_t)(void* arg, spi_slave_hd_event_t* event, BaseType_t* awoken);
50+
51+
/// Channel of SPI Slave HD to do data transaction
52+
typedef enum {
53+
SPI_SLAVE_CHAN_TX = 0, ///< The output channel (RDDMA)
54+
SPI_SLAVE_CHAN_RX = 1, ///< The input channel (WRDMA)
55+
} spi_slave_chan_t;
56+
57+
/// Callback configuration structure for SPI Slave HD
58+
typedef struct {
59+
slave_cb_t cb_recv; ///< Callback when receive data
60+
slave_cb_t cb_sent; ///< Callback when data sent
61+
slave_cb_t cb_buffer_tx; ///< Callback when master reads from shared buffer
62+
slave_cb_t cb_buffer_rx; ///< Callback when master writes to shared buffer
63+
slave_cb_t cb_cmd9; ///< Callback when CMD9 received
64+
slave_cb_t cb_cmdA; ///< Callback when CMDA received
65+
void* arg; ///< Argument indicating this SPI Slave HD peripheral instance
66+
} spi_slave_hd_callback_config_t;
67+
68+
/// Configuration structure for the SPI Slave HD driver
69+
typedef struct {
70+
int spics_io_num; ///< CS GPIO pin for this device
71+
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_HD_* flags
72+
#define SPI_SLAVE_HD_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
73+
#define SPI_SLAVE_HD_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
74+
#define SPI_SLAVE_HD_BIT_LSBFIRST (SPI_SLAVE_HD_TXBIT_LSBFIRST|SPI_SLAVE_HD_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
75+
76+
uint8_t mode; ///< SPI mode (0-3)
77+
int command_bits; ///< command field bits, multiples of 8 and at least 8.
78+
int address_bits; ///< address field bits, multiples of 8 and at least 8.
79+
int dummy_bits; ///< dummy field bits, multiples of 8 and at least 8.
80+
81+
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_hd_queue_trans but not yet finished using spi_slave_hd_get_trans_result) at the same time
82+
83+
int dma_chan; ///< DMA channel used
84+
spi_slave_hd_callback_config_t cb_config; ///< Callback configuration
85+
} spi_slave_hd_slot_config_t;
86+
87+
/**
88+
* @brief Initialize the SPI Slave HD driver.
89+
*
90+
* @param host_id The host to use
91+
* @param bus_config Bus configuration for the bus used
92+
* @param config Configuration for the SPI Slave HD driver
93+
* @return
94+
* - ESP_OK: on success
95+
* - ESP_ERR_INVALID_ARG: invalid argument given
96+
* - ESP_ERR_INVALID_STATE: function called in invalid state, may be some resources are already in use
97+
* - ESP_ERR_NO_MEM: memory allocation failed
98+
* - or other return value from `esp_intr_alloc`
99+
*/
100+
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config,
101+
const spi_slave_hd_slot_config_t *config);
102+
103+
/**
104+
* @brief Deinitialize the SPI Slave HD driver
105+
*
106+
* @param host_id The host to deinitialize the driver
107+
* @return
108+
* - ESP_OK: on success
109+
* - ESP_ERR_INVALID_ARG: if the host_id is not correct
110+
*/
111+
esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id);
112+
113+
/**
114+
* @brief Queue data transaction
115+
*
116+
* @param host_id Host to queue the transaction
117+
* @param chan Channel to queue the data, SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
118+
* @param trans Descriptor of data to queue
119+
* @param timeout Timeout before the data is queued
120+
* @return
121+
* - ESP_OK: on success
122+
* - ESP_ERR_INVALID_ARG: The input argument is invalid. Can be the following reason:
123+
* - The buffer given is not DMA capable
124+
* - The length of data is invalid (not larger than 0, or exceed the max transfer length)
125+
* - The function is invalid
126+
* - ESP_ERR_TIMEOUT: Cannot queue the data before timeout. This is quite possible if the master
127+
* doesn't read/write the slave on time.
128+
*/
129+
esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t* trans, TickType_t timeout);
130+
131+
/**
132+
* @brief Get the result of a data transaction
133+
*
134+
* @param host_id Host to queue the transaction
135+
* @param chan Channel to get the result, SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
136+
* @param[out] out_trans Output descriptor of the returned transaction
137+
* @param timeout Timeout before the result is got
138+
* @return
139+
* - ESP_OK: on success
140+
* - ESP_ERR_INVALID_ARG: Function is not valid
141+
* - ESP_ERR_TIMEOUT: There's no transaction done before timeout
142+
*/
143+
esp_err_t spi_slave_hd_get_trans_res(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t** out_trans, TickType_t timeout);
144+
145+
/**
146+
* @brief Read the shared registers
147+
*
148+
* @param host_id Host to read the shared registers
149+
* @param addr Address of register to read, 0 to ``SOC_SPI_MAXIMUM_BUFFER_SIZE-1``
150+
* @param[out] out_data Output buffer to store the read data
151+
* @param len Length to read, not larger than ``SOC_SPI_MAXIMUM_BUFFER_SIZE-addr``
152+
*/
153+
void spi_slave_hd_read_buffer(spi_host_device_t host_id, int addr, uint8_t *out_data, size_t len);
154+
155+
/**
156+
* @brief Write the shared registers
157+
*
158+
* @param host_id Host to write the shared registers
159+
* @param addr Address of register to write, 0 to ``SOC_SPI_MAXIMUM_BUFFER_SIZE-1``
160+
* @param data Buffer holding the data to write
161+
* @param len Length to write, ``SOC_SPI_MAXIMUM_BUFFER_SIZE-addr``
162+
*/
163+
void spi_slave_hd_write_buffer(spi_host_device_t host_id, int addr, uint8_t *data, size_t len);
164+
165+
166+
#ifdef __cplusplus
167+
}
168+
#endif

components/driver/spi_common.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,12 @@ esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_conf
268268
}
269269

270270
//check if the selected pins correspond to the iomux pins of the peripheral
271-
bool use_iomux = bus_uses_iomux_pins(host, bus_config);
272-
if (use_iomux) temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
271+
bool use_iomux = !(flags & SPICOMMON_BUSFLAG_GPIO_PINS) && bus_uses_iomux_pins(host, bus_config);
272+
if (use_iomux) {
273+
temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
274+
} else {
275+
temp_flag |= SPICOMMON_BUSFLAG_GPIO_PINS;
276+
}
273277

274278
uint32_t missing_flag = flags & ~temp_flag;
275279
missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag

0 commit comments

Comments
 (0)