---
title: "Unable to Flash W7500P, Write Protected"
url: "https://maker.wiznet.io/forum/16142"
markdown_url: "https://maker.wiznet.io/forum/16142/md"
type: "Forum topic"
category: "MCU & Boards"
author: "kelanucr"
created: "2026-08-20T04:05:44+09:00"
last_activity: "2026-08-31T16:44:49+09:00"
language: "en"
tags: ["C/C++", "W7500P"]
views: 4
replies: 5
source: "WIZnet Makers forum (https://maker.wiznet.io/forum/)"
---

# Unable to Flash W7500P, Write Protected

## Question

Asked by kelanucr on 2026-08-20 in MCU & Boards.

Hello,

I've run into an issue with the W7500P while flashing firmware. To start off I am unable to share the entire source code or schematic, but I can share sections of the source code and the schematic itself is functionally identical to the published reference schematic on the Wiznet GitHub; with the exception of GPIO pins being fanned out to headers, but these are unpopulated while I am testing code.

Currently when I reset the device with BOOT high, I can send commands to the chip via ISP. When I run LOCK READ I get C000000F FFFFFFFF, I can then run LOCK PROG 00000000 00000000, after which LOCK READ produces 00000000 00000000. This is the sequence that the provided ISP flashing tool does.

I can then run ERAS CHIP which returns 0 however running ERAS MASS returns 7. If I reset the chip or run REST then check LOCK READ again I get C000000F FFFFFFFF. If, after setting FLOCK0/1 to 00000000 00000000, I then run XPRG and try and program the device via the provided tool it either completes in ~1s (much shorter than it should) or it NACKs then aborts. If I then switch to APP mode and reset there is no output on the simple UART port which my application uses for debugging and I cannot reach any services over ethernet so it seems like the app itself did not flash.

This started when I was writing firmware to allow firmware updates over the internet, by creating a bootloader partition, app partition, and download partition in sections.ld. This booted correctly but I noticed that after a few downloads the device would stop responding and required a full power cycle; I'm sure this was some issue with my firmware so I attempted to downgrade to a firmware version that I knew worked that did not contain any separate partitions.

When attempting to flash the new firmware I'm now running into the LOCK issue. Supposing I still had app code on the flash it should not run in ISP mode, so I'm confused why the re-flashing process which previously worked is not anymore. It seems unlikely that I could have bricked it with my code in a way that also prevented new firmware from being flashed.

I attached the code I changed between working and non working builds for context, in case some way I was interacting with the flash controller did in fact permanently brick it. sections.ld and mem.ld are more or less identical to the stock library. The actual code that interacted with the flash controller was just the stock w7500x_flash.c and the following function which handled the downloads

My goal is to just be able to flash firmware again to the chip.

static uint32_t staged_sector[FLASH_SECTOR_SIZE / 4];

static uint16_t sectors_transfered = 0;
static bool restart_transfer = false;
uint8_t transfer_sector(const uint8_t * sector, uint16_t sector_id, uint16_t sector_total, uint16_t crc_key) {
uint32_t addr;

// reset counter
if (sector_id == 0) {
__disable_irq();
FLASH_IAP(IAP_ERAS_SECT, CRC_HEADER, 0, 0);
__enable_irq();
sectors_transfered = 0;
restart_transfer = false;
printf("Transfer started: %d sectors\r\n", sector_total);
}

// diagnostic print
printf("Received sector %d of %d\r\n", sector_id, sector_total);

// reject out of bounds sector_id
if (sector_id >= DOWNLOAD_SECTORS || sector_id >= sector_total) {
printf("Out of bounds sector ID\r\n");
restart_transfer = true;
}

// reject out of bounds sector_total
if (sector_total == 0 || sector_total > DOWNLOAD_SECTORS) {
printf("Out of bounds sector total\r\n");
restart_transfer = true;
}

// reject out of order sector_id
if (sector_id != sectors_transfered++) {
printf("Out of order sector ID\r\n");
restart_transfer = true;
}

// restart transfer
if (restart_transfer) {
printf("Aborting transfer\r\n");
return 0x00;
}

// target flash address
addr = DOWNLOAD_BASE + (uint32_t) sector_id * FLASH_SECTOR_SIZE;

// reset flash sector
__disable_irq();
FLASH_IAP(IAP_ERAS_SECT, addr, 0, 0);
__enable_irq();

const volatile uint32_t *const FSTATR = (const volatile uint32_t *) 0x41005010UL;
uint32_t fstat = *FSTATR;
printf("FSTATR=0x%08lX (bit0=%s)\r\n",
(unsigned long) fstat, (fstat & 1u) ? "RDY" : "BUSY");

__disable_irq();
FLASH_IAP(IAP_PROG, addr, (uint8_t *) staged_sector, FLASH_SECTOR_SIZE);
__enable_irq();

// verify crc_key
if (crc_gen((const uint8_t *) addr, FLASH_SECTOR_SIZE) != crc_key) {
restart_transfer = true;
printf("CRC Failed\r\n");
return 0x00;
} else {
printf("CRC Passed\r\n");
}

// set crc header
if (sector_id == sector_total - 1) {
struct crc_header rec = {
.slength = (uint32_t) sector_total,
.flag = CRC_FLAG_PENDING,
.crc_key = crc_gen((const uint8_t *) DOWNLOAD_BASE,
(uint32_t) sector_total * FLASH_SECTOR_SIZE)
};
__disable_irq();
FLASH_IAP(IAP_PROG, CRC_HEADER, (uint8_t *) &rec, sizeof rec);
__enable_irq();

printf("Transfer Finished\r\n");
}

return 0xFF;
}

