forked from espressif/esp-idf
Merge branch 'bugfix/check_sdm_clock_range' into 'master'
refactor(sdm): add check and error info to the clock division See merge request espressif/esp-idf!33394
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "hal/gpio_hal.h"
|
#include "hal/gpio_hal.h"
|
||||||
#include "hal/sdm_hal.h"
|
#include "hal/sdm_hal.h"
|
||||||
#include "hal/sdm_ll.h"
|
#include "hal/sdm_ll.h"
|
||||||
|
#include "hal/hal_utils.h"
|
||||||
#include "soc/sdm_periph.h"
|
#include "soc/sdm_periph.h"
|
||||||
#include "esp_private/esp_clk.h"
|
#include "esp_private/esp_clk.h"
|
||||||
#include "esp_private/io_mux.h"
|
#include "esp_private/io_mux.h"
|
||||||
@@ -242,7 +243,20 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_
|
|||||||
chan->gpio_num = config->gpio_num;
|
chan->gpio_num = config->gpio_num;
|
||||||
|
|
||||||
// set prescale based on sample rate
|
// set prescale based on sample rate
|
||||||
uint32_t prescale = src_clk_hz / config->sample_rate_hz;
|
uint32_t prescale = 0;
|
||||||
|
hal_utils_clk_info_t clk_info = {
|
||||||
|
.src_freq_hz = src_clk_hz,
|
||||||
|
.exp_freq_hz = config->sample_rate_hz,
|
||||||
|
.max_integ = SDM_LL_PRESCALE_MAX + 1,
|
||||||
|
.min_integ = 1,
|
||||||
|
.round_opt = HAL_DIV_ROUND,
|
||||||
|
};
|
||||||
|
uint32_t actual_freq = hal_utils_calc_clk_div_integer(&clk_info, &prescale);
|
||||||
|
ESP_GOTO_ON_FALSE(actual_freq, ESP_ERR_INVALID_ARG, err, TAG,
|
||||||
|
"sample rate out of range [%"PRIu32", %"PRIu32"] Hz", src_clk_hz / SDM_LL_PRESCALE_MAX, src_clk_hz);
|
||||||
|
if (actual_freq != config->sample_rate_hz) {
|
||||||
|
ESP_LOGW(TAG, "precision loss, expected sample rate %"PRIu32" Hz runs at %"PRIu32" Hz", config->sample_rate_hz, actual_freq);
|
||||||
|
}
|
||||||
sdm_ll_set_prescale(group->hal.dev, chan_id, prescale);
|
sdm_ll_set_prescale(group->hal.dev, chan_id, prescale);
|
||||||
chan->sample_rate_hz = src_clk_hz / prescale;
|
chan->sample_rate_hz = src_clk_hz / prescale;
|
||||||
// preset the duty cycle to zero
|
// preset the duty cycle to zero
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_sd_struct.h"
|
#include "soc/gpio_sd_struct.h"
|
||||||
|
#include "soc/gpio_sd_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_sd_struct.h"
|
#include "soc/gpio_sd_struct.h"
|
||||||
|
#include "soc/gpio_sd_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_ext_struct.h"
|
#include "soc/gpio_ext_struct.h"
|
||||||
|
#include "soc/gpio_ext_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], sdn_prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], sdn_prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_ext_struct.h"
|
#include "soc/gpio_ext_struct.h"
|
||||||
|
#include "soc/gpio_ext_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_ext_struct.h"
|
#include "soc/gpio_ext_struct.h"
|
||||||
|
#include "soc/gpio_ext_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_ext_struct.h"
|
#include "soc/gpio_ext_struct.h"
|
||||||
|
#include "soc/gpio_ext_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "soc/gpio_sd_struct.h"
|
#include "soc/gpio_sd_struct.h"
|
||||||
|
#include "soc/gpio_sd_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,14 @@
|
|||||||
#include "hal/assert.h"
|
#include "hal/assert.h"
|
||||||
#include "hal/misc.h"
|
#include "hal/misc.h"
|
||||||
#include "soc/gpio_sd_struct.h"
|
#include "soc/gpio_sd_struct.h"
|
||||||
|
#include "soc/gpio_sd_reg.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set Sigma-delta enable
|
* @brief Set Sigma-delta enable
|
||||||
*
|
*
|
||||||
@@ -49,7 +52,7 @@ static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8
|
|||||||
*/
|
*/
|
||||||
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
|
||||||
{
|
{
|
||||||
HAL_ASSERT(prescale && prescale <= 256);
|
HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX);
|
||||||
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,12 +10,6 @@ Introduction
|
|||||||
|
|
||||||
Delta-sigma modulation converts an analog voltage signal into a pulse frequency, or pulse density, which can be understood as pulse-density modulation (PDM) (refer to |wiki_ref|_).
|
Delta-sigma modulation converts an analog voltage signal into a pulse frequency, or pulse density, which can be understood as pulse-density modulation (PDM) (refer to |wiki_ref|_).
|
||||||
|
|
||||||
The main differences comparing to I2S PDM mode and DAC peripheral are:
|
|
||||||
|
|
||||||
1. SDM has no clock signal, it is just like the DAC mode of PDM;
|
|
||||||
2. SDM has no DMA, and it can not change its output density continuously. If you have to, you can update the density in a timer's callback;
|
|
||||||
3. Based on the former two points, unlike the DAC peripheral, an external active or passive low-pass filter is required additionally to restore the analog wave (See :ref:`convert_to_analog_signal`).
|
|
||||||
|
|
||||||
Typically, a Sigma-Delta modulated channel can be used in scenarios like:
|
Typically, a Sigma-Delta modulated channel can be used in scenarios like:
|
||||||
|
|
||||||
- LED dimming
|
- LED dimming
|
||||||
@@ -46,7 +40,7 @@ To install an SDM channel, you should call :cpp:func:`sdm_new_channel` to get a
|
|||||||
|
|
||||||
- :cpp:member:`sdm_config_t::gpio_num` sets the GPIO that the PDM pulses output from.
|
- :cpp:member:`sdm_config_t::gpio_num` sets the GPIO that the PDM pulses output from.
|
||||||
- :cpp:member:`sdm_config_t::clk_src` selects the source clock for the SDM module. Note that, all channels should select the same clock source.
|
- :cpp:member:`sdm_config_t::clk_src` selects the source clock for the SDM module. Note that, all channels should select the same clock source.
|
||||||
- :cpp:member:`sdm_config_t::sample_rate_hz` sets the sample rate of the SDM module.
|
- :cpp:member:`sdm_config_t::sample_rate_hz` sets the sample rate of the SDM module. A higher sample rate can help to output signals with higher SNR (Signal to Noise Ratio), and easier to restore the original signal after the filter.
|
||||||
- :cpp:member:`sdm_config_t::invert_out` sets whether to invert the output signal.
|
- :cpp:member:`sdm_config_t::invert_out` sets whether to invert the output signal.
|
||||||
- :cpp:member:`sdm_config_t::io_loop_back` is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral.
|
- :cpp:member:`sdm_config_t::io_loop_back` is for debugging purposes only. It enables both the GPIO's input and output ability through the GPIO matrix peripheral.
|
||||||
|
|
||||||
@@ -141,6 +135,7 @@ For example, you can take the following `Sallen-Key topology Low Pass Filter`_ a
|
|||||||
|
|
||||||
Sallen-Key Low Pass Filter
|
Sallen-Key Low Pass Filter
|
||||||
|
|
||||||
|
(Refer to :example_file:`peripherals/sigma_delta/sdm_dac/README.md` to see the waveforms before and after filtering.)
|
||||||
|
|
||||||
Application Examples
|
Application Examples
|
||||||
--------------------
|
--------------------
|
||||||
|
@@ -10,12 +10,6 @@ Sigma-Delta 调制器 (SDM)
|
|||||||
|
|
||||||
Sigma-Delta 调制器可以将模拟电压信号转换为脉冲频率或脉冲密度,该过程称为脉冲密度调制 (PDM)(请参阅 |wiki_ref|_)。
|
Sigma-Delta 调制器可以将模拟电压信号转换为脉冲频率或脉冲密度,该过程称为脉冲密度调制 (PDM)(请参阅 |wiki_ref|_)。
|
||||||
|
|
||||||
与 I2S 外设中的 PDM 模式和和数模转换器 (DAC) 相比,SDM 中的 PDM 主要有以下特点:
|
|
||||||
|
|
||||||
1. SDM 没有时钟信号,类似于 PDM 的 DAC 模式;
|
|
||||||
2. SDM 没有 DMA 支持,无法持续改变其输出密度。如果需要改变 SDM 的输出密度,可以在定时器的回调函数中进行操作;
|
|
||||||
3. 基于以上两点,不同于 DAC,要还原模拟波形,还必须使用外部的有源或无源低通滤波器,详情请参阅 :ref:`convert_to_analog_signal`。
|
|
||||||
|
|
||||||
Sigma-Delta 调制通道通常应用于以下场景:
|
Sigma-Delta 调制通道通常应用于以下场景:
|
||||||
|
|
||||||
- LED 调光
|
- LED 调光
|
||||||
@@ -46,7 +40,7 @@ Sigma-Delta 调制通道通常应用于以下场景:
|
|||||||
|
|
||||||
- :cpp:member:`sdm_config_t::gpio_num` 设置 PDM 脉冲输出的 GPIO 管脚号。
|
- :cpp:member:`sdm_config_t::gpio_num` 设置 PDM 脉冲输出的 GPIO 管脚号。
|
||||||
- :cpp:member:`sdm_config_t::clk_src` 选择 SDM 模块的时钟源。注意,所有通道选择的时钟源应保持一致。
|
- :cpp:member:`sdm_config_t::clk_src` 选择 SDM 模块的时钟源。注意,所有通道选择的时钟源应保持一致。
|
||||||
- :cpp:member:`sdm_config_t::sample_rate_hz` 设置 SDM 模块的采样率。
|
- :cpp:member:`sdm_config_t::sample_rate_hz` 设置 SDM 模块的采样率。提高采样率可以提高输出信号的信噪比,更容易在后级通过滤波获取高精度的原始信号。
|
||||||
- :cpp:member:`sdm_config_t::invert_out` 设置是否反转输出信号。
|
- :cpp:member:`sdm_config_t::invert_out` 设置是否反转输出信号。
|
||||||
- :cpp:member:`sdm_config_t::io_loop_back` 通过 GPIO 矩阵外设,启用 GPIO 的输入和输出功能。注意,该字段仅供调试使用。
|
- :cpp:member:`sdm_config_t::io_loop_back` 通过 GPIO 矩阵外设,启用 GPIO 的输入和输出功能。注意,该字段仅供调试使用。
|
||||||
|
|
||||||
@@ -141,6 +135,7 @@ Kconfig 选项
|
|||||||
|
|
||||||
Sallen-Key 拓扑低通滤波器
|
Sallen-Key 拓扑低通滤波器
|
||||||
|
|
||||||
|
(滤波前后的波形请参阅文档 :example_file:`peripherals/sigma_delta/sdm_dac/README.md`)
|
||||||
|
|
||||||
应用示例
|
应用示例
|
||||||
--------
|
--------
|
||||||
|
Reference in New Issue
Block a user