리플로우 오븐 컨트롤러예요. Cortex-M0 클론, arm-none-eabi-gcc -O2, Fedora 환경이고요. TMR3는 1 MHz로 돌아요. Update 이벤트가 1 ms tick이고, CH1은 교류 전원 zero-cross를 캡처하고, CH2 compare가 triac을 발화해요.
문제: 50 Hz에서 60초가 지나면 zc_count가 6000 정도여야 해요. 그런데 5900에서 5990 사이로 나오고, 실행할 때마다 달라요. zero-cross를 놓치면 그 반파에는 게이트 펄스가 없어서 히터 출력이 깜빡여요. UART 로그 속도를 올리면 더 심해져요.
확인한 것들:
- 스코프로 보면 zero-cross 펄스는 깨끗하고 간격도 10 ms로 일정해요. 그러니까 옵토커플러나 노이즈 문제는 아니에요.
- 카운터는 volatile이에요.
- 캡처 블록을 tick 블록 위로 옮겼어요. 손실이 덜 나기는 하는데 없어지지는 않아요.
- 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에서 base + 0x10에 있는 평범한 volatile uint32_t로 정의돼 있어요. 어쩌면 이 클론에 실리콘 quirk가 있을 수도 있는데, 타깃 밖에서는 테스트할 수 없어요. UART 카운터랑 스코프밖에 없어요.
영어에서 번역·원문 보기Reflow oven controller, Cortex-M0 clone, arm-none-eabi-gcc -O2, Fedora. TMR3 runs at 1 MHz. Update event is the 1 ms tick, CH1 captures mains zero-cross, CH2 compare fires the triac.
Problem: after 60 s on 50 Hz, zc_count should be about 6000. I get between 5900 and 5990, different on every run. A missed zero-cross means no gate pulse in that half-wave, so the heater power flickers. It gets worse when I raise the UART log rate.
What I checked:
- Scope shows clean zero-cross pulses, constant 10 ms spacing. So it is not the optocoupler or noise.
- Counters are volatile.
- Moved the capture block above the tick block. Loss is less frequent, not gone.
- Higher TMR3 interrupt priority changes nothing.
I don't get it. The datasheet says SR flags are write-1-to-clear, and I clear each flag as soon as I handle it. If a flag is set, the NVIC must enter the handler again. So how can an event with a set flag be missed?
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 is defined in regs.h as a plain volatile uint32_t at base + 0x10. Eventually the clone has a silicon quirk, but I can't test off-target. Only UART counters and the scope.