Как синхронизировать ATmega 328 Timer1, Timer2 и Timer3 при работе в режиме корректной фазы PWM и с предварительным масштабированием 1: 1

#c #timer #synchronization #arduino-uno

#c #таймер #синхронизация #arduino-uno

Вопрос:

Цель моего приложения — использовать ATMEGA328P в качестве ядра цифрового синусоидального генератора прямого синтеза на 400 Герц. Импульсы от микропроцессора отправляются на вентили четырех высоковольтных N-MOSFET транзисторов, соединенных как полноценный мост H. 16-разрядный таймер 1 использует режим WGM 10 и управляет северо-восточным и северо-западным МОП-транзисторами. 8-битные таймеры 0 и 8-битные таймеры 2 используют режим 5 и управляют МОП-транзисторами юго-востока и юго-запада соответственно. Я смог генерировать импульсы правильной ширины, но мне не удалось их правильно синхронизировать. Между импульсами Timer1 и соответствующими импульсами Timer0 и Timer2 происходит одно или два тактовых смещения.

Я не добился успеха, когда попытался компенсировать эту задержку, установив начальные отсчеты Timer0 и Timer2.

 #define CPU_FREQ 16000000UL
#define OUT_FREQ 400UL
#define SAMPLE_FREQ 40000UL
#define SAMPLE_COUNT SAMPLE_FREQ/OUT_FREQ/2
#define SAMPLE_MAX CPU_FREQ/SAMPLE_FREQ/2 - 1
#define TIMER0_MAX 255
#define TIMER2_MAX 255
#define TIMER0_DELAY 1
#define TIMER2_DELAY 1

void setupTimers() {
  cli();           // disable global interrupts;
  GTCCR = bit(TSM) | bit(PSRASY) | bit( PSRSYNC);
  setupTimer0();
  setupTimer1();
  setupTimer2();
  sei();           // enable global interrupts;
  GTCCR = 0;       
}

void setupTimer0() {
  // Waveform Generation Mode 5, PWM, Phase Correct
  // TOP = OCR0A, OCR1B updated at TOP,  TOV1 Flag set on BOTTOM
  // Set OC0B on Compare Match when up-counting.
  // Clear OC0B on Compare Match when down-counting
  // Clock Source Mode 1, No prescaling
  // OCIE0B, OCIE0A, TOIE0 interrupts disaabled
  // No Force Output Compare A or B
  // TCNT0 initial count compensation for OCR0A as TOP delay

  TCCR0A =   bit(COM0B1) |   bit(COM0B0) | bit(WGM00);
  TCCR0B = bit(CS00) | bit(WGM02) ;
  TCNT0 = TIMER0_DELAY;
  OCR0A  = SAMPLE_MAX;
  OCR0B  = nextOCR0B;
  TIMSK0 = 0;
}

void setupTimer1() {
  // Waveform Generation Mode 10, PWM, Phase Correct
  // TOP = ICR1, OCR1A and OCR1B updated at TOP,  TOV1 Flag set on TOP
  // Clear OC1A on Compare Match when upcounting.
  // Set OC1A on Compare Match when downcounting
  // Clear OC1B on Compare Match when upcounting.
  // Set OC1B on Compare Match when downcounting
  // Clock Source Mode 1, No prescaling
  // OCIE1B, OCIE1A, TOIE1 interrupts disaabled
  // No Force Output Compare A or B

  TCCR1A =  bit(COM1A1) | bit(COM1B1) | bit(WGM11) ;
  TCCR1B = bit(CS10) | bit(WGM13);
  TCCR1C = 0;
  TCNT1 = 0;
  OCR1A = nextOCR1A;
  OCR1B = nextOCR1B;
  ICR1 = SAMPLE_MAX;
  TIMSK1 = 0;
}

void setupTimer2() {
  // Waveform Generation Mode 5, PWM, Phase Correct
  // TOP = OCR0A, OCR1B updated at TOP,  TOV1 Flag set on BOTTOM
  // Set OC0B on Compare Match when up-counting.
  // Clear OC0B on Compare Match when down-counting
  // Clock Source Mode 1, No prescaling
  // OCIE0B, OCIE0A, TOIE0 interrupts disaabled
  // No Force Output Compare A or B
  // TCNT2 initial count compensation for OCR2A as TOP delay

  TCCR2A =   bit(COM2B1) | bit(COM2B0) | bit(WGM20);
  TCCR2B = bit(CS20) | bit(WGM22) ;
  TCNT2 = TIMER2_DELAY;
  OCR2A  = SAMPLE_MAX;
  OCR2B  = nextOCR2B;
  TIMSK2 = 0;
}
  

Ожидаемые результаты: синхронизированные импульсы
Фактические результаты: несинхронизированные импульсы

Ответ №1:

Методом проб и ошибок мне удалось найти комбинацию TIMER0_DELAY, TIMER1_DELAY и TIMER2_DELAY, которая решила мою проблему.