diff --git a/examples/adc_dma_opamp/Makefile b/examples/adc_dma_opamp/Makefile
index acbb935a099a3cc0df772edda761e88cf6f7aeed..7c4d8f1ba2aad23a3c593486ba15b183ec542028 100644
--- a/examples/adc_dma_opamp/Makefile
+++ b/examples/adc_dma_opamp/Makefile
@@ -1,5 +1,7 @@
 TARGET:=adc_dma_opamp
 
+CFLAGS+=-DSTDOUT_UART
+
 include ../../ch32v003fun/ch32v003fun.mk
 
 all : flash
diff --git a/examples/adc_dma_opamp/adc.h b/examples/adc_dma_opamp/adc.h
deleted file mode 100644
index 87201e6edfa5a7c1ea27d4fa1e5bb2a5e520fc46..0000000000000000000000000000000000000000
--- a/examples/adc_dma_opamp/adc.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Single-File-Header for using ADC with DMA
- * 04-13-2023 E. Brombaugh
- */
-
-#ifndef _ADC_H
-#define _ADC_H
-
-#include <stdint.h>
-
-#define ADC_NUMCHLS 4
-volatile uint16_t adc_buffer[ADC_NUMCHLS];
-
-/*
- * initialize adc for DMA
- */
-void adc_init( void )
-{
-	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
-	RCC->CFGR0 &= ~(0x1F<<11);
-	
-	// Enable GPIOD and ADC
-	RCC->APB2PCENR |=	RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
-						RCC_APB2Periph_ADC1;
-	
-	// PD4 is analog input chl 7
-	GPIOD->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
-	
-	// PD3 is analog input chl 4
-	GPIOD->CFGLR &= ~(0xf<<(4*3));	// CNF = 00: Analog, MODE = 00: Input
-	
-	// PD2 is analog input chl 3
-	GPIOD->CFGLR &= ~(0xf<<(4*2));	// CNF = 00: Analog, MODE = 00: Input
-	
-	// PC4 is analog input chl 2
-	GPIOC->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
-	
-	// Reset the ADC to init all regs
-	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
-	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
-	
-	// Set up four conversions on chl 7, 4, 3, 2
-	ADC1->RSQR1 = (ADC_NUMCHLS-1) << 20;	// four chls in the sequence
-	ADC1->RSQR2 = 0;
-	ADC1->RSQR3 = (7<<(5*0)) | (4<<(5*1)) | (3<<(5*2)) | (2<<(5*3));
-	
-	// set sampling time for chl 7, 4, 3, 2
-	// 0:7 => 3/9/15/30/43/57/73/241 cycles
-	ADC1->SAMPTR2 = (7<<(3*7)) | (7<<(3*4)) | (7<<(3*3)) | (7<<(3*2));
-
-	// turn on ADC
-	ADC1->CTLR2 |= ADC_ADON;
-	
-	// Reset calibration
-	ADC1->CTLR2 |= ADC_RSTCAL;
-	while(ADC1->CTLR2 & ADC_RSTCAL);
-	
-	// Calibrate
-	ADC1->CTLR2 |= ADC_CAL;
-	while(ADC1->CTLR2 & ADC_CAL);
-	
-	// Turn on DMA
-	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
-	
-	//DMA1_Channel1 is for ADC
-	DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR;
-	DMA1_Channel1->MADDR = (uint32_t)adc_buffer;
-	DMA1_Channel1->CNTR  = ADC_NUMCHLS;
-	DMA1_Channel1->CFGR  =
-		DMA_M2M_Disable |		 
-		DMA_Priority_VeryHigh |
-		DMA_MemoryDataSize_HalfWord |
-		DMA_PeripheralDataSize_HalfWord |
-		DMA_MemoryInc_Enable |
-		DMA_Mode_Circular |
-		DMA_DIR_PeripheralSRC;
-	
-	// Turn on DMA channel 1
-	DMA1_Channel1->CFGR |= DMA_CFGR1_EN;
-	
-	// enable scanning
-	ADC1->CTLR1 |= ADC_SCAN;
-	
-	// Enable continuous conversion and DMA
-	ADC1->CTLR2 |= ADC_CONT | ADC_DMA | ADC_EXTSEL;
-	
-	// start conversion
-	ADC1->CTLR2 |= ADC_SWSTART;
-}
-
-#endif
diff --git a/examples/adc_dma_opamp/adc_dma_opamp.c b/examples/adc_dma_opamp/adc_dma_opamp.c
index cb3d6a3b50b87dd3922f669080f090ba4e21dd4f..e56bc2a836d46cb12a02812baebab4dde36e435c 100644
--- a/examples/adc_dma_opamp/adc_dma_opamp.c
+++ b/examples/adc_dma_opamp/adc_dma_opamp.c
@@ -9,9 +9,105 @@
 
 #include "ch32v003fun.h"
 #include <stdio.h>
-#include "adc.h"
-#include "opamp.h"
 
