PIC18F4610: No Data EEPROM, So the Parameters Live in Flash

Half the read requests that arrive for this part include the line “and the EEPROM, please”. There is no EEPROM. The PIC18F4610 has zero bytes of data EEPROM, and every setting it stores is sitting inside the 64 KB array instead.

The PIC18F4610 is a 40-pin member of the PIC18F2515/2610/4515/4610 family, DS39636. It has 64 KB of program memory as 32,768 words, 3,968 bytes of RAM, thirteen 10-bit ADC channels, two comparators, four timers, a parallel slave port on the 4X1X devices, and a 40 MHz core delivering 10 MIPS. What it does not have is data EEPROM — the parameter table in the datasheet reads zero, not 256 and not 1,024.

The Consequence Nobody Plans For

On a part with EEPROM, the recovery problem splits cleanly: read the flash for the code, read the EEPROM for the settings. Two memories, two failure modes, two protection bits.

On a 4610 there is one memory. Calibration offsets, serial numbers, run-hour counters, the tuned constants of a control loop — all of it is stored as flash rows, either written at production and never touched, or rewritten by the application’s own self-programming routine. There is no separate region to ask for, and no separate region to lose.

That makes a 64 KB dump more valuable than the same dump from a part with EEPROM: it is the entire state of the device. It also makes a partial dump more damaging, because there is no second memory to fall back on.

64 KB in Four Blocks

Block Byte range Words Bit
0 0x000000–0x003FFF 8,192 CP0
1 0x004000–0x007FFF 8,192 CP1
2 0x008000–0x00BFFF 8,192 CP2
3 0x00C000–0x00FFFF 8,192 CP3

The bits are in CONFIG5L at 0x300008. Note the shape of this problem: the parameter rows that a self-writing application keeps are usually placed at the very top of the array, in the last block, and that is frequently the block a vendor protects. The part of the image a rebuild depends on most is the part most likely to be locked, and on a 4610 there is nowhere else to look for it.

Reading a Worn Row

Flash on this family is rated for 10,000 erase/write cycles per row, against a million for real EEPROM. An application that writes a counter once a minute will pass ten thousand cycles in a week of continuous operation, and a device that has been in the field for five years may hold rows that are marginal — programmed, but with cells that no longer read back cleanly at the margins.

When such a row is read, the value that comes out can be off by one bit, and one bit is enough to turn a calibrated gain constant into a wrong one. If the image is being taken from a working board, read the parameter rows twice and compare. A difference between passes is information about the silicon, not about the tool.

The Sibling With EEPROM

The PIC18F4620 shares the package, the pin count and the 64 KB array, and it comes from a different datasheet, DS39626, because it has 1,024 bytes of data EEPROM. Two parts, same outline, same flash size, and completely different parameter story.

This matters when a board is being rebuilt from spares. A 4620 dropped into a 4610 socket runs the flash you give it, but if that firmware expects EEPROM-backed parameters, there is no EEPROM behind them. The first write disappears, and the unit comes back from a power cycle with defaults. The fix is in the firmware, not in the copy, and it is better to know before the board is built.

The PIC18F4515 is the 48 KB member of the same datasheet, with the same zero-byte EEPROM line and the same quartered array.

What a Complete File Looks Like

For this part, completeness means: the array from 0x000000 to 0x00FFFF, the configuration block from 0x300000 to 0x30000D, and the device ID at 0x3FFFFE. Nothing else exists to include.

Two checks are worth running before the file is used. First, disassemble across 0x3FFF, 0x7FFF and 0xBFFF: a branch that lands mid-instruction at one of those seams means a word was dropped between blocks. Second, look for a zero run that starts and ends on a 16 KB boundary — that is a locked block, not empty flash, since erased words read 0xFFFF and 0x0000 decodes as NOP.

The reading the program memory page describes how the array and configuration regions are captured. If the file you have is short, or one quarter reads uniform, the services page sets out what the die-level route adds.