diff --git a/README.md b/README.md
index 664eb4dee8d12c87f400be3b07f412c2d422373b..2f7a73884935c818ca2311440908fcbf4d9a7ee5 100644
--- a/README.md
+++ b/README.md
@@ -90,6 +90,12 @@ Other third party tools are adding lots of examples, etc.  See the following rep
 
 You can open a github ticket or join my Discord in the #ch32v003fun channel. https://discord.gg/CCeyWyZ
 
+## General notes about the CH32V003.
+
+CPI/Processor Speed:
+
+Ignoring branches and load/stores, compressed instructions run at 1 CPI. Non-compressed instructions run at 1 CPI for the first 2 instructions, then further ones take 2 CPI regardless of how many more you have.  Running from RAM and running from FLASH have slightly different performance characteristics depending on wait states that should be measured in-situation.
+
 ### Footnotes/links
 
  * https://raw.githubusercontent.com/openwch/ch32v003/main/RISC-V%20QingKeV2%20Microprocessor%20Debug%20Manual.pdf Debugging Manual
diff --git a/examples/adc_fixed_fs/adc_fixed_fs.c b/examples/adc_fixed_fs/adc_fixed_fs.c
index c69b7ba6e965586b038ecc9b2d3e7f07bca1cf44..758b13c5d73a83cd4ad2a84771594d3d1e3ba4dd 100644
--- a/examples/adc_fixed_fs/adc_fixed_fs.c
+++ b/examples/adc_fixed_fs/adc_fixed_fs.c
@@ -68,8 +68,7 @@ void init_adc() {
     RCC->CFGR0 |= RCC_ADCPRE_DIV2;	// set it to 010xx for /2.
 
     // Keep CALVOL register with initial value
-    ADC1->CTLR1 |= ADC_ExternalTrigConv_T1_TRGO;
-    ADC1->CTLR2 = ADC_ADON | ADC_DMA | ADC_EXTTRIG;
+    ADC1->CTLR2 = ADC_ADON | ADC_DMA | ADC_EXTTRIG | ADC_ExternalTrigConv_T1_TRGO;
 
     // Possible times: 0->3,1->9,2->15,3->30,4->43,5->57,6->73,7->241 cycles
     ADC1->SAMPTR2 = 0/*3 cycles*/ << (3/*offset per channel*/ * 2/*channel*/);
diff --git a/examples/cap_touch_adc/cap_touch_adc.c b/examples/cap_touch_adc/cap_touch_adc.c
index 2bde0c92bc5091432592a47b6279288302836424..98457e9a96ddf11e3823df665af0b5d05bd5a3d4 100644
--- a/examples/cap_touch_adc/cap_touch_adc.c
+++ b/examples/cap_touch_adc/cap_touch_adc.c
@@ -21,101 +21,7 @@
 #include "ch32v003fun.h"
 #include <stdio.h>
 
-#define ADC_SAMPLE_TIME 2  // Tricky: Don't change this without a lot of experimentation.
-#define MAX_SCALECHECK  4
-
-// Can either be 0 or 1.
-// If 0: Measurement low and rises high.  So more pressed is smaller number.
-// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
-// If you are doing more prox, use mode 0, otherwise, use mode 1.
-#define TOUCH_SLOPE     1
-
-// If you set this to 1, it will glitch the line, so it will only read
-// anything reasonable if the capacitance can overcome that initial spike.
-// Typically, it seems if you use this you probbly don't need to do
-// any pre-use calibration.
-#define TOUCH_FLAT      0
-
-void InitTouchADC( )
-{
-	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
-	RCC->CFGR0 &= ~(0x1F<<11);
-
-	// Set up single conversion on chl 2
-	ADC1->RSQR1 = 0;
-	ADC1->RSQR2 = 0;
-
-	// turn on ADC and set rule group to sw trig
-	ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
-	
-	// Reset calibration
-	ADC1->CTLR2 |= ADC_RSTCAL;
-	while(ADC1->CTLR2 & ADC_RSTCAL);
-	
-	// Calibrate
-	ADC1->CTLR2 |= ADC_CAL;
-	while(ADC1->CTLR2 & ADC_CAL);
-}
-
-// Run from RAM to get even more stable timing.
-// This function call takes about 8.1uS to execute.
-uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
-uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
-{
-	uint32_t ret = 0;
-
-	ADC1->RSQR3 = adcno;
-	ADC1->SAMPTR2 = ADC_SAMPLE_TIME<<(3*adcno);
-
-	uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
-	uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
-	uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
-
-	// If we run multiple times with slightly different wait times, we can
-	// reduce the impact of the ADC's DNL.
-
-
-#if TOUCH_FLAT == 1
-#define RELEASEIO io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
-#else
-#define RELEASEIO io->CFGLR = CFGFLOAT; io->OUTDR = 1<<(portpin+16*TOUCH_SLOPE);
-#endif
-
-#define INNER_LOOP( n ) \
-	{ \
-		/* Only lock IRQ for a very narrow window. */                           \
-		__disable_irq();                                                        \
-                                                                                \
-		/* Tricky - we start the ADC BEFORE we transition the pin.  By doing    \
-			this We are catching it onthe slope much more effectively.  */      \
-		ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL;                      \
-                                                                                \
-		ADD_N_NOPS( n )                                                         \
-                                                                                \
-		RELEASEIO                                                               \
-																			    \
-		/* Sampling actually starts here, somewhere, so we can let other        \
-			interrupts run */                                                   \
-		__enable_irq();                                                         \
-		while(!(ADC1->STATR & ADC_EOC));                                        \
-		io->CFGLR = CFGDRIVE;                                                   \
-		io->OUTDR = 1<<(portpin+(16*(1-TOUCH_SLOPE)));                          \
-		ret += ADC1->RDATAR;                                                    \
-	}
-
-	int i;
-	for( i = 0; i < iterations; i++ )
-	{
-		// Wait a variable amount of time based on loop iteration, in order
-		// to get a variety of RC points and minimize DNL.
-
-		INNER_LOOP( 0 );
-		INNER_LOOP( 2 );
-		INNER_LOOP( 4 );
-	}
-
-	return ret;
-}
+#include "ch32v003_touch.h"
 
 int main()
 {
@@ -133,8 +39,6 @@ int main()
 	{
 		uint32_t sum[8] = { 0 };
 
-		int j;
-
 		uint32_t start = SysTick->CNT;
 
 		// Sampling all touch pads, 3x should take 6030 cycles, and runs at about 8kHz
@@ -156,28 +60,3 @@ int main()
 	}
 }
 
-/*
- * MIT License
- * 
- * Copyright (c) 2023 Valve Corporation
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-
diff --git a/extralibs/ch32v003_touch.h b/extralibs/ch32v003_touch.h
new file mode 100644
index 0000000000000000000000000000000000000000..88756afe48cb5464275262f1f06a84c613af72ef
--- /dev/null
+++ b/extralibs/ch32v003_touch.h
@@ -0,0 +1,201 @@
+#ifndef _CH32V003_TOUCH_H
+#define _CH32V003_TOUCH_H
+
+/** ADC-based Capactive Touch Control.
+
+	see cap_touch_adc.c for an example.
+
+	// Enable GPIOD, C and ADC
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
+	InitTouchADC();
+
+
+	// Then do this any time you want to read some touches.
+	sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
+	sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
+	sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
+	sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
+	sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
+	sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
+	sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
+	sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
+*/
+
+
+
+#define TOUCH_ADC_SAMPLE_TIME 2  // Tricky: Don't change this without a lot of experimentation.
+
+// Can either be 0 or 1.
+// If 0: Measurement low and rises high.  So more pressed is smaller number.
+// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
+// If you are doing more prox, use mode 0, otherwise, use mode 1.
+#define TOUCH_SLOPE     1
+
+// If you set this to 1, it will glitch the line, so it will only read
+// anything reasonable if the capacitance can overcome that initial spike.
+// Typically, it seems if you use this you probbly don't need to do
+// any pre-use calibration.
+#define TOUCH_FLAT      0
+
+static void InitTouchADC( );
+void InitTouchADC( )
+{
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+
+	// Set up single conversion on chl 2
+	ADC1->RSQR1 = 0;
+	ADC1->RSQR2 = 0;
+
+	// turn on ADC and set rule group to sw trig
+	ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
+	
+	// Reset calibration
+	ADC1->CTLR2 |= ADC_RSTCAL;
+	while(ADC1->CTLR2 & ADC_RSTCAL);
+	
+	// Calibrate
+	ADC1->CTLR2 |= ADC_CAL;
+	while(ADC1->CTLR2 & ADC_CAL);
+}
+
+// Run from RAM to get even more stable timing.
+// This function call takes about 8.1uS to execute.
+static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
+uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
+{
+	uint32_t ret = 0;
+
+	ADC1->RSQR3 = adcno;
+	ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
+
+	uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
+	uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
+	uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
+
+	// If we run multiple times with slightly different wait times, we can
+	// reduce the impact of the ADC's DNL.
+
+
+#if TOUCH_FLAT == 1
+#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
+#else
+#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
+#endif
+
+#define INNER_LOOP( n ) \
+	{ \
+		/* Only lock IRQ for a very narrow window. */                           \
+		__disable_irq();                                                        \
+                                                                                \
+		/* Tricky - we start the ADC BEFORE we transition the pin.  By doing    \
+			this We are catching it onthe slope much more effectively.  */      \
+		ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL;                      \
+                                                                                \
+		ADD_N_NOPS( n )                                                         \
+                                                                                \
+		RELEASEIO                                                               \
+																			    \
+		/* Sampling actually starts here, somewhere, so we can let other        \
+			interrupts run */                                                   \
+		__enable_irq();                                                         \
+		while(!(ADC1->STATR & ADC_EOC));                                        \
+		io->CFGLR = CFGDRIVE;                                                   \
+		io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE)));                          \
+		ret += ADC1->RDATAR;                                                    \
+	}
+
+	int i;
+	for( i = 0; i < iterations; i++ )
+	{
+		// Wait a variable amount of time based on loop iteration, in order
+		// to get a variety of RC points and minimize DNL.
+
+		INNER_LOOP( 0 );
+		INNER_LOOP( 2 );
+		INNER_LOOP( 4 );
+	}
+
+	return ret;
+}
+
+// Run from RAM to get even more stable timing.
+// This function call takes about 8.1uS to execute.
+static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
+uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
+{
+	uint32_t ret = 0;
+
+	ADC1->RSQR3 = adcno;
+	ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
+
+	// If we run multiple times with slightly different wait times, we can
+	// reduce the impact of the ADC's DNL.
+
+#define INNER_LOOP_SAFE( n ) \
+	{ \
+		/* Only lock IRQ for a very narrow window. */                           \
+		__disable_irq();                                                        \
+		                                                                        \
+                                                                                \
+		/* Tricky - we start the ADC BEFORE we transition the pin.  By doing    \
+			this We are catching it onthe slope much more effectively.  */      \
+		ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL;                      \
+                                                                                \
+		ADD_N_NOPS( n )                                                         \
+                                                                                \
+		io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin))));                                                 \
+        io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);                                \
+																			    \
+		/* Sampling actually starts here, somewhere, so we can let other        \
+			interrupts run */                                                   \
+		__enable_irq();                                                         \
+		while(!(ADC1->STATR & ADC_EOC));                                        \
+		__disable_irq();                                                        \
+		io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin))));                                                  \
+		__enable_irq();                                                         \
+		io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE)));                          \
+		ret += ADC1->RDATAR;                                                    \
+	}
+
+	int i;
+	for( i = 0; i < iterations; i++ )
+	{
+		// Wait a variable amount of time based on loop iteration, in order
+		// to get a variety of RC points and minimize DNL.
+
+		INNER_LOOP_SAFE( 0 );
+		INNER_LOOP_SAFE( 2 );
+		INNER_LOOP_SAFE( 4 );
+	}
+
+	return ret;
+}
+
+
+#endif
+
+/*
+ * MIT License
+ * 
+ * Copyright (c) 2023 Valve Corporation
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+