diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index 4363ed3a115f529e739dd67457b4c0e9d18fa331..f25595f66cde4f1debce05d487a311d514fc721e 100644
--- a/ch32v003fun/ch32v003fun.c
+++ b/ch32v003fun/ch32v003fun.c
@@ -854,7 +854,6 @@ int _write(int fd, const char *buf, int size)
 	#define DMDATA0 ((volatile uint32_t*)0xe00000f4)
 	#define DMDATA1 ((volatile uint32_t*)0xe00000f8)
 
-
 	char buffer[4] = { 0 };
 	int place = 0;
 	while( place < size )
diff --git a/examples/bootload/bootload.c b/examples/bootload/bootload.c
index aa107360e5ce3b6789c65d1b125256b86ef26b34..02b2385b74f0562f307f28b882b7dc12138c1fba 100644
--- a/examples/bootload/bootload.c
+++ b/examples/bootload/bootload.c
@@ -46,13 +46,23 @@ int main()
 	count = marker[0];
 
 	int i;
+
+	// Make a clear signature.
+	for( i = 0; i < 10; i++ )
+	{
+		GPIOD->BSHR = 1 | (1<<4);                // Turn on GPIOD0 + D4
+		GPIOC->BSHR = 1;                         // Turn on GPIOC0
+		GPIOD->BSHR = (1<<16) | (1<<(16+4));     // Turn off GPIOD0 + D4
+		GPIOC->BSHR = 1<<16;                     // Turn off GPIOC0
+	}
+
 	for( i = 0; i < 5; i++ )
 	{
-		GPIOD->BSHR = 1 | (1<<4);            // Turn on GPIOD0 + D4
-		GPIOC->BSHR = 1;                     // Turn on GPIOC0
+		GPIOD->BSHR = 1 | (1<<4);
+		GPIOC->BSHR = 1;
 		Delay_Ms( 250 );
 		GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIOD0 + D4
-		GPIOC->BSHR = 1;                     // Turn off GPIOC0
+		GPIOC->BSHR = 1<<16;                     // Turn off GPIOC0
 		Delay_Ms( 20 );
 		count++;
 	}
diff --git a/examples/debugprintfdemo/debugprintfdemo.c b/examples/debugprintfdemo/debugprintfdemo.c
index f5a801d6ae39a298e64ce9485eb7b4cd74df5f6a..297d2b8d640e1d1ac0aaa9202aaad30d39be630e 100644
--- a/examples/debugprintfdemo/debugprintfdemo.c
+++ b/examples/debugprintfdemo/debugprintfdemo.c
@@ -1,9 +1,5 @@
-// Really basic self-contained demo for the ch32v003
-// Doesn't rely on any of the weird HAL stuff from CH
-// Final executable is ~1/4th the size.
-
-// Could be defined here, or in the processor defines.
-#define SYSTEM_CORE_CLOCK 48000000
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
 
 #include "ch32v003fun.h"
 #include <stdio.h>
diff --git a/examples/optionbytes/optionbytes.c b/examples/optionbytes/optionbytes.c
index 25aaf5c9178eeae2dd395a1380a329ddb888d42d..fbec69aa3fadb2217ebacf4d07462e46e626e1ff 100644
--- a/examples/optionbytes/optionbytes.c
+++ b/examples/optionbytes/optionbytes.c
@@ -1,6 +1,17 @@
-// Really basic self-contained demo for the ch32v003
-// Doesn't rely on any of the weird HAL stuff from CH
-// Final executable is ~1/4th the size.
+/* This shows how to use the option bytes.  I.e. how do you disable NRST?
+   WARNING Portions of this code are under the following copyright.
+*/
+/********************************** (C) COPYRIGHT  *******************************
+ * File Name          : ch32v00x_flash.c
+ * Author             : WCH
+ * Version            : V1.0.0
+ * Date               : 2022/08/08
+ * Description        : This file provides all the FLASH firmware functions.
+ *********************************************************************************
+ * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+ * Attention: This software (modified or not) and binary are used for 
+ * microcontroller manufactured by Nanjing Qinheng Microelectronics.
+ *******************************************************************************/
 
 // Could be defined here, or in the processor defines.
 #define SYSTEM_CORE_CLOCK 48000000
diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index e31c7b9a836c419651fac200631e9e9626e5d230..b4cb47a24f5298637caebeda62c0acc2470398d6 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -385,8 +385,7 @@ help:
 	fprintf( stderr, " -b Reboot out of Halt\n" );
 	fprintf( stderr, " -e Resume from halt\n" );
 	fprintf( stderr, " -h Place into Halt\n" );