The constants are defined in bootloader.h

Attachments:

- [bootloader.h](https://maker.wiznet.io/forum/getAttach.asp?aidx=409)
- [sys_init.c](https://maker.wiznet.io/forum/getAttach.asp?aidx=410)
- [bootloader.c](https://maker.wiznet.io/forum/getAttach.asp?aidx=411)
- [sys_init.c](https://maker.wiznet.io/forum/getAttach.asp?aidx=412)
- [main.c](https://maker.wiznet.io/forum/getAttach.asp?aidx=413)

## Replies

### Reply 1 by Grace_Koo, 2026-08-20

Hi,

Good news first: your chip is not bricked, and your firmware could not have locked it. `ERAS CHIP` returning `0` proves the code flash still erases fine, and the lock information sits in the read-only Information block, which no IAP command can touch.

Two quick facts to clear up what you saw: `7` means Write Lock Protected, and `C000000F FFFFFFFF` after every reset is normal — FLOCKR0/FLOCKR1 are volatile and the device always enters ISP mode fully locked, so the unlock has to be redone after every reset and the erase/program must happen in that same session.

Here is what to do.

1. Check two settings in the ISP tool

- Step 3 / Step 4: click "All Code Read Unlock / Data R/W Unlock" and "All Code Write Unlock". When you open the serial port the tool fills those checkboxes from the chip's current (locked) state, and it sends `LOCK PROG` with those values *before* erasing — so if they are left ticked, the chip is re-locked and the erase returns 7.

- Step 2: select "Erase All Code Block" (= `ERAS CHIP`), not "Erase Data Block All Code Block" (= `ERAS MASS`). `ERAS MASS` also targets the two data sectors and is not needed for firmware.

Also note the "Download Complete" popup is shown unconditionally — the tool does not check the XMODEM result — so it is not proof the write succeeded.

2. If that does not fix it, run this manually

From a plain terminal, in one session with no reset in between:

```plaintext
U
LOCK PROG 00000000 00000000
ERAS CHIP
DUMP 00000000 00000010
XPRG 00000000 <file size, 8 hex digits>     <- then send the .bin over XMODEM
DUMP 00000000 00000010
REMP FLSH
REST
```

The first `DUMP` should read back all `FF`; the second should show your vector table. That tells us whether the flash is refusing the data, or whether it takes the data and the app still doesn't start. (If `XPRG` rejects the address, try `10000000` — the app note uses that alias for code flash in boot mode.)

3. If the second DUMP looks correct but there is still no UART output

In your `bootloader.c` the magic check is commented out:

```plaintext
//if(hdr->magic==APP_MAGIC) {
    void (*app_entry)(void) = (void (*)(void))(hdr->entry | 1u);
```

`Boot_Entry` therefore jumps to `hdr->entry` unconditionally. If the app area is blank that value is `0xFFFFFFFF` and the core faults immediately with no output — which looks exactly like a failed flash. Please also confirm the .bin you are programming is the old non-partitioned build.

4. If it still fails, please send me. (Grace@wiznet.io)

The exact error text from the tool, your Step 3 / Step 4 checkbox state, your baud rate and .bin size, and the return value of each command in the sequence above.

Separately — the "stops responding after a few downloads" problem

We can't diagnose this from here, but two things are worth checking:

- `CRC_HEADER` is `0x00001F00`, and `transfer_sector()` erases that sector at the start of every transfer. Please check your .map file and confirm your `sections.ld` really keeps `0x1F00`–`0x1FFF` free — if anything else was placed there, every transfer erases live code or data, which would fit the symptom.

- When you re-enable the copy loop in `Boot_Entry`, note that `FLASH_IAP(IAP_PROG, dst, (uint8_t *)src, ...)` passes a flash address as the source. All WIZnet IAP examples program from an SRAM buffer, so we'd recommend staging each sector through RAM instead.

Also, in the `transfer_sector()` you posted, the `sector` argument is never copied into `staged_sector` — we assume that was trimmed for the post, but worth a quick check.

Best regards,

### Reply 2 by kelanucr, 2026-08-25 (in reply to reply 1)

Hi Grace, thanks for the reply!

The provided version of my code is the minimal example that I was running just before I was having flashing issues. I'm currently attempting to flash a version that uses the default ldscripts and contains no separate bootloader, it just goes directly to the main function.

I tried DUMP 00000000 00000010 to read the IVT as well as DUMP 10000000 00000100 to attempt to read the start of my image, before and after flashing, both return all 0s.

The ISP tool itself has multiple failure modes, sometimes it completes in ~1s with no error but it does not seem like anything was flashed as, when switched back to APP mode, there is no output on the simple UART port. If I select erase flash and data it runs ERAS MASS which returns 7. Occasionally, XMODEM will reach the NACK limit and abort.

I tried LOCK READ -> LOCK PROG -> ERAS CHIP -> LOCK READ -> REST -> LOCK READ (I also tried a manual power reset cycle instead of REST) just to see if any change to the lock info was sticking. The first LOCK READ returned C000000F FFFFFFFF, the second LOCK READ returned 00000000 00000000, the third LOCK READ then returned C000000F FFFFFFFF.

Unfortunately the board which was having this issue, now does not respond to the auto-baud sequence in ISP mode at all. The electrical connection between my serial bridge and the pins is good, I tested my serial bridge in loopback, so I think there are no more tests I can run and I have to throw in the towel at this point and proceed with swapping out the uC.

### Reply 3 by Grace_Koo, 2026-08-26 (in reply to reply 1)

Hi,

A few notes before you swap the part:

Your lock test result is normal. `C000000F` → unlock → `00000000` → reset → `C000000F` is the expected behaviour. FLOCKR0/1 are volatile and reload to the locked state on every reset.

The DUMP test was invalid — our omission. Erased flash reads back `FF`, not `00`. All zeros is what you get when the Code Read Lock is still set, and it is set again after every reset. `DUMP` must be issued in the same session as the unlock, with no reset in between:

```
U
LOCK PROG 00000000 00000000
DUMP 00000000 00000010
```

For the board that no longer answers `U`: ISP mode runs entirely from the internal boot ROM and never touches flash, so firmware cannot cause this. Please measure at the package:

- TEST (W7500P pin 12) — dedicated pin, must be held low. Floating or high means no ISP and no `U` response.

- BOOT — high, at the pin rather than the header.

- RSTn — confirm it releases.

- ISP UART is PC_10 (U_TXD2) / PC_11 (U_RXD2) — confirm your bridge is on those pins.

One test left: SWD. In BOOT mode your application never runs, so `PA_03` / `PA_04` are still SWCLK / SWDIO and a probe should see the core. If SWD enumerates, the chip is alive and the problem is in the ISP UART path; if not, it is the supply or the part.

For the replacement board: in `jtag_sys_init()` you reconfigure `PA_03` as a GPIO output for your bit-banged TCK. `PA_03` is SWCLK by default (`PA_04` is SWDIO), so once your application starts, SWD is gone and ISP becomes the only way back in. Moving TCK to another pin would leave you a recovery path independent of ISP.

Best regards,

### Reply 4 by kelanucr, 2026-08-27

Hi Grace thanks for the update,

I ended up swapping the chip. However, before doing so my first attempt at unlocking the chip was to access it via SWD, the core never enumerated. I was using openocd with a TE0790. TEST, BOOT, RSTn were in the correct mode and I also measured the voltage rails on my scope and verified multiple times that the Simple UART connection was good.

Is this an issue that other people have had and in other cases what turned out to be the underlying cause?

### Reply 5 by Grace_Koo, 2026-08-31 (in reply to reply 4)

Hi kelanucr

On your question: we do not have a documented case of a W7500P becoming unresponsive to both ISP and SWD, so I am checking internally whether this has been seen before and what the cause was. I will come back to you once I have an answer.

One thing I would like to confirm: is the board working normally with the replacement chip? If the same PCB is fine now, that points at the part; if the symptom returns after a while, it points at the board or the firmware. Your answer will decide where we look next.

Best regards,

---

Source: https://maker.wiznet.io/forum/16142
