diff --git a/examples/i2c_slave/Makefile b/examples/i2c_slave/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..49b91ce536597c14d0d8273010cba332c68baef1
--- /dev/null
+++ b/examples/i2c_slave/Makefile
@@ -0,0 +1,9 @@
+all : flash
+
+TARGET:=i2c_slave
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples/i2c_slave/README.md b/examples/i2c_slave/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..cfdbd1b46fb2f58e9bea2c7b4ce8d2aa0e4ee367
--- /dev/null
+++ b/examples/i2c_slave/README.md
@@ -0,0 +1,9 @@
+# I2C peripheral in slave mode
+
+This library and example show how to use the I2C peripheral in slave mode.
+
+The library uses a one-byte address, allowing for up to 256 registers to be defined.
+
+The first byte written to the device within a transaction determines the offset for following reads and writes, emulating a simple EEPROM.
+
+The example will turn on a LED connected to PD0 when the LSB of register 0 is set to 1 and off when it's set to 0.
diff --git a/examples/i2c_slave/i2c_slave.c b/examples/i2c_slave/i2c_slave.c
new file mode 100644
index 0000000000000000000000000000000000000000..dbfaf80ec8448a67b4f5ab3e5ece38b1bb6c02d3
--- /dev/null
+++ b/examples/i2c_slave/i2c_slave.c
@@ -0,0 +1,30 @@
+#define SYSTEM_CORE_CLOCK 48000000
+
+#include "ch32v003fun.h"
+#include "i2c_slave.h"
+#include <stdio.h>
+
+// The I2C slave library uses a one byte address so you can extend the size of this array up to 256 registers
+// note that the register set is modified by interrupts, to prevent the compiler from accidently optimizing stuff
+// away make sure to declare the register array volatile
+
+volatile uint8_t i2c_registers[32] = {0x00};
+
+int main() {
+    SystemInit48HSI();
+    SetupDebugPrintf();
+    SetupI2CSlave(0x9, i2c_registers, sizeof(i2c_registers));
+
+    // Enable GPIOD and set pin 0 to output
+    RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
+    GPIOD->CFGLR &= ~(0xf<<(4*0));
+    GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
+
+    while (1) {
+        if (i2c_registers[0] & 1) { // Turn on LED (PD0) if bit 1 of register 0 is set
+            GPIOD-> BSHR |= 1 << 16;
+        } else {
+            GPIOD-> BSHR |= 1;
+        }
+    }
+}
diff --git a/examples/i2c_slave/i2c_slave.h b/examples/i2c_slave/i2c_slave.h
new file mode 100644
index 0000000000000000000000000000000000000000..a488eaf8ea046d5ca80e395a2715650d9213dbeb
--- /dev/null
+++ b/examples/i2c_slave/i2c_slave.h
@@ -0,0 +1,150 @@
+/*
+ * Single-File-Header for using the I2C peripheral in slave mode
+ *
+ * MIT License
+ *
+ * Copyright (c) 2023 Renze Nicolai
+ *
+ * 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.
+ */
+
+#ifndef __I2C_SLAVE_H
+#define __I2C_SLAVE_H
+
+#include <stdint.h>
+
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+
+struct _i2c_slave_state {
+    uint8_t first_write;
+    uint8_t offset;
+    uint8_t position;
+    volatile uint8_t* volatile registers;
+    uint8_t size;
+} i2c_slave_state;
+
+void SetupI2CSlave(uint8_t address, volatile uint8_t* registers, uint8_t size) {
+    i2c_slave_state.first_write = 1;
+    i2c_slave_state.offset = 0;
+    i2c_slave_state.position = 0;
+    i2c_slave_state.registers = registers;
+    i2c_slave_state.size = size;
+
+    // Enable GPIOC and I2C
+    RCC->APB2PCENR |= RCC_APB2Periph_GPIOC;
+    RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
+
+    // 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);
+
+    // Reset I2C1 to init all regs
+    RCC->APB1PRSTR |= RCC_APB1Periph_I2C1;
+    RCC->APB1PRSTR &= ~RCC_APB1Periph_I2C1;
+
+    I2C1->CTLR1 |= I2C_CTLR1_SWRST;
+    I2C1->CTLR1 &= ~I2C_CTLR1_SWRST;
+
+    // Set module clock frequency
+    uint32_t prerate = 2000000; // I2C Logic clock rate, must be higher than the bus clock rate
+    I2C1->CTLR2 |= (APB_CLOCK/prerate) & I2C_CTLR2_FREQ;
+
+    // Enable interrupts
+    I2C1->CTLR2 |= I2C_CTLR2_ITBUFEN;
+    I2C1->CTLR2 |= I2C_CTLR2_ITEVTEN; // Event interrupt
+    I2C1->CTLR2 |= I2C_CTLR2_ITERREN; // Error interrupt
+
+    NVIC_EnableIRQ(I2C1_EV_IRQn); // Event interrupt
+    NVIC_SetPriority(I2C1_EV_IRQn, 2 << 4);
+    NVIC_EnableIRQ(I2C1_ER_IRQn); // Error interrupt
+
+    // Set clock configuration
+    uint32_t clockrate = 1000000; // I2C Bus clock rate, must be lower than the logic clock rate
+    I2C1->CKCFGR = ((APB_CLOCK/(3*clockrate))&I2C_CKCFGR_CCR) | I2C_CKCFGR_FS; // Fast mode 33% duty cycle
+    //I2C1->CKCFGR = ((APB_CLOCK/(25*clockrate))&I2C_CKCFGR_CCR) | I2C_CKCFGR_DUTY | I2C_CKCFGR_FS; // Fast mode 36% duty cycle
+    //I2C1->CKCFGR = (APB_CLOCK/(2*clockrate))&I2C_CKCFGR_CCR; // Standard mode good to 100kHz
+
+    // Set I2C address
+    I2C1->OADDR1 = address << 1;
+
+    // Enable I2C
+    I2C1->CTLR1 |= I2C_CTLR1_PE;
+
+    // Acknowledge the first address match event when it happens
+    I2C1->CTLR1 |= I2C_CTLR1_ACK;
+}
+
+void I2C1_EV_IRQHandler(void) __attribute__((interrupt));
+void I2C1_EV_IRQHandler(void) {
+    uint16_t STAR1, STAR2 __attribute__((unused));
+    STAR1 = I2C1->STAR1;
+    STAR2 = I2C1->STAR2;
+
+    I2C1->CTLR1 |= I2C_CTLR1_ACK;
+
+    if (STAR1 & I2C_STAR1_ADDR) { // Start event
+        i2c_slave_state.first_write = 1; // Next write will be the offset
+        i2c_slave_state.position = i2c_slave_state.offset; // Reset position
+    }
+
+    if (STAR1 & I2C_STAR1_RXNE) { // Write event
+        if (i2c_slave_state.first_write) { // First byte written, set the offset
+            i2c_slave_state.offset = I2C1->DATAR;
+            i2c_slave_state.position = i2c_slave_state.offset;
+            i2c_slave_state.first_write = 0;
+        } else { // Normal register write
+            if (i2c_slave_state.position < i2c_slave_state.size) {
+                i2c_slave_state.registers[i2c_slave_state.position] = I2C1->DATAR;
+                i2c_slave_state.position++;
+            }
+        }
+    }
+
+    if (STAR1 & I2C_STAR1_TXE) { // Read event
+        if (i2c_slave_state.position < i2c_slave_state.size) {
+            I2C1->DATAR = i2c_slave_state.registers[i2c_slave_state.position];
+            i2c_slave_state.position++;
+        } else {
+            I2C1->DATAR = 0x00;
+        }
+    }
+}
+
+void I2C1_ER_IRQHandler(void) __attribute__((interrupt));
+void I2C1_ER_IRQHandler(void) {
+    uint16_t STAR1 = I2C1->STAR1;
+
+    if (STAR1 & I2C_STAR1_BERR) { // Bus error
+        I2C1->STAR1 &= ~(I2C_STAR1_BERR); // Clear error
+    }
+
+    if (STAR1 & I2C_STAR1_ARLO) { // Arbitration lost error
+        I2C1->STAR1 &= ~(I2C_STAR1_ARLO); // Clear error
+    }
+
+    if (STAR1 & I2C_STAR1_AF) { // Acknowledge failure
+        I2C1->STAR1 &= ~(I2C_STAR1_AF); // Clear error
+    }
+}
+
+#endif
diff --git a/examples/tim2_pwm/.gdbinit b/examples/tim2_pwm/.gdbinit
new file mode 100644
index 0000000000000000000000000000000000000000..427595ae0e4d2332e7e580facfd2c4327e8441c6
--- /dev/null
+++ b/examples/tim2_pwm/.gdbinit
@@ -0,0 +1,2 @@
+file tim1_pwm.elf
+target extended-remote localhost:3333
diff --git a/examples/tim2_pwm/Makefile b/examples/tim2_pwm/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7b3d0c031265e2b750553f45da8dfce649a99c68
--- /dev/null
+++ b/examples/tim2_pwm/Makefile
@@ -0,0 +1,11 @@
+all : flash
+
+TARGET:=tim2_pwm
+
+CFLAGS+=-DSTDOUT_UART
+
+include ../../ch32v003fun/ch32v003fun.mk
+
+flash : cv_flash
+clean : cv_clean
+
diff --git a/examples/tim2_pwm/README.md b/examples/tim2_pwm/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..36c81a1f41d8414c953a7060f43aaeb94e3282ce
--- /dev/null
+++ b/examples/tim2_pwm/README.md
@@ -0,0 +1,6 @@
+# Demonstration of PWM using Timer 2
+This example shows how to set up Timer 2 (the General Purpose Timer) to generate Pulse-Width Modulation (PWM) on two output pins.
+PWM is frequently used to do variable brightness on LEDs or for digital-to-analog conversion when combined with a suitable lowpass filter.
+
+## Use
+Connect GPIO pins PD04 and PD3 to LEDs (with appropriate current limiting) and observe that they fade at the same speed, but phase-rotatd by 180°.
diff --git a/examples/tim2_pwm/debug.sh b/examples/tim2_pwm/debug.sh
new file mode 100755
index 0000000000000000000000000000000000000000..bb05a9465959cb153fad95bba4b2175667830528
--- /dev/null
+++ b/examples/tim2_pwm/debug.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# before running this you should start OOCD server
+#../../../MRS_Toolchain_Linux_x64_V1.70/OpenOCD/bin/openocd -f ../../../MRS_Toolchain_Linux_x64_V1.70/OpenOCD/bin/wch-riscv.cfg
+ 
+../../../MRS_Toolchain_Linux_x64_V1.70/RISC-V\ Embedded\ GCC/bin/riscv-none-embed-gdb
diff --git a/examples/tim2_pwm/tim2_pwm.c b/examples/tim2_pwm/tim2_pwm.c
new file mode 100644
index 0000000000000000000000000000000000000000..37e949d727dfd01883b1271ff9bb9e41bac54b36
--- /dev/null
+++ b/examples/tim2_pwm/tim2_pwm.c
@@ -0,0 +1,131 @@
+/*
+ * Example for using Advanced Control Timer (TIM2) for PWM generation
+ * 03-28-2023 E. Brombaugh
+ * 05-29-2023 recallmenot adapted from Timer1 to Timer2
+ */
+
+/*
+Timer 2 pin mappings by AFIO->PCFR1
+	00 (default)
+		D4		T2CH1ETR
+		D3		T2CH2
+		C0		T2CH3
+		D7		T2CH4
+	01
+		C5		T2CH1ETR_
+		C2		T2CH2_
+		D2		T2CH3_
+		C1		T2CH4_
+	10
+		C1		T2CH1ETR_
+		D3		T2CH2
+		C0		T2CH3
+		D7		T2CH4
+	11
+		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 GPIOD and TIM2
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
+	RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
+
+	// PD4 is T2CH1, 10MHz Output alt func, push-pull
+	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
+	GPIOD->CFGLR &= ~(0xf<<(4*3));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*3);
+		
+	// 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 | 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
+}
+
+
+
+/*
+ * entry
+ */
+int main()
+{
+	uint32_t count = 0;
+	
+	SystemInit48HSI();
+
+	// start serial @ default 115200bps
+	SetupUART( UART_BRR );
+	Delay_Ms( 100 );
+	printf("\r\r\n\ntim2_pwm example\n\r");
+
+	// init TIM2 for PWM
+	printf("initializing tim2...");
+	t2pwm_init();
+	printf("done.\n\r");
+		
+	printf("looping...\n\r");
+	while(1)
+	{
+		t2pwm_setpw(0, count);			// Chl 1
+		t2pwm_setpw(1, (count + 128)&255);	// Chl 2 180° out-of-phase
+		count++;
+		count &= 255;
+		Delay_Ms( 5 );
+	}
+}