mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 09:39:10 -04:00
Merge branch 'fix/p4_spi_master_clock_sourse_sel' into 'master'
fix(spi_master): Fix p4 spi clock source support other than XTAL See merge request espressif/esp-idf!28392
This commit is contained in:
commit
73ff086e21
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -126,6 +126,7 @@ We have two bits to control the interrupt:
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/spi_hal.h"
|
||||
#include "hal/spi_ll.h"
|
||||
#include "hal/hal_utils.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "esp_cache.h"
|
||||
@ -163,7 +164,6 @@ typedef struct {
|
||||
|
||||
struct spi_device_t {
|
||||
int id;
|
||||
int real_clk_freq_hz;
|
||||
QueueHandle_t trans_queue;
|
||||
QueueHandle_t ret_queue;
|
||||
spi_device_interface_config_t cfg;
|
||||
@ -368,11 +368,30 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
#endif
|
||||
spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
|
||||
uint32_t clock_source_hz = 0;
|
||||
uint32_t clock_source_div = 1;
|
||||
if (dev_config->clock_source) {
|
||||
clk_src = dev_config->clock_source;
|
||||
}
|
||||
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz);
|
||||
#if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV
|
||||
SPI_CHECK((dev_config->clock_speed_hz > 0) && (dev_config->clock_speed_hz <= MIN(clock_source_hz / 2, (80 * 1000000))), "invalid sclk speed", ESP_ERR_INVALID_ARG);
|
||||
|
||||
if (clock_source_hz / 2 > (80 * 1000000)) { //clock_source_hz beyond peripheral HW limitation, calc pre-divider
|
||||
hal_utils_clk_info_t clk_cfg = {
|
||||
.src_freq_hz = clock_source_hz,
|
||||
.exp_freq_hz = dev_config->clock_speed_hz * 2, //we have (hs_clk = 2*mst_clk), calc hs_clk first
|
||||
.round_opt = HAL_DIV_ROUND,
|
||||
};
|
||||
hal_utils_calc_clk_div_integer(&clk_cfg, &clock_source_div);
|
||||
}
|
||||
clock_source_div *= 2; //convert to mst_clk function divider
|
||||
if (clock_source_div > SPI_LL_CLK_SRC_PRE_DIV_MAX) {
|
||||
clock_source_div = SPI_LL_CLK_SRC_PRE_DIV_MAX;
|
||||
}
|
||||
clock_source_hz /= clock_source_div; //actual freq enter to SPI peripheral
|
||||
#else
|
||||
SPI_CHECK((dev_config->clock_speed_hz > 0) && (dev_config->clock_speed_hz <= clock_source_hz), "invalid sclk speed", ESP_ERR_INVALID_ARG);
|
||||
#endif
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
//The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
|
||||
//duplex mode does absolutely nothing on the ESP32.
|
||||
@ -416,10 +435,10 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
|
||||
//output values of timing configuration
|
||||
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;
|
||||
esp_err_t ret = spi_hal_cal_clock_conf(&timing_param, &temp_timing_conf);
|
||||
SPI_CHECK(ret == ESP_OK, "assigned clock speed not supported", ret);
|
||||
temp_timing_conf.clock_source = clk_src;
|
||||
temp_timing_conf.source_pre_div = clock_source_div;
|
||||
|
||||
//Allocate memory for device
|
||||
dev = malloc(sizeof(spi_device_t));
|
||||
@ -447,7 +466,6 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
//We want to save a copy of the dev config in the dev struct.
|
||||
memcpy(&dev->cfg, dev_config, sizeof(spi_device_interface_config_t));
|
||||
dev->cfg.duty_cycle_pos = duty_cycle;
|
||||
dev->real_clk_freq_hz = freq;
|
||||
// TODO: if we have to change the apb clock among transactions, re-calculate this each time the apb clock lock is locked.
|
||||
|
||||
//Set CS pin, CS options
|
||||
@ -483,7 +501,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
hal_dev->positive_cs = dev_config->flags & SPI_DEVICE_POSITIVE_CS ? 1 : 0;
|
||||
|
||||
*handle = dev;
|
||||
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %dkHz", host_id + 1, freecs, freq / 1000);
|
||||
ESP_LOGD(SPI_TAG, "SPI%d: New device added to CS%d, effective clock: %d Hz", host_id + 1, freecs, temp_timing_conf.real_freq);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
@ -545,7 +563,7 @@ esp_err_t spi_device_get_actual_freq(spi_device_handle_t handle, int* freq_khz)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*freq_khz = handle->real_clk_freq_hz / 1000;
|
||||
*freq_khz = handle->hal_dev.timing_conf.real_freq / 1000;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -567,6 +585,11 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev)
|
||||
/* Configuration has not been applied yet. */
|
||||
spi_hal_setup_device(hal, hal_dev);
|
||||
SPI_MASTER_PERI_CLOCK_ATOMIC() {
|
||||
#if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV
|
||||
//we set mst_div as const 2, then (hs_clk = 2*mst_clk) to ensure timing turning work as past
|
||||
//and sure (hs_div * mst_div = source_pre_div)
|
||||
spi_ll_clk_source_pre_div(hal->hw, hal_dev->timing_conf.source_pre_div / 2, 2);
|
||||
#endif
|
||||
spi_ll_set_clk_source(hal->hw, hal_dev->timing_conf.clock_source);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -40,6 +40,8 @@ extern "C" {
|
||||
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral
|
||||
#define SPI_LL_CLK_SRC_PRE_DIV_MAX 512//div1(8bit) * div2(8bit but set const 2)
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@ -175,6 +177,12 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s
|
||||
{
|
||||
uint32_t clk_id = 0;
|
||||
switch (clk_source) {
|
||||
case SPI_CLK_SRC_SPLL:
|
||||
clk_id = 4;
|
||||
break;
|
||||
case SPI_CLK_SRC_RC_FAST:
|
||||
clk_id = 1;
|
||||
break;
|
||||
case SPI_CLK_SRC_XTAL:
|
||||
clk_id = 0;
|
||||
break;
|
||||
@ -193,6 +201,32 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define spi_ll_set_clk_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_set_clk_source(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Config clock source integrate pre_div before it enter GPSPI peripheral
|
||||
*
|
||||
* @note 1. For timing turning(e.g. input_delay) feature available, should be (mst_div >= 2)
|
||||
* 2. From peripheral limitation: (sour_freq/hs_div <= 160M) and (sour_freq/hs_div/mst_div <= 80M)
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param hs_div Timing turning clock divider: (hs_clk_o = sour_freq/hs_div)
|
||||
* @param mst_div Functional output clock divider: (mst_clk_o = sour_freq/hs_div/mst_div)
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
|
||||
{
|
||||
if (hw == &GPSPI2) {
|
||||
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_hs_clk_div_num = hs_div - 1;
|
||||
HP_SYS_CLKRST.peri_clk_ctrl116.reg_gpspi2_mst_clk_div_num = mst_div - 1;
|
||||
} else if (hw == &GPSPI3) {
|
||||
HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_hs_clk_div_num = hs_div - 1;
|
||||
HP_SYS_CLKRST.peri_clk_ctrl117.reg_gpspi3_mst_clk_div_num = mst_div - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define spi_ll_clk_sour_pre_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; spi_ll_clk_sour_pre_div(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Initialize SPI peripheral (master).
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -70,6 +70,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
|
||||
spi_clock_source_t clock_source; ///< Clock source of each device used by LL layer
|
||||
uint32_t source_pre_div; ///< Pre divider befor enter SPI peripheral
|
||||
int real_freq; ///< Output of the actual frequency
|
||||
int timing_dummy; ///< Extra dummy needed to compensate the timing
|
||||
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
|
||||
} spi_hal_timing_conf_t;
|
||||
@ -222,12 +224,11 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal);
|
||||
* It is highly suggested to do this at initialization, since it takes long time.
|
||||
*
|
||||
* @param timing_param Input parameters to calculate timing configuration
|
||||
* @param out_freq Output of the actual frequency, left NULL if not required.
|
||||
* @param timing_conf Output of the timing configuration.
|
||||
*
|
||||
* @return ESP_OK if desired is available, otherwise fail.
|
||||
*/
|
||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf);
|
||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, spi_hal_timing_conf_t *timing_conf);
|
||||
|
||||
/**
|
||||
* Get the frequency actual used.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -52,7 +52,7 @@ void spi_hal_deinit(spi_hal_context_t *hal)
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf)
|
||||
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, spi_hal_timing_conf_t *timing_conf)
|
||||
{
|
||||
spi_hal_timing_conf_t temp_conf = {};
|
||||
|
||||
@ -73,12 +73,10 @@ Specify ``SPI_DEVICE_NO_DUMMY`` to ignore this checking. Then you can output dat
|
||||
ESP_ERR_NOT_SUPPORTED, freq_limit / 1000. / 1000 );
|
||||
#endif
|
||||
|
||||
temp_conf.real_freq = eff_clk_n;
|
||||
if (timing_conf) {
|
||||
*timing_conf = temp_conf;
|
||||
}
|
||||
if (out_freq) {
|
||||
*out_freq = eff_clk_n;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -991,6 +991,14 @@ config SOC_SPI_SUPPORT_CLK_XTAL
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_SPI_SUPPORT_CLK_RC_FAST
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_SPI_SUPPORT_CLK_SPLL
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_MEMSPI_IS_INDEPENDENT
|
||||
bool
|
||||
default y
|
||||
|
@ -403,14 +403,10 @@ typedef enum {
|
||||
* @brief Type of SPI clock source.
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */
|
||||
#if SOC_CLK_TREE_SUPPORTED
|
||||
SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST,
|
||||
SPI_CLK_SRC_SPLL_480 = SOC_MOD_CLK_SPLL,
|
||||
SPI_CLK_SRC_DEFAULT = SPI_CLK_SRC_SPLL_480, /*!< Select SPLL_480M as SPI source clock */
|
||||
#else
|
||||
SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */
|
||||
#endif
|
||||
SPI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as SPI source clock */
|
||||
SPI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST_20M as SPI source clock */
|
||||
SPI_CLK_SRC_SPLL = SOC_MOD_CLK_SPLL, /*!< Select SPLL as SPI source clock */
|
||||
SPI_CLK_SRC_DEFAULT = SOC_MOD_CLK_SPLL, /*!< Select SPLL as SPI source clock */
|
||||
} soc_periph_spi_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////PSRAM////////////////////////////////////////////////////////////////////
|
||||
|
@ -427,10 +427,8 @@
|
||||
#define SOC_SPI_SUPPORT_CD_SIG 1
|
||||
#define SOC_SPI_SUPPORT_OCT 1
|
||||
#define SOC_SPI_SUPPORT_CLK_XTAL 1
|
||||
// #define SOC_SPI_SUPPORT_CLK_RC_FAST 1 //bellow clks are waiting for clock tree
|
||||
// #define SOC_SPI_SUPPORT_CLK_SPLL_F480M 1 //super pll
|
||||
// #define SOC_SPI_SUPPORT_CLK_SDIO 1 //sdio pll
|
||||
// #define SOC_SPI_SUPPORT_CLK_APLL 1 //audio pll
|
||||
#define SOC_SPI_SUPPORT_CLK_RC_FAST 1
|
||||
#define SOC_SPI_SUPPORT_CLK_SPLL 1
|
||||
|
||||
// Peripheral supports DIO, DOUT, QIO, or QOUT
|
||||
// host_id = 0 -> SPI0/SPI1, host_id = 1 -> SPI2,
|
||||
|
@ -1,2 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
Loading…
x
Reference in New Issue
Block a user