diff --git a/.github/workflows/minichlink.yml b/.github/workflows/minichlink.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ce757ad9bd8769549d533db2140f992e21439653
--- /dev/null
+++ b/.github/workflows/minichlink.yml
@@ -0,0 +1,67 @@
+name: Build minichlink
+
+on: [push, pull_request]
+#    push:
+#        paths:
+#            - minichlink/**
+#    pull_request:
+#        paths:
+#            - minichlink/**
+jobs:
+  build-minichlink:
+    strategy:
+        fail-fast: false
+        matrix:
+            os: [ubuntu-latest, macos-12, macos-11]
+    runs-on: ${{matrix.os}}
+    steps:
+    - uses: actions/checkout@v3
+    - name: Install Dependencies (Linux)
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      run: sudo apt-get update && sudo apt-get install -y build-essential make libusb-1.0-0-dev libudev-dev mingw-w64-x86-64-dev gcc-mingw-w64-x86-64
+    # we don't need to brew install libusb on Mac, actually preinstalled on the runner! :)
+    - name: Build (Linux, Mac)
+      run: |
+       cd minichlink
+       make clean
+       make V=1 -j3
+    # we cross-compile the Windows binaries from Linux 
+    - name: Build (for Windows)
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      run: |
+        cd minichlink
+        OS=Windows_NT make clean
+        OS=Windows_NT make V=1 -j3 minichlink.exe
+
+    - name: "Pack (Linux)"
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      run: tar czf minichlink.tar.gz -C minichlink minichlink minichlink.so 99-minichlink.rules
+    - name: "Pack (Mac)"
+      if: ${{ matrix.os == 'macos-12' || matrix.os == 'macos-11' }}
+      run: tar czf minichlink.tar.gz -C minichlink minichlink
+    # no packing needed for Windows as it's .exe only
+
+    - name: "Upload minichlink (Linux)"
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      uses: actions/upload-artifact@v3
+      with:
+        name: minichlink (Linux)
+        path: minichlink.tar.gz
+    - name: "Upload minichlink (MacOs 11)"
+      if: ${{ matrix.os == 'macos-11' }}
+      uses: actions/upload-artifact@v3
+      with:
+        name: minichlink (MacOS 11)
+        path: minichlink.tar.gz  
+    - name: "Upload minichlink (MacOs 12)"
+      if: ${{ matrix.os == 'macos-12' }}
+      uses: actions/upload-artifact@v3
+      with:
+        name: minichlink (MacOS 12)
+        path: minichlink.tar.gz  
+    - name: "Upload minichlink (Windows)"
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      uses: actions/upload-artifact@v3
+      with:
+        name: minichlink (Windows)
+        path: minichlink/minichlink.exe
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a9445131bff9ac74f443e4f7865bb47e32f54769..f79293a9c0b686f0cb5fcd5f5760dfcea671c309 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,5 @@
 minichlink/minichlink
 minichlink/minichlink.so
 compile_commands.json
+.clangd
+.cache
diff --git a/README.md b/README.md
index 51f5dc2d84e4edcada885326421857ba424124a1..95d0ace963f9abe23b676beee54473ed2a37da40 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,8 @@ Via gdbserver built into minichlink!  It works with `gdb-multiarch` as well as i
 
 ## System Prep
 
-For installation instructions, see the [https://github.com/cnlohr/ch32v003fun/wiki/Installation](wiki page here)
+For installation instructions, see the [wiki page here](https://github.com/cnlohr/ch32v003fun/wiki/Installation)
+
 
 You can use the pre-compiled minichlink or go to minichlink dir and `make` it.
 
diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index 3db230e278ae919ad2949855dda25c9299b9711a..6e6e60d4cd857cfa262c115b104370d6eef845c1 100644
--- a/ch32v003fun/ch32v003fun.c
+++ b/ch32v003fun/ch32v003fun.c
@@ -780,10 +780,10 @@ void handle_reset()
 "	li a0, 0x80\n\
 	csrw mstatus, a0\n\
 	li a3, 0x3\n\
-	csrw 0x804, a3\n\
 	la a0, InterruptVector\n\
 	or a0, a0, a3\n\
-	csrw mtvec, a0\n" );
+	csrw mtvec, a0\n" 
+	: : : "a0", "a3", "memory");
 
 	// Careful: Use registers to prevent overwriting of self-data.
 	// This clears out BSS.
@@ -810,8 +810,11 @@ asm volatile(
 #ifdef CPLUSPLUS
 	// Call __libc_init_array function
 "	call %0 \n\t"
-: : "i" (__libc_init_array) :
+: : "i" (__libc_init_array)
+#else
+: :
 #endif
+: "a0", "a1", "a2", "a3", "memory"
 );
 
 	SETUP_SYSTICK_HCLK
diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h
index 10d5fc22529216ca898f9b61e9c957712743bff4..1634bcb8e1d59b10b564fba9e94370168f4dddee 100644
--- a/ch32v003fun/ch32v003fun.h
+++ b/ch32v003fun/ch32v003fun.h
@@ -4633,6 +4633,47 @@ RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
   NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
 }
 