+#define ADC_NUMCHLS 4
+volatile uint16_t adc_buffer[ADC_NUMCHLS];
+
+/*
+ * initialize adc for DMA
+ */
+void adc_init( void )
+{
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+	
+	// Enable GPIOD and ADC
+	RCC->APB2PCENR |=	RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
+						RCC_APB2Periph_ADC1;
+	
+	// PD4 is analog input chl 7
+	GPIOD->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PD3 is analog input chl 4
+	GPIOD->CFGLR &= ~(0xf<<(4*3));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PD2 is analog input chl 3
+	GPIOD->CFGLR &= ~(0xf<<(4*2));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// PC4 is analog input chl 2
+	GPIOC->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// Reset the ADC to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
+	
+	// Set up four conversions on chl 7, 4, 3, 2
+	ADC1->RSQR1 = (ADC_NUMCHLS-1) << 20;	// four chls in the sequence
+	ADC1->RSQR2 = 0;
+	ADC1->RSQR3 = (7<<(5*0)) | (4<<(5*1)) | (3<<(5*2)) | (2<<(5*3));
+	
+	// set sampling time for chl 7, 4, 3, 2
+	// 0:7 => 3/9/15/30/43/57/73/241 cycles
+	ADC1->SAMPTR2 = (7<<(3*7)) | (7<<(3*4)) | (7<<(3*3)) | (7<<(3*2));
+
+	// turn on ADC
+	ADC1->CTLR2 |= ADC_ADON;
+	
+	// Reset calibration
+	ADC1->CTLR2 |= ADC_RSTCAL;
+	while(ADC1->CTLR2 & ADC_RSTCAL);
+	
+	// Calibrate
+	ADC1->CTLR2 |= ADC_CAL;
+	while(ADC1->CTLR2 & ADC_CAL);
+	
+	// Turn on DMA
+	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
+	
+	//DMA1_Channel1 is for ADC
+	DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR;
+	DMA1_Channel1->MADDR = (uint32_t)adc_buffer;
+	DMA1_Channel1->CNTR  = ADC_NUMCHLS;
+	DMA1_Channel1->CFGR  =
+		DMA_M2M_Disable |		 
+		DMA_Priority_VeryHigh |
+		DMA_MemoryDataSize_HalfWord |
+		DMA_PeripheralDataSize_HalfWord |
+		DMA_MemoryInc_Enable |
+		DMA_Mode_Circular |
+		DMA_DIR_PeripheralSRC;
+	
+	// Turn on DMA channel 1
+	DMA1_Channel1->CFGR |= DMA_CFGR1_EN;
+	
+	// enable scanning
+	ADC1->CTLR1 |= ADC_SCAN;
+	
+	// Enable continuous conversion and DMA
+	ADC1->CTLR2 |= ADC_CONT | ADC_DMA | ADC_EXTSEL;
+	
+	// start conversion
+	ADC1->CTLR2 |= ADC_SWSTART;
+}
+
+/*
+ * turn on op-amp, select input pins
+ */
+void opamp_init( void )
+{
+	// turn on the op-amp
+	EXTEN->EXTEN_CTR |= EXTEN_OPA_EN;
+	
+	// select op-amp pos pin: 0 = PA2, 1 = PD7
+	//EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL;
+
+	// select op-amp neg pin: 0 = PA1, 1 = PD0
+	//EXTEN->EXTEN_CTR |= EXTEN_OPA_NSEL;
+}
+
+/*
+ * entry
+ */
 int main()
 {
 	SystemInit48HSI();
@@ -26,25 +122,15 @@ int main()
 	adc_init();
 	printf("done.\n\r");
 	
-#if 0
-	printf("MADDR = 0x%08X, Buffer = 0x%08X\n\r",
-		DMA1_Channel1->CNTR, adc_buffer);
-	while(1)
-	{
-		//printf("STATR = 0x%08X, RDATAR = 0x%04X, CNTR = 0x%04X\n\r",
-			//ADC1->STATR, ADC1->RDATAR, DMA1_Channel1->CNTR);
-	}
-#endif
-
 	// init op-amp
 	printf("initializing op-amp...\n\r");
 	opamp_init();
 	printf("done.\n\r");
 	
-	// Enable GPIOs
+	// Enable GPIO for blinky diag
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
 
-	// GPIO C1 Push-Pull
+	// GPIO C1 Push-Pull for blinky diag
 	GPIOC->CFGLR &= ~(0xf<<(4*1));
 	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1);
 
diff --git a/examples/adc_dma_opamp/opamp.h b/examples/adc_dma_opamp/opamp.h
deleted file mode 100644
index 20b0786fe7108e23a7c82383fe596f74f456db19..0000000000000000000000000000000000000000
--- a/examples/adc_dma_opamp/opamp.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Single-File-Header for using op-amp
- * 04-13-2023 E. Brombaugh
- */
-
-#ifndef _OPAMP_H
-#define _OPAMP_H
-
-#include <stdint.h>
-
-/*
- * initialize adc for polling
- */
-void opamp_init( void )
-{
-	// turn on the op-amp
-	EXTEN->EXTEN_CTR |= EXTEN_OPA_EN;
-	
-	// select op-amp pos pin: 0 = PA2, 1 = PD7
-	//EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL;
-
-	// select op-amp neg pin: 0 = PA1, 1 = PD0
-	//EXTEN->EXTEN_CTR |= EXTEN_OPA_NSEL;
-}
-#endif
-
diff --git a/examples/adc_polled/Makefile b/examples/adc_polled/Makefile
index 0a4ea74980b737226422795be13e88cdb8f62611..11afe2ea9535ca5cdd34755e263a2653f54fdc83 100644
--- a/examples/adc_polled/Makefile
+++ b/examples/adc_polled/Makefile
@@ -1,5 +1,7 @@
 TARGET:=adc_polled
 
+CFLAGS+=-DSTDOUT_UART
+
 include ../../ch32v003fun/ch32v003fun.mk
 
 all : flash
