sdm: support sdm on esp32h2

This commit is contained in:
laokaiyao 2023-01-09 16:31:54 +08:00
parent b1ff550f69
commit 482a26e284
15 changed files with 107 additions and 31 deletions

View File

@ -232,9 +232,19 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_
sprintf(chan->pm_lock_name, "sdm_%d_%d", group->group_id, chan_id); // e.g. sdm_0_0
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, chan->pm_lock_name, &chan->pm_lock);
ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
#endif
#endif // CONFIG_PM_ENABLE
break;
#endif // SOC_SDM_CLK_SUPPORT_PLL_F80M
#if SOC_SDM_CLK_SUPPORT_PLL_F48M
case SDM_CLK_SRC_PLL_F48M:
src_clk_hz = 48 * 1000 * 1000;
#if CONFIG_PM_ENABLE
sprintf(chan->pm_lock_name, "sdm_%d_%d", group->group_id, chan_id); // e.g. sdm_0_0
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, chan->pm_lock_name, &chan->pm_lock);
ESP_RETURN_ON_ERROR(ret, TAG, "create NO_LIGHT_SLEEP lock failed");
#endif // CONFIG_PM_ENABLE
break;
#endif // SOC_SDM_CLK_SUPPORT_PLL_F48M
default:
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "clock source %d is not support", config->clk_src);
break;

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
@ -15,6 +15,7 @@ CONFIGS = [
@pytest.mark.esp32c6
@pytest.mark.esp32s2
@pytest.mark.esp32s3
# @pytest.mark.esp32h2 // TODO: IDF-6263
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
def test_sdm(dut: IdfDut) -> None:

View File

@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "soc/gpio_ext_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set Sigma-delta enable
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param en Sigma-delta enable value
*/
static inline void sdm_ll_enable_clock(gpio_sd_dev_t *hw, bool en)
{
hw->misc.function_clk_en = en;
}
/**
* @brief Set Sigma-delta channel duty.
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param channel Sigma-delta channel number
* @param density Sigma-delta quantized density of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90.
* The waveform is more like a random one in this range.
*/
__attribute__((always_inline))
static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8_t density)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], duty, (uint32_t)density);
}
/**
* @brief Set Sigma-delta channel's clock pre-scale value.
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param channel Sigma-delta channel number
* @param prescale The divider of source clock, ranges from 1 to 256
*/
static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale)
{
HAL_ASSERT(prescale && prescale <= 256);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale - 1);
}
#ifdef __cplusplus
}
#endif

View File

@ -35,6 +35,10 @@ config SOC_RTC_MEM_SUPPORTED
bool
default y
config SOC_SDM_SUPPORTED
bool
default y
config SOC_SYSTIMER_SUPPORTED
bool
default y
@ -531,7 +535,7 @@ config SOC_SDM_CHANNELS_PER_GROUP
int
default 4
config SOC_SDM_CLK_SUPPORT_PLL_F80M
config SOC_SDM_CLK_SUPPORT_PLL_F48M
bool
default y

View File

