ATmega640PV: Binary Dumps, Offsets, and the Missing Addresses
A binary dump is a sequence of bytes and nothing else. It carries no addresses, no record boundaries, no checksum, and no end marker. Everything that makes the file interpretable comes from outside it: an assumed start offset, an assumed length, and an assumption that no region in between was skipped.
Those assumptions are usually correct. When they are not, the file is not obviously wrong — it is wrong in a way that shifts everything after the error by a fixed amount, which is the failure mode that consumes the most time.
Three assumptions, three ways to be wrong
Start offset. The internal flash begins at address zero. A dump taken with the tool’s default offset usually starts there. A dump taken after a partial read may not, and a file that begins mid-page will disassemble into plausible nonsense that never quite makes sense.
Length. The file’s length should equal the die’s flash size. A shorter file means the read stopped early; a longer one means the tool padded to a configured size. Padding with FF and truncating a real read look identical in a hex viewer.
Continuity. A binary implies that byte n follows byte n-1 in the address space. If the tool skipped a page because it failed verification, the file contains no signal of that — the skipped page simply is not there, and every subsequent byte is at the wrong address.
| Assumption | How it fails | How to check |
|---|---|---|
| Start offset | File begins mid-page | Decode the first word |
| Length | Truncated or padded | Compare with die size |
| Continuity | A page was skipped | Read page by page with addresses |
The third is the one worth guarding against actively, and the guard is to build the dump page by page with an explicit address for each page, then assemble the binary from verified pages rather than from a single streaming read.
Why the vector table is the alignment check
Every AVR image begins with a vector table: a reset vector at address zero followed by interrupt vectors, usually a fixed number of bytes apart. On this family the reset vector is a jump instruction, and a jump instruction has a recognisable encoding in the first word and a target in the following word.
That structure is a powerful alignment test. If the file is correctly aligned, the first word decodes as a jump and the second word points somewhere inside the code region. If the file is off by one byte, the first word decodes as garbage that does not exist in the instruction set.
So the first four bytes of the file tell you whether the offset is right, before any interpretation of content. That check costs seconds and catches the most common offset error.
The P and V suffixes and the read itself
Neither suffix changes the file format. Both change the electrical envelope: P for the picoPower die with its revised oscillator and lower sleep current, V for the extended low-voltage range.
What they change for a binary dump is the probability of a silent page error. A dump assembled from a marginal read contains bytes that were sampled before the bus settled, and a binary gives you no checksum to notice with. A hex file at least fails its per-line checksum; a binary just looks like data.
The practical consequence: when the tool produces a binary, the verification has to be built in. Read each page twice, compare, and only append when they match. A page that never matches is a page to investigate, not to average.
What the file cannot tell you
Three things are structurally absent from any binary of the flash:
- The fuse byte. Clock source, start-up delay, boot section size, interface enables. Without it, the image may be applied to a blank part that then fails to start.
- The lock byte. Current protection state, which is not content.
- The EEPROM. A separate array, addressed separately, and not part of a flash dump even though it often holds the values that make the product work.
A binary that is passed on without those three is a partial recovery, regardless of how cleanly it disassembles.
Reconstructing confidence
The sequence that produces a binary worth trusting:
- Read the signature. Confirms which member of the family and therefore how much of the map is real.
- Read the fuse and lock bytes and record them alongside the file, not separately.
- Read page by page, twice, with an explicit address for each page.
- Assemble from verified pages only, and log any page that failed verification.
- Disassemble the first word and confirm it is a jump into the code region.
- Disassemble the last page and confirm it is not an artefact of padding.
Step 6 is the one people skip. A file padded to a round length ends in FF, which decodes as an invalid instruction. That is expected. A file that ends in valid-looking code is telling you the real length is shorter than the file.
Related notes
- ATmega640P and complete hex files — the same content in a container that carries addresses.
- ATmega640 and the external bus — the case where the internal image is not the whole program.
- ATmega324PA and marginal reads — why two passes are not optional.
FAQ
Is a binary smaller than a hex of the same data? Yes, roughly half, because it omits the address and checksum text. The size difference is not a sign of missing content.
Can a binary be converted to hex later? Yes, given a start offset. That conversion is the point at which the missing address information is restored — but the offset must be right, or every address in the resulting file is wrong.
Why does padding matter? Because padding and truncation are indistinguishable in a hex viewer. The only way to tell is the instruction encoding at the boundary.
Is the EEPROM in the binary if the tool was configured to include it? Possibly, at a separate offset, which the binary does not record. Never assume; read it explicitly.
Conclusion
A binary dump is a claim about ordering with no evidence attached. The address, the length, and the continuity are all supplied by the tool and none of them is checkable from the file. Building the dump page by page with explicit addresses, verifying twice, and testing the first instruction’s encoding turns the claim into something that can be relied on.
PIC24FJ16GA002: The Phantom Byte in Every Instruction
Instructions on this architecture are twenty-four bits wide, and memory is organised in thirty-two-bit slots for convenience. The unused eight bits are not missing data — they are padding, and they are zero.
The convention exists because a byte-addressable file format cannot express a twenty-four-bit unit cleanly. Every instruction therefore occupies four bytes in a hex file, the first three carrying the opcode and the fourth carrying nothing.
Why this matters immediately
A hex file that looks like it has a quarter more content than the instruction count suggests is correct. Four bytes per instruction is the storage, three bytes is the information.
The practical consequences:
A dump is larger than expected. Sixteen kilobytes of flash is not sixteen thousand bytes of instruction if the array is organised in instruction slots.
Every fourth byte is 00. A pattern of three meaningful bytes followed by a zero repeats throughout the image. That regularity is a strong confirmation that the read is aligned.
Misalignment is easy to detect. If the zeros appear at the wrong position in the repeating group, the file is shifted, and everything after it disassembles incorrectly.
| Stored as | Bytes | Contains |
|---|---|---|
| Instruction word | 4 | 3 bytes of opcode, 1 padding byte |
| Data table | variable | no padding |
| Configuration | separate | read through its own mechanism |
Alignment as the first check
Because of the padding, alignment is verifiable without understanding a single instruction. Look for the recurring zero at a fixed position in every four-byte group. If it is there, the image is aligned. If it is not, the file is shifted or the read started at an odd address.
That check takes seconds and it prevents the entire class of errors that follow from a one-byte shift, which on this architecture is severe: a shifted image produces instructions that do not exist, and a disassembler will happily render them as something plausible.
Data does not follow the convention
Constant tables in program memory do not pad. They are stored as bytes, and a table can occupy any number of bytes, which means the padding convention stops at the boundary between code and data.
That boundary is therefore visible: a region with the regular three-and-one pattern is code, and a region without it is data. Finding where the pattern stops is a fast way to locate the constant tables, which is usually the objective.
Reading the reset path
The vector table occupies the first instructions, and on this family the reset vector is a jump whose target is a word address. Reading it establishes where the code begins, and confirming that the three-and-one padding pattern continues past the target confirms the alignment through the whole region.
From there, the disassembly proceeds with a known instruction width. The two-word forms exist here as well, so instruction width must still be checked at branches rather than assumed.
Configuration and protection
As on every architecture, the oscillator selection and the code protection bits live in configuration registers outside the program array. They are read separately, they are absent from the hex file, and they decide whether a restored image will start.
The protection model is the same in principle as everywhere else: enforcement at the programming interface, execution unaffected. A protected part runs normally and refuses to be read, and the operation that clears protection erases the array.
Reading order
- Device identifier and configuration, recorded first.
- Program array read, verified per region.
- Alignment check: confirm the padding byte position.
- Reset vector, then disassembly with width checked at branches.
- Locate the transition from padded code to unpadded data.
Step 5 is the deliverable that makes the rest useful, because the unpadded region is where the tables are — and on a device of this size, the tables are usually the product.
Related notes
- PIC18F4620 and word addressing — the same family’s other addressing model.
- PIC18F2550 and protection blocks — how the other Microchip family partitions its protection.
- ATmega8A and lock modes — protection in a different architecture.
FAQ
Is the fourth byte always zero? By convention, yes. A non-zero value there indicates either a different storage convention or a misread.
Can the padding be stripped? For disassembly, yes, and it should be. For archival, no — keep the file as read.
Does data memory use the same layout? No. Data is byte-addressed without padding.
Why not store twenty-four bits densely? Because the memory is organised in wider slots for access speed.
Conclusion
The phantom byte is a convention, not content, and it turns alignment into a check that costs nothing. Three meaningful bytes and a zero, repeated, is code; the absence of that pattern is data. Reading the padding position before anything else is what keeps the whole image from sliding by a byte.
Recover MCU PIC16F77 Eeprom
The PIC16F77 microcontroller is a powerhouse of versatility within legacy industrial and commercial electronics, prized for its expansive input/output pin layout, dual capture/compare/PWM modules, and high-performance RISC architecture. This highly capable embedded controller serves as the central processing core in heavy-duty factory automation systems, HVAC control units, commercial vending machinery, and complex telecommunication routing hardware.