diff --git a/examples/adc_polled/adc.h b/examples/adc_polled/adc.h
deleted file mode 100644
index b9777ec29ea01c15ce6048a7fc3f9bbcbcdd750b..0000000000000000000000000000000000000000
--- a/examples/adc_polled/adc.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Single-File-Header for using ADC with polling
- * 03-27-2023 E. Brombaugh
- */
-
-#ifndef _ADC_H
-#define _ADC_H
-
-#include <stdint.h>
-
-/*
- * initialize adc for polling
- */
-void adc_init( void )
-{
-	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
-	RCC->CFGR0 &= ~(0x1F<<11);
-	
-	// Enable GPIOD and ADC
-	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1;
-	
-	// PD4 is analog input chl 7
-	GPIOD->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
-	
-	// Reset the ADC to init all regs
-	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
-	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
-	
-	// Set up single conversion on chl 7
-	ADC1->RSQR1 = 0;
-	ADC1->RSQR2 = 0;
-	ADC1->RSQR3 = 7;	// 0-9 for 8 ext inputs and two internals
-	
-	// set sampling time for chl 7
-	ADC1->SAMPTR2 &= ~(ADC_SMP0<<(3*7));
-	ADC1->SAMPTR2 |= 7<<(3*7);	// 0:7 => 3/9/15/30/43/57/73/241 cycles
-		
-	// 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);
-	
-	// should be ready for SW conversion now
-}
-
-/*
- * start conversion, wait and return result
- */
-uint16_t adc_get( void )
-{
-	// start sw conversion (auto clears)
-	ADC1->CTLR2 |= ADC_SWSTART;
-	
-	// wait for conversion complete
-	while(!(ADC1->STATR & ADC_EOC));
-	
-	// get result
-	return ADC1->RDATAR;
-}
-
-#endif
diff --git a/examples/adc_polled/adc_polled.c b/examples/adc_polled/adc_polled.c
index 56283d10853a3cfeba6cb98ace926d1682160901..65ed99c9c261c7d7328f5e0e24c83b09bdf4faa9 100644
--- a/examples/adc_polled/adc_polled.c
+++ b/examples/adc_polled/adc_polled.c
@@ -9,8 +9,66 @@
 
 #include "ch32v003fun.h"
 #include <stdio.h>
-#include "adc.h"
 
+/*
+ * initialize adc for polling
+ */
+void adc_init( void )
+{
+	// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide by 2
+	RCC->CFGR0 &= ~(0x1F<<11);
+	
+	// Enable GPIOD and ADC
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1;
+	
+	// PD4 is analog input chl 7
+	GPIOD->CFGLR &= ~(0xf<<(4*4));	// CNF = 00: Analog, MODE = 00: Input
+	
+	// Reset the ADC to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
+	
+	// Set up single conversion on chl 7
+	ADC1->RSQR1 = 0;
+	ADC1->RSQR2 = 0;
+	ADC1->RSQR3 = 7;	// 0-9 for 8 ext inputs and two internals
+	
+	// set sampling time for chl 7
+	ADC1->SAMPTR2 &= ~(ADC_SMP0<<(3*7));
+	ADC1->SAMPTR2 |= 7<<(3*7);	// 0:7 => 3/9/15/30/43/57/73/241 cycles
+		
+	// 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);
+	
+	// should be ready for SW conversion now
+}
+
+/*
+ * start conversion, wait and return result
+ */
+uint16_t adc_get( void )
+{
+	// start sw conversion (auto clears)
+	ADC1->CTLR2 |= ADC_SWSTART;
+	
+	// wait for conversion complete
+	while(!(ADC1->STATR & ADC_EOC));
+	
+	// get result
+	return ADC1->RDATAR;
+}
+
+/*
+ * entry
+ */
 int main()
 {
 	uint32_t count = 0;
diff --git a/examples/i2c_oled/Makefile b/examples/i2c_oled/Makefile
index 2da3d040f9198403a7e306626b2d171c0c9373a7..e2e933a29f60c3cc30163258029f222918fd6224 100644
--- a/examples/i2c_oled/Makefile
+++ b/examples/i2c_oled/Makefile
@@ -1,5 +1,7 @@
 TARGET:=i2c_oled
 
+CFLAGS+=-DSTDOUT_UART
+
 include ../../ch32v003fun/ch32v003fun.mk
 
 all : flash
diff --git a/examples/i2c_oled/i2c.h b/examples/i2c_oled/i2c.h
index 92cfbdd58ec091024723f96c417a4a96860c0af7..335aafa969ffee617a09d8346f9ebc895f7ffb37 100644
--- a/examples/i2c_oled/i2c.h
+++ b/examples/i2c_oled/i2c.h
@@ -89,13 +89,13 @@ void i2c_init(void)
 	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
 	RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
 	
-	// PC1/PC2 are SDA/SCL, 50MHz Output PP CNF = 11: Mux OD, MODE = 11: Out 50MHz
-	GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE1 | GPIO_CFGLR_CNF1 |
-						GPIO_CFGLR_MODE1 | GPIO_CFGLR_CNF1);
-	GPIOC->CFGLR |= GPIO_CFGLR_CNF1_1 | GPIO_CFGLR_CNF1_0 |
-					GPIO_CFGLR_MODE1_1 | GPIO_CFGLR_MODE1_0 |
-					GPIO_CFGLR_CNF2_1 | GPIO_CFGLR_CNF2_0 |
-					GPIO_CFGLR_MODE2_1 | GPIO_CFGLR_MODE2_0;
+	// PC1 is SDA, 10MHz Output, alt func, open-drain
+	GPIOC->CFGLR &= ~(0xf<<(4*1));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*1);
+	
+	// PC2 is SCL, 10MHz Output, alt func, open-drain
+	GPIOC->CFGLR &= ~(0xf<<(4*2));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_OD_AF)<<(4*2);
 	
 #ifdef IRQ_DIAG
 	// GPIO diags on PC3/PC4
