回流焊炉控制器,Cortex-M0 兼容芯片,arm-none-eabi-gcc -O2,Fedora。TMR3 跑在 1 MHz。更新事件是 1 ms 的 tick,CH1 捕获市电过零,CH2 比较输出触发 triac。
问题是,50 Hz 下跑 60 s 后,zc_count 应该在 6000 左右。实际每次都不一样,在 5900 到 5990 之间。漏掉一次过零,这个半波就没有门极脉冲,加热功率就会闪烁。提高 UART 日志速率会更严重。
我已经检查过这几项。
- 示波器显示过零脉冲干净,间隔恒定 10 ms。所以不是光耦或噪声的问题。
- 计数器都是 volatile。
- 把捕获块挪到 tick 块前面。丢失变少了,但没有消失。
- 提高 TMR3 中断优先级,没有任何变化。
我想不通。数据手册说 SR 标志是写 1 清零,我也是处理完每个标志就立刻清掉。只要标志置位,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。说不定这个克隆芯片有硅片层面的缺陷,但我没法脱离目标板测试。只有 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.