Sigma-Delta 调制器 (SDM)

[English]

简介

ESP32-C5 具备二阶 Sigma-Delta 调制器,可以为多个通道生成独立的脉冲密度调制 (PDM) 脉冲。请参阅技术参考手册,查看可用的硬件通道数量。[1]

Sigma-Delta 调制器可以将模拟电压信号转换为脉冲频率或脉冲密度,该过程称为脉冲密度调制 (PDM)(请参阅 维基百科上有关 Sigma-Delta 调制的介绍)。

Sigma-Delta 调制通道通常应用于以下场景:

  • LED 调光

  • 使用有源 RC 低通滤波器,实现简单的数模转换(8 位分辨率)

  • 结合半桥或全桥回路,以及 LC 低通滤波器,实现 D 级功率放大

功能概述

下文将分节概述安装和操作 SDM 通道的一般步骤:

  • 资源分配 - 介绍如何初始化和配置 SDM 通道,以及在通道完成任务后如何回收相关资源。

  • 启用和禁用通道 - 介绍如何启用和禁用 SDM 通道。

  • 设置脉冲密度 - 介绍如何设置 PDM 脉冲的等效占空比。

  • 电源管理 - 介绍不同时钟源对功耗的影响。

  • IRAM 安全 - 介绍禁用 cache 时仍可使用的功能。

  • 线程安全 - 介绍由驱动程序认证为线程安全的 API。

  • Kconfig 选项 - 介绍 SDM 驱动程序支持的各种 Kconfig 选项,这些选项可以给驱动程序的行为造成不同影响。

资源分配

在 ESP-IDF 中,SDM 通道的信息和属性通过特定的数据结构进行管理和访问,该数据结构表示为 sdm_channel_handle_t。每个通道都可以输出由硬件生成的二进制信号,且这些信号都经过 Sigma-Delta 调制。所有可用通道均存放在资源池中,由驱动程序管理,无需手动将固定通道分配给 GPIO。

要安装 SDM 通道,请调用 sdm_new_channel() 获取通道句柄。通道的具体配置信息由结构体 sdm_config_t 传递。

函数 sdm_new_channel() 可能因为各种原因失败,如内存不足、参数无效等。当缺少空闲通道(即所有的硬件 SDM 通道均在使用中)时,将返回 ESP_ERR_NOT_FOUND

SDM 通道完成任务后,请调用 sdm_del_channel() 回收相应资源,以便底层硬件通道用于其他目的。在删除 SDM 通道句柄前,请通过 sdm_channel_disable() 禁用要删除的通道,或确保该通道尚未由 sdm_channel_enable() 启用,再继续删除操作。

创建采样率为 1 MHz 的 SDM 通道

 sdm_channel_handle_t chan = NULL;
 sdm_config_t config = {
     .clk_src = SDM_CLK_SRC_DEFAULT,
     .sample_rate_hz = 1 * 1000 * 1000,
     .gpio_num = 0,
 };
ESP_ERROR_CHECK(sdm_new_channel(&config, &chan));

启用和禁用通道

在对 SDM 通道进行进一步的 IO 控制之前,需要先调用 sdm_channel_enable() 启用通道。在内部,该函数实现了以下操作:

  • 将通道状态从 init 切换到 enable

  • 如果选择了特定时钟源(如 APB 锁),则会获取合适的电源管理锁。要了解更多有关信息,请参阅 电源管理

调用 sdm_channel_disable() 则执行相反操作,即将通道恢复到 init 状态,并释放电源管理锁。

设置脉冲密度

在 PDM 中,脉冲密度决定了低通滤波器转换后的输出模拟电压,该模拟电压可以通过公式 Vout = VDD_IO / 256 * duty + VDD_IO / 2 计算。使用函数 sdm_channel_set_pulse_density() 时,需要传入一个名为 density 的参数。这个参数是一个整数值,范围在 -128 到 127 之间,表示一个 8 位有符号整数。根据 density 参数的不同取值,输出信号的占空比也会相应改变。例如,如果将 density 参数设置为零,输出信号的占空比约为 50%。

电源管理

启用电源管理(即启用 CONFIG_PM_ENABLE)时,在进入 Light-sleep 模式前,系统会调整 APB 频率,这可能会改变 Sigma-Delta 调制器的采样率。

但是,通过获取类型为 ESP_PM_APB_FREQ_MAX 的电源管理锁,驱动程序可以防止系统改变 APB 频率。每当驱动程序创建 SDM 通道,且该通道选择 SDM_CLK_SRC_APB 作为其时钟源时,在通过 sdm_channel_enable() 启用通道的过程中,驱动程序会确保获取类型为 ESP_PM_APB_FREQ_MAX 的电源管理锁。反之,调用 sdm_channel_disable() 禁用通道时,驱动程序释放该锁。

IRAM 安全

Kconfig 选项 CONFIG_SDM_CTRL_FUNC_IN_IRAM 支持将常用的 IO 控制函数存放在 IRAM 中,以保证在禁用 cache 时可以正常使用函数。IO 控制函数如下所示:

线程安全

驱动使用了临界区保证了对寄存器的原子操作。句柄内部的关键成员也受临界区保护。驱动内部的状态机使用了原子指令保证了线程安全,通过状态检查还能进一步防止一些不合法的并发操作(例如 enabledelete 冲突)。因此, SDM 驱动的 API 可以在多线程环境下使用,无需自行加锁。

同时,以下这些函数还允许在中断上下文中使用:

Kconfig 选项

转换为模拟信号(可选)

