From 555e8ccf7a554eb269e905b0adc59fca7948d840 Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Sun, 12 Mar 2023 23:52:18 -0400
Subject: [PATCH] Add examples using the external crystal/oscillator

---
 ch32v003fun/ch32v003fun.c                    | 31 ++++++++++++
 ch32v003fun/ch32v003fun.h                    |  5 ++
 examples/external_crystal/Makefile           | 51 ++++++++++++++++++++
 examples/external_crystal/external_crystal.c | 36 ++++++++++++++
 4 files changed, 123 insertions(+)
 create mode 100644 examples/external_crystal/Makefile
 create mode 100644 examples/external_crystal/external_crystal.c

diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index c1d3dc2..e40153e 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 5639341..3115d7c 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 0000000..4f4b542
--- /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 0000000..55de9d2
--- /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++;
+	}
+}
-- 
GitLab