PIC18F4331 Firmware: The Calibration Is Not in the Flash

The PIC18F4331 is not a general-purpose part. It ships with a power-control PWM module, a quadrature encoder interface and a 200 ksps ADC, which means almost every design built on it is driving a motor. And in motor control, the code is the smaller half of the design — the tuning constants are the part that took the engineer six weeks.

The device carries 8 KB of flash — 4,096 instruction words — plus 768 bytes of SRAM, 256 bytes of EEPROM, 36 I/O pins and a nine-channel 10-bit ADC. It runs to 40 MHz and shares datasheet DS39616 with the 2331, 2431 and 4431.

Read the Peripheral Map First

Before looking at a single instruction, the peripheral set tells you where the design keeps its numbers.

A power-control PWM block with complementary outputs and a dead-time generator is configured through a small set of registers — period, duty for each channel, dead-band, fault input. The firmware writes those either from immediates compiled into the image or from values it loads at boot. The distinction is everything: an immediate comes out with the read, a loaded value does not.

The quadrature encoder interface splits the same way: its position counters are hardware, but the counts-per-revolution scaling, the direction inversion and the index alignment are parameters — as is the current-sense scale, which depends on a shunt resistor on the customer’s board, not on anything inside the chip.

Where a Motion Design Actually Keeps Its Numbers

Region Address Size Typical contents here
Program flash 0x000000 8 KB Control loop, PWM setup, state machine
Config words 0x300000 14 bytes Oscillator mode, brown-out, watchdog, protection
Data EEPROM 0xF00000 256 bytes Gains, offsets, pole pairs, serial number, run hours
Last flash page top of 0x001FFF 64 bytes Sometimes used as EEPROM extension by the bootloader

The EEPROM row is the one that decides whether a clone works. Two hundred and fifty-six bytes is not much storage, which is why a production line writes the *result* of calibration there rather than a log: the current-loop gain measured on the bench, the zero offset of each phase, the encoder alignment, and the fault thresholds trimmed so the unit would pass its end-of-line test.

None of that is derived from the code. It is measured per unit, and it exists nowhere else.

8 KB Is Only Two Protection Blocks

The flash array is protected in 4 KB blocks, and an 8 KB part has two of them: CP0 covering 0x0000–0x0FFF and CP1 covering 0x1000–0x1FFF, both bits sitting in CONFIG5L at 0x300008.

That granularity has a specific failure mode. If a designer set CP0 and left CP1 clear — common when protection is added late and only the first bit is ticked — the upper 4 KB reads back normally. A supplier who stops there hands over half an image that contains the register definitions and the interrupt structure but not the lookup tables, and it assembles into something that looks complete.

Full-array copy protection closes that door, and the only route left is semi-invasive work on the die itself.

What a Clone Without the Calibration Does

It powers up cleanly, which is the deceptive part. The PWM starts, the encoder counts, the state machine advances. Then one of three things happens on the first real ramp: the motor turns the wrong way because the direction bit was calibrated per unit rather than fixed in code; the current loop oscillates because the gain it loaded was a default of zero; or the bridge shoots through because the dead-time the firmware wrote was tuned to a different gate driver than the one on this board.

All three read as hardware faults, and none of them are.

What to Ask For

The deliverable for this part is flash plus config words plus the full 256 bytes of EEPROM, and it should be delivered as Intel HEX with all three regions present so nothing is silently dropped in a converter. Two independent reading passes that agree on checksum are worth more than one careful pass.

A photograph of the board is worth as much as the file. The shunt value, gate driver part number and crystal frequency are on the silkscreen, and they let the recovered constants be cross-checked against the hardware they were tuned for — routine in reading the firmware from control boards.

If the unit in hand is the older PIC18F4320 instead, the approach is the same but the peripheral map is not: that part has no power-control PWM, so a file from one will not run on the other.

Send the marking photograph and the board picture together and the job can be scoped before anything is quoted; the services page lists what each route includes.