1. trigger every X number cycles (to give time for later steps to work effectively)
2. use a callback function (or something of the sort) to trigger an ADC read (with the ADC set to operate at [LEDC_FREQ] / [CONSTANT] Hz in order to ensure the reads are perfectly synchronized with the PWM)
3. follow the ADC read, likely on completion, with a PID loop that adjusts the PWM duty cycle toward a given target
My most current code is as follows (I'm using the ESP32-S2). It's able to properly run the PWM, but the interrupt is still completely unresponsive:
Code: Select all
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <driver/ledc.h>
#include <esp_intr_alloc.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_err.h>
#define HVCTL_PIN 1
/* LEDC DEFINITIONS */
#define DR_REG_LEDC_BASE 0x3F419000
#define LEDC_CH0_CONF0_REG (DR_REG_LEDC_BASE + 0x00)
#define LEDC_TIMER0_CONF_REG (DR_REG_LEDC_BASE + 0xA0)
#define LEDC_INT_ST_REG (DR_REG_LEDC_BASE + 0xC4)
#define LEDC_INT_ENA_REG (DR_REG_LEDC_BASE + 0xC8)
#define LEDC_INT_CLR_REG (DR_REG_LEDC_BASE + 0xCC)
#define LEDC_CONF_REG (DR_REG_LEDC_BASE + 0xD0)
#define LEDC_CH0_CONF0 (*((volatile uint32_t *)LEDC_CH0_CONF0_REG))
#define LEDC_TIMER0_CONF (*((volatile uint32_t *)LEDC_TIMER0_CONF_REG))
#define LEDC_INT_ENA (*((volatile uint32_t *)LEDC_INT_ENA_REG))
#define LEDC_INT_CLR (*((volatile uint32_t *)LEDC_INT_CLR_REG))
#define LEDC_APB_CLK_SEL (*((volatile uint32_t *)LEDC_CONF_REG))
/* GPIO DEFINITIONS */
#define DR_REG_GPIO_BASE 0x3F404000
#if (HVCTL_PIN < 32)
#define GPIO_ENABLE_W1TS_REG (DR_REG_GPIO_BASE + 0x24)
#else
#define GPIO_ENABLE_W1TS_REG (DR_REG_GPIO_BASE + 0x30)
#endif
#define GPIO_OUT_ENABLE (*((volatile uint32_t *)GPIO_ENABLE_W1TS_REG))
/* IO MUX DEFINITIONS */
#define DR_REG_IO_MUX_BASE 0x3F409000
#define GPIO_FUNC_OUT_SEL_REG (DR_REG_IO_MUX_BASE + 0x0554 + 4*HVCTL_PIN)
#define GPIO_FUNC_SEL (*((volatile uint32_t *)GPIO_FUNC_OUT_SEL_REG))
#define LEDC_CLK_SEL (1) // use APB_CLK (80 MHz)
#define LEDC_OVF_NUM (9 << 5) // 10-count overflow
#define LEDC_OVF_CNT_EN (1 << 15) // enable overflow counter
#define LEDC_DUTY_RES (8) // 8-bit duty resolution
#define LEDC_CLK_DIV (234 << 4) // 342 kHz duty cycle (actually 341880 Hz)
#define LEDC_TIMER_PARA_UP (1 << 25) // update LEDC timer settings
#define LEDC_INT_MASK (1 << 12)
#define LEDC_INT_FLAGS (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM)
ledc_timer_config_t t_cfg =
{
.duty_resolution = LEDC_TIMER_8_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 10000,
.clk_cfg = LEDC_APB_CLK
};
ledc_channel_config_t c_cfg =
{
.gpio_num = 1,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.duty = 0
};
static TaskHandle_t s_task_handle;
static bool callback = false;
void IRAM_ATTR ledc_cb()
{
LEDC_INT_CLR = LEDC_INT_MASK;
vTaskNotifyGiveFromISR(s_task_handle, NULL);
callback = true;
}
void app_main(void)
{
s_task_handle = xTaskGetCurrentTaskHandle();
ledc_timer_config(&t_cfg);
ledc_channel_config(&c_cfg);
printf("%ld\n", ledc_get_freq(0, LEDC_TIMER_0));
/*set LEDC signal in gpio matrix*/
GPIO_FUNC_SEL = 1;
GPIO_OUT_ENABLE = (1 << (HVCTL_PIN % 32));
esp_rom_gpio_connect_out_signal(HVCTL_PIN, 79, 0, 0);
LEDC_APB_CLK_SEL = LEDC_CLK_SEL;
LEDC_CH0_CONF0 |= LEDC_OVF_NUM | LEDC_OVF_CNT_EN;
LEDC_TIMER0_CONF = LEDC_DUTY_RES | LEDC_CLK_DIV | LEDC_TIMER_PARA_UP;
printf("%ld\n", ledc_get_freq(0, LEDC_TIMER_0));
ESP_ERROR_CHECK(esp_intr_alloc_intrstatus(45, LEDC_INT_FLAGS, LEDC_INT_ST_REG, LEDC_INT_MASK, ledc_cb, NULL, NULL));
LEDC_INT_ENA = LEDC_INT_MASK;
while(1)
{
ESP_ERROR_CHECK(ulTaskNotifyTake(pdTRUE, portMAX_DELAY));
if(callback) return;
vTaskDelay(1);
}
}