Таймеры ESP32 — контроллер выходит из строя при частоте выше 240 кГц, рабочий цикл становится нестабильным

Я пытаюсь сгенерировать три синхронизированных сигнала на ESP32 для устройства, требующего точной синхронизации. Однако при увеличении частоты выше 240 кГц контроллер зависает, а скважность сигналов становится крайне нестабильной.

неустойчивый рабочий цикл

неустойчивый рабочий цикл

Требуемые сроки следующие:

  1. MainClock: прямоугольный сигнал с частотой 1–2 МГц или выше.
  2. SH должен перейти в высокий уровень с задержкой от 100 до 1000 нс после ICG
  3. SH должен оставаться высоким в течение как минимум 1000 нс.
  4. ICG должен быть высоким, когда MainClock высокий

Пока что я застрял на первой точке, чтобы получить стабильные 2 МГц...

    #include "Arduino.h"

    #define MCLK_PIN 25 // MCLK (главный тактовый генератор) для CCD GPIO.out ^= (1 << MCLK_PIN);
    
    volatile int interruptCounter; // для подсчета прерываний
    int totalInterruptCounter;     // общий подсчет прерываний
    hw_timer_t *timer = NULL;      // Определение аппаратного таймера (Указатель на структуру)
    portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
    
    void IRAM_ATTR onTimer()
    { // Определение функции прерывания с помощью IRAM_ATTR для более быстрого доступа
      portENTER_CRITICAL_ISR(&timerMux);
      interruptCounter++;
      GPIO.out ^= (1 << MCLK_PIN); // инвертировать состояние MCLK_PIN
      portEXIT_CRITICAL_ISR(&timerMux);
    }
    
    unsigned long prescaler = 2; // если делитель HW TIMER выходит за пределы диапазона [2, 65536] ошибка
    unsigned long timerValue = 162;
    
    void setup()
    {
      Serial.begin(115200);
      pinMode(MCLK_PIN, OUTPUT);
    
      timer = timerBegin(1, prescaler, true);      // таймер 0, предделитель: 40, счет вверх
      timerAttachInterrupt(timer, &onTimer, true); // Присоединить прерывание
      timerAlarmWrite(timer, timerValue, true);    // Соответствует значению = 1000000 для задержки в 1 секунду.
      timerAlarmEnable(timer);                     // Включить таймер с прерыванием (Alarm Enable)
    }
    
    unsigned long lastTime = 0, currentTime = 0;
    float frequency = 0, period = 0;
    
    void loop()
    {
      if (interruptCounter > 0)
      {
        portENTER_CRITICAL(&timerMux);
        interruptCounter--;
        portEXIT_CRITICAL(&timerMux);
    
        totalInterruptCounter++;
    
        period = (timerValue * prescaler) / 80.0;
        frequency = 1000.0 / period;
        if (millis() > currentTime)
        {
          lastTime = currentTime;
          printf("An interrupt has occurred. Total number: %d\n", totalInterruptCounter);
          printf("Frequency: %.2f kHz\n", frequency);
          printf("Period: %.2f µs\n", period);
          currentTime = millis() + 1000;
        }
      }
    }

В чём причина этой нестабильности? Какие методы можно использовать для повышения стабильности?

РЕДАКТИРОВАТЬ

Если я попытаюсь сделать это с помощью ledc, прерывание тоже не будет работать должным образом :(

#include <Arduino.h>
// Расчет настроек для каждой полосы частот
// Разрешение = log2(Частота(80 МГц)/f) + 1 например: 50,000 Гц = 80,0000/50,000 = 1,600 log2(1600) = 10 + 1 = 11
// Обязанность 50% = (2**Разрешение)/2 например: 2**11 = 2048 2048/2 = 1024

#include "driver/ledc.h"

#define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0 // канал LEDC 0
#define LEDC_HS_MODE LEDC_HIGH_SPEED_MODE  // LEDC на высокой скорости
#define LEDC_HS_TIMER LEDC_TIMER_0         // Использовать timer0ledc

#define MCLK_PIN 25 
#define SH_PIN 26


uint32_t resolution = 0;      // Разрешение var
uint32_t oscilator = 2000000; // Частота Гц
uint32_t mDuty = 0;           // Вычислить нагрузку ledc var


volatile int counter = 0;

void IRAM_ATTR onFallingEdge() {
    counter++;
    if (counter >= 4) { // 4 падающих ребра
      GPIO.out ^= (1 << SH_PIN);  // Інверсія стану
        counter = 0;
    }
}
//-----------------------------------------------------------------------
void ledcInit()
{
  resolution = log((80000000 / oscilator) + 1) / log(2); // Расчет разрешения светодиода
  if (resolution > 20)
    resolution = 20;                // Максимальное разрешение 20
  mDuty = (pow(2, resolution)) / 2; // Расчет коэффициента заполнения ledc 50%
  // Serial.println(mDuty); // Печать

  ledc_timer_config_t ledc_timer = {}; // Создаём экземпляр таймера LEDC

  ledc_timer.duty_resolution = (ledc_timer_bit_t) + resolution; // Разрешение конфигурации
  ledc_timer.freq_hz = oscilator;                               // Частота
  ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;                 // Рабочий режим: высокая скорость
  ledc_timer.timer_num = LEDC_TIMER_0;                          // Используем таймер0
  ledc_timer_config(&ledc_timer);                               // Конфигурация таймера ledc

  ledc_channel_config_t ledc_channel = {}; // Создает экземпляр конфигурации канала LEDC

  ledc_channel.channel = LEDC_HS_CH0_CHANNEL;     // Конфигурация канала
  ledc_channel.duty = mDuty;                      // Расчет пошлины %
  ledc_channel.gpio_num = MCLK_PIN;               // Выходной GPIO
  ledc_channel.intr_type = LEDC_INTR_DISABLE;     // Отключено прерывание светодиода
  ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; // Работает на высокой скорости
  ledc_channel.timer_sel = LEDC_TIMER_0;          // Используем таймер0

  ledc_channel_config(&ledc_channel); // Конфигурация канала ledc
}
//-----------------------------------------------------------------------
void setup()
{

  Serial.begin(115200);
  pinMode(SH_PIN, OUTPUT);
  ledcInit();
  attachInterrupt(digitalPinToInterrupt(MCLK_PIN), onFallingEdge, FALLING);
}
//-----------------------------------------------------------------------
void loop() {}

, 👍0

Обсуждение

Вы измеряли время выполнения вашего ISR? Пожалуйста, [отредактируйте] свой вопрос, добавив это. Скорее всего, ваш ISR использует все тактовые частоты процессора на этой частоте, и это вызывает наблюдаемое поведение., @the busybee


1 ответ


0

По моему опыту, он не справляется с высокочастотным взаимодействием. В вашем случае, похоже, вы переусердствовали с его технической стороной. Возможно, стоит просто использовать аппаратные средства, например, делители тактовой частоты, для формирования сигнала.

,