What sets this specific chip apart is its ability to handle dense, real-time operating parameters alongside a robust internal flash memory array and critical eeprom storage zones, which often hold unique calibration metrics, system runtime data, and cryptographic variables. Because these settings are fundamental to the host machine’s identity and function, manufacturers invariably engage the chip’s rigid, protective security fuses. Consequently, the chip operates in a permanently locked or encrypted environment, keeping the proprietary programming secured against direct read attempts or external tampering.

Program Memory Organization:
The PIC16F7X devices have a 13-bit program counter capable of addressing an 8K word x 14-bit program memory space. The PIC16F77/76 devices have 8K words of FLASH program memory and the PIC16F73/74 devices have 4K words. The program memory maps for PIC16F7X devices are shown in Figure 2-1. Accessing a location above the physically implemented address will cause a wraparound. in the PICmicro Mid-Range Reference Manual.

The 28-pin devices have 11 interrupts, while the 40/44-pin devices have 12
· The 28-pin devices have 5 A/D input channels, while the 40/44-pin devices have 8
· The Parallel Slave Port is implemented only on the 40/44-pin devices

The RESET Vector is at 0000h and the Interrupt Vector is at 0004h;
Each bank extends up to 7Fh (128 bytes). The lower locations of each bank are reserved for the Special Function Registers. Above the Special Function Registers are General Purpose Registers, implemented as
static RAM. All implemented banks contain Special
Function Registers. Some frequently used Special