-	fprintf( stderr, " -D Configure NRST as GPIO **WARNING** If you do this and you reconfig\n" );
-	fprintf( stderr, "      the SWIO pin (PD1) on boot, your part can never again be programmed!\n" );
+	fprintf( stderr, " -D Configure NRST as GPIO\n" );
 	fprintf( stderr, " -d Configure NRST as NRST\n" );
 //	fprintf( stderr, " -P Enable Read Protection (UNTESTED)\n" );
 //	fprintf( stderr, " -p Disable Read Protection (UNTESTED)\n" );
@@ -562,6 +561,61 @@ static int InternalUnlockBootloader( void * dev )
 	return ret;
 }
 
+
+
+static int DefaultWriteHalfWord( void * dev, uint32_t address_to_write, uint32_t data )
+{
+	int ret = 0;
+	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
+	if( MCF.VoidHighLevelState ) MCF.VoidHighLevelState( dev );
+	iss->statetag = STTAG( "XXXX" );
+
+	MCF.WriteReg32( dev, DMABSTRACTAUTO, 0x00000000 ); // Disable Autoexec.
+
+	// Different address, so we don't need to re-write all the program regs.
+	// sh x8,0(x9)  // Write to the address.
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x00849023 );
+	MCF.WriteReg32( dev, DMPROGBUF1, 0x00100073 ); // c.ebreak
+
+	MCF.WriteReg32( dev, DMDATA0, address_to_write );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00231009 ); // Copy data to x9
+	MCF.WriteReg32( dev, DMDATA0, data );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00271008 ); // Copy data to x8, and execute program.
+
+	ret |= MCF.WaitForDoneOp( dev );
+	iss->currentstateval = -1;
+
+
+	return ret;
+}
+
+static int DefaultReadHalfWord( void * dev, uint32_t address_to_write, uint32_t * data )
+{
+	int ret = 0;
+	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
+	if( MCF.VoidHighLevelState ) MCF.VoidHighLevelState( dev );
+	iss->statetag = STTAG( "XXXX" );
+
+	MCF.WriteReg32( dev, DMABSTRACTAUTO, 0x00000000 ); // Disable Autoexec.
+
+	// Different address, so we don't need to re-write all the program regs.
+	// lh x8,0(x9)  // Write to the address.
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x00049403 );
+	MCF.WriteReg32( dev, DMPROGBUF1, 0x00100073 ); // c.ebreak
+
+	MCF.WriteReg32( dev, DMDATA0, address_to_write );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00231009 ); // Copy data to x9
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00241000 ); // Only execute.
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00221008 ); // Read x8 into DATA0.
+
+	ret |= MCF.WaitForDoneOp( dev );
+	iss->currentstateval = -1;
+
+
+	return ret | MCF.ReadReg32( dev, DMDATA0, data );
+}
+
+
 static int DefaultWriteWord( void * dev, uint32_t address_to_write, uint32_t data )
 {
 	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
@@ -764,13 +818,11 @@ timedout:
 static int DefaultReadWord( void * dev, uint32_t address_to_read, uint32_t * data )
 {
 	struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal);
-
 	if( iss->statetag != STTAG( "RDSQ" ) || address_to_read != iss->currentstateval )
 	{
 		if( iss->statetag != STTAG( "RDSQ" ) )
 		{
 			MCF.WriteReg32( dev, DMABSTRACTAUTO, 0 ); // Disable Autoexec.
-
 			// c.lw x8,0(x11) // Pull the address from DATA1
 			// c.lw x9,0(x8)  // Read the data at that location.
 			MCF.WriteReg32( dev, DMPROGBUF0, 0x40044180 );
@@ -1021,7 +1073,7 @@ int DefaultUnbrick( void * dev )
 
 	if( timeout == max_timeout ) 
 	{
-		printf( "Timed out trying to unbrick\n" );
+		fprintf( stderr, "Timed out trying to unbrick\n" );
 		return -5;
 	}
 	MCF.Erase( dev, 0, 0, 1);
@@ -1029,6 +1081,144 @@ int DefaultUnbrick( void * dev )
 	return -5;
 }
 
+int DefaultConfigureNRSTAsGPIO( void * dev, int one_if_yes_gpio  )
+{
+	fprintf( stderr, "Error: DefaultConfigureNRSTAsGPIO does not work via the programmer here.  Please see the demo \"optionbytes\"\n" );
+	return -5;
+#if 0
+	int ret = 0;
+	uint32_t csw;
+
+
+	if( MCF.ReadWord( dev, 0x1FFFF800, &csw ) )
+	{
+		fprintf( stderr, "Error: failed to get user word\n" );
+		return -5;
+	}
+
+	printf( "CSW WAS : %08x\n", csw );
+
+	MCF.WriteWord( dev, 0x40022008, 0x45670123 ); // OBKEYR = 0x40022008
+	MCF.WriteWord( dev, 0x40022008, 0xCDEF89AB );
+	MCF.WriteWord( dev, 0x40022004, 0x45670123 ); // FLASH->KEYR = 0x40022004
+	MCF.WriteWord( dev, 0x40022004, 0xCDEF89AB );
+	MCF.WriteWord( dev, 0x40022024, 0x45670123 ); // MODEKEYR = 0x40022024
+	MCF.WriteWord( dev, 0x40022024, 0xCDEF89AB );
+
+//XXXX THIS DOES NOT WORK IT CANNOT ERASE.
+	uint32_t ctlr;
+	if( MCF.ReadWord( dev, 0x40022010, &ctlr ) ) // FLASH->CTLR = 0x40022010
+	{
+		return -9;
+	}
+	ctlr |= CR_OPTER_Set | CR_STRT_Set; // OBER
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+
+	MCF.WriteHalfWord( dev, (intptr_t)&OB->RDPR, RDP_Key );
+
+    ctlr &=~CR_OPTER_Reset;
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+    ctlr |= CR_OPTPG_Set;
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+    ctlr &=~CR_OPTPG_Reset;
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+
+
+// This does work to write the option bytes, but does NOT work to erase.
+
+	if( MCF.ReadWord( dev, 0x40022010, &ctlr ) ) // FLASH->CTLR = 0x40022010
+	{
+		return -9;
+	}
+	ctlr |= CR_OPTPG_Set; //OBPG
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+
+	uint32_t config = OB_IWDG_HW | OB_STOP_NoRST | OB_STDBY_NoRST | (one_if_yes_gpio?OB_RST_NoEN:OB_RST_EN_DT1ms) | (uint16_t)0xE0;
+	printf( "Config (%08x): %08x\n", (intptr_t)&OB->USER, config );
+	MCF.WriteHalfWord( dev,  (intptr_t)&OB->USER, config );
+
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+
+	ctlr &= CR_OPTPG_Reset;
+	MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010
+
+
+	if( MCF.ReadWord( dev, 0x1FFFF800, &csw ) )
+	{
+		fprintf( stderr, "Error: failed to get user word\n" );
+		return -5;
+	}
+
+	//csw >>= 16; // Only want bottom part of word.
+	printf( "CSW: %08x\n", csw );
+
+#if 0
+	uint32_t prevuser;
+	if( MCF.ReadWord( dev, 0x1FFFF800, &prevuser ) )
+	{
+		fprintf( stderr, "Error: failed to get user word\n" );
+		return -5;
+	}
+
+	ret |= MCF.WaitForFlash( dev );
+
+	// Erase.
+	MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010
+	csw |= 1<<5;//OBER;
+	MCF.WriteWord( dev, 0x40022010, csw ); // FLASH->CTLR = 0x40022010
+	MCF.WriteHalfWord( dev, 0x1FFFF802, 0xffff );
+	ret |= MCF.WaitForDoneOp( dev );
+	ret |= MCF.WaitForFlash( dev );
+
+	MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010
+	printf( "CTLR: %08x\n", csw );
+	csw |= 1<<9;//OBPG, OBWRE
+	MCF.WriteWord( dev, 0x40022010, csw );
+
+	int j;
+	for( j = 0; j < 5; j++ )
+	{
+		if( MCF.ReadWord( dev, 0x1FFFF800, &prevuser ) )
+		{
+			fprintf( stderr, "Error: failed to get user word\n" );
+			return -5;
+		}
+
+		//csw >>= 16; // Only want bottom part of word.
+		printf( "CSW was: %08x\n", prevuser );
+		csw = prevuser >> 16;
+		csw = csw & 0xe7e7;
+		csw |= (one_if_yes_gpio?0b11:0b00)<<(3+0);
+		csw |= (one_if_yes_gpio?0b00:0b11)<<(3+8);
+		printf( "CSW writing: %08x\n", csw );
+		MCF.WriteHalfWord( dev, 0x1FFFF802, csw );
+		ret |= MCF.WaitForDoneOp( dev );
+		ret |= MCF.WaitForFlash( dev );
+	}
+
+
+	MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010
+	printf( "CTLR: %08x\n", csw );
+	csw &= ~(1<<9);//OBPG, OBWRE
+	MCF.WriteWord( dev, 0x40022010, csw );
+
+#endif
+	printf( "RET: %d\n", ret );
+	return 0;
+#endif
+}
+
 int DefaultPrintChipInfo( void * dev )
 {
 	uint32_t reg;
@@ -1072,8 +1262,12 @@ int SetupAutomaticHighLevelFunctions( void * dev )
 		MCF.ReadBinaryBlob = DefaultReadBinaryBlob;
 	if( !MCF.WriteWord )
 		MCF.WriteWord = DefaultWriteWord;
+	if( !MCF.WriteHalfWord )
+		MCF.WriteHalfWord = DefaultWriteHalfWord;
 	if( !MCF.ReadWord )
 		MCF.ReadWord = DefaultReadWord;
+	if( !MCF.ReadHalfWord )
+		MCF.ReadHalfWord = DefaultReadHalfWord;
 	if( !MCF.Erase )
 		MCF.Erase = DefaultErase;
 	if( !MCF.HaltMode )
@@ -1088,6 +1282,8 @@ int SetupAutomaticHighLevelFunctions( void * dev )
 		MCF.PrintChipInfo = DefaultPrintChipInfo;
 	if( !MCF.Unbrick )
 		MCF.Unbrick = DefaultUnbrick;
+	if( !MCF.ConfigureNRSTAsGPIO )
+		MCF.ConfigureNRSTAsGPIO = DefaultConfigureNRSTAsGPIO;
 
 	struct InternalState * iss = malloc( sizeof( struct InternalState ) );
 	iss->statetag = 0;
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
index de5302a76dd9847e9ea4c7a8d4b823f4668069a0..d10f1ffb20722357851caa5e8dbd5209b3932d94 100644
--- a/minichlink/minichlink.h
+++ b/minichlink/minichlink.h
@@ -31,7 +31,8 @@ struct MiniChlinkFunctions
 	int (*Erase)( void * dev, uint32_t address, uint32_t length, int type ); //type = 0 for fast, 1 for whole-chip
 
 	// MUST be 4-byte-aligned.
-	int (*WriteWord)( void * dev, uint32_t address_to_write, uint32_t data ); // Flags = 1 for "doing a fast FLASH write."
+	int (*VoidHighLevelState)( void * dev );
+	int (*WriteWord)( void * dev, uint32_t address_to_write, uint32_t data );
 	int (*ReadWord)( void * dev, uint32_t address_to_read, uint32_t * data );
 
 	int (*WaitForFlash)( void * dev );
@@ -52,6 +53,10 @@ struct MiniChlinkFunctions
 	int (*PollTerminal)( void * dev, uint8_t * buffer, int maxlen );
 
 	int (*PerformSongAndDance)( void * dev );
+
+	// Do Not override these.  they are cursed.
+	int (*WriteHalfWord)( void * dev, uint32_t address_to_write, uint32_t data );
+	int (*ReadHalfWord)( void * dev, uint32_t address_to_read, uint32_t * data );
 };
 
 /** If you are writing a driver, the minimal number of functions you can implement are:
diff --git a/minichlink/pgm-esp32s2-ch32xx.c b/minichlink/pgm-esp32s2-ch32xx.c
index 2b3c67d5574832dab892fdf1ef44316b6725be01..6f7b7fa041cc4fa3d58af3cb09033108784e2659 100644
--- a/minichlink/pgm-esp32s2-ch32xx.c
+++ b/minichlink/pgm-esp32s2-ch32xx.c
@@ -105,7 +105,7 @@ int ESPFlushLLCommands( void * dev )
 	if( r < 0 )
 	{
 		fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
-		return r;
+		exit( -9 );
 	}
 retry:
 	eps->reply[0] = 0xad; // Key report ID
@@ -247,6 +247,13 @@ int ESPPerformSongAndDance( void * dev )
 	return 0;
 }
 
+int ESPVoidHighLevelState( void * dev )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+	Write2LE( eps, 0x05fe );
+	ESPFlushLLCommands( dev );	
+	return 0;
+}
 
 void * TryInit_ESP32S2CHFUN()
 {
@@ -268,6 +275,7 @@ void * TryInit_ESP32S2CHFUN()
 	MCF.DelayUS = ESPDelayUS;
 	MCF.Control3v3 = ESPControl3v3;
 	MCF.Exit = ESPExit;
+	MCF.VoidHighLevelState = ESPVoidHighLevelState;
 
 	// These are optional. Disabling these is a good mechanismto make sure the core functions still work.
 	MCF.WriteWord = ESPWriteWord;