diff --git a/examples/spi_dac/Makefile b/examples/spi_dac/Makefile
index 109146ea58aa15694cb0213829b9ccb8cf43ddf9..98e7abf89391863e9082a989e53c584224db3ee5 100644
--- a/examples/spi_dac/Makefile
+++ b/examples/spi_dac/Makefile
@@ -1,5 +1,7 @@
 TARGET:=spi_dac
 
+CFLAGS+=-DSTDOUT_UART
+
 include ../../ch32v003fun/ch32v003fun.mk
 
 all : flash
diff --git a/examples/spi_dac/spi_dac.c b/examples/spi_dac/spi_dac.c
index cab61e6c82b4548f9d0ed090abf40f23b0e41a4a..aaed51fc769d463ec64a9e4d4eb949362b86a6d8 100644
--- a/examples/spi_dac/spi_dac.c
+++ b/examples/spi_dac/spi_dac.c
@@ -9,8 +9,187 @@
 
 #include "ch32v003fun.h"
 #include <stdio.h>
-#include "spidac.h"
 
+// this table contains a 512-sample 16-bit sine waveform
+#include "Sine16bit.h"
+
+// uncomment this to enable GPIO diag
+#define DAC_DIAG
+
+// Length of the DAC DMA buffer
+#define DACBUFSZ 32
+
+uint16_t dac_buffer[DACBUFSZ];
+uint32_t osc_phs[2], osc_frq[2];
+
+/*
+ * initialize SPI and DMA
+ */
+void spidac_init( void )
+{
+	// init two oscillators
+	osc_phs[0] = 0;
+	osc_phs[1] = 0;
+	osc_frq[0] = 0x01000000;
+	osc_frq[1] = 0x00400000;
+	
+	// Enable DMA + Peripherals
+	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
+
+#ifdef DAC_DIAG
+	// GPIO D0 10MHz Push-Pull for diags
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
+	GPIOD->CFGLR &= ~(0xf<<(4*0));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
+#endif
+	
+	// MOSI on PC6, 10MHz Output, alt func, push-pull
+	GPIOC->CFGLR &= ~(0xf<<(4*6));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
+	
+	// SCK on PC5, 10MHz Output, alt func, push-pull
+	GPIOC->CFGLR &= ~(0xf<<(4*5));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
+
+	// Configure SPI 
+	SPI1->CTLR1 = 
+		SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
+		SPI_Mode_Master | SPI_Direction_1Line_Tx |
+		SPI_BaudRatePrescaler_16;
+
+	// enable SPI port
+	SPI1->CTLR1 |= CTLR1_SPE_Set;
+
+	// TIM1 generates DMA Req and external signal
+	// Enable TIM1
+	RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
+	
+	// PC4 is T1CH4, 10MHz Output, alt func, push-pull
+	GPIOC->CFGLR &= ~(0xf<<(4*4));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
+		
+	// Reset TIM1 to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
+	
+	// CTLR1: default is up, events generated, edge align
+	// CTLR1: up/down, events on both edges
+	TIM1->CTLR1 = TIM_CMS;
+	// SMCFGR: default clk input is CK_INT
+	
+	// Prescaler 
+	TIM1->PSC = 0x0000;
+	
+	// Auto Reload - sets period to ~47kHz
+	TIM1->ATRLR = 499;
+	
+	// Reload immediately
+	TIM1->SWEVGR |= TIM_UG;
+	
+	// Enable CH4 output, positive pol
+	TIM1->CCER |= TIM_CC4E;// | TIM_CC4P;
+	
+	// CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
+	TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1;
+	
+	// Set the Capture Compare Register value to 50% initially
+	TIM1->CH4CVR = 256;
+	
+	// Enable TIM1 outputs
+	TIM1->BDTR |= TIM_MOE;
+	
+	// Enable CH4 DMA Req
+	TIM1->DMAINTENR |= TIM_CC4DE;
+	
+	// Enable TIM1
+	TIM1->CTLR1 |= TIM_CEN;
+
+	//DMA1_Channel4 is for TIM1CH4 
+	DMA1_Channel4->PADDR = (uint32_t)&SPI1->DATAR;
+	DMA1_Channel4->MADDR = (uint32_t)dac_buffer;
+	DMA1_Channel4->CNTR  = DACBUFSZ;
+	DMA1_Channel4->CFGR  =
+		DMA_M2M_Disable |		 
+		DMA_Priority_VeryHigh |
+		DMA_MemoryDataSize_HalfWord |
+		DMA_PeripheralDataSize_HalfWord |
+		DMA_MemoryInc_Enable |
+		DMA_Mode_Circular |
+		DMA_DIR_PeripheralDST |
+		DMA_IT_TC | DMA_IT_HT;
+
+	NVIC_EnableIRQ( DMA1_Channel4_IRQn );
+	DMA1_Channel4->CFGR |= DMA_CFGR1_EN;
+}
+
+/*
+ * DAC buffer updates - called at IRQ time
+ */
+void dac_update(uint16_t *buffer)
+{
+	int i;
+	
+	// fill the buffer with stereo data
+	for(i=0;i<DACBUFSZ/2;i+=2)
+	{
+		// right chl
+		*buffer++ = Sine16bit[osc_phs[0]>>24];
+		osc_phs[0] += osc_frq[0];
+		
+		// left chl
+		//*buffer++ = Sine16bit[osc_phs[1]>>24];
+		*buffer++ = osc_phs[1]>>16;
+		osc_phs[1] += osc_frq[1];
+	}
+}
+
+/*
+ * TIM1CH4 DMA IRQ Handler
+ */
+void DMA1_Channel4_IRQHandler( void ) __attribute__((interrupt));
+void DMA1_Channel4_IRQHandler( void ) 
+{
+#ifdef DAC_DIAG
+	GPIOD->BSHR = 1;
+#endif
+	
+	// why is this needed? Can't just direct compare the reg in tests below
+	volatile uint16_t intfr = DMA1->INTFR;
+
+	if( intfr & DMA1_IT_TC4 )
+	{
+		// Transfer complete - update 2nd half
+		dac_update(dac_buffer+DACBUFSZ/2);
+		
+		// clear TC IRQ
+		DMA1->INTFCR = DMA1_IT_TC4;
+		
+		GPIOC->BSHR = (1<<1); // NSS 1
+	}
+	
+	if( intfr & DMA1_IT_HT4 )
+	{
+		// Half transfer - update first half
+		dac_update(dac_buffer);
+		
+		// clear HT IRQ
+		DMA1->INTFCR = DMA1_IT_HT4;
+		
+		GPIOC->BSHR = (1<<(1+16)); // NSS 0
+	}
+
+	// clear the Global IRQ
+	DMA1->INTFCR = DMA1_IT_GL4;
+	
+#ifdef DAC_DIAG
+	GPIOD->BSHR = 1<<16;
+#endif
+}
+
+/*
+ * entry
+ */
 int main()
 {
 	SystemInit48HSI();
diff --git a/examples/spi_dac/spidac.h b/examples/spi_dac/spidac.h
deleted file mode 100644
index e8242b9321abaada92d2d6c7bcd513cc15de2c26..0000000000000000000000000000000000000000
--- a/examples/spi_dac/spidac.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Single-File-Header for SPI with circular DMA for audio output
- * 04-10-2023 E. Brombaugh
- */
-
-#ifndef _SPIDAC_H
-#define _SPIDAC_H
-
-#include <stdint.h>
-#include "Sine16bit.h"
-
-// uncomment this to enable GPIO diag
-#define DAC_DIAG
-
-// uncomment this to fill the buffer with static test data
-//#define DAC_STATIC
-
-// uncomment this for timer-generated DMA
-#define DAC_TIMDMA
-
-#define DACBUFSZ 32
-
-uint16_t dac_buffer[DACBUFSZ];
-uint32_t osc_phs[2], osc_frq[2];
-
-/*
- * initialize SPI and DMA
- */
-void spidac_init( void )
-{
-#ifdef DAC_STATIC
-	// fill output buffer with diag data
-	uint16_t data = 0xffff;
-	for(int i=0;i<DACBUFSZ;i++)
-	{
-		/* just a full-scale ramp for now */
-		dac_buffer[i] = data;
-		data >>= 1;
-	}
-#else
-	// init two oscillators
-	osc_phs[0] = 0;
-	osc_phs[1] = 0;
-	osc_frq[0] = 0x01000000;
-	osc_frq[1] = 0x00400000;
-#endif
-	
-	// Enable DMA + Peripherals
-	RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
-	RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1;
-
-#ifdef DAC_DIAG
-	// GPIO D0 Push-Pull for diags
-	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
-	GPIOD->CFGLR &= ~(0xf<<(4*0));
-	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
-#endif
-	
-	// MOSI on PC6
-	GPIOC->CFGLR &= ~(0xf<<(4*6));
-	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*6);
-	// SCK on PC5
-	GPIOC->CFGLR &= ~(0xf<<(4*5));
-	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
-	// NSS on PC1 is GPIO
-	GPIOC->CFGLR &= ~(0xf<<(4*1));
-	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*1);
-
-	// Configure SPI 
-	SPI1->CTLR1 = 
-		SPI_NSS_Soft | SPI_CPHA_1Edge | SPI_CPOL_Low | SPI_DataSize_16b |
-		SPI_Mode_Master | SPI_Direction_1Line_Tx |
-		SPI_BaudRatePrescaler_16;
-
-	// enable SPI port
-	SPI1->CTLR1 |= CTLR1_SPE_Set;
-
-	// TIM1 generates DMA Req and external signal
-	// Enable TIM1
-	RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
-	
-	// PC4 is T1CH4, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz
-	GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE4 | GPIO_CFGLR_CNF4);
-	GPIOC->CFGLR |= GPIO_CFGLR_CNF4_1 | GPIO_CFGLR_MODE4_0 | GPIO_CFGLR_MODE4_1;
-		
-	// Reset TIM1 to init all regs
-	RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
-	RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
-	
-	// CTLR1: default is up, events generated, edge align
-	// CTLR1: up/down, events on both edges
-	TIM1->CTLR1 = TIM_CMS;
-	// SMCFGR: default clk input is CK_INT
-	
-	// Prescaler 
-	TIM1->PSC = 0x0000;
-	
-	// Auto Reload - sets period to ~47kHz
-	TIM1->ATRLR = 499;
-	
-	// Reload immediately
-	TIM1->SWEVGR |= TIM_UG;
-	
-	// Enable CH4 output, positive pol
-	TIM1->CCER |= TIM_CC4E;// | TIM_CC4P;
-	
-	// CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
-	TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1;
-	
-	// Set the Capture Compare Register value to 50% initially
-	TIM1->CH4CVR = 256;
-	
-	// Enable TIM1 outputs
-	TIM1->BDTR |= TIM_MOE;
-	
-	// Enable CH4 DMA Req
-	TIM1->DMAINTENR |= TIM_CC4DE;
-	
-	// Enable TIM1
-	TIM1->CTLR1 |= TIM_CEN;
-
-	//DMA1_Channel4 is for TIM1CH4 
-	DMA1_Channel4->PADDR = (uint32_t)&SPI1->DATAR;
-	DMA1_Channel4->MADDR = (uint32_t)dac_buffer;
-	DMA1_Channel4->CNTR  = DACBUFSZ;
-	DMA1_Channel4->CFGR  =
-		DMA_M2M_Disable |		 
-		DMA_Priority_VeryHigh |
-		DMA_MemoryDataSize_HalfWord |
-		DMA_PeripheralDataSize_HalfWord |
-		DMA_MemoryInc_Enable |
-		DMA_Mode_Circular |
-		DMA_DIR_PeripheralDST |
-		DMA_IT_TC | DMA_IT_HT;
-
-	NVIC_EnableIRQ( DMA1_Channel4_IRQn );
-	DMA1_Channel4->CFGR |= DMA_CFGR1_EN;
-}
-
-/*
- * DAC buffer updates - called at IRQ time
- */
-void dac_update(uint16_t *buffer)
-{
-	int i;
-	
-	// fill the buffer with stereo data
-	for(i=0;i<DACBUFSZ/2;i+=2)
-	{
-		// right chl
-		*buffer++ = Sine16bit[osc_phs[0]>>24];
-		osc_phs[0] += osc_frq[0];
-		
-		// left chl
-		//*buffer++ = Sine16bit[osc_phs[1]>>24];
-		*buffer++ = osc_phs[1]>>16;
-		osc_phs[1] += osc_frq[1];
-	}
-}
-
-/*
- * TIM1CH4 DMA IRQ Handler
- */
-void DMA1_Channel4_IRQHandler( void ) __attribute__((interrupt));
-void DMA1_Channel4_IRQHandler( void ) 
-{
-#ifdef DAC_DIAG
-	GPIOD->BSHR = 1;
-#endif
-	
-	// why is this needed? Can't just direct compare the reg in tests below
-	volatile uint16_t intfr = DMA1->INTFR;
-
-	if( intfr & DMA1_IT_TC4 )
-	{
-		// Transfer complete - update 2nd half
-		dac_update(dac_buffer+DACBUFSZ/2);
-		
-		// clear TC IRQ
-		DMA1->INTFCR = DMA1_IT_TC4;
-		
-		GPIOC->BSHR = (1<<1); // NSS 1
-	}
-	
-	if( intfr & DMA1_IT_HT4 )
-	{
-		// Half transfer - update first half
-		dac_update(dac_buffer);
-		
-		// clear HT IRQ
-		DMA1->INTFCR = DMA1_IT_HT4;
-		
-		GPIOC->BSHR = (1<<(1+16)); // NSS 0
-	}
-
-	// clear the Global IRQ
-	DMA1->INTFCR = DMA1_IT_GL4;
-	
-#ifdef DAC_DIAG
-	GPIOD->BSHR = 1<<16;
-#endif
-}
-#endif
diff --git a/examples/systick_irq/Makefile b/examples/systick_irq/Makefile
index c9c13def5aa9978795a523d8d019e17d54c3f4e3..e72ba9807b0ce6f59d5e2bf6d9e69ca7472d7108 100644
--- a/examples/systick_irq/Makefile
+++ b/examples/systick_irq/Makefile
@@ -1,5 +1,7 @@
 TARGET:=systick_irq
 