Function Registers from one bank may be mirrored in
another bank for code reduction and quicker access. implemented address will cause a wraparound. in the PICmicro Mid-Range Reference Manual

The 28-pin devices have 11 interrupts, while the 40/44-pin devices have 12
· The 28-pin devices have 5 A/D input channels, while the 40/44-pin devices have 8
· The Parallel Slave Port is implemented only on the 40/44-pin devices.
When an industrial facility or hardware engineering team encounters a critical system failure paired with a complete loss of the original source code or project archive, our dedicated laboratory provides a vital lifeline to recover MCU PIC16F77 eeprom allocations and firmware. Overcoming the integrated security flags of an obsolete microcontroller requires a sophisticated blend of material science and micro-electronics engineering. Our specialists approach this task by utilizing a highly precise physical methodology: we carefully decapsulate the resilient plastic package using controlled chemical or mechanical etching to bring the microscopic silicon die into view. Once the internal micro-structures are accessible, engineers can decode the physical state of the memory cells and attack the embedded security lock bits. By understanding the chip’s internal layout, we can safely break past the hardware-level restrictions, allowing us to hack the read-protection barriers, retrieve the uncorrupted binary data, and extract the complete heximal file flawlessly.

The core purpose of this micro-engineering intervention is to safeguard industrial longevity and eliminate the astronomical costs associated with unplanned system redesigns. When a vital piece of production equipment goes offline due to a corrupted or inaccessible chip, trying to rewrite the original program from scratch can take months of speculative engineering. Our technical services allow clients to seamlessly duplicate or clone the exact operational parameters of the failing device onto replacement hardware. The major benefit for the end user is a fast, non-destructive, and predictable restoration pathway that breathes new life into obsolete infrastructure. By transforming an unreadable, protected microcontroller into a fully accessible data asset, we ensure your daily business operations continue smoothly, entirely insulated from the threat of hardware obsolescence.

ATmega640P: Three Ways In, and the Fuse That Removes One
A microcontroller with a lot of pins can afford more than one programming interface, and this family does. There is serial programming over the SPI pins, there is JTAG over four dedicated pins, and there is the high-voltage parallel mode that every AVR supports as the last resort.
Three doors, three different sets of conditions, and a fuse that can close one of them for a reason that has nothing to do with security.
The three interfaces, compared
| Interface | Pins used | Closed by | Can it clear lock bits |
|---|---|---|---|
| Serial ISP | Reset, SCK, MOSI, MISO | SPIEN unprogrammed, RSTDISBL set | no |
| JTAG | TCK, TMS, TDI, TDO, Reset | JTAGEN unprogrammed, lock mode 2 | no |
| Parallel (HVPP) | Reset plus the data and control bus | nothing, always available | no |
The last column is the important one and it is the same for all three: no interface clears lock bits without an erase. The interfaces differ in how you get in, not in what you are allowed to do once inside.
The JTAG fuse is a pin-count decision
JTAG occupies four pins. On a part where those four pins are also port pins with useful peripherals behind them, a designer counting pins will disable JTAG to get four GPIOs back. The fuse is called JTAGEN and it is programmed by default — enabled — so disabling it is a deliberate act.
The result is a device that can only be entered over serial programming. That is usually fine, until the same designer also needs the reset pin as an output and sets RSTDISBL. Then both convenient doors are closed and only the parallel interface remains.
None of that is defensive design. It is pin budgeting, and it produces a configuration that looks deliberate from the outside.
What JTAG offers that ISP does not
For examination purposes JTAG has one genuine advantage: it can halt the core and inspect registers and memory while the firmware runs. On an unlocked part that is a far more informative view than a static dump, because it shows what the code does rather than what it says.
Two caveats. The debug capability is gated by the lock bits — in mode 2 the JTAG programming interface is still reachable enough to erase, but the debug access is gone. And the on-chip debug system has its own enable fuse on some members, separate again from JTAGEN.
So “the part has JTAG” is not the same as “the part can be debugged”. The fuse byte decides, and it decides separately for programming and for debugging.
Why the parallel interface always survives
The parallel interface exists because a factory needs a way to program a part whose serial interface might be disabled by a mistake in the fuse settings. It is the recovery path for the fuse byte itself: a part with SPIEN off and JTAGEN off can still be reached in parallel mode, and the fuses can be restored.
It is also the only interface that works on a completely blank part with no clock configured, which is why it is used in production programming rather than serial programming for high volume.
What it does not do is bypass protection. A parallel programmer reads the lock byte, sees mode 2, and behaves exactly as the serial one would: it can erase, and the erase takes the contents.
Establishing which doors are open
Before any read attempt, four cheap measurements:
- Supply at the socket, at the design rail.
- Signature over whichever interface responds. If serial fails, try JTAG before concluding anything.
- Fuse byte. SPIEN, JTAGEN, RSTDISBL — three bits that explain most “no device” reports.
- Lock byte. Determines whether a read is even permitted.
Only after those four is a decision about the memory meaningful. Skipping them produces a conclusion about the die that is really a conclusion about the wiring.
The interpretation trap
A part that responds to signature reads but refuses flash reads is locked. A part that responds to nothing is unpowered, miswired, or fuse-disabled. Those are different problems with different costs, and the same programmer error message covers both.
The distinguishing observation is the fuse read. If the fuse read succeeds, the interface works and the lock byte is the obstacle. If the fuse read fails too, the interface itself is closed or the connection is wrong — and the fuse byte, ironically, is the only thing that could tell you which.
That circularity is why the parallel interface exists, and why it is worth having an adapter for it before a locked device arrives rather than after.
Related notes
- ATmega640 and the external bus — the other thing that can make an image incomplete.
- ATmega640PA and the erase threshold — what happens to an erase at low voltage.
- ATmega644PA and RSTDISBL — the fuse discussed above, in detail.
FAQ
Which interface should I try first? Serial, because it needs the fewest connections. Then JTAG if the part has it and a fuse read is refused. Parallel only when both fail.
Can JTAG be used to read flash on a locked part? No. Debug access is removed by the lock bits; JTAG remains useful only to reach the erase command.
Does disabling JTAG improve security? Marginally, by removing a debug path. It is almost always done to recover four pins, not to protect anything.
Is the parallel adapter worth owning? If you regularly receive parts whose fuse history is unknown, yes. It is the only interface that cannot be closed by a fuse.
Conclusion
Three interfaces, three closure conditions, one shared constraint: none of them bypasses the lock byte. The practical work is establishing which doors remain open before drawing any conclusion about the die, and the fuse byte is the only measurement that answers it — which is exactly why a parallel adapter earns its place on the shelf.
Recover MCU PIC16F73 Binary
Recover MCU PIC16F73 Binary from flash memory and data extracted from eeprom memory of Microcontroller, reprogramme the firmware into blank MCU PIC16F73 for Microprocessor cloning;

