Контроллер reflow-печи, клон Cortex-M0, arm-none-eabi-gcc -O2, Fedora. TMR3 работает на 1 МГц. Update event — тик 1 мс, CH1 захватывает переход сетевого напряжения через ноль, сравнение CH2 запускает симистор.
Проблема: после 60 с на 50 Гц zc_count должен быть около 6000. У меня получается от 5900 до 5990, при каждом запуске по-разному. Пропущенный zero-cross значит, что в этой полуволне нет импульса на управляющий электрод, и мощность нагревателя мерцает. Становится хуже, когда я повышаю частоту логов по UART.
Что я проверил:
- Осциллограф показывает чистые импульсы zero-cross, интервал постоянный, 10 мс. Так что это не оптрон и не шум.
- Счётчики volatile.
- Перенёс блок capture выше блока тика. Потери стали реже, но не пропали.
- Более высокий приоритет прерывания TMR3 ничего не меняет.
Не понимаю. В даташите сказано, что флаги SR сбрасываются записью единицы (write-1-to-clear), и я сбрасываю каждый флаг сразу, как обработал его. Если флаг установлен, NVIC должен снова войти в обработчик. Так как может потеряться событие с установленным флагом?
void TMR3_IRQHandler(void)
{
uint32_t sr = TMR3_SR;
if (sr & TMR_SR_UIF) {
TMR3_SR |= TMR_SR_UIF;
tick_ms++;
if ((tick_ms % 500u) == 0)
log_due = 1;
}
if (sr & TMR_SR_CC1IF) {
TMR3_SR |= TMR_SR_CC1IF;
zc_count++;
zc_stamp = TMR3_CCR1;
TMR3_CCR2 = (zc_stamp + fire_delay_us) & 0xFFFFu;
}
if (sr & TMR_SR_CC2IF) {
TMR3_SR |= TMR_SR_CC2IF;
TRIAC_ON();
}
}
SR определён в regs.h как обычный volatile uint32_t по адресу base + 0x10. В конце концов, возможно, у клона есть кремниевый баг, но проверить без железа я не могу. Только счётчики по UART и осциллограф.