+CFLAGS+=-DSTDOUT_UART
+
 include ../../ch32v003fun/ch32v003fun.mk
 
 all : flash
diff --git a/examples/systick_irq/systick.h b/examples/systick_irq/systick.h
deleted file mode 100644
index 53bde7c828e74e77d60ffc8c59b5b7680ee3774f..0000000000000000000000000000000000000000
--- a/examples/systick_irq/systick.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Single-File-Header for using SysTick with millisecond interrupts
- * 03-25-2023 E. Brombaugh
- */
-
-#ifndef _SYSTICK_H
-#define _SYSTICK_H
-
-#include <stdint.h>
-
-/* some bit definitions for systick regs */
-#define SYSTICK_SR_CNTIF (1<<0)
-#define SYSTICK_CTLR_STE (1<<0)
-#define SYSTICK_CTLR_STIE (1<<1)
-#define SYSTICK_CTLR_STCLK (1<<2)
-#define SYSTICK_CTLR_STRE (1<<3)
-#define SYSTICK_CTLR_SWIE (1<<31)
-
-volatile uint32_t systick_cnt;
-
-/*
- * Start up the SysTick IRQ
- */
-void systick_init(void)
-{
-	/* enable the SysTick IRQ */
-	NVIC_EnableIRQ(SysTicK_IRQn);
-	
-	/* Clear any existing IRQ */
-    SysTick->SR &= ~SYSTICK_SR_CNTIF;
-	
-	/* Set the tick interval to 1ms for normal op */
-    SysTick->CMP = (SYSTEM_CORE_CLOCK/1000)-1;
-	
-	/* Start at zero */
-    SysTick->CNT = 0;
-	systick_cnt = 0;
-	
-	/* Enable SysTick counter, IRQ, HCLK/1, auto reload */
-    SysTick->CTLR = SYSTICK_CTLR_STE | SYSTICK_CTLR_STIE | 
-					SYSTICK_CTLR_STCLK | SYSTICK_CTLR_STRE;
-}
-
-#if 1
-/*
- * SysTick ISR just counts ticks
- * note - the __attribute__((interrupt)) syntax is crucial!
- */
-void SysTick_Handler(void) __attribute__((interrupt));
-void SysTick_Handler(void)
-{
-	/* clear IRQ */
-    SysTick->SR &= 0;
-	
-	/* update counter */
-	systick_cnt++;
-}
-#endif
-
-/*
- * Millisecond delay routine
- */
-void systick_delay_ms(uint32_t milliseconds)
-{
-	/* compute end time */
-	uint32_t etime = systick_cnt + milliseconds;
-	
-	/* wait for current time == end time */
-	while(systick_cnt != etime);
-}
-
-#endif
diff --git a/examples/systick_irq/systick_irq.c b/examples/systick_irq/systick_irq.c
index ebc0165e190a3aa6f209b216f529e9bc40986e48..0ec6631adb0e58d553a3bfe8f97afb0bb7b59091 100644
--- a/examples/systick_irq/systick_irq.c
+++ b/examples/systick_irq/systick_irq.c
@@ -9,8 +9,69 @@
 
 #include "ch32v003fun.h"
 #include <stdio.h>
