diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index c1d3dc22969978f84d5fd0cfa0f4e3bca4092bbd..e40153eefe7a2f1cb00b5f35a9dc43ae8b84d0ab 100644
--- a/ch32v003fun/ch32v003fun.c
+++ b/ch32v003fun/ch32v003fun.c
@@ -819,6 +819,37 @@ void SystemInit48HSI( void )
 	while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08);                // Wait till PLL is used as system clock source
 }
 
+
+void SystemInitHSE( int HSEBYP )
+{
+	// Values lifted from the EVT.  There is little to no documentation on what this does.
+	RCC->CTLR  = RCC_HSION | RCC_HSEON | RCC_PLLON | HSEBYP;      // Enable HSE and keep HSI+PLL on.
+	while(!(RCC->CTLR&RCC_HSERDY));
+	// Not using PLL.
+	FLASH->ACTLR = FLASH_ACTLR_LATENCY_0;                         // 1 Cycle Latency
+	RCC->INTR  = 0x009F0000;                                      // Clear PLL, CSSC, HSE, HSI and LSI ready flags.
+	RCC->CFGR0 = RCC_HPRE_DIV1 | RCC_SW_HSE;                      // HCLK = SYSCLK = APB1 and use HSE for System Clock.
+	while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04);   // Wait till HSE is used as system clock source
+	RCC->CTLR = RCC_HSEON | HSEBYP; // Turn off HSI + PLL.
+}
+
+
+void SystemInitHSEPLL( int HSEBYP )
+{
+	// Values lifted from the EVT.  There is little to no documentation on what this does.
+	RCC->CTLR  = RCC_HSION | RCC_HSEON | RCC_PLLON | HSEBYP;       // Enable HSE and keep HSI+PLL on.
+	while(!(RCC->CTLR&RCC_HSERDY));
+	RCC->CFGR0 = RCC_SW_HSE | RCC_HPRE_DIV1;                       // HCLK = SYSCLK = APB1 and use HSE for System Clock.
+	RCC->CTLR  = RCC_HSEON | HSEBYP;                               // Turn off PLL and HSI.
+	RCC->CFGR0 = RCC_SW_HSE | RCC_HPRE_DIV1 | RCC_PLLSRC_HSE_Mul2; // Use PLL with HSE.
+	RCC->CTLR  = RCC_HSEON | RCC_PLLON | HSEBYP;                   // Turn PLL Back on..
+	while((RCC->CTLR & RCC_PLLRDY) == 0);                          // Wait till PLL is ready
+	RCC->CFGR0 = RCC_SW_PLL | RCC_HPRE_DIV1 | RCC_PLLSRC_HSE_Mul2; // Select PLL as system clock source
+	while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08);    // Wait till PLL is used as system clock source
+}
+
+
+
 void SetupUART( int uartBRR )
 {
 	// Enable GPIOD and UART.
diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h
index 56393414e1432ea9d3b1da24a4fd7cf98b19e023..3115d7ce0df4316438bc38dd30d09345e23881ef 100644
--- a/ch32v003fun/ch32v003fun.h
+++ b/ch32v003fun/ch32v003fun.h
@@ -4833,6 +4833,11 @@ void SystemInit(void) __attribute__((used));
 
 // Useful functions
 void SystemInit48HSI( void );
+// NOTE: HSEBYP is ORed with RCC_CTLR.  Set it to RCC_HSEBYP or 0.
+// If you are using an external oscillator, set it to RCC_HSEBYP.  Otherwise, if you are using a crystal, it must be 0.
+void SystemInitHSE( int HSEBYP );
+void SystemInitHSEPLL( int HSEBYP );
+
 
 #define UART_BAUD_RATE 115200
 #define OVER8DIV 4
diff --git a/examples/external_crystal/Makefile b/examples/external_crystal/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4f4b542e0ff670e4b1ad4cf990adcb7e55d552b0
--- /dev/null
+++ b/examples/external_crystal/Makefile
@@ -0,0 +1,51 @@
+TARGET:=external_crystal
+
+all : flash
+
+PREFIX:=riscv64-unknown-elf
+
+GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
+
+EVT:=../../ch32v003evt
+
+MINICHLINK:=../../minichlink
+
+ifeq ($(OS),Windows_NT)
+# On Windows, all the major RISC-V GCC installs are missing the -ec libgcc.
+LIB_GCC=../../misc/libgcc.a
+else
+LIB_GCC=-lgcc
+endif
+
+CH32V003FUN:=../../ch32v003fun
+
+CFLAGS:= \
+	-g -Os -flto -ffunction-sections \
+	-static-libgcc $(LIB_GCC) \
+	-march=rv32ec \
+	-mabi=ilp32e \
+	-I/usr/include/newlib \
+	-I$(CH32V003FUN) \
+	-nostdlib \
+	-I. -DTINYVECTOR
+
+LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections
+
+SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
+
+$(TARGET).elf : $(SYSTEM_C) $(TARGET).c
+	$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+$(TARGET).bin : $(TARGET).elf
+	$(PREFIX)-size $^
+	$(PREFIX)-objdump -S $^ > $(TARGET).lst
+	$(PREFIX)-objdump -t $^ > $(TARGET).map
+	$(PREFIX)-objcopy -O binary $< $(TARGET).bin
+	$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
+
+flash : $(TARGET).bin
+	$(MINICHLINK)/minichlink -w $< flash -b
+
+clean :
+	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex
+
diff --git a/examples/external_crystal/external_crystal.c b/examples/external_crystal/external_crystal.c
new file mode 100644
index 0000000000000000000000000000000000000000..55de9d22f741f4dc8aca5ba7cb9f6fbdf463aded
--- /dev/null
+++ b/examples/external_crystal/external_crystal.c
@@ -0,0 +1,36 @@
+// XXX XXX XXX XXX XXX THIS IS UNTESTED XXX XXX XXX XXX XXX
+
+// Could be defined here, or in the processor defines.
+#define SYSTEM_CORE_CLOCK 24000000
+
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+#define APB_CLOCK SYSTEM_CORE_CLOCK
+
+uint32_t count;
+
+int main()
+{
+	SystemInitHSE( 0 );
+
+	// Enable GPIOD.
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD;
+
+	// GPIO D0 Push-Pull, 10MHz Output
+	GPIOD->CFGLR &= ~(0xf<<(4*0));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
+
+	// GPIO D0 Push-Pull, 10MHz Output
+	GPIOD->CFGLR &= ~(0xf<<(4*4));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
+
+	while(1)
+	{
+		GPIOD->BSHR = 1 | (1<<4);	 // Turn on GPIOD0
+		Delay_Ms( 200 );
+		GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIOD0
+		Delay_Ms( 200 );
+		count++;
+	}
+}