PIC18F4458 Code Read-Out: The 12-Bit ADC Trap

Two PIC18 parts, same 24 KB of flash, same 40-pin package, same USB interface — and one of them returns four times the resolution on every analogue channel. If a rebuilt board reads every sensor slightly wrong, this is the first place to look.

The PIC18F4458 carries 24 KB of program memory — 12,288 instruction words — with 2,048 bytes of SRAM, 256 bytes of data EEPROM, 35 I/O pins, a full-speed USB 2.0 interface, 48 MHz operation, and a twelve-bit ADC with thirteen channels. It belongs to the PIC18F2458/2553/4458/4553 datasheet, which is a different document from the one covering the PIC18F4455.

Four Times the Counts

A 10-bit converter returns 0 to 1,023. A 12-bit converter returns 0 to 4,095. Same input voltage, same reference, four times the number in the result register.

That number does not stay a number. It becomes a control variable. A temperature loop compares the reading against a setpoint written as a raw count. A current limit trips at a threshold written as a raw count. A pressure sensor is linearised by a constant whose units are counts per bar. Every one of those constants was chosen against a 12-bit result and is wrong by a factor of four on a 10-bit part.

The failure mode is not “the reading is garbage”. It is subtler:

  • A temperature loop settles four degrees off, and the offset is consistent
  • A current limit trips at a quarter of the rated load
  • A display shows a plausible value with the decimal point in the wrong place

All of it looks like a calibration problem, and none of it is.

Where the Justification Setting Hides

On this family the 12-bit result is split across ADRESH and ADRESL, and ADCON2 bit 7 — ADFM — decides whether the result is right-justified or left-justified. With a 12-bit converter and ADFM set, ADRESL holds bits 7 to 0 and ADRESH holds bits 11 to 8 in its low nibble.

Firmware that reads only ADRESH as a full byte gets a value in the 0 to 15 range on a 12-bit part, or 0 to 3 on a 10-bit part. Firmware that assumes the opposite justification shifts by two bits and loses the two least significant bits of a 12-bit reading, which is exactly the same result as using a 10-bit part.

This is why the recovered image has to be read as *code for this part*, not as bytes. The ADFM bit and the shift amount in the assembly are the fingerprint. If you see a right-shift by two immediately after a MOVFF ADRESL/MOVFF ADRESH pair, the source was a 12-bit device with left justification.

Why the Sibling Substitution Fails Quietly

The 4455 and the 4458 have the same flash size, the same package, the same USB block and the same pinout. A board built around either one will boot whichever part is fitted. The ADC resolution differs, and the difference does not announce itself.

For a product where the analogue path is a slow sensor, a factor-of-four error shows up as a bad reading and gets noticed. For a product where the analogue path closes a loop — motor current, heater power, LED brightness — a factor-of-four error becomes instability, and instability gets attributed to the mechanical assembly.

If you are sourcing a donor part, the checks are:

1. The marking. PIC18F4458 and PIC18F4455 are visible on the package, and they are different strings. 2. The device ID at 0x3FFFFE. Read it from the recovered dump before programming anything. 3. The datasheet family. 2458/2553/4458/4553 versus 2455/2550/4455/4550.

None of these is expensive. All three are skipped routinely.

What the File Should Contain

A 4458 delivery is the 24 KB flash image in four protection blocks, the twelve configuration bytes at 0x300000, the 256 bytes of EEPROM at 0xF00000, and the device and revision IDs. The code protection note should say which blocks were locked, because on a USB design the descriptors frequently sit in block 0 and the application above it — so a one-block read can hand you a device that enumerates and does nothing else.

The other 12-bit member worth knowing in this family is the PIC18F4523, which is the same converter type on a non-USB die. If the board has no USB connector but the analogue readings behave the way this article describes, the source part may be that one.

Reading firmware out of a USB board is routine, and the read the firmware page covers the general sequence. What is specific to the 4458 is that the analogue constants are as much a part of the product as the code, and they only make sense against a known converter width. Say which part is on the board when you send the photograph, and the contact us page will route it correctly.