Recover MCU PIC16F73 Binary from flash memory and data extracted from eeprom memory of Microcontroller, reprogramme the firmware into blank MCU PIC16F73 for Microprocessor cloning
High Performance RISC CPU:
· High performance RISC CPU
· Only 35 single word instructions to learn
· All single cycle instructions except for program branches which are two-cycle
· Operating speed: DC – 20 MHz clock input DC – 200 ns instruction cycle
· Up to 8K x 14 words of FLASH Program Memory, Up to 368 x 8 bytes of Data Memory (RAM)
· Pinout compatible to the PIC16C73B/74B/76/77
· Pinout compatible to the PIC16F873/874/876/877
· Interrupt capability (up to 12 sources)
· Eight level deep hardware stack
· Direct, Indirect and Relative Addressing modes
· Processor read access to program memory
Special Microcontroller Features:
· Power-on Reset (POR)
· Power-up Timer (PWRT) and
Oscillator Start-up Timer (OST)

unlock PIC16F73 microprocessor fuse bit and open mcu flash memory and eeprom memory to readout heximal program and binary data
· Watchdog Timer (WDT) with its own on-chip RC oscillator for reliable operation
· Programmable code protection
· Power saving SLEEP mode
· Selectable oscillator options
· In-Circuit Serial Programming (ICSP) via two pins
Peripheral Features:
· Timer0: 8-bit timer/counter with 8-bit prescaler
· Timer1: 16-bit timer/counter with prescaler, can be incremented during SLEEP via external crystal/clock
· Timer2: 8-bit timer/counter with 8-bit period register, prescaler and postscaler
· Two Capture, Compare, PWM modules if Recover mcu binary
– Capture is 16-bit, max. resolution is 12.5 ns
– Compare is 16-bit, max. resolution is 200 ns
– PWM max. resolution is 10-bit
· 8-bit, up to 8-channel Analog-to-Digital converter
· Synchronous Serial Port (SSP) with SPI (Master mode) and I2C (Slave)
· Universal Synchronous Asynchronous Receiver Transmitter (USART/SCI)
· Parallel Slave Port (PSP), 8-bits wide with external RD, WR and CS controls (40/44-pin only)
· Brown-out detection circuitry for Brown-out Reset (BOR)
ATmega640P: What a Complete Hex File Should Contain
A hex file and a binary file describe the same memory, and they are not interchangeable. The hex format carries addresses, record types, and a checksum per line; the binary carries bytes in order from a starting offset and nothing else. On a part with a large flash and a non-trivial address space, that difference decides whether you can tell “empty” from “not included”.
This matters most when an image is recovered and then handed to someone else. A file that looks complete, assembles without error, and silently omits a region is worse than a file that is obviously truncated.
The records that matter
The format used by essentially every AVR toolchain encodes four record kinds:
| Record | Purpose | Why it matters to a recovery |
|---|---|---|
| Data | Bytes at an address | The payload |
| End of file | Terminates | A missing one means truncation |
| Extended address | Sets the upper address bits | Required once the image passes 64 KB |
| Start address | Entry point hint | Usually zero on AVR; non-zero is a signal |
The extended address record is the one that trips people up on larger parts. Without it, addresses wrap at 64 KB, and a file assembled from a 128 KB read will contain a second copy of the first half written over itself. The result is a file that opens, disassembles, and is wrong in a way that only a checksum comparison reveals.
What is not in the hex at all
Three things live outside the address space the hex describes:
The fuse bytes. They are read and written through separate commands and they determine clock source, start-up delay, boot section size, and interface enable. A hex file says nothing about them, which is why a recovered image applied to a blank part with default fuses can fail to start at all.
The lock byte. Same category. It records protection state, not content.
The calibration byte. Stored in the signature area, read through a different address space, and not part of the file. Firmware that reads it at run time does not need it; firmware that hard-coded a value already carries it in the payload, usually invisibly.
A recovery that produces only a hex file has produced the payload and left three inputs behind. That is fine when the intent is analysis and a problem when the intent is reproduction.
Holes in the address space
A 64 KB part does not necessarily have 64 KB of program memory. Smaller members of a family occupy a subset of the same map, so an image read from a smaller die on a programmer configured for the larger one contains a large FF region that means “not implemented”, not “erased”.
Telling those apart requires the device signature. A signature read tells you which member you have, which tells you how much of the map is real. Reading without that step produces files with unexplained empty tails, and those tails get interpreted as erased code, missing firmware, or a failed read — three different wrong conclusions from one missing read.
The same logic applies in reverse: a full-map read of a small part is not wasteful, because the unimplemented region is a reliable marker once you know to expect it.
Verification that actually verifies
Reading a page and comparing it to itself proves the interface is stable. It does not prove the address was right. Two checks that do:
Read the vector table and disassemble the reset vector. On a part with a boot section, the reset vector either points into the application area or is redirected by a fuse. Either way, the first instruction is a jump, and the target must land inside a region that actually contains code. A jump into the empty half of the map is the signature of an offset error.
Read the same page at two different addresses in the tool. If the tool returns identical content for two addresses you know are different, the address latch is not working and every byte after the first page is in the wrong place.
Both are cheap, both catch errors that a self-comparison cannot.
Why the P revision affects none of this
The P suffix marks a picoPower die — lower current, revised oscillator, more brown-out levels. None of that changes the file format, the address map, or the relationship between the hex and the fuse bytes.
What it does change is the electrical margin during the read, and therefore the probability that a marginal read silently corrupts a page. On a picoPower part, read at the design rail, verify twice, and treat any difference between passes as a voltage problem rather than a memory problem.
Related notes
- ATmega640 and the external bus — the case where the file is genuinely incomplete.
- ATmega640A and revision differences — how a different die changes interpretation.
- ATmega644 and page buffers — the granularity behind every partial region.
FAQ
Is a hex file better than a binary? It carries addresses and a per-line checksum, which makes truncation and misalignment visible. For anything passed between people, yes.
Does the hex include the EEPROM? Only if the tool put it there, and usually at a separate address range. A hex of the flash does not imply the EEPROM is included.
Can fuses be reconstructed from a hex? No. They can sometimes be inferred from behaviour — a part that starts slowly was configured with a long start-up delay — but inference is not recovery.
Why does the tail of my dump read FF? Either the die is a smaller member of the family, or the region is unimplemented. The signature read distinguishes the two.
Conclusion
A hex file is a claim about addresses, and a claim is only as good as the checks behind it. Three items live outside the file — fuses, lock byte, calibration byte — and two regions inside it are routinely misread: unimplemented tails and address wraps past 64 KB. Reading the signature first and disassembling the vector table afterwards turns a plausible file into a verified one.
Recover MCU PIC16F72A Firmware
Recover MCU PIC16F72A Firmware in the format of binary or heximal, reset the configurate bits of Microcontroller PIC16F72A from locked to open one by crack microcontroller fuse bit, then readout code from MCU;