+/*********************************************************************
+ * SUSPEND ALL INTERRUPTS EXCEPT
+ * The following 3 functions serve to suspend all interrupts, except for the one you momentarily need.
+ * The purpose of this is to not disturb the one interrupt of interest and let it run unimpeded.
+ * procedure:
+ * 1. save the enabled IRQs: uint32_t IRQ_backup = NVIC_get_enabled_IRQs();
+ * 2. disable all IRQs: NVIC_clear_all_IRQs_except(IRQ_of_interest);
+ * 3. restore the previously enabled IRQs: NVIC_restore_IRQs(IRQ_backup);
+ * 
+ * bit layout of the IRQ backup
+ * bit		0 | 1 | 2  |  3  | 4  |  5  | 6  .. 22 | 23 .. 28
+ * IRQn		2 | 3 | 12 | res | 14 | res | 16 .. 31 | 32 .. 38
+ * IRQn 2 and 3 aren't actually user-settable (see RM).
+ * 
+ * Specifying an invalid IRQn_to_keep like 0 will disable all interrupts.
+ */
+
+RV_STATIC_INLINE uint32_t NVIC_get_enabled_IRQs()
+{
+	return ( ((NVIC->ISR[0] >> 2) & 0b11) | ((NVIC->ISR[0] >> 12) << 2) | ((NVIC->ISR[1] & 0b1111111) << 23) );
+}
+
+RV_STATIC_INLINE void NVIC_clear_all_IRQs_except(uint8_t IRQn_to_keep)
+{
+	if (!(IRQn_to_keep >> 5)) {		// IRQn_to_keep < 32
+		NVIC->IRER[0] = (~0) & (~(1 << IRQn_to_keep));
+		NVIC->IRER[1] = (~0);
+	}
+	else {
+		IRQn_to_keep = IRQn_to_keep >> 5;
+		NVIC->IRER[0] = (~0);
+		NVIC->IRER[1] = (~0) & (~(1 << IRQn_to_keep));
+	}
+}
+
+RV_STATIC_INLINE void NVIC_restore_IRQs(uint32_t old_state)
+{
+	NVIC->IENR[0] = (old_state >> 2) << 12;
+	NVIC->IENR[1] = old_state >> 23;
+}
+
 /*********************************************************************
  * @fn       __WFI
  *
diff --git a/ch32v003fun/ch32v003fun.mk b/ch32v003fun/ch32v003fun.mk
index 15330b3b62a6a343138612e7198d59cf3a89f9ca..278b7361d74b728961d7fe4678ce8931aca58ee3 100644
--- a/ch32v003fun/ch32v003fun.mk
+++ b/ch32v003fun/ch32v003fun.mk
@@ -52,9 +52,12 @@ gdbserver :
 clangd :
 	make clean
 	bear -- make build
+	@echo "CompileFlags:" > .clangd
+	@echo "  Remove: [-march=*, -mabi=*]" >> .clangd
 
 clangd_clean :
-	rm -f compile_commands.json
+	rm -f compile_commands.json .clangd
+	rm -rf .cache
 
 FLASH_COMMAND?=$(MINICHLINK)/minichlink -w $< $(WRITE_SECTION) -b
 
diff --git a/examples/GPIO/GPIO.c b/examples/GPIO/GPIO.c
index 148aa0198a1710d1b298fbf2f6c038201a90b6e6..a761850c339f8e445fc38585064b58a92c73a6ec 100644
--- a/examples/GPIO/GPIO.c
+++ b/examples/GPIO/GPIO.c
@@ -1,47 +1,199 @@
-// blink, but with arduino-like HAL
-// Could be defined here, or in the processor defines.
+// 2023-06-07 recallmenot
+
+#define DEMO_GPIO_blink					1
+#define DEMO_GPIO_out					0
+#define DEMO_GPIO_in_btn				0
+#define DEMO_ADC_bragraph				0
+#define DEMO_PWM_dayrider				0
+
+#if ((DEMO_GPIO_blink + DEMO_GPIO_out + DEMO_GPIO_in_btn + DEMO_ADC_bragraph + DEMO_PWM_dayrider) > 1 \
+  || (DEMO_GPIO_blink + DEMO_GPIO_out + DEMO_GPIO_in_btn + DEMO_ADC_bragraph + DEMO_PWM_dayrider) < 1)
+#error "please enable ONE of the demos by setting it to 1 and the others to 0"
+#endif
+
+
 #define SYSTEM_CORE_CLOCK 48000000
+#define APB_CLOCK SYSTEM_CORE_CLOCK
 
 #include "ch32v003fun.h"
-#include "wiring.h"
+
+#include "ch32v003_GPIO_branchless.h"
+
 #include <stdio.h>
 
-#define APB_CLOCK SYSTEM_CORE_CLOCK
 
-uint32_t count;
 
 int main() {
 	SystemInit48HSI();
 
-	// Enable GPIO ports
-	portEnable(port_C);
-	portEnable(port_D);
-
-	for (int i = pin_C0; i <= pin_C7; i++) {
-		pinMode(i, pinMode_O_pushPull);
+#if DEMO_GPIO_blink == 1
+	GPIO_portEnable(GPIO_port_C);
+	GPIO_portEnable(GPIO_port_D);
+	// GPIO D0 Push-Pull
+	GPIO_pinMode(GPIO_port_D, 0, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	// GPIO D4 Push-Pull
+	GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	// GPIO C0 Push-Pull
+	GPIO_pinMode(GPIO_port_C, 0, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+#elif DEMO_GPIO_out == 1
+	GPIO_portEnable(GPIO_port_C);
+	GPIO_portEnable(GPIO_port_D);
+	// GPIO D4 Push-Pull
+	GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	// GPIO C0 - C7 Push-Pull
+	for (int i = 0; i <= 7; i++) {
+		GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
 	}
-
+#elif DEMO_GPIO_in_btn == 1
+	GPIO_portEnable(GPIO_port_C);
+	GPIO_portEnable(GPIO_port_D);
+	// GPIO D4 Push-Pull
+	GPIO_pinMode(GPIO_port_D, 3, GPIO_pinMode_I_pullUp, GPIO_SPEED_IN);
+	// GPIO C0 - C7 Push-Pull
+	for (int i = 0; i <= 7; i++) {
+		GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	}
+#elif DEMO_ADC_bragraph == 1
+	GPIO_portEnable(GPIO_port_C);
+	GPIO_portEnable(GPIO_port_D);
 	// GPIO D4 Push-Pull
-	pinMode(pin_D4, pinMode_O_pushPull);
+	GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	// GPIO D6 analog in
+	GPIO_pinMode(GPIO_port_D, 6, GPIO_pinMode_I_analog, GPIO_SPEED_IN);
+	// GPIO C0 - C7 Push-Pull
+	for (int i = 0; i<= 7; i++) {
+		GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	}
+	GPIO_ADCinit();
+#elif DEMO_PWM_dayrider == 1
+	//SetupUART( UART_BRR );
+	GPIO_portEnable(GPIO_port_C);
+	GPIO_portEnable(GPIO_port_D);
+	// GPIO D4 Push-Pull
+	GPIO_pinMode(GPIO_port_D, 4, GPIO_pinMode_O_pushPull, GPIO_Speed_10MHz);
+	// GPIO D6 analog in
+	GPIO_pinMode(GPIO_port_D, 6, GPIO_pinMode_I_analog, GPIO_SPEED_IN);
+	// GPIO C0 - C7 Push-Pull
+	for (int i = 0; i<= 7; i++) {
+		GPIO_pinMode(GPIO_port_C, i, GPIO_pinMode_O_pushPullMux, GPIO_Speed_50MHz);
+	}
+	GPIO_tim2_map(GPIO_tim2_output_set_1__C5_C2_D2_C1);
+	GPIO_tim2_init();
+	GPIO_tim2_enableCH(4);
+	GPIO_tim2_enableCH(2);
+	GPIO_tim2_enableCH(1);
+	GPIO_tim1_map(GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1);
+	GPIO_tim1_init();
+	GPIO_tim1_enableCH(3);
+	GPIO_tim1_enableCH(4);
+#endif
+	
+
 
 	while (1) {
-		// Turn on pins
-		digitalWrite(pin_C0, high);
-		digitalWrite(pin_D4, high);
+#if DEMO_GPIO_blink == 1
+		GPIO_digitalWrite(GPIO_port_D, 0, high);
+		GPIO_digitalWrite(GPIO_port_D, 4, high);
+		GPIO_digitalWrite(GPIO_port_C, 0, high);
+		Delay_Ms( 250 );
+		GPIO_digitalWrite(GPIO_port_D, 0, low);
+		GPIO_digitalWrite(GPIO_port_D, 4, low);
+		GPIO_digitalWrite(GPIO_port_C, 0, low);
+		Delay_Ms( 250 );
+#elif DEMO_GPIO_out == 1
+		GPIO_digitalWrite(GPIO_port_D, 4, low);
+		Delay_Ms(1000);
+		GPIO_digitalWrite(GPIO_port_D, 4, high);
 		Delay_Ms(250);
-		// Turn off pins
-		digitalWrite(pin_C0, low);
-		digitalWrite(pin_D4, low);
-		Delay_Ms(250);
-		for (int i = pin_C0; i <= pin_C7; i++) {
-			digitalWrite(i, high);
+		for (int i = 0; i <= 7; i++) {
+			GPIO_digitalWrite_hi(GPIO_port_C, i);
 			Delay_Ms(50);
 		}
-		for (int i = pin_C7; i >= pin_C0; i--) {
-			digitalWrite(i, low);
+		for (int i = 7; i >= 0; i--) {
+			GPIO_digitalWrite_lo(GPIO_port_C, i);
 			Delay_Ms(50);
 		}
-		Delay_Ms(250);
-		count++;
+#elif DEMO_GPIO_in_btn == 1
+		uint8_t button_is_pressed = !GPIO_digitalRead(GPIO_port_D, 3);
+		static uint8_t leds_to_turn_on;
+		if (button_is_pressed && leds_to_turn_on < 8) {
+			leds_to_turn_on++;
+		}
+		else if (!button_is_pressed && leds_to_turn_on > 0) {
+			leds_to_turn_on--;
+		}
+		uint8_t led_i = 0;
+		for (int i = 0; i<= 7; i++) {
+			if (led_i < leds_to_turn_on) {
+				GPIO_digitalWrite_hi(GPIO_port_C, i);
+			}
+			else {
+				GPIO_digitalWrite_lo(GPIO_port_C, i);
+			}
+			led_i++;
+		}
+		Delay_Ms(50);
+#elif DEMO_ADC_bragraph == 1
+		GPIO_digitalWrite(GPIO_port_D, 4, high);
+		uint16_t analog_result = GPIO_analogRead(GPIO_Ain6_D6);
+		analog_result = analog_result > 10 ?
+				(analog_result < ((1 << 10) - 42) ? analog_result + 42 : (1 << 10))
+			: 0;
+		uint8_t leds_to_turn_on = analog_result >> 7;
+		uint8_t led_i = 0;
+		for (int i = 0; i<= 7; i++) {
+			if (led_i < leds_to_turn_on) {
+				GPIO_digitalWrite_hi(GPIO_port_C, i);
+			}
+			else {
+				GPIO_digitalWrite_lo(GPIO_port_C, i);
+			}
+			led_i++;
+		}
+		GPIO_digitalWrite(GPIO_port_D, 4, low);
+		Delay_Ms(50);
+#elif DEMO_PWM_dayrider == 1
+		#define NUMLEDS		5
+		#define TICKS_NEXT	149			// lower = faster scanning
+		#define TICK_i		2143			// lower = faster fade-out
+		GPIO_digitalWrite(GPIO_port_D, 4, high);
+		static uint8_t led_focus = 0;
+		static uint8_t direction = 0;
+
+		static uint16_t led_PW[NUMLEDS];
+
+		static uint32_t tick;
+
+		for (uint8_t i = 0; i < NUMLEDS; i++) {
+			if ((i == led_focus) && ((tick % TICKS_NEXT) == 0)) {
+				led_PW[i] = 1023;
+				//printf("focus %u, tick %u, direction %u\r\n", led_focus, tick, direction);
+				if (direction == 0) {
+					led_focus++;
+					if (led_focus >= (NUMLEDS - 1)) {
+						direction = 1;
+					}
+				}
+				else {
+					led_focus--;
+					if (led_focus == 0) {
+						direction = 0;
+					}
+				}
+				tick++;
+			}
+			else {
+				led_PW[i] = (led_PW[i] > 2) ? (led_PW[i] - 3) : 0;
+			}
+		}
+		GPIO_tim2_analogWrite(4, led_PW[0]);
+		GPIO_tim2_analogWrite(2, led_PW[1]);
+		GPIO_tim1_analogWrite(3, led_PW[2]);
+		GPIO_tim1_analogWrite(4, led_PW[3]);
+		GPIO_tim2_analogWrite(1, led_PW[4]);
+		GPIO_digitalWrite(GPIO_port_D, 4, low);
+		tick++;
+		Delay_Us(TICK_i);
+#endif
 	}
 }
diff --git a/examples/GPIO/Makefile b/examples/GPIO/Makefile
index 87347371d38e65e7c05f84225b553f957d5d1eca..7e60f814bb33181340eca2ad204cee695088fcc8 100644
--- a/examples/GPIO/Makefile
+++ b/examples/GPIO/Makefile
@@ -3,7 +3,7 @@ all : flash
 TARGET:=GPIO
 
 CFLAGS+=-DTINYVECTOR
-ADDITIONAL_C_FILES+=../../extralibs/wiring.c
+CFLAGS+=-DSTDOUT_UART
 
 include ../../ch32v003fun/ch32v003fun.mk
 
diff --git a/examples/GPIO/README.md b/examples/GPIO/README.md
index a6c23799ff7e6df932b10774273f86094daac8b3..33ac22d79daecb0e64c0c96c8df2f0d50450934a 100644
--- a/examples/GPIO/README.md
+++ b/examples/GPIO/README.md
@@ -1,14 +1,22 @@
-# GPIO Libaray
-On the shoulders of the Blink example, this Arduino-like GPIO library stands.
+# one GPIO libaray to rule them all
 
-All pins are adressable as outputs, inputs, with pull-up, etc.
-The pins are in an enum, so you can call them by their name and iterate over them.
+This Arduino-like GPIO library offers
+ * digital IO
+ * analog-to-digital
+ * digital-to-analog (PWM)
 
-It's your responsibility to not blow up a pin.
-Only use one pin for one thing and you should be fine.
+Great care has been taken to make the resulting code as fast and tiny as possible. Let the compiler suffer!  
+Hand-written blink compiles to 500 bytes, blink using this library compiles to 504 bytes!  
 
 # GPIO Example
-Connect LED + 1k resistor to each pin (C0 to C7 and D4) and GND.
-Marvel at the colorful glory.
 
-https://user-images.githubusercontent.com/104343143/231585338-725f1197-dfa0-484d-8707-f0824af80b7e.mp4
+Connect LED + 1k resistor to each LED pin (C0 to C7 and D4) and GND.  
+Connect a button to GND and D3.  
+Connect a 10k pot between GND and VCC, wiper to D6.  
+
+The desired demo may be selected in GPIO.c by setting it to 1 and the others to 0.  
+Marvel at the colorful glory.  
+
+
+
+https://github.com/recallmenot/ch32v003fun/assets/104343143/afb4027d-a609-467a-96c5-0cc3283366a4
diff --git a/examples/GPIO_analogRead/GPIO_analogRead.c b/examples/GPIO_analogRead/GPIO_analogRead.c
deleted file mode 100644
index 76df1facacafbbf45260486402d91266f1f93d7a..0000000000000000000000000000000000000000
--- a/examples/GPIO_analogRead/GPIO_analogRead.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// blink, but with arduino-like HAL
-// Could be defined here, or in the processor defines.
-#define SYSTEM_CORE_CLOCK 48000000
-
-#include "ch32v003fun.h"
-#include "wiring.h"
-#include <stdio.h>
-
-#define APB_CLOCK SYSTEM_CORE_CLOCK
-
-uint32_t count;
-
-int main() {
-	SystemInit48HSI();
-
-	// Enable GPIO ports
-	portEnable(port_C);
-	portEnable(port_D);
-
-	for (int i = pin_C0; i <= pin_C7; i++) {
-		pinMode(i, pinMode_O_pushPull);
-	}
-
-	// GPIO D4 Push-Pull
-	pinMode(pin_D4, pinMode_O_pushPull);
-
-	pinMode(pin_D6, pinMode_I_analog);
-	ADCinit();
-
-	while (1) {
-		digitalWrite(pin_D4, high);
-		uint8_t leds_to_turn_on = (uint8_t)(((float)(analogRead(Ain6_D6)) / 1024.f) * 8.f * 1.2 - 1.f);
-		uint8_t led_i = 0;
-		for (int i = pin_C0; i <= pin_C7; i++) {
-			if (led_i < leds_to_turn_on) {
-				digitalWrite(i, high);
-			}
-			else {
-				digitalWrite(i, low);
-			}
-			led_i++;
-		}
-		digitalWrite(pin_D4, low);
-		Delay_Ms(250);
-		count++;
-	}
-}
diff --git a/examples/GPIO_analogRead/README.md b/examples/GPIO_analogRead/README.md
deleted file mode 100644
index 3b9e1b6ca6799c77987e830cf7ea868d095601b5..0000000000000000000000000000000000000000
--- a/examples/GPIO_analogRead/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# GPIO Libaray
-On the shoulders of the Blink and the adc_polled example, this Arduino-like GPIO + ADC library stands.
-
-All pins are adressable as outputs, inputs, with pull-up, etc. but now you can also read the eight muxed inputs.
-The pins are in an enum, so you can call them by their name and iterate over them.
-
-It has been extended by an arduino-like analogRead function.
-
-It's your responsibility to not blow up a pin.
-Only use one pin for one thing and you should be fine.
-
-# GPIO Example
-Connect LED + 1k resistor to each pin (C0 to C7 and D4) and GND.
-Connect a 10k pot between GND and VCC, wiper to D6.
-Marvel at the colorful glory.
-
-https://user-images.githubusercontent.com/104343143/231814680-d41ae68f-dc7b-4c9c-a3c7-0b88cc82e541.mp4
diff --git a/examples/blink/blink.bin b/examples/blink/blink.bin
index 9d2f625331af46afe752e4c674ea3ca6a67b5f49..b2c6174d1dac1759b26f345f4dde42f709e0e59e 100755
Binary files a/examples/blink/blink.bin and b/examples/blink/blink.bin differ
diff --git a/examples/GPIO_analogRead/Makefile b/examples/tim2_pwm_remap/Makefile
similarity index 50%
rename from examples/GPIO_analogRead/Makefile
rename to examples/tim2_pwm_remap/Makefile
index a965d90a0e3e624237b8b7234cfce7e09475c44e..36df10e860825f2e0d005debbe3cbcb791b2b591 100644
--- a/examples/GPIO_analogRead/Makefile
+++ b/examples/tim2_pwm_remap/Makefile
@@ -1,9 +1,7 @@
 all : flash
 
-TARGET:=GPIO_analogRead
+TARGET:=tim2_pwm_remap
 
-CFLAGS+=-DTINYVECTOR
-ADDITIONAL_C_FILES+=../../extralibs/wiring.c
 
 include ../../ch32v003fun/ch32v003fun.mk
 
diff --git a/examples/tim2_pwm_remap/tim2_pwm_remap.c b/examples/tim2_pwm_remap/tim2_pwm_remap.c
new file mode 100644
index 0000000000000000000000000000000000000000..1d2c4bbfa43fab930c8ccdbd69b776b7e84e33dd
--- /dev/null
+++ b/examples/tim2_pwm_remap/tim2_pwm_remap.c
@@ -0,0 +1,175 @@
+/*
+ * Example for using AFIO to remap peripheral outputs to alternate configuration
+ * 06-01-2023 B. Roy, based on previous work by:
+ * 03-28-2023 E. Brombaugh
+ * 05-29-2023 recallmenot adapted from Timer1 to Timer2
+ *
+ * Usage: 
+ * Connect LEDs between PD3 and GND, PD4 and GND, PC1 and GND, and PC7 and GND
+ * Observe activity on PD3 and PD4, then activity on PC1 and PC7, and back
+ *
+ * Nutshell:
+ * 1. Ensure you're providing a clock to the AFIO peripheral! Save yourself an 
+ * 	hour of troubleshooting!
+ *	RCC->APB2PCENR |= RCC_APB2Periph_AFIO
+ * 2. Apply the remapping configuration bits to the AFIO register:
+ * 	AFIO->PCFR1 |= AFIO_PCFR1_TIM2_REMAP_FULLREMAP
+ * 3. Go on about your business.
+ *
+ * /
+
+
+Timer 2 pin mappings by AFIO->PCFR1
+	00	AFIO_PCFR1_TIM2_REMAP_NOREMAP
+		D4		T2CH1ETR
+		D3		T2CH2
+		C0		T2CH3
+		D7		T2CH4  --note: requires disabling nRST in opt
+	01	AFIO_PCFR1_TIM2_REMAP_PARTIALREMAP1
+		C5		T2CH1ETR_
+		C2		T2CH2_
+		D2		T2CH3_
+		C1		T2CH4_
+	10	AFIO_PCFR1_TIM2_REMAP_PARTIALREMAP2
+		C1		T2CH1ETR_
+		D3		T2CH2
+		C0		T2CH3
+		D7		T2CH4  --note: requires disabling nRST in opt
+	11	AFIO_PCFR1_TIM2_REMAP_FULLREMAP
+		C1		T2CH1ETR_
+		C7		T2CH2_
+		D6		T2CH3_
+		D5		T2CH4_
+*/
+
+// Could be defined here, or in the processor defines.
+#define SYSTEM_CORE_CLOCK 48000000
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+/******************************************************************************************
+ * initialize TIM2 for PWM
+ ******************************************************************************************/
+void t2pwm_init( void )
+{
+	// Enable GPIOC, GPIOD, TIM2, and AFIO *very important!*
+	RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC;
+	RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
+
+	// PD4 is T2CH1, 10MHz Output alt func, push-pull (also works in oepn drain OD_AF)
+	GPIOD->CFGLR &= ~(0xf<<(4*4));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
+
+	// PD3 is T2CH2, 10MHz Output alt func, push-pull (also works in oepn drain OD_AF)
+	GPIOD->CFGLR &= ~(0xf<<(4*3));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
+
+	// PC1 is T2CH1_, 10MHz Output alt func, push-pull (also works in oepn drain OD_AF)
+	GPIOC->CFGLR &= ~(0xf<<(4*1));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*1);
+
+	// PC7 is T2CH2_, 10MHz Output alt func, push-pull (also works in oepn drain OD_AF)
+	GPIOC->CFGLR &= ~(0xf<<(4*7));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*7);
+	
+	// Reset TIM2 to init all regs
+	RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
+	RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
+	
+	// SMCFGR: default clk input is CK_INT
+	// set TIM2 clock prescaler divider 
+	TIM2->PSC = 0x0000;
+	// set PWM total cycle width
+	TIM2->ATRLR = 255;
+	
+	// for channel 1 and 2, let CCxS stay 00 (output), set OCxM to 110 (PWM I)
+	// enabling preload causes the new pulse width in compare capture register only to come into effect when UG bit in SWEVGR is set (= initiate update) (auto-clears)
+	TIM2->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1 | TIM_OC1PE;
+	TIM2->CHCTLR1 |= TIM_OC2M_2 | TIM_OC2M_1 | TIM_OC2PE;
+
+	// CTLR1: default is up, events generated, edge align
+	// enable auto-reload of preload
+	TIM2->CTLR1 |= TIM_ARPE;
+
+	// Enable CH1 output, positive pol
+	TIM2->CCER |= TIM_CC1E | TIM_CC1P;
+	// Enable CH2 output, positive pol
+	TIM2->CCER |= TIM_CC2E | TIM_CC2P;
+
+	// initialize counter
+	TIM2->SWEVGR |= TIM_UG;
+
+	// Enable TIM2
+	TIM2->CTLR1 |= TIM_CEN;
+}
+
+/*****************************************************************************************
+ * set timer channel PW
+ *****************************************************************************************/
+void t2pwm_setpw(uint8_t chl, uint16_t width)
+{
+	switch(chl&3)
+	{
+		case 0: TIM2->CH1CVR = width; break;
+		case 1: TIM2->CH2CVR = width; break;
+		case 2: TIM2->CH3CVR = width; break;
+		case 3: TIM2->CH4CVR = width; break;
+	}
+	TIM2->SWEVGR |= TIM_UG; // load new value in compare capture register
+}
+
+/*****************************************************************************************
+ * Remap T1CH1/T1CH2 from PD4/PD3 to PC1/PC7
+ *
+ * Can remap on-the fly; no need to re-initialize timers, reset GPIO mode/config, etc.
+ *
+ * Leaves the previous pins configured as 'alternate function' mode - i.e. disconnected
+ * from the GPIO peripheral, and floating.
+ *
+ *****************************************************************************************/
+void ToggleRemap(void) {
+	if(AFIO->PCFR1 & AFIO_PCFR1_TIM2_REMAP_FULLREMAP) {
+		AFIO->PCFR1 &= AFIO_PCFR1_TIM2_REMAP_NOREMAP;   //clear remapping bits
+		printf("Standard Mapping!\r\n");
+	}
+	else {
+		AFIO->PCFR1 |= AFIO_PCFR1_TIM2_REMAP_FULLREMAP; //set fullremap mode
+		printf("Full Remapping!\r\n");
+	}
+};
+
+/*****************************************************************************************
+ * entry
+ *****************************************************************************************/
+int main()
+{
+	uint32_t count = 0;
+	
+	SystemInit48HSI();
+
+	// start serial @ default 115200bps
+	SetupDebugPrintf();
+
+	Delay_Ms( 100 );
+	printf("\r\r\n\ntim2_pwm example, with remap\n\r");
+
+	// init TIM2 for PWM
+	printf("initializing tim2...");
+	t2pwm_init();
+	printf("done.\n\r");
+		
+	printf("looping...\n\r");
+	
+	while(1)
+	{
+		for(;count<255;count++){
+			t2pwm_setpw(0, count);		// Chl 1
+			t2pwm_setpw(1, 255-count);	// Chl 2 180° out-of-phase
+			Delay_Ms( 5 );
+		}
+		count = 0;
+		ToggleRemap();
+	}
+}
diff --git a/extralibs/ch32v003_GPIO_branchless.h b/extralibs/ch32v003_GPIO_branchless.h
new file mode 100644
index 0000000000000000000000000000000000000000..455716b669f8438108fccdfd0c9f27feb82c263f
--- /dev/null
+++ b/extralibs/ch32v003_GPIO_branchless.h
@@ -0,0 +1,474 @@
+// 2023-06-07 recallmenot
+
+//######## necessities
+
+// include guards
+#ifndef CH32V003_GPIO_BR_H
+#define CH32V003_GPIO_BR_H
+
+// includes
+#include <stdint.h>								//uintN_t support
+#include "../ch32v003fun/ch32v003fun.h"
+
+
+
+/*######## library description
+This is a speedy and light GPIO library due to
+	static inlining of most functions
+	compile-time abstraction
+	branchless where it counts
+*/
+
+
+
+/*######## library usage and configuration
+
+first, enable the desired port.
+
+digital usage is quite Arduino-like:
+pinMode
+digitalWrite
+digitalWrite_lo
+digitalWrite_hi
+digitalRead
+
+
+
+analog-to-digital usage is almost Arduino-like:
+pinMode
+ADCinit
+analogRead
+
+By default, this library inserts a delay of 300 µs between configuration of the ADC input mux and the time the conversion starts.
+This serves to counteract the high input impedance of the ADC, especially if it is increased by external resistors.
+The input impedance of port A appears to be especially large.
+You may modify it to your liking using the following define before including this library.
+#define GPIO_ADC_MUX_DELAY 1200
+
+GPIO_ADC_sampletime controls the time each conversion is granted, by default it is GPIO_ADC_sampletime_241cy_default, all options originate from the GPIO_ADC_sampletimes enum.
+To alter it, you have 3 options:
+ * `#define GPIO_ADC_sampletime GPIO_ADC_sampletime_43cy` before including this library
+ * call the GPIO_ADC_set_sampletime function-like macro to momentarrily set it for one channel
+ * call the GPIO_ADC_set_sampletimes_all function-like macro to to momentarrily set it for all channels
+
+You may also disable the ADC to save power between infrequent measurements.
+
+
+
+digital-to-analog (PWM) usage is quite different:
+pinMode
+GPIO_timX_map
+GPIO_timX_init
+GPIO_timX_enableCH
+GPIO_timX_analogWrite
+
+This is due to the fact that the CH32V003 has 2 timers, which each can be connected to 4 pre-defined sets (mappings) of pins.
+Then you address the 4 channels of the timers, instead of the pins.
+
+By default, the timers will be configured to count up to 2^10, which is 10 bits or 1024 discrete steps.
+You may alter this to suit your needs, for example to an 8 bit resolution (256 discrete steps).
+Insert this before including this library:
+#define GPIO_timer_resolution (1 << 8)
+
+By default, the timers will operate with a clock prescaler of 2 but you may choose 1 or 4 if you wish to alter the speed.
+Insert this before including this library:
+#define GPIO_timer_prescaler TIM_CKD_DIV1;		// APB_CLOCK / 1024 / 1 = 46.9kHz
+
+You may calculate the base frequency of the timer (the rate of repetition of your signal) like follows:
+fpwm = APB_CLOCK / resolution / prescaler
+This puts the defaults at an inaudible 23.4kHz.
+The higher the frequency, the greater the EMI radiation will be.
+With low frequencies, say below 1000Hz, LEDs may exhibit perceivable flicker.
+
+*/
+
+
+
+//######## ports, pins and states: use these for the functions below!
+
+enum GPIO_port_n {
+	GPIO_port_A = 0b00,
+	GPIO_port_C = 0b10,
+	GPIO_port_D = 0b11,
+};
+
+enum GPIO_pinModes {
+	GPIO_pinMode_I_floating,
+	GPIO_pinMode_I_pullUp,
+	GPIO_pinMode_I_pullDown,
+	GPIO_pinMode_I_analog,
+	GPIO_pinMode_O_pushPull,
+	GPIO_pinMode_O_openDrain,
+	GPIO_pinMode_O_pushPullMux,
+	GPIO_pinMode_O_openDrainMux,
+};
+
+enum lowhigh {
+	low,
+	high,
+};
+
+// analog inputs
+enum GPIO_analog_inputs {
+	GPIO_Ain0_A2,
+	GPIO_Ain1_A1,
+	GPIO_Ain2_C4,
+	GPIO_Ain3_D2,
+	GPIO_Ain4_D3,
+	GPIO_Ain5_D5,
+	GPIO_Ain6_D6,
+	GPIO_Ain7_D4,
+	GPIO_AinVref,
+	GPIO_AinVcal,
+};
+
+// how many cycles the ADC shall sample the input for (speed vs precision)
+enum GPIO_ADC_sampletimes {
+	GPIO_ADC_sampletime_3cy,
+	GPIO_ADC_sampletime_9cy,
+	GPIO_ADC_sampletime_15cy,
+	GPIO_ADC_sampletime_30cy,
+	GPIO_ADC_sampletime_43cy,
+	GPIO_ADC_sampletime_57cy,
+	GPIO_ADC_sampletime_73cy,
+	GPIO_ADC_sampletime_241cy_default,
+};
+
+enum GPIO_tim1_output_sets {
+	GPIO_tim1_output_set_0__D2_A1_C3_C4__D0_A2_D1,
+	GPIO_tim1_output_set_1__C6_C7_C0_D3__C3_C4_D1,
+	GPIO_tim1_output_set_2__D2_A1_C3_C4__D0_A2_D1,
+	GPIO_tim1_output_set_3__C4_C7_C5_D4__C3_D2_C6,
+};
+
+enum GPIO_tim2_output_sets {
+	GPIO_tim2_output_set_0__D4_D3_C0_D7,
+	GPIO_tim2_output_set_1__C5_C2_D2_C1,
+	GPIO_tim2_output_set_2__C1_D3_C0_D7,
+	GPIO_tim2_output_set_3__C1_C7_D6_D5,
+};
+
+
+
+//######## interface function overview: use these!
+// most functions have been reduced to function-like macros, actual definitions downstairs
+
+// setup
+#define GPIO_portEnable(GPIO_port_n)
+#define GPIO_pinMode(GPIO_port_n, pin, pinMode, GPIO_Speed)
+
+// digital
+#define GPIO_digitalWrite_hi(GPIO_port_n, pin)
+#define GPIO_digitalWrite_lo(GPIO_port_n, pin)
+#define GPIO_digitalWrite(GPIO_port_n, pin, lowhigh)
+#define GPIO_digitalWrite_branching(GPIO_port_n, pin, lowhigh)
+#define GPIO_digitalRead(GPIO_port_n, pin)
+
+// analog to digital
+static inline void GPIO_ADCinit();
+#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime)
+#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime)
+#define GPIO_ADC_set_power(enable)
+#define GPIO_ADC_calibrate()
+static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input);
+
+// digital to analog (PWM)
+#define GPIO_tim1_map(GPIO_tim1_output_set)
+#define GPIO_tim2_map(GPIO_tim2_output_set)
+static inline void GPIO_tim1_init();
+static inline void GPIO_tim2_init();
+#define GPIO_tim1_enableCH(channel)
+#define GPIO_tim2_enableCH(channel)
+#define GPIO_tim1_analogWrite(channel, value)
+#define GPIO_tim2_analogWrite(channel, value)
+
+
+
+//######## internal function declarations
+
+
+
+//######## internal variables
+
+
+
+//######## preprocessor macros
+
+#define CONCAT(a, b) a ## b
+#define CONCAT_INDIRECT(a, b) CONCAT(a, b)
+
+#define GPIOx_to_port_n2(GPIOx)				GPIOx_to_port_n_##GPIOx
+#define GPIOx_to_port_n(GPIOx)				GPIOx_to_port_n2(GPIOx)
+#define GPIOx_to_port_n_GPIO_port_A			0b00
+#define GPIOx_to_port_n_GPIO_port_C			0b10
+#define GPIOx_to_port_n_GPIO_port_D			0b11
+
+#define GPIO_port_n_to_GPIOx2(GPIO_port_n)		GPIO_port_n_to_GPIOx_##GPIO_port_n
+#define GPIO_port_n_to_GPIOx(GPIO_port_n)		GPIO_port_n_to_GPIOx2(GPIO_port_n)
+#define GPIO_port_n_to_GPIOx_GPIO_port_A		GPIOA
+#define GPIO_port_n_to_GPIOx_GPIO_port_C		GPIOC
+#define GPIO_port_n_to_GPIOx_GPIO_port_D		GPIOD
+
+#define GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)	GPIO_port_n_to_RCC_APB2Periph_##GPIO_port_n
+#define GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n)	GPIO_port_n_to_RCC_APB2Periph2(GPIO_port_n)
+#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_A	RCC_APB2Periph_GPIOA
+#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_C	RCC_APB2Periph_GPIOC
+#define GPIO_port_n_to_RCC_APB2Periph_GPIO_port_D	RCC_APB2Periph_GPIOD
+
+#define GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)				GPIO_pinMode_to_CFG_##GPIO_pinMode(GPIO_Speed)
+#define GPIO_pinMode_to_CFG(GPIO_pinMode, GPIO_Speed)				GPIO_pinMode_to_CFG2(GPIO_pinMode, GPIO_Speed)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_floating(GPIO_Speed)			(GPIO_SPEED_IN	| GPIO_CNF_IN_FLOATING)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullUp(GPIO_Speed)			(GPIO_SPEED_IN	| GPIO_CNF_IN_PUPD)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_pullDown(GPIO_Speed)			(GPIO_SPEED_IN	| GPIO_CNF_IN_PUPD)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_I_analog(GPIO_Speed)			(GPIO_SPEED_IN	| GPIO_CNF_IN_ANALOG)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPull(GPIO_Speed)			(GPIO_Speed	| GPIO_CNF_OUT_PP)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrain(GPIO_Speed)		(GPIO_Speed	| GPIO_CNF_OUT_OD)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_pushPullMux(GPIO_Speed)		(GPIO_Speed	| GPIO_CNF_OUT_PP_AF)
+#define GPIO_pinMode_to_CFG_GPIO_pinMode_O_openDrainMux(GPIO_Speed)		(GPIO_Speed	| GPIO_CNF_IN_ANALOG)
+
+#define GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n, pin)			GPIO_pinMode_set_PUPD_##GPIO_pinMode(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD(GPIO_pinMode, GPIO_port_n, pin)			GPIO_pinMode_set_PUPD2(GPIO_pinMode, GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_floating(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullUp(GPIO_port_n, pin)		GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_pullDown(GPIO_port_n, pin)		GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << (pin + 16))
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_I_analog(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPull(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrain(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_pushPullMux(GPIO_port_n, pin)
+#define GPIO_pinMode_set_PUPD_GPIO_pinMode_O_openDrainMux(GPIO_port_n, pin)
+
+#if !defined(GPIO_ADC_MUX_DELAY)
+#define GPIO_ADC_MUX_DELAY 200
+#endif
+
+#if !defined(GPIO_ADC_sampletime)
+#define GPIO_ADC_sampletime GPIO_ADC_sampletime_241cy_default
+#endif
+
+#if !defined(GPIO_timer_resolution)
+#define GPIO_timer_resolution (1 << 10)
+#endif
+
+#if !defined(GPIO_timer_prescaler)
+#define GPIO_timer_prescaler TIM_CKD_DIV2		// APB_CLOCK / 1024 / 2 = 23.4kHz
+#endif
+
+// maintenance define
+#if !defined(SYSTEM_CORE_CLOCK)
+#define SYSTEM_CORE_CLOCK 48000000
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+#endif
+
+
+
+//######## define requirements / maintenance defines
+
+
+
+//######## small function definitions, static inline
+
+
+#undef GPIO_portEnable
+#define GPIO_portEnable(GPIO_port_n) RCC->APB2PCENR |= GPIO_port_n_to_RCC_APB2Periph(GPIO_port_n);
+
+#undef GPIO_pinMode
+#define GPIO_pinMode(GPIO_port_n, pin, pinMode, GPIO_Speed) ({							\
+	GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR &= ~(0b1111 << (4 * pin));					\
+	GPIO_port_n_to_GPIOx(GPIO_port_n)->CFGLR |= (GPIO_pinMode_to_CFG(pinMode, GPIO_Speed) << (4 * pin));	\
+	GPIO_pinMode_set_PUPD(pinMode, GPIO_port_n, pin);							\
+})
+
+#undef GPIO_digitalWrite_hi
+#define GPIO_digitalWrite_hi(GPIO_port_n, pin)		GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << pin)
+#undef GPIO_digitalWrite_lo
+#define GPIO_digitalWrite_lo(GPIO_port_n, pin)		GPIO_port_n_to_GPIOx(GPIO_port_n)->BSHR = (1 << (pin + 16))
+
+#undef GPIO_digitalWrite
+#define GPIO_digitalWrite2(GPIO_port_n, pin, lowhigh)	GPIO_digitalWrite_##lowhigh(GPIO_port_n, pin)
+#define GPIO_digitalWrite(GPIO_port_n, pin, lowhigh)	GPIO_digitalWrite2(GPIO_port_n, pin, lowhigh)
+#define GPIO_digitalWrite_low(GPIO_port_n, pin)		GPIO_digitalWrite_lo(GPIO_port_n, pin)
+#define GPIO_digitalWrite_0(GPIO_port_n, pin)		GPIO_digitalWrite_lo(GPIO_port_n, pin)
+#define GPIO_digitalWrite_high(GPIO_port_n, pin)	GPIO_digitalWrite_hi(GPIO_port_n, pin)
+#define GPIO_digitalWrite_1(GPIO_port_n, pin)		GPIO_digitalWrite_hi(GPIO_port_n, pin)
+
+#undef GPIO_digitalWrite_branching
+#define GPIO_digitalWrite_branching(GPIO_port_n, pin, lowhigh)		(lowhigh ? GPIO_digitalWrite_hi(GPIO_port_n, pin) : GPIO_digitalWrite_lo(GPIO_port_n, pin))
+
+#undef GPIO_digitalRead
+#define GPIO_digitalRead(GPIO_port_n, pin)	 	((GPIO_port_n_to_GPIOx(GPIO_port_n)->INDR >> pin) & 0b1)
+
+
+#undef GPIO_ADC_set_sampletime
+// 0:7 => 3/9/15/30/43/57/73/241 cycles
+#define GPIO_ADC_set_sampletime(GPIO_analog_input, GPIO_ADC_sampletime) ({	\
+	ADC1->SAMPTR2 &= ~(0b111) << (3 * GPIO_analog_input);			\
+	ADC1->SAMPTR2 |= GPIO_ADC_sampletime << (3 * GPIO_analog_input);	\
+})
+
+#undef GPIO_ADC_set_sampletimes_all
+#define GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime) ({	\
+	ADC1->SAMPTR2 &= 0;					\
+	ADC1->SAMPTR2 |=					\
+			GPIO_ADC_sampletime << (0 * 3)		\
+		|	GPIO_ADC_sampletime << (1 * 3)		\
+		|	GPIO_ADC_sampletime << (2 * 3)		\
+		|	GPIO_ADC_sampletime << (3 * 3)		\
+		|	GPIO_ADC_sampletime << (4 * 3)		\
+		|	GPIO_ADC_sampletime << (5 * 3)		\
+		|	GPIO_ADC_sampletime << (6 * 3)		\
+		|	GPIO_ADC_sampletime << (7 * 3)		\
+		|	GPIO_ADC_sampletime << (8 * 3)		\
+		|	GPIO_ADC_sampletime << (9 * 3);		\
+	ADC1->SAMPTR1 &= 0;					\
+	ADC1->SAMPTR1 |=					\
+			GPIO_ADC_sampletime << (0 * 3)		\
+		|	GPIO_ADC_sampletime << (1 * 3)		\
+		|	GPIO_ADC_sampletime << (2 * 3)		\
+		|	GPIO_ADC_sampletime << (3 * 3)		\
+		|	GPIO_ADC_sampletime << (4 * 3)		\
+		|	GPIO_ADC_sampletime << (5 * 3);		\
+})
+
+#undef GPIO_ADC_set_power
+#define GPIO_ADC_set_power2(enable) GPIO_ADC_set_power_##enable
+#define GPIO_ADC_set_power(enable) GPIO_ADC_set_power2(enable)
+#define GPIO_ADC_set_power_1 ADC1->CTLR2 |= ADC_ADON
+#define GPIO_ADC_set_power_0 ADC1->CTLR2 &= ~(ADC_ADON)
+
+#undef GPIO_ADC_calibrate
+#define GPIO_ADC_calibrate() ({			\
+	ADC1->CTLR2 |= ADC_RSTCAL;		\
+	while(ADC1->CTLR2 & ADC_RSTCAL);	\
+	ADC1->CTLR2 |= ADC_CAL;			\
+	while(ADC1->CTLR2 & ADC_CAL);		\
+})
+
+// large but will likely only ever be called once
+static inline void GPIO_ADCinit() {
+	// select ADC clock source
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+
+	// enable clock to the ADC
+	RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
+
+	// Reset the ADC to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
+
+	// set sampling time for all inputs to 241 cycles
+	GPIO_ADC_set_sampletimes_all(GPIO_ADC_sampletime);
+
+	// set trigger to software
+	ADC1->CTLR2 |= ADC_EXTSEL;
+
+	// pre-clear conversion queue
+	ADC1->RSQR1 = 0;
+	ADC1->RSQR2 = 0;
+	ADC1->RSQR3 = 0;
+
+	// power the ADC
+	GPIO_ADC_set_power(1);
+	GPIO_ADC_calibrate();
+}
+
+static inline uint16_t GPIO_analogRead(enum GPIO_analog_inputs input) {
+	// set mux to selected input
+	ADC1->RSQR3 = input;
+	// allow everything to precharge
+	Delay_Us(GPIO_ADC_MUX_DELAY);
+	// start sw conversion (auto clears)
+	ADC1->CTLR2 |= ADC_SWSTART;
+	// wait for conversion complete
+	while(!(ADC1->STATR & ADC_EOC)) {}
+	// get result
+	return ADC1->RDATAR;
+}
+
+
+
+#undef GPIO_tim1_map
+#define GPIO_tim1_map(GPIO_tim1_output_set) ({					\
+	RCC->APB2PCENR |= RCC_APB2Periph_AFIO;					\
+	AFIO->PCFR1 |= ((GPIO_tim1_output_set & 0b11) << 6);			\
+})
+
+#undef GPIO_tim2_map
+#define GPIO_tim2_map(GPIO_tim2_output_set) ({					\
+	RCC->APB2PCENR |= RCC_APB2Periph_AFIO;					\
+	AFIO->PCFR1 |= ((GPIO_tim2_output_set & 0b11) << 8);			\
+})
+
+static inline void GPIO_tim1_init() {
+	// enable TIM1
+	RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
+	// reset TIM1 to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
+	// SMCFGR: default clk input is CK_INT
+	// set clock prescaler divider 
+	TIM1->PSC = GPIO_timer_prescaler;
+	// set PWM total cycle width
+	TIM1->ATRLR = GPIO_timer_resolution;
+	// CTLR1: default is up, events generated, edge align
+	// enable auto-reload of preload
+	TIM1->CTLR1 |= TIM_ARPE;
+	// initialize counter
+	TIM1->SWEVGR |= TIM_UG;
+	// disengage brake
+	TIM1->BDTR |= TIM_MOE;
+	// Enable TIM1
+	TIM1->CTLR1 |= TIM_CEN;
+}
+static inline void GPIO_tim2_init() {
+	// enable TIM2
+	RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
+	// reset TIM2 to init all regs
+	RCC->APB1PRSTR |= RCC_APB1Periph_TIM2;
+	RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM2;
+	// SMCFGR: default clk input is CK_INT
+	// set clock prescaler divider 
+	TIM2->PSC = GPIO_timer_prescaler;
+	// set PWM total cycle width
+	TIM2->ATRLR = GPIO_timer_resolution;
+	// CTLR1: default is up, events generated, edge align
+	// enable auto-reload of preload
+	TIM2->CTLR1 |= TIM_ARPE;
+	// initialize counter
+	TIM2->SWEVGR |= TIM_UG;
+	// Enable TIM2
+	TIM2->CTLR1 |= TIM_CEN;
+}
+
+#define GPIO_timer_channel_set2(timer, channel)		GPIO_timer_channel_set_##channel(timer)
+#define GPIO_timer_channel_set(timer, channel)		GPIO_timer_channel_set2(timer, channel)
+#define GPIO_timer_channel_set_1(timer)			timer->CHCTLR1 |=  (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
+#define GPIO_timer_channel_set_2(timer)			timer->CHCTLR1 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
+#define GPIO_timer_channel_set_3(timer)			timer->CHCTLR2 |=  (TIM_OCMode_PWM1 | TIM_OCPreload_Enable)
+#define GPIO_timer_channel_set_4(timer)			timer->CHCTLR2 |= ((TIM_OCMode_PWM1 | TIM_OCPreload_Enable) << 8)
+
+#undef GPIO_tim1_enableCH
+#define GPIO_tim1_enableCH(channel) ({						\
+	GPIO_timer_channel_set(TIM1, channel);					\
+	TIM1->CCER |= (TIM_OutputState_Enable) << (4 * (channel - 1));		\
+})
+#undef GPIO_tim2_enableCH
+#define GPIO_tim2_enableCH(channel) ({						\
+	GPIO_timer_channel_set(TIM2, channel);					\
+	TIM2->CCER |= (TIM_OutputState_Enable ) << (4 * (channel - 1));		\
+})
+
+#define GPIO_timer_CVR(channel)		CONCAT_INDIRECT(CH, CONCAT_INDIRECT(channel, CVR))
+
+#undef GPIO_tim1_analogWrite
+#define GPIO_tim1_analogWrite(channel, value) ({				\
+	TIM1->GPIO_timer_CVR(channel) = value;					\
+	TIM1->SWEVGR |= TIM_UG;							\
+})
+#undef GPIO_tim2_analogWrite
+#define GPIO_tim2_analogWrite(channel, value) ({				\
+	TIM2->GPIO_timer_CVR(channel) = value;					\
+	TIM2->SWEVGR |= TIM_UG;							\
+})
+
+#endif // CH32V003_GPIO_BR_H
diff --git a/extralibs/wiring.c b/extralibs/wiring.c
deleted file mode 100644
index b04f8e46dc07a1832b4332edbc3a0e44b02e427b..0000000000000000000000000000000000000000
--- a/extralibs/wiring.c
+++ /dev/null
@@ -1,238 +0,0 @@
-//#include <stdio.h>
-
-#include "wiring.h"
-#include <stdint.h>
-
-
-
-enum GPIOports getPort (enum GPIOpins pin) {
-	if (pin <= pin_A2) {
-		return port_A;
-	}
-	else if (pin <= pin_C7) {
-		return port_C;
-	}
-	else if (pin <= pin_D7) {
-		return port_D;
-	}
-	return port_none;
-}
-
-
-
-void portEnable(enum GPIOports port) {
-	// Enable GPIOs
-	switch (port) {
-		case port_A:
-			RCC->APB2PCENR |= RCC_APB2Periph_GPIOA;
-			break;
-		case port_C:
-			RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
-			break;
-		case port_D:
-			RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
-			break;
-		case port_none:
-			break;
-	}
-}
-
-
-
-void pinMode(enum GPIOpins pin, enum GPIOpinMode mode) {
-	GPIO_TypeDef * GPIOx;
-	uint16_t PinOffset;
-
-	GPIOx = (GPIO_TypeDef *)(((uint8_t*)(GPIOA))+(pin>>3)*0x0400);
-	PinOffset = (pin & 0x7)<<2;
-
-	GPIOx->CFGLR &= ~(0b1111<<PinOffset);							// zero the 4 configuration bits
-	
-	uint8_t target_pin_state = pinState_nochange;					// by default, pin shall retain its state
-
-	uint8_t modeMask = 0;												// configuration mask
-
-	switch (mode) {
-		case pinMode_I_floating:
-			modeMask = GPIO_CNF_IN_FLOATING;
-			break;
-		case pinMode_I_pullUp:
-			modeMask = GPIO_CNF_IN_PUPD;
-			target_pin_state = pinState_high;
-			break;
-		case pinMode_I_pullDown:
-			modeMask = GPIO_CNF_IN_PUPD;
-			target_pin_state = pinState_low;
-			break;
-		case pinMode_I_analog:
-			modeMask = GPIO_CNF_IN_ANALOG;
-			break;
-		case pinMode_O_pushPull:
-			modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_PP;
-			break;
-		case pinMode_O_openDrain:
-			modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_OD;
-			break;
-		case pinMode_O_pushPullMux:
-			modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF;
-			break;
-		case pinMode_O_openDrainMux:
-			modeMask = GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF;
-			break;
-	}
-
-	// wirte mask to CFGR
-	GPIOx->CFGLR |= modeMask<<PinOffset;
-
-	// set pin state
-	if (target_pin_state > pinState_nochange) {
-		digitalWrite(pin, target_pin_state - 1);
-	}
-}
-
-
-
-void digitalWrite(enum GPIOpins pin, uint8_t value) {
-	// no checks given whether pin is currently being toggled by timer! your output trannys are in your hands! beware the magic smoke!
-	GPIO_TypeDef * GPIOx;
-	uint16_t PinOffset = 0;
-	
-	if (pin <= pin_A2) {
-		GPIOx = GPIOA;
-		PinOffset = pin;
-	}
-	else if (pin <= pin_C7) {
-		GPIOx = GPIOC;
-		PinOffset = (pin - 16);
-	}
-	else if (pin <= pin_D7) {
-		GPIOx = GPIOD;
-		PinOffset = (pin - 24);
-	}
-	else {
-		return;
-	}
-
-	if (value) {
-		GPIOx-> BSHR |= 1 << PinOffset;
-	}
-	else {
-		GPIOx-> BSHR |= 1 << (16 + PinOffset);
-	}
-}
-
-
-
-uint8_t digitalRead(uint8_t pin) {
-	GPIO_TypeDef * GPIOx;
-	uint16_t PinOffset = 0;
-	
-	if (pin <= pin_A2) {
-		GPIOx = GPIOA;
-		PinOffset = pin;
-	}
-	else if (pin <= pin_C7) {
-		GPIOx = GPIOC;
-		PinOffset = (pin - 16);
-	}
-	else if (pin <= pin_D7) {
-		GPIOx = GPIOD;
-		PinOffset = (pin - 24);
-	}
-	else {
-		return 0;
-	}
-
-	int8_t result = (GPIOx->INDR >> PinOffset) & 1;
-	return result;
-}
-
-
-
-
-
-void ADCinit() {
-	// select ADC clock source
-	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
-	RCC->CFGR0 &= ~(0x1F<<11);
-
-	// enable clock to the ADC
-	RCC->APB2PCENR |= RCC_APB2Periph_ADC1;
-
-	// Reset the ADC to init all regs
-	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
-	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
-
-	// set sampling time for all inputs to 241 cycles
-	for (uint8_t i = Ain0_A2; i <= AinVcal; i++) {
-		ADCsetSampletime(i, Ast_241cy_default);
-	}
-
-	// set trigger to software
-	ADC1->CTLR2 |= ADC_EXTSEL;
-
-	// pre-clear conversion queue
-	ADC1->RSQR1 = 0;
-	ADC1->RSQR2 = 0;
-	ADC1->RSQR3 = 0;
-
-	// power the ADC
-	ADCsetPower(1);
-}
-
-
-
-void ADCsetSampletime(enum ANALOGinputs input, enum ANALOGsampletimes time) {
-	// clear
-	ADC1->SAMPTR2 &= ~(0b111)<<(3*input);
-	// set
-	ADC1->SAMPTR2 |= time<<(3*input);	// 0:7 => 3/9/15/30/43/57/73/241 cycles
-}
-
-
-
-void ADCsetPower(uint8_t enable) {
-	if (enable) {
-		ADC1->CTLR2 |= ADC_ADON;
-		if (enable == 1) {
-			// auto-cal each time after turning on the ADC
-			// can be overridden by calling with enable > 1.
-			ADCcalibrate();					
-		}
-	}
-	else {
-		ADC1->CTLR2 &= ~(ADC_ADON);
-	}
-}
-
-
-
-void ADCcalibrate() {
-	// reset calibration
-	ADC1->CTLR2 |= ADC_RSTCAL;
-	while(ADC1->CTLR2 & ADC_RSTCAL);
-	
-	// calibrate
-	ADC1->CTLR2 |= ADC_CAL;
-	while(ADC1->CTLR2 & ADC_CAL);
-}
-
-
-
-// inspired by arduinos analogRead()
-uint16_t analogRead(enum ANALOGinputs input) {
-	// set mux to selected input
-	ADC1->RSQR3 = input;
-
-	// may need a delay right here for the mux to actually finish switching??
-	// Arduino inserts a full ms delay right here!
-	
-	// start sw conversion (auto clears)
-	ADC1->CTLR2 |= ADC_SWSTART;
-	
-	// wait for conversion complete
-	while(!(ADC1->STATR & ADC_EOC));
-	
-	// get result
-	return ADC1->RDATAR;
-}
diff --git a/extralibs/wiring.h b/extralibs/wiring.h
deleted file mode 100644
index 3b7d0d74e0a1a8f1d41fca115b4aaeb3901cc8e2..0000000000000000000000000000000000000000
--- a/extralibs/wiring.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef WIRING_H
-#define WIRING_H
-
-#include "ch32v003fun.h"
-
-
-
-enum lowhigh {
-	low,
-	high,
-};
-
-
-
-enum GPIOports{
-	port_A,
-	port_C,
-	port_D,
-	port_none,
-};
-
-enum GPIOpins{
-	pin_A1 = 1,
-	pin_A2,
-	pin_C0 = 16,
-	pin_C1,
-	pin_C2,
-	pin_C3,
-	pin_C4,
-	pin_C5,
-	pin_C6,
-	pin_C7,
-	pin_D0 = 24,
-	pin_D1,
-	pin_D2,
-	pin_D3,
-	pin_D4,
-	pin_D5,
-	pin_D6,
-	pin_D7,
-	pin_none,
-};
-
-enum GPIOpinMode {
-	pinMode_I_floating,
-	pinMode_I_pullUp,			//pull-mode + ODR(1)
-	pinMode_I_pullDown,			//pull-mode + ODR(0)
-	pinMode_I_analog,
-	pinMode_O_pushPull,
-	pinMode_O_openDrain,
-	pinMode_O_pushPullMux,
-	pinMode_O_openDrainMux,
-};
-
-enum GPIOpinState {
-	pinState_nochange,
-	pinState_low,
-	pinState_high,
-};
-
-enum ANALOGinputs {
-	Ain0_A2,
-	Ain1_A1,
-	Ain2_C4,
-	Ain3_D2,
-	Ain4_D3,
-	Ain5_D5,
-	Ain6_D6,
-	Ain7_D4,
-	AinVref,
-	AinVcal,
-};
-
-enum ANALOGsampletimes {
-	Ast_3cy,
-	Ast_9cy,
-	Ast_15cy,
-	Ast_30cy,
-	Ast_43cy,
-	Ast_57cy,
-	Ast_73cy,
-	Ast_241cy_default,
-};
-
-
-enum GPIOports getPort (enum GPIOpins pin);
-
-void portEnable(enum GPIOports port);
-void pinMode(enum GPIOpins pin, enum GPIOpinMode mode);
-void digitalWrite(enum GPIOpins pin, uint8_t value);
-uint8_t digitalRead(uint8_t pin);
-
-void ADCinit();
-void ADCsetPower(uint8_t enable);
-void ADCsetSampletime(enum ANALOGinputs input, enum ANALOGsampletimes time);
-void ADCcalibrate();
-uint16_t analogRead(enum ANALOGinputs input);
-
-#endif					// WIRING_H
diff --git a/platformio.ini b/platformio.ini
index 263b6ac00e167e52572d7cda8edff404de3f7e12..3edc591904e025923f2883664a83269f1e1840eb 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -39,9 +39,6 @@ build_src_filter = ${fun_base.build_src_filter} +<examples/external_crystal>
 [env:GPIO]
 build_src_filter = ${fun_base.build_src_filter} ${fun_base.extra_libs_srcs} +<examples/GPIO>
 
-[env:GPIO_analogRead]
-build_src_filter = ${fun_base.build_src_filter} ${fun_base.extra_libs_srcs} +<examples/GPIO_analogRead>
-
 [env:optionbytes]
 build_src_filter = ${fun_base.build_src_filter} +<examples/optionbytes>