Seven kilobytes of program memory is 4,096 fourteen-bit words. Two of the phone calls we get about this part each month are the same: the file is 4 KB long, it programs, the board does not run.
The PIC16F1783 is the larger of the two 28-pin parts in the PIC16(L)F178x family, covered by DS41410 alongside the PIC16F1782. It brings 4,096 words of flash, 512 bytes of RAM, 256 bytes of data EEPROM, 24 I/O pins, an 11-channel 12-bit ADC, an 8-bit DAC, three comparators, two op amps and two programmable switch-mode controllers on an enhanced mid-range core with a 16-level stack and a 32 MHz internal oscillator. In practice it lands in digital power supplies, LED ballasts and small three-phase drives, where the peripherals do more work than the CPU itself.
The Two Halves Are Not Interchangeable
The 1782 has 2,048 words and the 1783 has 4,096. They share a datasheet, a pinout, a configuration layout and a device ID address. That similarity is the trap.
An image from a 1782 written into a 1783 will program without error, because everything it addresses exists on both parts. The top 2,048 words simply stay erased at 0x3FFF. Whether the board runs depends on where the linker put the tables. XC8 places constant arrays and string literals at the end of the array, so a 1782 image sits in the low half and runs on a 1783 until code looks for a table above 0x07FF, which a 1782 build never had.
The reverse direction fails harder. A 1783 image cut down to 4 KB drops 2,048 words of exactly the content a compiler puts last, and the result is a board that boots, passes its start-up checks and then jumps into erased memory the first time a control loop looks up a coefficient.
Why 4 KB Looks Like a Full File
Intel HEX stores two bytes per word, so 4,096 words occupy 0x0000–0x1FFF in the file even though the program address space ends at 0x0FFF. A tool that reports “4 KB” may mean 2,048 words or 4,096 words depending on which unit it is counting. The only number worth trusting is the highest word address, and on a complete 1783 that is 0x0FFF.
If you are holding a .hex, look at the highest data address. HEX addresses are byte offsets, twice the word address, so a complete 1783 ends at 0x1FFE. A file that ends at 0x0FFE holds 2,048 words and came off a 1782.
Above the Array
| Word address | Contents |
|---|---|
0x0000–0x0FFF |
program memory, 4,096 words |
0x8000–0x8003 |
user ID, 14 bits each |
0x8006 |
device ID, DEV<8:0> reads 0x151 |
0x8007 |
CONFIG1, holds the CP bit |
0x8008 |
CONFIG2 |
0x8009–0x8011 |
calibration words |
The device ID is the discriminator. 0x150 is a 1782, 0x151 is a 1783, and the difference is one bit in the nine-bit field. Because both parts share the package and the marking convention, this word is often the only evidence of which die is on the board — particularly after a conformal coat has lifted the laser marking.
One Bit Covers Everything
There is no block granularity here. A single CP bit in CONFIG1 at 0x8007 covers the whole array, and a protected part returns zeros for every read, which is what NOP looks like when disassembled. The configuration words and the calibration words remain readable, so the recovery route is code protection work on the die rather than a software trick.
The Problem With Table-Heavy Firmware
A 1783 firmware image is mostly data. PSMC period, duty and phase registers are written from 16-bit tables at start-up; ADC results are linearised against a calibration curve; the current-loop coefficients are constants. When such a region is disassembled, it produces instructions that reference impossible addresses — reads from 0x7F3A, calls to 0x9A21. That is not corruption. It is a table being read as code, and it is the most common reason a perfectly good extraction gets rejected as “garbage” by someone who only looked at the listing.
The check that actually matters is whether every branch target lands on a word that decodes as a real instruction, and whether the tables are reachable from the code that uses them.
The 256 Bytes You Will Miss
EEPROM on a power-conversion board carries the numbers that were tuned on the bench: dead-time trimming, current-sense offset, the reference value the ADC compares against. A replacement built from a correct flash image and an empty EEPROM runs, but its output sits a few percent off and its over-current trip point moves. Ask for the EEPROM in the same file as the array, and ask which protection bits were set. The reading the program memory page covers the regions a complete image includes; scope questions can go straight through contact us.