@@ -157,6 +157,8 @@ We have two bits to control the interrupt:
157157#define SPI_MASTER_PERI_CLOCK_ATOMIC ()
158158#endif
159159
160+ #define SPI_PERIPH_SRC_FREQ_MAX (80*1000*1000) //peripheral hardware limitation for clock source into peripheral
161+
160162static const char * SPI_TAG = "spi_master" ;
161163#define SPI_CHECK (a , str , ret_val , ...) ESP_RETURN_ON_FALSE_ISR(a, ret_val, SPI_TAG, str, ##__VA_ARGS__)
162164
@@ -395,6 +397,25 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns)
395397#endif
396398}
397399
400+ #if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV
401+ static uint32_t s_spi_find_clock_src_pre_div (uint32_t src_freq , uint32_t target_freq )
402+ {
403+ // pre division must be even and at least 2
404+ uint32_t min_div = ((src_freq / SPI_PERIPH_SRC_FREQ_MAX ) + 1 ) & (~0x01UL );
405+ min_div = min_div < 2 ? 2 : min_div ;
406+
407+ uint32_t total_div = src_freq / target_freq ;
408+ // Loop the `div` to find a divisible value of `total_div`
409+ for (uint32_t pre_div = min_div ; pre_div <= total_div ; pre_div += 2 ) {
410+ if ((total_div % pre_div ) || (total_div / pre_div ) > SPI_LL_PERIPH_CLK_DIV_MAX ) {
411+ continue ;
412+ }
413+ return pre_div ;
414+ }
415+ return min_div ;
416+ }
417+ #endif //SPI_LL_SUPPORT_CLK_SRC_PRE_DIV
418+
398419/*
399420 Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks
400421 up the CS pin to whatever is specified.
@@ -416,34 +437,22 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
416437 spi_host_t * host = bus_driver_ctx [host_id ];
417438 const spi_bus_attr_t * bus_attr = host -> bus_attr ;
418439 SPI_CHECK (dev_config -> spics_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO (dev_config -> spics_io_num ), "spics pin invalid" , ESP_ERR_INVALID_ARG );
440+ SPI_CHECK (dev_config -> clock_speed_hz > 0 , "invalid sclk speed" , ESP_ERR_INVALID_ARG );
419441#if SOC_SPI_SUPPORT_CLK_RC_FAST
420442 if (dev_config -> clock_source == SPI_CLK_SRC_RC_FAST ) {
421443 SPI_CHECK (periph_rtc_dig_clk8m_enable (), "the selected clock not available" , ESP_ERR_INVALID_STATE );
422444 }
423445#endif
424- spi_clock_source_t clk_src = dev_config -> clock_source ? dev_config -> clock_source : SPI_CLK_SRC_DEFAULT ;
425446 uint32_t clock_source_hz = 0 ;
426447 uint32_t clock_source_div = 1 ;
448+ spi_clock_source_t clk_src = dev_config -> clock_source ? dev_config -> clock_source : SPI_CLK_SRC_DEFAULT ;
427449 SPI_CHECK (esp_clk_tree_enable_src (clk_src , true) == ESP_OK , "clock source enable failed" , ESP_ERR_INVALID_STATE );
428450 esp_clk_tree_src_get_freq_hz (clk_src , ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED , & clock_source_hz );
429451#if SPI_LL_SUPPORT_CLK_SRC_PRE_DIV
430- 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 );
431-
432- if (clock_source_hz / 2 > (80 * 1000000 )) { //clock_source_hz beyond peripheral HW limitation, calc pre-divider
433- hal_utils_clk_info_t clk_cfg = {
434- .src_freq_hz = clock_source_hz ,
435- .exp_freq_hz = dev_config -> clock_speed_hz * 2 , //we have (hs_clk = 2*mst_clk), calc hs_clk first
436- .round_opt = HAL_DIV_ROUND ,
437- .min_integ = 1 ,
438- .max_integ = SPI_LL_CLK_SRC_PRE_DIV_MAX / 2 ,
439- };
440- hal_utils_calc_clk_div_integer (& clk_cfg , & clock_source_div );
441- }
442- clock_source_div *= 2 ; //convert to mst_clk function divider
443- clock_source_hz /= clock_source_div ; //actual freq enter to SPI peripheral
444- #else
445- SPI_CHECK ((dev_config -> clock_speed_hz > 0 ) && (dev_config -> clock_speed_hz <= clock_source_hz ), "invalid sclk speed" , ESP_ERR_INVALID_ARG );
452+ clock_source_div = s_spi_find_clock_src_pre_div (clock_source_hz , dev_config -> clock_speed_hz );
453+ clock_source_hz /= clock_source_div ; //actual freq enter to SPI peripheral
446454#endif
455+ SPI_CHECK (dev_config -> clock_speed_hz <= clock_source_hz , "invalid sclk speed" , ESP_ERR_INVALID_ARG );
447456#ifdef CONFIG_IDF_TARGET_ESP32
448457 //The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full
449458 //duplex mode does absolutely nothing on the ESP32.
0 commit comments