@ -330,9 +330,13 @@ typedef enum {
* @brief Sigma Delta Modulator clock source
*/
typedef enum {
SDM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */
SDM_CLK_SRC_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the source clock */
SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the default clock choice */
SDM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */
SDM_CLK_SRC_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the source clock */
#if CONFIG_IDF_ENV_FPGA
SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
#else
SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M as the default clock choice */
#endif
} soc_periph_sdm_clk_src_t;
//////////////////////////////////////////////////GPIO Glitch Filter////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -16,11 +16,11 @@ extern "C" {
*/
typedef union {
struct {
/** sd0_in : R/W; bitpos: [7:0]; default: 0;
/** duty : R/W; bitpos: [7:0]; default: 0;
* This field is used to configure the duty cycle of sigma delta modulation output.
*/
uint32_t duty:8;
/** sd0_prescale : R/W; bitpos: [15:8]; default: 255;
/** prescale : R/W; bitpos: [15:8]; default: 255;
* This field is used to set a divider value to divide APB clock.
*/
uint32_t prescale:8;
@ -272,7 +272,7 @@ typedef union {
uint32_t val;
} gpio_ext_version_reg_t;
typedef struct {
typedef struct gpio_sd_dev_t {
volatile gpio_sigmadelta_chn_reg_t channel[4];
uint32_t reserved_010[4];
volatile gpio_sigmadelta_misc_reg_t misc;

View File

@ -46,7 +46,7 @@
#define SOC_RTC_MEM_SUPPORTED 1
// #define SOC_I2S_SUPPORTED 1 // TODO: IDF-6219
// #define SOC_RMT_SUPPORTED 1 // TODO: IDF-6224
// #define SOC_SDM_SUPPORTED 1 // TODO: IDF-6220
#define SOC_SDM_SUPPORTED 1
// #define SOC_GPSPI_SUPPORTED 1 // TODO: IDF-6264
#define SOC_SYSTIMER_SUPPORTED 1
// #define SOC_SUPPORT_COEXISTENCE 1 // TODO: IDF-6416
@ -294,11 +294,10 @@
#define SOC_SHA_SUPPORT_SHA224 (1)
#define SOC_SHA_SUPPORT_SHA256 (1)
// TODO: IDF-6220
/*-------------------------- Sigma Delta Modulator CAPS -----------------*/
#define SOC_SDM_GROUPS 1U
#define SOC_SDM_CHANNELS_PER_GROUP 4
#define SOC_SDM_CLK_SUPPORT_PLL_F80M 1
#define SOC_SDM_CLK_SUPPORT_PLL_F48M 1
#define SOC_SDM_CLK_SUPPORT_XTAL 1
// TODO: IDF-6245 (Copy from esp32c6, need check)

View File

@ -128,7 +128,8 @@ For example, you can take the following `Sallen-Key topology Low Pass Filter`_ a
Application Example
-------------------
* LED driven by a GPIO that is modulated with Sigma-Delta: :example:`peripherals/sigma_delta`.
* 100 Hz sine wave that is modulated with Sigma-Delta: :example:`peripherals/sigma_delta/sdm_dac`.
* LED driven by a GPIO that is modulated with Sigma-Delta: :example:`peripherals/sigma_delta/sdm_led`.
API Reference
-------------

View File

@ -5,7 +5,7 @@
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example uses the sigma-delta driver to generate modulated output on a GPIO. If you filter the output signal with an active or passive filter, you can get a 1 KHz sine wave.
This example uses the sigma-delta driver to generate modulated output on a GPIO. If you filter the output signal with an active or passive filter, you can get a 100 Hz sine wave.
## How to use example
@ -46,21 +46,17 @@ Once the upload is complete and the board is reset, the program should start run
I (299) main_task: Calling app_main()
I (309) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (309) sdm_dac: Sigma-delta output is attached to GPIO 0
I (319) sdm_dac: Timer allocated with resolution 10000000 Hz
I (329) sdm_dac: Timer callback registered, interval 10 us
I (319) sdm_dac: Timer allocated with resolution 1000000 Hz
I (329) sdm_dac: Timer callback registered, interval 100 us
I (329) sdm_dac: Timer enabled
I (339) sdm_dac: Output start
```
After the output stated, you can monitor the output signal by an oscilloscope.
If you monitor on the GPIO directly, you can see the raw SDM output, it consists by square waves (i.e. pulse) with different density
If you monitor on the GPIO directly, you can see the raw SDM output, it consists of square waves (i.e. pulse) with different densities (see the blue wave in the figure), and if you monitor the signal after a low-pass filter, you can see the pulses are filtered into a sine wave already (see the yellow wave in the figure).
![raw_sdm_output](raw_sdm_output.png)
If you monitor the signal after a low-pass filter, you can see the pulses are filtered into a sine wave already
![filtered_sine_wave](filtered_sine_wave.png)
![example_figure](example_figure.png)
## Troubleshooting

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -11,15 +11,16 @@
#include "driver/sdm.h"
#include "driver/gptimer.h"
#define EXAMPLE_SIGMA_DELTA_GPIO_NUM (0) // Select GPIO_NUM_0 as the sigma-delta output pin
#define EXAMPLE_OVER_SAMPLE_RATE (20 * 1000 * 1000) // 20 MHz over sample rate
#define EXAMPLE_TIMER_RESOLUTION (10 * 1000 * 1000) // 10 MHz timer counting resolution
#define EXAMPLE_CALLBACK_INTERVAL_US (10) // 10 us interval of each timer callback
#define EXAMPLE_ALARM_COUNT (EXAMPLE_CALLBACK_INTERVAL_US * (EXAMPLE_TIMER_RESOLUTION / 1000000))
#define EXAMPLE_SINE_WAVE_FREQ_HZ (1000) // 1 KHz wave, adjust this value to decide the sine wave frequency
#define EXAMPLE_SINE_WAVE_AMPLITUDE (127.0f) // 1 ~ 127, adjust this value to decide the sine wave amplitude
#define EXAMPLE_SINE_WAVE_POINT_NUM (1000000 / (EXAMPLE_CALLBACK_INTERVAL_US * EXAMPLE_SINE_WAVE_FREQ_HZ))
#define MHZ (1000000)
#define CONST_PI (3.1416f) // Constant of PI, used for calculating the sine wave
#define EXAMPLE_SIGMA_DELTA_GPIO_NUM (0) // Select GPIO_NUM_0 as the sigma-delta output pin
#define EXAMPLE_OVER_SAMPLE_RATE (10 * MHZ) // 10 MHz over sample rate
#define EXAMPLE_TIMER_RESOLUTION (1 * MHZ) // 1 MHz timer counting resolution
#define EXAMPLE_CALLBACK_INTERVAL_US (100) // 100 us interval of each timer callback
#define EXAMPLE_ALARM_COUNT (EXAMPLE_CALLBACK_INTERVAL_US * (EXAMPLE_TIMER_RESOLUTION / MHZ))
#define EXAMPLE_SINE_WAVE_FREQ_HZ (100) // 100 Hz sine wave, adjust this value to decide the sine wave frequency
#define EXAMPLE_SINE_WAVE_AMPLITUDE (127.0f) // 1 ~ 127, adjust this value to decide the sine wave amplitude
#define EXAMPLE_SINE_WAVE_POINT_NUM (MHZ / (EXAMPLE_CALLBACK_INTERVAL_US * EXAMPLE_SINE_WAVE_FREQ_HZ))
ESP_STATIC_ASSERT(EXAMPLE_SINE_WAVE_POINT_NUM > 1, "Sine wave frequency is too high");
ESP_STATIC_ASSERT(EXAMPLE_CALLBACK_INTERVAL_US >= 7, "Timer callback interval is too short");

View File

@ -10,6 +10,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
# @pytest.mark.esp32h2 // TODO: IDF-6263, IDF-6242
@pytest.mark.generic
def test_sdm_dac_example(dut: Dut) -> None:
dut.expect(r'sdm_dac: Sigma-delta output is attached to GPIO \w+')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -10,6 +10,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
# @pytest.mark.esp32h2 // TODO: IDF-6263
@pytest.mark.generic
def test_sdm_led_example(dut: Dut) -> None:
dut.expect_exact('sdm_led: Install sigma delta channel')