一般而言,Sigma-Delta 信号连接到 LED 用来调节明暗时,无需在信号和 LED 之间添加滤波器,因为人眼本身对光强变化有低通滤波作用。但是,如果你想测量实际电压,或观察模拟波形,就需要设计一个模拟低通滤波器。此外,建议使用有源滤波器,相较于无源滤波器,有源滤波器在处理信号时具有更强的抗干扰性,且损失的电压较少。

请参阅如下示例 Sallen-Key 拓扑低通滤波器,了解滤波器的相关知识。

Sallen-Key 拓扑低通滤波器

Sallen-Key 拓扑低通滤波器

(滤波前后的波形请参阅文档 peripherals/sigma_delta/sdm_dac/README.md

应用示例

API 参考

Header File

  • components/esp_driver_sdm/include/driver/sdm.h

  • This header file can be included with:

    #include "driver/sdm.h"
    
  • This header file is a part of the API provided by the esp_driver_sdm component. To declare that your component depends on esp_driver_sdm, add the following to your CMakeLists.txt:

    REQUIRES esp_driver_sdm
    

    or

    PRIV_REQUIRES esp_driver_sdm
    

Functions

esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_chan)

Create a new Sigma Delta channel.

参数:
  • config -- [in] SDM configuration

  • ret_chan -- [out] Returned SDM channel handle

返回:

  • ESP_OK: Create SDM channel successfully

  • ESP_ERR_INVALID_ARG: Create SDM channel failed because of invalid argument

  • ESP_ERR_NO_MEM: Create SDM channel failed because out of memory

  • ESP_ERR_NOT_FOUND: Create SDM channel failed because all channels are used up and no more free one

  • ESP_FAIL: Create SDM channel failed because of other error

esp_err_t sdm_del_channel(sdm_channel_handle_t chan)

Delete the Sigma Delta channel.

参数:

chan -- [in] SDM channel created by sdm_new_channel

返回:

  • ESP_OK: Delete the SDM channel successfully

  • ESP_ERR_INVALID_ARG: Delete the SDM channel failed because of invalid argument

  • ESP_ERR_INVALID_STATE: Delete the SDM channel failed because the channel is not in init state

  • ESP_FAIL: Delete the SDM channel failed because of other error

esp_err_t sdm_channel_enable(sdm_channel_handle_t chan)

Enable the Sigma Delta channel.

备注

This function will transit the channel state from init to enable.

备注

This function will acquire a PM lock, if a specific source clock (e.g. APB) is selected in the sdm_config_t, while CONFIG_PM_ENABLE is enabled.

参数:

chan -- [in] SDM channel created by sdm_new_channel

返回:

  • ESP_OK: Enable SDM channel successfully

  • ESP_ERR_INVALID_ARG: Enable SDM channel failed because of invalid argument

  • ESP_ERR_INVALID_STATE: Enable SDM channel failed because the channel is already enabled

  • ESP_FAIL: Enable SDM channel failed because of other error

esp_err_t sdm_channel_disable(sdm_channel_handle_t chan)

Disable the Sigma Delta channel.

备注

This function will do the opposite work to the sdm_channel_enable()

参数:

chan -- [in] SDM channel created by sdm_new_channel

返回:

  • ESP_OK: Disable SDM channel successfully

  • ESP_ERR_INVALID_ARG: Disable SDM channel failed because of invalid argument

  • ESP_ERR_INVALID_STATE: Disable SDM channel failed because the channel is not enabled yet

  • ESP_FAIL: Disable SDM channel failed because of other error

esp_err_t sdm_channel_set_pulse_density(sdm_channel_handle_t chan, int8_t density)

Set the pulse density of the PDM output signal.

备注

The raw output signal requires a low-pass filter to restore it into analog voltage, the restored analog output voltage could be Vout = VDD_IO / 256 * density + VDD_IO / 2

备注

This function is allowed to run within ISR context

备注

This function will be placed into IRAM if CONFIG_SDM_CTRL_FUNC_IN_IRAM is on, so that it's allowed to be executed when Cache is disabled

参数:
  • chan -- [in] SDM channel created by sdm_new_channel

  • density -- [in] Quantized pulse density of the PDM output signal, ranges from -128 to 127. But the range of [-90, 90] can provide a better randomness.

返回:

  • ESP_OK: Set pulse density successfully

  • ESP_ERR_INVALID_ARG: Set pulse density failed because of invalid argument

  • ESP_FAIL: Set pulse density failed because of other error

esp_err_t sdm_channel_set_duty(sdm_channel_handle_t chan, int8_t duty)

The alias function of sdm_channel_set_pulse_density, it decides the pulse density of the output signal.

备注

sdm_channel_set_pulse_density has a more appropriate name compare this alias function, suggest to turn to sdm_channel_set_pulse_density instead

参数:
  • chan -- [in] SDM channel created by sdm_new_channel

  • duty -- [in] Actually it's the quantized pulse density of the PDM output signal

返回:

  • ESP_OK: Set duty cycle successfully

  • ESP_ERR_INVALID_ARG: Set duty cycle failed because of invalid argument

  • ESP_FAIL: Set duty cycle failed because of other error

Structures

struct sdm_config_t

Sigma Delta channel configuration.

Public Members

gpio_num_t gpio_num

GPIO number

sdm_clock_source_t clk_src

Clock source

uint32_t sample_rate_hz

Over sample rate in Hz, it determines the frequency of the carrier pulses

uint32_t invert_out

Whether to invert the output signal

uint32_t allow_pd

If set, driver allows the power domain to be powered off when system enters sleep mode. This can save power, but at the expense of more RAM being consumed to save register context.

struct sdm_config_t flags

Extra flags

Type Definitions

typedef struct sdm_channel_t *sdm_channel_handle_t

Type of Sigma Delta channel handle.

Header File

Type Definitions

typedef soc_periph_sdm_clk_src_t sdm_clock_source_t

此文档对您有帮助吗?