Hopefully somebody else finds this interesting, because I think it is a somewhat clever non-obvious use of specialty programmable logic. This only applies to the parts with built in I2C (GreenPAK5/6) to my knowledge.
If you already know what these parts are, or don't care about the story about how and why I started using these parts and figured this out and just want the technical information, skip to paragraph #4 (after the horizontal rule). Even with that, it's still a bit of a wall of text. There is also a TLDR summarizing at the end.
If you are not familiar with the Dialog/Silego GreenPAK devices, they are a line of parts that aim to integrate multiple simple discrete logic (and in some cases analog) functions into a single low cost chip, often lower cost than the parts it would replace. The idea is you'd design a a circuit in their schematic tool, test it on a dev kit, and then burn the OTP and solder it down for testing in your real circuit. Once your project enters production, they would then sell you pre-programmed reels with your design.
A couple of years ago, I was working on a design at work that would been a nice fit for a small programmable logic device like the GreekPAK, but I did not really want to deal with OTP in my development cycle, especially if I was going cram a number of complicated functions into the device and use it as more than just a logic gate replacement. I was prepared to go through a number of chips for testing, but I wondered if I could figure out a way to just program the internal volatile memory in the at the time fairly new GreenPAK5 devices that allow you to modify the configuration over I2C of a programmed chip (allowing you to edit the crossbar switch, change timer counter values, select analog comparator setpoints, etc) without ever starting with a programmed device. So I hooked a logic analyzer to the progammer and tried using the emulate mode on a blank device, and it sure looked a bunch like the sequence for runtime changing, although with VPP set to 7.5V. I tested without VPP connected and it still worked fine.
I also wondered if I could extract the chip configuration from the project, to avoid extra steps in the process for testing, and it turns out that the final device bitstream is stored in an aptly named "nvmData" XML element in the project file that I could simply extract and generate a copy of the data to be included in the processor binary. This let me iterate on a fairly complex device quickly and in parallel with the software. The final system contains several configurations that are switched out wholesale depending on the main system operational mode, with slight tweaks more in the intended manner happening at run time. The full function GreenPAK configuration included complementary piezo drive with DC removal, button debounce and interrupt, other external interrupts, and an autonomous battery voltage monitor during deep sleep to wake up and update the epaper display with battery status.
Using these OTP GreenPAK5 parts as fully programmable over I2C devices is very simple. They document the process for changing settings on an already programmed device like the analog comparator thesholds or timer counter max values and document all the bits in the device as well (even the internal crossbar switch). I2C access on these parts follows the typical byte addressed memory array with auto increment where you would send a byte 0-255 to select the starting address, followed by N bytes of data to write sequentially. The blank state of a device is to show up on I2C address 0x00, although that is programmable through the (unused in this case) OTP. To program a blank devices with an already obtained bitstream, access I2C address 0, register 0 and send the entire bitstream over sequentially. This could have the possibility of generating glitches on external pins during the process, depending on the internal implementation of I2C programming, but I have not investigated this possibility as it is not an issue in the current designs I use these parts.
It is also fairly simple to extract the bitstream from the project file to aid in integration with a build system and/or improve cycle time in testing and development. The project files are XML with an "nvmData" element containing the bytes that need to be programmed to the device as spece separated hexadecimal bytes. I have attached some code as an example implementation for parsing a GreenPAK5 project. It is in Rust, but hopefully it's clear enough even if you don't know the language.
I have tested these techniques on the SLG46537 (and a couple other similar part numbers that are escaping me at the moment) from the GreenPAK5 family, and on the SLG46880 from the GreenPAK6, but based on common features, I would expect this to work on all the GreenPAK5 and 6 devices with slight tweaks. In the rest of this port I will generalize and assume that all GreenPAK5 parts are equivalent to the SLG46537 and all GreenPAK6 devies are equivalent to the SLG56880 as this has held true on a sample of other chips in the family. There one major difference that applies to this information between the GreenPAK5 and 6. The GP6 devices have a 512 byte configuration memory, but still only a single byte address. This is handled with the same thing the 24XX EEPROMS do, taking over another sequential I2C address for the second page of data. My code explicitly does two I2C writes to the appropriate addresses rather than testing if auto increment crosses the 256 byte boundary.
There are a couple of caveats to be aware of with this. First, the default I2C address of a blank device is address 0, which some other I2C devices may assign special meaning to communications directed at. Second, the parts are documented as potentially using addresses 1-7 for other purposes (possibly in the OTP programming logic), and the GP6 device with a larger memory uses address 1 for the second half of it's internal memory. I worked around both of these by placing them on their own I2C bus away from other potentially conflicting devices, but a careful study of the other devices could resolve this issue. You could also program the OTP to select a different address if you needed to use this in production, but could not deal with the constraints of a blank device. Third, it is entirely possible to turn off I2C over the I2C bus, and the chip will drop off the bus mid write when it happens. This also can happen if you forget to send the register address byte in which case you will be writing values to the wrong place in memory dictated by the first bye of the firmware. If you have broken I2C, you will need to correct the condition in your I2C host software, and then power cycle to regain communication. I didn't do it on the first project using this technique, but on a more recent project this last week, and I spent some time chasing the problem as a hardware issue, because I didn't notice that the first time after a power up, it would partially write to the device. Fourth, it should be obvious, but if you don't have a programmed OTP, the part will not come up in a state where it is performing it's desired functions until the processor can intervene, so this is probably not the best choice for a PSU sequencer that powers on the processor.
While I was writing this, I looked at their product list to confirm some of the general statements and they now make a device with in circuit programmable EEPROM over the I2C bus. That could be interesting if a design wanted to be able to change itself, but only on a firmware update, not dynamically at run time. They also now have an application note describing some of this, mostly in the context of in-system debugging and testing with their software and hardware in the loop versus my technique avoiding programming the NVM at all, and managing the configuration as just another pice of the main software, but this is not as unique and undocumented as I thought before I started writing this.
Hopefully this is as clear to somebody else as it was to me. This came out of a discussion with a coworker about a problem I was having with a system that was using this trick but with a new processor so I couldn't just migrate over my old software to talk I2C to the part and I introduced a bug in the process. Along the way, I thought that if I thought this was a cool application, maybe somebody else would too.
TLDR: You can just send a full configuration over I2C to a blank device as if you were changing the settings of a pre-programmed device, with some minor caveats. Their schematic capture designer tools store the needed bitstream in an "nvmData" element in the XML as space separated hexadecimal.