mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
feat(driver_spi): master driver support higher speed limit if 'input_delay_ns' not use
This commit is contained in:
@@ -407,15 +407,24 @@ int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns)
|
||||
}
|
||||
|
||||
#if SPI_LL_SRC_PRE_DIV_MAX
|
||||
static uint32_t s_spi_find_clock_src_pre_div(uint32_t src_freq, uint32_t target_freq)
|
||||
static uint32_t s_spi_find_clock_src_pre_div(uint32_t src_freq, uint32_t target_freq, bool need_timing_tune)
|
||||
{
|
||||
// pre division must be even and at least 2
|
||||
uint32_t min_div = ((src_freq / SPI_PERIPH_SRC_FREQ_MAX) + 1) & (~0x01UL);
|
||||
min_div = min_div < 2 ? 2 : min_div;
|
||||
uint32_t min_div;
|
||||
uint32_t step;
|
||||
if (need_timing_tune) {
|
||||
// mst_div == 2: total pre_div must be even and at least 2
|
||||
min_div = ((src_freq / SPI_PERIPH_SRC_FREQ_MAX) + 1) & (~0x01UL);
|
||||
min_div = min_div < 2 ? 2 : min_div;
|
||||
step = 2;
|
||||
} else {
|
||||
// mst_div == 1: only guarantee peripheral input <= SPI_PERIPH_SRC_FREQ_MAX
|
||||
min_div = (src_freq + SPI_PERIPH_SRC_FREQ_MAX - 1) / SPI_PERIPH_SRC_FREQ_MAX;
|
||||
min_div = min_div < 1 ? 1 : min_div;
|
||||
step = 1;
|
||||
}
|
||||
|
||||
uint32_t total_div = src_freq / target_freq;
|
||||
// Loop the `div` to find a divisible value of `total_div`
|
||||
for (uint32_t pre_div = min_div; pre_div <= MIN(total_div, SPI_LL_SRC_PRE_DIV_MAX); pre_div += 2) {
|
||||
for (uint32_t pre_div = min_div; pre_div <= MIN(total_div, SPI_LL_SRC_PRE_DIV_MAX); pre_div += step) {
|
||||
if ((total_div % pre_div) || (total_div / pre_div) > SPI_LL_PERIPH_CLK_DIV_MAX) {
|
||||
continue;
|
||||
}
|
||||
@@ -453,7 +462,7 @@ esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interfa
|
||||
SPI_CHECK(esp_clk_tree_enable_src(clk_src, true) == ESP_OK, "clock source enable failed", ESP_ERR_INVALID_STATE);
|
||||
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clock_source_hz);
|
||||
#if SPI_LL_SRC_PRE_DIV_MAX
|
||||
clock_source_div = s_spi_find_clock_src_pre_div(clock_source_hz, dev_config->clock_speed_hz);
|
||||
clock_source_div = s_spi_find_clock_src_pre_div(clock_source_hz, dev_config->clock_speed_hz, dev_config->input_delay_ns > 0);
|
||||
clock_source_hz /= clock_source_div; //actual freq enter to SPI peripheral
|
||||
#endif
|
||||
SPI_CHECK(dev_config->clock_speed_hz <= clock_source_hz, "invalid sclk speed", ESP_ERR_INVALID_ARG);
|
||||
@@ -703,10 +712,13 @@ static SPI_MASTER_ISR_ATTR void spi_setup_device(spi_device_t *dev, spi_trans_pr
|
||||
spi_hal_setup_device(hal, hal_dev);
|
||||
PERIPH_RCC_ATOMIC() {
|
||||
#if SPI_LL_SRC_PRE_DIV_MAX
|
||||
//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)
|
||||
assert(hal_dev->timing_conf.source_pre_div >= 2); // source_pre_div must be even and at least 2
|
||||
spi_ll_clk_source_pre_div(hal->hw, hal_dev->timing_conf.source_pre_div / 2, 2);
|
||||
// input_delay_ns > 0: mst_div = 2 for timing tuning; otherwise mst_div = 1
|
||||
uint32_t pre_div = hal_dev->timing_conf.source_pre_div;
|
||||
if (dev->cfg.input_delay_ns > 0) {
|
||||
spi_ll_clk_source_pre_div(hal->hw, pre_div / 2, 2);
|
||||
} else {
|
||||
spi_ll_clk_source_pre_div(hal->hw, pre_div, 1);
|
||||
}
|
||||
#endif
|
||||
spi_ll_set_clk_source(hal->hw, hal_dev->timing_conf.clock_source);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#endif
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 26666*1000
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 38 //TODO: IDF-9551, check perform
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 22
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 32
|
||||
@@ -70,7 +70,7 @@
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 54
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 60*1000*1000
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 44
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 28
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 26
|
||||
@@ -98,14 +98,14 @@
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 26
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32H4
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 24*1000*1000
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 24*1000*1000 // gpio matrix @48M and AHB@32M which limit slave's speed
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 70
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 35
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_CPU 60
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 25
|
||||
|
||||
#elif CONFIG_IDF_TARGET_ESP32S31
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 40*1000*1000
|
||||
#define IDF_TARGET_MAX_SPI_CLK_FREQ 60*1000*1000
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_DMA 22
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_POLL_CPU 17
|
||||
#define IDF_TARGET_MAX_TRANS_TIME_INTR_DMA 32
|
||||
|
||||
@@ -96,15 +96,21 @@ static void check_spi_pre_n_for(int clk, int pre, int n)
|
||||
* Only test on SPI_CLK_SRC_DEFAULT here
|
||||
*/
|
||||
#define TEST_CLK_TIMES 8
|
||||
uint32_t clk_param_80m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 16, 50}, {333333, 4, 60}, {800000, 2, 50}, {900000, 2, 44}, {8000000, 1, 10}, {20000000, 1, 4}, {26000000, 1, 3} };
|
||||
uint32_t clk_param_160m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 16, 50}, {333333, 4, 60}, {800000, 2, 50}, {900000, 2, 44}, {8000000, 1, 10}, {20000000, 1, 4}, {26000000, 1, 3} };
|
||||
#if SPI_LL_SRC_PRE_DIV_MAX
|
||||
uint32_t clk_param_40m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 4, 50}, {333333, 1, 60}, {800000, 1, 25}, {2000000, 1, 10}, {5000000, 1, 4}, {12000000, 1, 2}, {18000000, 1, 1} };
|
||||
uint32_t clk_param_48m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 4, 60}, {333333, 2, 36}, {800000, 1, 30}, {5000000, 1, 5}, {12000000, 1, 2}, {18000000, 1, 2}, {24000000, 1, 1} };
|
||||
#else
|
||||
uint32_t clk_param_40m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 8, 50}, {333333, 2, 60}, {800000, 1, 50}, {2000000, 1, 20}, {5000000, 1, 8}, {12000000, 1, 3}, {18000000, 1, 2} };
|
||||
uint32_t clk_param_48m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 8, 60}, {333333, 3, 48}, {800000, 1, 60}, {5000000, 1, 10}, {12000000, 1, 4}, {18000000, 1, 3}, {26000000, 1, 2} };
|
||||
#endif
|
||||
uint32_t clk_param_80m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 16, 50}, {333333, 4, 60}, {800000, 2, 50}, {900000, 2, 44}, {8000000, 1, 10}, {20000000, 1, 4}, {26000000, 1, 3} };
|
||||
uint32_t clk_param_160m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 16, 50}, {333333, 4, 60}, {800000, 2, 50}, {900000, 1, 59}, {8000000, 1, 10}, {20000000, 1, 4}, {26000000, 1, 3} };
|
||||
uint32_t clk_param_480m[TEST_CLK_TIMES][3] = {{1, SPI_LL_MAX_PRE_DIV_NUM, 64}, {100000, 16, 50}, {333333, 4, 60}, {800000, 2, 50}, {900000, 1, 41}, {8000000, 1, 10}, {20000000, 1, 4}, {26000000, 1, 3} };
|
||||
static struct {
|
||||
uint32_t clock_source_hz;
|
||||
uint32_t (*clk_param)[3];
|
||||
} clk_param_map[] = {
|
||||
{40 * 1000 * 1000, clk_param_40m},
|
||||
{48 * 1000 * 1000, clk_param_48m},
|
||||
{80 * 1000 * 1000, clk_param_80m},
|
||||
{160 * 1000 * 1000, clk_param_160m},
|
||||
{480 * 1000 * 1000, clk_param_480m},
|
||||
};
|
||||
|
||||
TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
|
||||
{
|
||||
@@ -113,27 +119,19 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]")
|
||||
uint32_t clock_source_hz;
|
||||
|
||||
esp_clk_tree_src_get_freq_hz(SPI_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz);
|
||||
printf("\nTest clock source SPI_CLK_SRC_DEFAULT = %ld\n", clock_source_hz);
|
||||
if ((160 * 1000 * 1000) == clock_source_hz) {
|
||||
for (int i = 0; i < TEST_CLK_TIMES; i++) {
|
||||
check_spi_pre_n_for(clk_param_160m[i][0], clk_param_160m[i][1], clk_param_160m[i][2]);
|
||||
printf("\nTest clock source SPI_CLK_SRC_DEFAULT = %ld Hz\n", clock_source_hz);
|
||||
int i = 0;
|
||||
for (; i < sizeof(clk_param_map) / sizeof(clk_param_map[0]); i++) {
|
||||
if (clk_param_map[i].clock_source_hz == clock_source_hz) {
|
||||
for (int j = 0; j < TEST_CLK_TIMES; j++) {
|
||||
check_spi_pre_n_for(clk_param_map[i].clk_param[j][0], clk_param_map[i].clk_param[j][1], clk_param_map[i].clk_param[j][2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if ((80 * 1000 * 1000) == clock_source_hz) {
|
||||
for (int i = 0; i < TEST_CLK_TIMES; i++) {
|
||||
check_spi_pre_n_for(clk_param_80m[i][0], clk_param_80m[i][1], clk_param_80m[i][2]);
|
||||
}
|
||||
} else if ((48 * 1000 * 1000) == clock_source_hz) {
|
||||
for (int i = 0; i < TEST_CLK_TIMES; i++) {
|
||||
check_spi_pre_n_for(clk_param_48m[i][0], clk_param_48m[i][1], clk_param_48m[i][2]);
|
||||
}
|
||||
} else if ((40 * 1000 * 1000) == clock_source_hz) {
|
||||
for (int i = 0; i < TEST_CLK_TIMES; i++) {
|
||||
check_spi_pre_n_for(clk_param_40m[i][0], clk_param_40m[i][1], clk_param_40m[i][2]);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (i == sizeof(clk_param_map) / sizeof(clk_param_map[0])) {
|
||||
ESP_LOGW(TAG, "Don't find any routing param!!");
|
||||
}
|
||||
|
||||
TEST_ESP_OK(spi_bus_free(TEST_SPI_HOST));
|
||||
}
|
||||
|
||||
@@ -158,12 +156,10 @@ TEST_CASE("SPI Master clk_source and divider accuracy", "[spi]")
|
||||
for (uint8_t sour_idx = 0; sour_idx < sizeof(spi_clk_sour); sour_idx++) {
|
||||
esp_clk_tree_src_get_freq_hz(spi_clk_sour[sour_idx], ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &clock_source_hz);
|
||||
printf("\nTesting unknown clock source @%ld Hz\n", clock_source_hz);
|
||||
#if SPI_LL_SRC_PRE_DIV_MAX
|
||||
clock_source_hz /= 2; //targets support pre-div will divide clock by 2 before SPI peripheral
|
||||
#endif
|
||||
for (uint8_t test_time = 0; test_time < 8; test_time ++) {
|
||||
spi_device_handle_t handle;
|
||||
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.input_delay_ns = 0;
|
||||
devcfg.clock_source = spi_clk_sour[sour_idx];
|
||||
devcfg.clock_speed_hz = MIN(IDF_TARGET_MAX_SPI_CLK_FREQ, clock_source_hz) >> test_time;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
@@ -216,6 +212,8 @@ TEST_CASE("test_device_dynamic_freq_update", "[spi]")
|
||||
|
||||
spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG();
|
||||
spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG();
|
||||
devcfg.input_delay_ns = 0;
|
||||
devcfg.clock_speed_hz = IDF_TARGET_MAX_SPI_CLK_FREQ;
|
||||
devcfg.flags |= SPI_DEVICE_HALFDUPLEX;
|
||||
TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
|
||||
|
||||
@@ -1512,8 +1512,11 @@ static void test_master_hd_dma(void)
|
||||
.dummy_bits = 8,
|
||||
.queue_size = 10,
|
||||
};
|
||||
if (is_gpio && devcfg.clock_speed_hz > 40 * 1000 * 1000) {
|
||||
devcfg.clock_speed_hz = 40 * 1000 * 1000; // using gpio matrix, clk freq <= 40MHz
|
||||
}
|
||||
TEST_ESP_OK(spi_bus_add_device(TEST_SPI_HOST, &devcfg, &dev0));
|
||||
printf("Next trans: %s\tmode:%d\t@%.2f MHz\n", (is_gpio) ? "GPIO_Matrix" : "IOMUX", mode, s_spi_bus_freq[speed_level] / 1000000.f);
|
||||
printf("Next trans: %s\tmode:%d\t@%.2f MHz\n", (is_gpio) ? "GPIO_Matrix" : "IOMUX", mode, devcfg.clock_speed_hz / 1000000.f);
|
||||
|
||||
unity_send_signal("Master ready");
|
||||
for (int i = 0; i < TEST_STEP; i++) {
|
||||
|
||||
@@ -183,9 +183,10 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
|
||||
{
|
||||
// In IDF master driver 'mst_div' will be const 2 and 'hs_div' is actually pre_div temporally
|
||||
(void) hs_div;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, mst_div - 1);
|
||||
(void) hw;
|
||||
// Single-stage PCR divider: program total_div = hs_div * mst_div
|
||||
uint16_t total_div = (uint16_t)hs_div * mst_div;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, total_div - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -184,9 +184,10 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
|
||||
{
|
||||
// In IDF master driver 'mst_div' will be const 2 and 'hs_div' is actually pre_div temporally
|
||||
(void) hs_div;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, mst_div - 1);
|
||||
(void) hw;
|
||||
// Single-stage PCR divider: program total_div = hs_div * mst_div
|
||||
uint16_t total_div = (uint16_t)hs_div * mst_div;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, total_div - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -199,12 +199,12 @@ static inline void spi_ll_set_clk_source(spi_dev_t *hw, spi_clock_source_t clk_s
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_clk_source_pre_div(spi_dev_t *hw, uint8_t hs_div, uint8_t mst_div)
|
||||
{
|
||||
// In IDF master driver 'mst_div' will be const 2 and 'hs_div' is actually pre_div temporally
|
||||
(void) hs_div;
|
||||
// Single-stage PCR divider: program total_div = hs_div * mst_div
|
||||
uint16_t total_div = (uint16_t)hs_div * mst_div;
|
||||
if (hw == &GPSPI2) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, mst_div - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi2_clkm_conf, spi2_clkm_div_num, total_div - 1);
|
||||
} else if (hw == &GPSPI3) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi3_clkm_conf, spi3_clkm_div_num, mst_div - 1);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PCR.spi3_clkm_conf, spi3_clkm_div_num, total_div - 1);
|
||||
} else {
|
||||
HAL_ASSERT(false);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ GPIO Matrix and IO_MUX
|
||||
|
||||
Most of chip's peripheral signals have direct connection to their dedicated IO_MUX pins. However, the signals can also be routed to any other available pins using the less direct GPIO matrix. If at least one signal is routed through the GPIO matrix, then all signals will be routed through it.
|
||||
|
||||
When an SPI Host is set to 80 MHz or lower frequencies, routing SPI pins via GPIO matrix will behave the same compared to routing them via IO_MUX.
|
||||
When transferring data with the SPI slave on a clock frequency 40 MHz or lower, routing SPI pins via GPIO matrix will behave the same compared to routing them via IO_MUX.
|
||||
|
||||
The IO_MUX pins for SPI buses are given below.
|
||||
|
||||
@@ -215,7 +215,7 @@ You can also configure a GPIO pin through which the Device will signal to the Ho
|
||||
SCLK Frequency Requirements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
{IDF_TARGET_MAX_FREQ:default="60", esp32="10", esp32s2="40", esp32c6="40", esp32h2="32"}
|
||||
{IDF_TARGET_MAX_FREQ:default="60", esp32="10", esp32s2="40", esp32c6="40", esp32h2="32", esp32c5="40", esp32c61="40", esp32h21="32"}
|
||||
|
||||
The SPI slaves are designed to operate at up to {IDF_TARGET_MAX_FREQ} MHz. The data cannot be recognized or received correctly if the clock is too fast or does not have a 50% duty cycle.
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ GPIO 交换矩阵和 IO_MUX
|
||||
|
||||
{IDF_TARGET_NAME} 的大多数外设信号都直接连接到其专用的 IO_MUX 管脚。不过,也可以使用 GPIO 交换矩阵,将信号路由到任何可用的其他管脚。如果通过 GPIO 交换矩阵路由了至少一个信号,则所有信号都将通过 GPIO 交换矩阵路由。
|
||||
|
||||
当 SPI 主机频率配置为 80 MHz 或更低时,则通过 GPIO 交换矩阵或 IO_MUX 路由 SPI 管脚效果相同。
|
||||
当与从机的通信时钟频率为 40 MHz 或更低时,则通过 GPIO 交换矩阵或 IO_MUX 路由 SPI 管脚效果相同。
|
||||
|
||||
下表列出了 SPI 总线的 IO_MUX 管脚。
|
||||
|
||||
@@ -215,7 +215,7 @@ GPIO 交换矩阵和 IO_MUX
|
||||
时钟频率要求
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
{IDF_TARGET_MAX_FREQ:default="60", esp32="10", esp32s2="40", esp32c6="40", esp32h2="32"}
|
||||
{IDF_TARGET_MAX_FREQ:default="60", esp32="10", esp32s2="40", esp32c6="40", esp32h2="32", esp32c5="40", esp32c61="40", esp32h21="32"}
|
||||
|
||||
SPI 从机的工作频率最高可达 {IDF_TARGET_MAX_FREQ} MHz。如果时钟频率过快或占空比不足 50%,数据就无法被正确识别或接收。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user