Blank chip, my code running, display lighting up. Time to weld. Except the timing was wrong — a 3-second test pulse took over 12 seconds — and the zero-cross timer read out nonsense.
I had no debugger. What I had was a 4-digit 7-segment display, so I built a test mode that shows raw register values in hex and jumps between them with the encoder. The chip told me its own story, one register at a time.
The root cause of everything: the register-reference markdown I started from had OCR errors in the timer chapter's bit tables. Six bugs fell out of it:
- 4× slow milliseconds. The time-base timer divider was one setting off (fcgck/2¹² instead of /2¹⁰). Every duration in the firmware ran 4× long. This alone was the original "welds take forever" symptom.
- The microsecond timer was never clocked. The peripheral clock-enable bit for the 16-bit timer is bit 0 of the power register — the excerpt said bit 2. Writes to the timer's own registers were silently ignored because the block had no clock.
- The boot ROM leaves that timer running. After every flash cycle the bootloader had configured the timer for its baud detection and left it going — and its mode register is write-locked while running. Fix: stop the timer before configuring it.
- Wrong timer mode. The mode register's bit fields were laid out differently than the excerpt claimed; my "timer mode, 1 MHz" value was actually selecting external-trigger mode. The chip's own boot-ROM code, quoted elsewhere in the real datasheet, gave the correct value.
- Auto-capture bit in the wrong place. The feature that lets you read the live counter is a different bit than documented — I found the truth by pulling the register table out of the datasheet PDF using the word x-coordinates, since the plain-text extraction was ambiguous.
- Interrupt enables in the wrong register. Two interrupts (the µs timer and the zero-cross input) had their enable bits placed in the wrong of two enable registers. Neither ever fired. A simple formula — bit = (0xFFFE − vector)/2, split across two registers — got both right.
Each fix, the display showed a little more life: a counter that finally
counted, an overflow tally that finally incremented. When the last one
landed, timer_us() was accurate to the microsecond and the 3-second
pulse took exactly 3 seconds.
Lesson filed under "trust the primary source": the official PDF was correct all along; a well-meaning transcription of it cost a day.
wichers
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.