Don’t ask me what happened or what fixed the problem. I regressed back through code that was working previously and nothing worked anymore. I ordered a couple replacement boards from Spark Fun but that didn’t make it work either.
I unplugged everything for the umpteenth time, but this time I popped the cork from a bottle of red wine and after a couple of glasses came back for one more try. It all started to work again.
Also strange that flash protect_check / flash info always reports “protected” for every page, but flash erase (mostly) passes even though it shows protected.
The LPC doesn’t really fit into OpenOCD’s concept of “protect” sectors, as all sectors are protected by default, and you have to unlock them for every operation again. This is done implicitly in the code.
I’ve never seen a flash operation fail on an LPC2000 when the target was in a clean state (for example with run_and_halt after a 1 or 2 seconds in bootloader mode, or in a simple led-blinking program). You have to make sure that the frequency specified in the .cfg file matches the actual core frequency - if you specify the value of your crystal, make sure the PLL is turned off. You can achieve that by writing the LPC register from within OpenOCD.