Recover MCU PIC16F72A Firmware in the format of binary or heximal, reset the configurate bits of Microcontroller PIC16F72A from locked to open one by crack microcontroller fuse bit, then readout code from MCU
This document contains device specific information for the operation of the PIC16F72 device. Additional information may be found in the PIC™ Mid-Range MCU Reference Manual (DS33023), which may be downloaded from the Microchip website. The Reference Manual should be considered a complementary document to this data sheet, and is highly recommended reading for a better understanding of the device architecture and operation of the peripheral modules.
The PIC16F72 belongs to the Mid-Range family of the PIC devices. The program memory contains 2K words, which translate to 2048 instructions, since each 14-bit program memory word is the same width as each device instruction. The data memory (RAM) contains 128 bytes after recover mcu AT89C4051 heximal.
There are 22 I/O pins that are user configurable on a pin-to-pin basis. Some pins are multiplexed with other device functions. These functions include:
· External interrupt
· Change on PORTB interrupt
· Timer0 clock input
· Timer1 clock/oscillator
· Capture/Compare/PWM
· A/D converter
· SPI/I2C
Table 1-1 details the pinout of the device with descriptions and details for each pin.
There are two memory blocks in the PIC16F72 device. These are the program memory and the data memory. Each block has separate buses so that concurrent access can occur. Program memory and data memory are explained in this section. Program memory can be read internally by the user code (see Section 7.0).
The data memory can further be broken down into the general purpose RAM and the Special Function Registers (SFRs). The operation of the SFRs that control the “core” are described here. The SFRs used to control the peripheral modules are described in the section discussing each individual peripheral module.
Additional information on device memory may be found in the PIC™ Mid-Range Reference Manual, (DS33023).
PIC16F72 devices have a 13-bit program counter capable of addressing a 8K x 14 program memory space.
The address range for this program memory is 0000h 07FFh. Accessing a location above the physically implemented address will cause a wraparound.
The RESET Vector is at 0000h and the Interrupt Vector is at 0004h.
The Data Memory is partitioned into multiple banks that contain the General Purpose Registers and the Special Function Registers. Bits RP1 (STATUS<6>) and RP0 (STATUS<5>) are the bank select bits.
ATmega1284V: Initialised Data Appears Twice in the Image
Point a disassembler at an AVR image and it will decode everything as instructions, because that is what it was asked to do. Somewhere in the middle of the output there will be a region that decodes into instructions that make no sense — reads from implausible addresses, jumps into the middle of themselves, opcodes that the part does not implement.
That region is usually not corruption and not encryption. It is data that the programmer never intended to execute, and the reason it sits in the flash at all is one of the more useful pieces of structure in an AVR image.
Why the data is there
The AVR has a modified Harvard architecture: program memory and data memory are separate address spaces. A global variable lives in SRAM, but its initial value has to survive a power cycle, and SRAM does not. So the compiler stores the initial value in flash, in a section that the linker places after the code, and generates a startup routine that copies it into SRAM before main runs.
The same routine zeroes the block of variables that start at zero, which need no stored value at all. Between the two, the startup block defines the entire static memory layout of the program.
| Section | Lives in | Contains | Executable |
|---|---|---|---|
.text |
Flash | Instructions | Yes |
.data load image |
Flash | Initial values of globals | No |
.data run address |
SRAM | The same values after copy | No |
.bss |
SRAM only | Zero-initialised globals | No |
.rodata |
Flash | Constants, string literals | No |
.progmem |
Flash | Tables the code reads by address | No |
Finding the copy loop
The loop is easy to recognise once you know what to look for. It is one of the first things after the reset vector, it reads from flash using the load-from-program-memory instruction, it writes to SRAM through a pointer register pair, and it terminates on a comparison against an end address.
Three values in that loop are the whole map:
- The flash source address, which tells you where the data block begins.
- The SRAM destination address, which tells you where the variables live.
- The length, either as a count or as an end address, which tells you how big the block is.
Write those three down. The data block is now a known region that must be excluded from disassembly, and the SRAM window is a known range that the code will address by direct load and store throughout.
The zeroing loop immediately after
The second loop writes zeros to a different SRAM range. That range is .bss, and its size tells you something practical: how much of the part’s SRAM the design uses. On a device with a generous SRAM this is a fast way to see whether the firmware is tight or comfortable, and a tight firmware tends to be hand-optimised in ways that make the code easier to read.
Why the data block matters to the analysis
Two reasons, and both save hours.
It removes false instructions from the output. A disassembler that decodes a block of initial values produces hundreds of lines of nonsense that a reader has to evaluate and discard. Cutting the region out at the start means everything remaining is either code or a table you have already identified.
It reveals the program’s vocabulary. Initialised globals are rarely random bytes. They are configuration structures with recognisable contents: a baud divisor, a timeout in milliseconds, a set of default setpoints, a string with a version number. Reading the data block as data — hex plus ASCII — frequently produces more insight per minute than reading the code, because the values are the design decisions.
Where the compiler puts the rest
Three other regions cause confusion and are worth locating deliberately.
String literals and constants. Placed with the code but never executed. They are recognisable by producing readable ASCII at a hex offset, and by being referenced through the load-immediate-address instructions rather than by a jump.
Tables read by address. Lookup tables, font bitmaps, segment maps, CRC tables. These decode as instructions and are the most common source of “why does the firmware jump into a table” confusion. A table is usually referenced by a Z register load, not by a call, and that reference is the way to find its boundaries.
Interrupt vector table and the boot section. Fixed by the silicon rather than the compiler, and already covered by the vector analysis. The boot section, if present, is a separate program with its own startup and possibly its own data block, so the copy-loop pattern appears twice.
Reconstructing a map
The exercise that pulls all of this together is to produce a memory map of the image: code from here to here, data block here, strings here, tables here, boot section here. It is not a reconstruction of the source, but it is the closest thing to a table of contents that a binary will give you, and every later question is answered faster with it in hand.
The map also has a diagnostic use. Two images of the same product from different firmware versions should differ in code and in strings and should have nearly identical data blocks. If the data blocks differ wildly, the two versions were built with different compiler settings or different configurations, which is worth knowing before comparing behaviour.
Related reading
- ATmega1284P and the vector table as an index — the fixed part of the map.
- ATmega1284 and what the flash image does not contain — memory layout from the other direction.
- ATmega128P and layout past the sixty-four kilobyte line — where the load instructions change form.
FAQ
Can the two copies ever disagree? Only if the firmware writes to those variables, which is normal. The flash copy is the initial value; the SRAM copy is the current one.
What if there is no copy loop? A program with no initialised globals has nothing to copy, which is common in small firmware. The absence is itself informative.
Does the compiler always place the data block immediately after the code? The linker decides, and it usually places it after the code region. The copy loop’s source address is authoritative regardless of where the block sits.
Why do constants sometimes execute correctly by accident? Because they occasionally decode into valid instructions that do not crash. That is worse than an obvious crash, since it produces plausible but wrong analysis.
Conclusion
Two copies of the same bytes, one of them patently not code, and a three-value loop that connects them. Finding that loop first turns an unreadable 128 KB into a map with regions, and regions are what make the rest of the work tractable.
ATmega1284V: Putting the Fuses Back the Way You Found Them
There is a specific kind of bad afternoon that begins with a successful read. The image is on disk, the customer is happy, and then the part is programmed with default fuses so it can be tested — and the part no longer starts the way it used to, because the default is not what the device was configured with.
The fuses are three bytes. They are also the difference between a device that runs and a device that appears dead, and between a device that can be worked on again and one that cannot.
The three bytes and what they own
On this part the configuration is split into low, high, and extended bytes. Each bit or field has a defined job, and the jobs are not equally dangerous.
The low byte owns the clock. Source selection, startup delay, whether the internal oscillator is divided by eight at reset, whether the clock is emitted on a pin. Get the source wrong and the part runs at the wrong speed or waits for a crystal that is not fitted.
The high byte owns the boot section size, whether reset vectors into the boot section, the watchdog’s power-on state, the EEPROM save-on-erase bit, the programming interface enable, and the debug interface enable.
The extended byte owns the brown-out level and a small number of hardware-behaviour bits that differ between revisions.
| Fuse area | What it decides | Risk if restored wrongly |
|---|---|---|
| Clock source | Where the CPU gets its time | Part does not start, or starts at wrong speed |
| Startup delay | How long before the core runs | Unreliable start on slow supplies |
| Clock output | Whether a pin emits the clock | Pin behaves as output unexpectedly |
| Boot size and reset | Where the part starts | Bootloader skipped, or application never reached |
| Watchdog on power-up | Whether the dog starts enabled | Part resets in a loop before the application disables it |
| EEPROM save on erase | Whether a chip erase keeps the data | Production data destroyed by a routine erase |
| Interface enables | Which programming paths exist | The only remaining route in is closed |
| Brown-out level | When the part holds itself in reset | Spurious resets, or no protection at all |
Record first, touch nothing
The first operation on any device, before the flash read, is to read the fuse bytes and the lock bytes and write them into the job record with the decoded meaning next to each field. Not just the hex value — the decode, because the decode is what gets checked later when something does not start.
Two reasons. The obvious one is that you will need the values to program the replacement. The less obvious one is that the decode is a cross-check on everything else you conclude: if the fuse says the clock is the internal oscillator at 8 MHz and the firmware’s baud divisor says 8 MHz, both readings confirm each other. If they disagree, one of them is wrong, and finding out which is much cheaper now than after delivery.
The interfaces that can be closed
Two bits on this family are genuinely one-way in practice, and both are in the high or extended byte.
The reset pin as an input. Programming that bit removes the reset function from the pin permanently short of a high-voltage programmer. If the part is on a board where that pin was the only way to synchronise the ISP protocol, the route in is gone. Nothing about this is recoverable with a normal programmer.
The debug interface disable. Turning off the debug port leaves ISP as the remaining path on many parts, so it is survivable — but only if ISP still works. A device with both the debug interface disabled and the reset pin repurposed has no conventional entry at all.
Before changing any configuration bit, ask what the current state allows and what the proposed state would allow. The answer is a decision about the next hour, not just about this write.
Restoring, and what “the same” means
Restoring the fuses is a write of three bytes, and the temptation is to write the recorded values and move on. Two refinements make it reliable.
First, verify by reading back and comparing decoded fields, not raw bytes. A programmer that masks or reorders bits will produce a raw mismatch on a part that is actually configured correctly, and chasing that wastes time.
Second, decide deliberately what the lock bits should be at the end. Returning a part to its owner in an unlocked state changes the security posture of their product, and doing so without saying it is a decision made on their behalf. The default should be to restore what was there, and to state in the delivery what that state is.
The programming order that avoids self-inflicted failures
A sequence that works, in order:
- Read fuses, lock bits, signature, and the calibration row. Record them with decodes.
- Read flash and EEPROM. Verify by re-reading.
- Only after both images are secure, consider any change to configuration.
- When programming a replacement, write flash and EEPROM first, fuses second, lock bits last.
- Verify the replacement by behaviour — power it, watch it start — before it goes back into the product.
Step four matters because the lock bits are the only configuration that can stop you from correcting a mistake in step four. Do them last, always.
Related reading
- ATmega1284 and the artefacts the image does not hold — why the fuses belong in the delivery at all.
- ATmega644PA and the fuse that removes your way in — the reset-pin case in detail.
- ATmega640P and the three ways in — which interfaces exist and what removes each one.
FAQ
Are fuse bits readable on a locked part? On most AVR parts, yes. The lock bits protect the arrays, not the configuration bytes. Confirm per revision.
Can fuse values be recovered if the part is dead? Only by inference from the firmware and the board. The clock source is often deducible from baud divisors and timer constants.
Does a chip erase reset the fuses? No. Erase affects the arrays; the fuses persist. This is why an erased part can still refuse to start.
Is it safe to leave the lock bits unlocked? It is safe for the hardware and unsafe for the customer’s intellectual property. Make it an explicit, stated choice.
Conclusion
Configuration is three bytes of data and the largest source of avoidable disasters in this work. Read them first, write the decode into the record, restore exactly, and always leave the lock bits for last.
ATmega1284: What a Flash Image Does Not Contain
The satisfaction of a clean read is real: address zero to the top, no gaps, a checksum that repeats. It is also deceptive, because a flash image is one of five things a working device holds, and the other four are the ones that make a copy fail in a way nobody expects — it installs, it boots, and then it does something subtly wrong.
Knowing what is missing is what separates a delivery that the customer can use from a delivery that generates a week of support.
The four things that are not in the array
An ATmega1284 that leaves the factory with firmware in it also carries:
- Runtime state in SRAM. Cleared at reset by the C runtime, so it does not matter — until it does, because some products keep a magic word or a boot counter in a section that survives a warm reset.
- Peripheral configuration. Written by initialisation code, so it is derivable from the image, but only if you read that code rather than skipping to
main. - EEPROM contents. Two kilobytes, separate array, separate command, and usually the part with the actual product-specific data in it.
- Fuse and lock bytes. Three bytes that decide the clock source, the boot section size, the brown-out level, and whether the part can be programmed at all.
A fifth item sits outside the silicon entirely: the external parts the firmware expects. A 1284 driving an external latch, a specific crystal, or a sensor with a particular address is not reproducible from code alone.
| Item | Where it lives | How it is recovered |
|---|---|---|
| Program | Flash, 128 KB | Read the array |
| Constants and tables | Flash | Read the array |
| Initialised variables | Flash copy plus SRAM | Read the array, then find the copy loop |
| EEPROM payload | Separate 2 KB array | Issue the EEPROM read command |
| Clock and boot configuration | Fuse bytes | Read fuses, or infer from the code |
| Peripheral setup | Written at run time | Read the initialisation sequence |
| External hardware behaviour | Not in the device | Ask, or measure on the board |
Reading the initialisation block as a specification
The first few hundred instructions of an AVR program are the most informative part of the image, and they are usually the part people skim. Before main runs, the reset vector jumps to a startup block that sets the stack pointer, copies initialised data from flash to SRAM, zeroes the BSS, and then calls the application’s init function.
That init function is a written record of the hardware. It configures the clock prescaler, the USART baud registers, the timer prescalers, the ADC reference, and the pin directions. Every one of those writes encodes a design decision that the schematic may not show — the baud rate tells you the clock, the timer prescaler tells you the intended time base, and the pin directions tell you which pins are outputs even if the net names are unhelpful.
Reading that block takes twenty minutes and answers questions that would otherwise take a day of probing.
Reconstructing the fuses
The fuse bytes are readable through the programming interface even on a locked part on most AVR families, which makes this the easiest of the four. Read them, record them, and write the same values to the replacement.
The trap is that the same numeric value does not always mean the same thing across revisions. The low fuse byte’s clock selection field has been extended over the years, and a value that selects “internal 8 MHz” on one revision can select something else on another. Cross-check the decoded meaning against the code: if the firmware sets a baud divisor consistent with an 8 MHz clock, and your fuse decode says 1 MHz, the decode is wrong.
The EEPROM question
Two kilobytes is small enough to ignore and large enough to matter. On this part the EEPROM is a separate array with its own read and write commands, its own endurance, and its own fuse bit that decides whether a chip erase takes it with the flash.
Reading it is one extra command and takes seconds. Not reading it is the single most common cause of a clone that runs but misbehaves, because production data — a serial number, a calibration constant, an accumulated hour meter — usually lives there rather than in flash.
Why the copy boots and then fails
Three failure patterns account for most of the “it works but” reports after a recovery.
The clock is wrong. The image was built for a crystal that the replacement board does not have, or the fuse selects a source that is not fitted. The device runs, but every timing constant is off by a ratio, and serial communication fails while the rest appears fine.
The EEPROM is blank. Code reads a configuration structure, finds 0xFF everywhere, and either refuses to start or falls back to defaults that are not the customer’s.
The boot section moved. A device with a bootloader needs the boot reset vector and the right BOOTSZ setting. Program the application into a part whose fuses point somewhere else and the device starts in the wrong place, or not at all.
Each of these has a different fix, and none of them is visible in the flash image. That is the argument for treating the image as one deliverable among several: fuses recorded, EEPROM captured, boot configuration documented, and the external hardware assumptions written down while somebody still remembers them.
Related reading
- ATmega1284P and the vector table as a map of the firmware — using the vector table to find the code that matters.
- ATmega1280P and EEPROM on a large part — the same array, a different package.
- ATmega1284V and restoring the fuse bytes — the configuration side of the same job.
FAQ
Can the fuses be read from a locked device? On most AVR parts the fuse and lock bytes remain readable when the flash does not. Confirm on the specific revision, because the behaviour has changed across generations.
Is the EEPROM protected by the lock bits? It is covered by the same protection scheme, so a locked part blocks EEPROM reads through the programming interface as well.
What if the customer has no second unit to compare against? Then the initialisation block and the fuse decode are the only sources of truth, and both should be documented explicitly in the delivery rather than left implicit.
Does a full chip erase clear the fuses? No. A chip erase clears the flash and, depending on the EESAVE bit, the EEPROM. The fuse and lock bytes are separate and must be handled deliberately.
Conclusion
The array is the largest and least interesting of the artefacts. The four things it does not contain are what the customer actually needs, and all four are recoverable in the same session — provided somebody thinks to look before the original part goes back on the shelf.


