mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
feat(driver_spi): support using SPI_DEVICE_STD_TIMING to adjust master rx in standard timing
This commit is contained in:
parent
cb1cf073ae
commit
caf0d04a31
@ -411,8 +411,12 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
spi_hal_timing_conf_t temp_timing_conf;
|
||||
int freq;
|
||||
esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &freq, &temp_timing_conf);
|
||||
temp_timing_conf.clock_source = clk_src;
|
||||
SPI_CHECK(ret == ESP_OK, "assigned clock speed not supported", ret);
|
||||
temp_timing_conf.clock_source = clk_src;
|
||||
temp_timing_conf.rx_sample_point = dev_config->sample_point;
|
||||
if (temp_timing_conf.rx_sample_point == SPI_SAMPLING_POINT_PHASE_1) {
|
||||
SPI_CHECK(spi_ll_master_is_rx_std_sample_supported(), "SPI_SAMPLING_POINT_PHASE_1 is not supported on this chip", ESP_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
//Allocate memory for device
|
||||
dev = malloc(sizeof(spi_device_t));
|
||||
|
@ -77,6 +77,7 @@ typedef struct {
|
||||
delay before the MISO is ready on the line. Leave at 0 unless you know you need a delay. For better timing
|
||||
performance at high frequency (over 8MHz), it's suggest to have the right value.
|
||||
*/
|
||||
spi_sampling_point_t sample_point; ///< Sample point tuning of spi master receiving bit.
|
||||
int spics_io_num; ///< CS GPIO pin for this device, or -1 if not used
|
||||
uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags
|
||||
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same time
|
||||
|
@ -525,6 +525,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -562,7 +581,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(SPI1.clock) reg;
|
||||
typeof(SPI1.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -638,6 +638,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -675,7 +694,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -638,6 +638,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -675,7 +694,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -642,6 +642,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -679,7 +698,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -20,11 +20,13 @@
|
||||
#include "esp_types.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "soc/spi_struct.h"
|
||||
#include "soc/chip_revision.h"
|
||||
#include "soc/pcr_struct.h"
|
||||
#include "soc/lldesc.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
#include "hal/spi_types.h"
|
||||
#include "soc/pcr_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -644,6 +646,26 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
* This config take effect only when SPI_CLK (pre-div before periph) div >=2
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
hw->clock.clk_edge_sel = (sample_point == SPI_SAMPLING_POINT_PHASE_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -681,7 +703,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -600,6 +600,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -637,7 +656,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -652,6 +652,25 @@ static inline void spi_ll_master_keep_cs(spi_dev_t *hw, int keep_active)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the standard clock mode for master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable_std True for std timing, False for half cycle delay sampling.
|
||||
*/
|
||||
static inline void spi_ll_master_set_rx_timing_mode(spi_dev_t *hw, spi_sampling_point_t sample_point)
|
||||
{
|
||||
//This is not supported
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if standard clock mode is supported.
|
||||
*/
|
||||
static inline bool spi_ll_master_is_rx_std_sample_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
@ -689,7 +708,7 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(GPSPI2.clock) reg;
|
||||
typeof(GPSPI2.clock) reg = {.val = 0};
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
|
@ -58,6 +58,7 @@ typedef struct {
|
||||
spi_clock_source_t clock_source; ///< Clock source of each device used by LL layer
|
||||
int timing_dummy; ///< Extra dummy needed to compensate the timing
|
||||
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
|
||||
spi_sampling_point_t rx_sample_point;///< Sample data follow standard SPI timing in master mode
|
||||
} spi_hal_timing_conf_t;
|
||||
|
||||
/**
|
||||
|
@ -73,8 +73,15 @@ typedef enum {
|
||||
SPI_CMD_HD_INT2 = BIT(9),
|
||||
} spi_command_t;
|
||||
|
||||
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
|
||||
/**
|
||||
* @brief SPI master RX sample point mode configuration
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_SAMPLING_POINT_PHASE_0, ///< Data sampling point at 50% cycle delayed then standard timing, (default).
|
||||
SPI_SAMPLING_POINT_PHASE_1, ///< Data sampling point follows standard SPI timing in master mode
|
||||
} spi_sampling_point_t;
|
||||
|
||||
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
|
||||
//alias for different chips, deprecated for the chips after esp32s2
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define SPI_HOST SPI1_HOST
|
||||
@ -86,5 +93,4 @@ typedef enum {
|
||||
#define FSPI_HOST SPI2_HOST
|
||||
#define HSPI_HOST SPI3_HOST
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
|
@ -37,6 +37,7 @@ void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *de
|
||||
#endif
|
||||
spi_ll_master_set_pos_cs(hw, dev->cs_pin_id, dev->positive_cs);
|
||||
spi_ll_master_set_clock_by_reg(hw, &dev->timing_conf.clock_reg);
|
||||
spi_ll_master_set_rx_timing_mode(hw, dev->timing_conf.rx_sample_point);
|
||||
spi_ll_set_clk_source(hw, dev->timing_conf.clock_source);
|
||||
//Configure bit order
|
||||
spi_ll_set_rx_lsbfirst(hw, dev->rx_lsbfirst);
|
||||
|
@ -622,7 +622,15 @@ typedef union {
|
||||
* In the master mode it is pre-divider of spi_clk. Can be configured in CONF state.
|
||||
*/
|
||||
uint32_t clkdiv_pre:4;
|
||||
uint32_t reserved_22:9;
|
||||
uint32_t reserved_22:8;
|
||||
/** clk_edge_sel : R/W; bitpos: [30]; default: 0;
|
||||
* Configures use standard clock sampling edge or delay the sampling edge by half a
|
||||
* cycle in master transfer.
|
||||
* 0: clock sampling edge is delayed by half a cycle.
|
||||
* 1: clock sampling edge is standard.
|
||||
* Can be configured in CONF state. Only support on chip version >= 1.2
|
||||
*/
|
||||
uint32_t clk_edge_sel:1;
|
||||
/** clk_equ_sysclk : R/W; bitpos: [31]; default: 1;
|
||||
* In the master mode 1: spi_clk is eqaul to system 0: spi_clk is divided from system
|
||||
* clock. Can be configured in CONF state.
|
||||
|
21
docs/_static/diagrams/spi/spi_mode0_delay.json
vendored
Normal file
21
docs/_static/diagrams/spi/spi_mode0_delay.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"signal": [
|
||||
{
|
||||
"name": "CS",
|
||||
"wave": "10.......1"
|
||||
},
|
||||
{
|
||||
"name": "CLK",
|
||||
"wave": "lnN......l",
|
||||
},
|
||||
{
|
||||
"name": "MISO",
|
||||
"wave": "x22222222x",
|
||||
"phase": 0,
|
||||
"data": "7 6 5 4 3 2 1 0"
|
||||
}
|
||||
],
|
||||
"foot": {
|
||||
"text": "SPI delayed mode 0"
|
||||
}
|
||||
}
|
22
docs/_static/diagrams/spi/spi_mode0_std.json
vendored
Normal file
22
docs/_static/diagrams/spi/spi_mode0_std.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"signal": [
|
||||
{
|
||||
"name": "CS",
|
||||
"wave": "10.......1"
|
||||
},
|
||||
{
|
||||
"name": "CLK",
|
||||
"wave": "l.P.......l",
|
||||
"phase": 0.5
|
||||
},
|
||||
{
|
||||
"name": "MISO",
|
||||
"wave": "x22222222x",
|
||||
"phase": 0,
|
||||
"data": "7 6 5 4 3 2 1 0"
|
||||
}
|
||||
],
|
||||
"foot": {
|
||||
"text": "SPI normal mode 0"
|
||||
}
|
||||
}
|
@ -568,6 +568,26 @@ When a transaction length is short, the cost of transaction interval is high. If
|
||||
|
||||
Please note that the ISR is disabled during flash operation by default. To keep sending transactions during flash operations, enable :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` and set :c:macro:`ESP_INTR_FLAG_IRAM` in the member :cpp:member:`spi_bus_config_t::intr_flags`. In this case, all the transactions queued before starting flash operations will be handled by the ISR in parallel. Also note that the callback of each Device and their callee functions should be in IRAM, or your callback will crash due to cache miss. For more details, see :ref:`iram-safe-interrupt-handlers`.
|
||||
|
||||
.. only:: esp32h2
|
||||
|
||||
Timing Tuning
|
||||
-------------
|
||||
|
||||
.. only:: esp32h2
|
||||
|
||||
This feature is supported only on chip revision v1.2 or later.
|
||||
|
||||
To accommodate the timing requirements of different slave devices and improve signal stability, GP-SPI controllers support two sampling modes when receiving data: Sample Phase 0 and Sample Phase 1. These can be configured via :cpp:member:`spi_device_interface_config_t::sample_point`.
|
||||
|
||||
Sample Phase 0 (SPI mode 0):
|
||||
|
||||
.. wavedrom:: /../_static/diagrams/spi/spi_mode0_delay.json
|
||||
|
||||
Sample Phase 1 (SPI mode 0):
|
||||
|
||||
.. wavedrom:: /../_static/diagrams/spi/spi_mode0_std.json
|
||||
|
||||
By default, the driver uses sample phase 0, when the slave device adheres to standard SPI timing specifications, sample phase 0 provides more stable data reception at high clock frequencies.
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
|
@ -32,3 +32,11 @@ typedef enum {
|
||||
SPI_CLK_SRC_XTAL, /*!< Select XTAL as SPI source clock */
|
||||
SPI_CLK_SRC_RC_FAST, /*!< Select RC_FAST as SPI source clock */
|
||||
} spi_clock_source_t;
|
||||
|
||||
/**
|
||||
* @brief SPI master RX sample point mode configuration
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_SAMPLING_POINT_PHASE_0, ///< Data sampling point at 50% cycle delayed then standard timing, (default).
|
||||
SPI_SAMPLING_POINT_PHASE_1, ///< Data sampling point follows standard SPI timing in master mode
|
||||
} spi_sampling_point_t;
|
||||
|
Loading…
x
Reference in New Issue
Block a user