-#include "systick.h"
 
+/* some bit definitions for systick regs */
+#define SYSTICK_SR_CNTIF (1<<0)
+#define SYSTICK_CTLR_STE (1<<0)
+#define SYSTICK_CTLR_STIE (1<<1)
+#define SYSTICK_CTLR_STCLK (1<<2)
+#define SYSTICK_CTLR_STRE (1<<3)
+#define SYSTICK_CTLR_SWIE (1<<31)
+
+volatile uint32_t systick_cnt;
+
+/*
+ * Start up the SysTick IRQ
+ */
+void systick_init(void)
+{
+	/* enable the SysTick IRQ */
+	NVIC_EnableIRQ(SysTicK_IRQn);
+	
+	/* Clear any existing IRQ */
+    SysTick->SR &= ~SYSTICK_SR_CNTIF;
+	
+	/* Set the tick interval to 1ms for normal op */
+    SysTick->CMP = (SYSTEM_CORE_CLOCK/1000)-1;
+	
+	/* Start at zero */
+    SysTick->CNT = 0;
+	systick_cnt = 0;
+	
+	/* Enable SysTick counter, IRQ, HCLK/1, auto reload */
+    SysTick->CTLR = SYSTICK_CTLR_STE | SYSTICK_CTLR_STIE | 
+					SYSTICK_CTLR_STCLK | SYSTICK_CTLR_STRE;
+}
+
+/*
+ * SysTick ISR just counts ticks
+ * note - the __attribute__((interrupt)) syntax is crucial!
+ */
+void SysTick_Handler(void) __attribute__((interrupt));
+void SysTick_Handler(void)
+{
+	/* clear IRQ */
+    SysTick->SR &= 0;
+	
+	/* update counter */
+	systick_cnt++;
+}
+
+/*
+ * Millisecond delay routine
+ */
+void systick_delay_ms(uint32_t milliseconds)
+{
+	/* compute end time */
+	uint32_t etime = systick_cnt + milliseconds;
+	
+	/* wait for current time == end time */
+	while(systick_cnt != etime);
+}
+
+/*
+ * entry
+ */
 int main()
 {
 	uint32_t count = 0;
@@ -21,8 +82,6 @@ int main()
 	SetupUART( UART_BRR );
 	printf("\r\r\n\nsystick_irq example\n\r");
 
-	printf("SysTick_Handler = 0x%08X\n\r", SysTick_Handler);
-
 	// init systick @ 1ms rate
 	printf("initializing systick...");
 	systick_init();
diff --git a/examples/tim1_pwm/t1pwm.h b/examples/tim1_pwm/t1pwm.h
deleted file mode 100644
index 261659d35a2cf5c3d40e2619bb3a9ab762f952d8..0000000000000000000000000000000000000000
--- a/examples/tim1_pwm/t1pwm.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Single-File-Header for using Advanced Control Timer (TIM1) for PWM generation
- * 03-28-2023 E. Brombaugh
- */
-
-#ifndef _T1PWM_H
-#define _T1PWM_H
-
-#include <stdint.h>
-
-/*
- * initialize act
- */
-void t1pwm_init( void )
-{
-	// Enable GPIOC, GPIOD and TIM1
-	RCC->APB2PCENR |= 	RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC |
-						RCC_APB2Periph_TIM1;
-	
-	// PD0 is T1CH1N, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz
-	GPIOD->CFGLR &= ~(GPIO_CFGLR_MODE0 | GPIO_CFGLR_CNF0);
-	GPIOD->CFGLR |= GPIO_CFGLR_CNF0_1 | GPIO_CFGLR_MODE0_0 | GPIO_CFGLR_MODE0_1;
-	
-	// PC4 is T1CH4, 50MHz Output PP CNF = 10: Mux PP, MODE = 11: Out 50MHz
-	GPIOC->CFGLR &= ~(GPIO_CFGLR_MODE4 | GPIO_CFGLR_CNF4);
-	GPIOC->CFGLR |= GPIO_CFGLR_CNF4_1 | GPIO_CFGLR_MODE4_0 | GPIO_CFGLR_MODE4_1;
-		
-	// Reset TIM1 to init all regs
-	RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
-	RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
-	
-	// CTLR1: default is up, events generated, edge align
-	// SMCFGR: default clk input is CK_INT
-	
-	// Prescaler 
-	TIM1->PSC = 0x0000;
-	
-	// Auto Reload - sets period
-	TIM1->ATRLR = 255;
-	
-	// Reload immediately
-	TIM1->SWEVGR |= TIM_UG;
-	
-	// Enable CH1N output, positive pol
-	TIM1->CCER |= TIM_CC1NE | TIM_CC1NP;
-	
-	// Enable CH4 output, positive pol
-	TIM1->CCER |= TIM_CC4E | TIM_CC4P;
-	
-	// CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
-	TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1;
-	
-	// CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
-	TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1;
-	
-	// Set the Capture Compare Register value to 50% initially
-	TIM1->CH1CVR = 128;
-	TIM1->CH4CVR = 128;
-	
-	// Enable TIM1 outputs
-	TIM1->BDTR |= TIM_MOE;
-	
-	// Enable TIM1
-	TIM1->CTLR1 |= TIM_CEN;
-}
-
-/*
- * set timer channel PW
- */
-void t1pwm_setpw(uint8_t chl, uint16_t width)
-{
-	switch(chl&3)
-	{
-		case 0: TIM1->CH1CVR = width; break;
-		case 1: TIM1->CH2CVR = width; break;
-		case 2: TIM1->CH3CVR = width; break;
-		case 3: TIM1->CH4CVR = width; break;
-	}
-}
-
-/*
- * force output
- */
-void t1pwm_force(uint8_t chl, uint8_t val)
-{
-	uint16_t temp;
-	
-	chl &= 3;
-	
-	if(chl < 2)
-	{
-		temp = TIM1->CHCTLR1;
-		temp &= ~(TIM_OC1M<<(8*chl));
-		temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl);
-		TIM1->CHCTLR1 = temp;
-	}
-	else
-	{
-		chl &= 1;
-		temp = TIM1->CHCTLR2;
-		temp &= ~(TIM_OC1M<<(8*chl));
-		temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl);
-		TIM1->CHCTLR2 = temp;
-	}
-}
-
-#endif
diff --git a/examples/tim1_pwm/tim1_pwm.c b/examples/tim1_pwm/tim1_pwm.c
index 84d77bdd9cb0a9446874f8ecd68b1b0febcf2628..1ead833489df1901e18f63e7f28f4009783527e7 100644
--- a/examples/tim1_pwm/tim1_pwm.c
+++ b/examples/tim1_pwm/tim1_pwm.c
@@ -9,8 +9,106 @@
 
 #include "ch32v003fun.h"
 #include <stdio.h>
-#include "t1pwm.h"
 
+/*
+ * initialize TIM1 for PWM
+ */
+void t1pwm_init( void )
+{
+	// Enable GPIOC, GPIOD and TIM1
+	RCC->APB2PCENR |= 	RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC |
+						RCC_APB2Periph_TIM1;
+	
+	// PD0 is T1CH1N, 10MHz Output alt func, push-pull
+	GPIOD->CFGLR &= ~(0xf<<(4*0));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*0);
+	
+	// PC4 is T1CH4, 10MHz Output alt func, push-pull
+	GPIOC->CFGLR &= ~(0xf<<(4*4));
+	GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*4);
+		
+	// Reset TIM1 to init all regs
+	RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
+	RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
+	
+	// CTLR1: default is up, events generated, edge align
+	// SMCFGR: default clk input is CK_INT
+	
+	// Prescaler 
+	TIM1->PSC = 0x0000;
+	
+	// Auto Reload - sets period
+	TIM1->ATRLR = 255;
+	
+	// Reload immediately
+	TIM1->SWEVGR |= TIM_UG;
+	
+	// Enable CH1N output, positive pol
+	TIM1->CCER |= TIM_CC1NE | TIM_CC1NP;
+	
+	// Enable CH4 output, positive pol
+	TIM1->CCER |= TIM_CC4E | TIM_CC4P;
+	
+	// CH1 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
+	TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1;
+	
+	// CH2 Mode is output, PWM1 (CC1S = 00, OC1M = 110)
+	TIM1->CHCTLR2 |= TIM_OC4M_2 | TIM_OC4M_1;
+	
+	// Set the Capture Compare Register value to 50% initially
+	TIM1->CH1CVR = 128;
+	TIM1->CH4CVR = 128;
+	
+	// Enable TIM1 outputs
+	TIM1->BDTR |= TIM_MOE;
+	
+	// Enable TIM1
+	TIM1->CTLR1 |= TIM_CEN;
+}
+
+/*
+ * set timer channel PW
+ */
+void t1pwm_setpw(uint8_t chl, uint16_t width)
+{
+	switch(chl&3)
+	{
+		case 0: TIM1->CH1CVR = width; break;
+		case 1: TIM1->CH2CVR = width; break;
+		case 2: TIM1->CH3CVR = width; break;
+		case 3: TIM1->CH4CVR = width; break;
+	}
+}
+
+/*
+ * force output (used for testing / debug)
+ */
+void t1pwm_force(uint8_t chl, uint8_t val)
+{
+	uint16_t temp;
+	
+	chl &= 3;
+	
+	if(chl < 2)
+	{
+		temp = TIM1->CHCTLR1;
+		temp &= ~(TIM_OC1M<<(8*chl));
+		temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl);
+		TIM1->CHCTLR1 = temp;
+	}
+	else
+	{
+		chl &= 1;
+		temp = TIM1->CHCTLR2;
+		temp &= ~(TIM_OC1M<<(8*chl));
+		temp |= (TIM_OC1M_2 | (val?TIM_OC1M_0:0))<<(8*chl);
+		TIM1->CHCTLR2 = temp;
+	}
+}
+
+/*
+ * entry
+ */
 int main()
 {
 	uint32_t count = 0;