Repository: cnlohr/ch32fun
Pull request #534: CH59x bringup and blinky
Author: login: biemster
Created: 2025-02-24T13:51:04Z | Merged: 2025-03-12T21:38:51Z

CH592/1 bringup and blinky. This is the start of CH59x support, and will conclude in merging the https://github.com/biemster/ch592_noblob_advertiser functionality in here.

One major issue is that the CH59x SDK is not based on structs like ch32, but just pointer #defines. Also I could not find anything resembling `RCC` in those #defines, so this might need some refactoring on both sides.


Diff:
diff --git a/ch32fun/ch32fun.c b/ch32fun/ch32fun.c
index b6280864..a33d7a82 100644
--- a/ch32fun/ch32fun.c
+++ b/ch32fun/ch32fun.c
@@ -966,6 +966,24 @@ void USBPD_WKUP_IRQHandler( void )		__attribute__((section(".text.vector_handler
 void TIM2_CC_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void TIM2_TRG_IRQHandler( void )		__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
 void TIM2_BRK_IRQHandler( void )		__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+// CH59x
+void TMR0_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void GPIOA_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void GPIOB_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void SPI0_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USB_IRQHandler( void )				__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TMR1_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TMR2_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void UART0_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void UART1_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void ADC_IRQHandler( void )				__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void I2C_IRQHandler( void )				__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void PWMX_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TMR3_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void UART2_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void UART3_IRQHandler( void )			__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void WDOG_BAT_IRQHandler( void )		__attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+
 
 
 void InterruptVector()         __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("InterruptVectorDefault"))) __attribute((naked));
@@ -1060,7 +1078,7 @@ asm volatile(
 "	mret\n" : : [main]"r"(main) );
 }
 
-#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x)
+#elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH59x)
 
 void handle_reset( void )
 {
@@ -1472,7 +1490,7 @@ void DelaySysTick( uint32_t n )
 #ifdef CH32V003
 	uint32_t targend = SysTick->CNT + n;
 	while( ((int32_t)( SysTick->CNT - targend )) < 0 );
-#elif defined(CH32V20x) || defined(CH32V30x)
+#elif defined(CH32V20x) || defined(CH32V30x) || defined(CH59x)
 	uint64_t targend = SysTick->CNT + n;
 	while( ((int64_t)( SysTick->CNT - targend )) < 0 );
 #elif defined(CH32V10x) || defined(CH32X03x)
@@ -1541,7 +1559,36 @@ void SystemInit( void )
 	#endif
 #endif
 
-#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
+#if defined(CH59x) // has no HSI
+	// SYS_SAFE_ACCESS for writing RWA and WA registers
+	#define SYS_SAFE_ACCESS_ENABLE  { R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1; R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2; ADD_N_NOPS(2); }
+	#define SYS_SAFE_ACCESS_DISABLE { R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG0; ADD_N_NOPS(2); }
+#ifndef CLK_SOURCE_CH59X
+	#define CLK_SOURCE_CH59X CLK_SOURCE_PLL_60MHz
+#endif
+	SYS_SAFE_ACCESS_ENABLE
+	R8_PLL_CONFIG &= ~(1 << 5);
+	SYS_CLKTypeDef sc = CLK_SOURCE_CH59X;
+	if(sc & 0x20)  // HSE div
+	{
+		R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+		ADD_N_NOPS(4);
+		R8_FLASH_CFG = 0X51;
+	}
+
+	else if(sc & 0x40) // PLL div
+	{
+		R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+		ADD_N_NOPS(4);
+		R8_FLASH_CFG = 0X52;
+	}
+	else
+	{
+		R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+	}
+	R8_PLL_CONFIG |= 1 << 7;
+	SYS_SAFE_ACCESS_DISABLE
+#elif defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
 	#if defined(CH32V30x) || defined(CH32V20x) || defined(CH32V10x)
 		EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
 	#endif
@@ -1600,9 +1647,11 @@ void SystemInit( void )
 	#endif
 #endif
 
+#if !defined(CH59x)
 	RCC->INTR  = 0x009F0000;                               // Clear PLL, CSSC, HSE, HSI and LSI ready flags.
+#endif
 
-#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL
+#if defined(FUNCONF_USE_PLL) && FUNCONF_USE_PLL && !defined(CH59x)
 	while((RCC->CTLR & RCC_PLLRDY) == 0);                       	// Wait till PLL is ready
 	uint32_t tmp32 = RCC->CFGR0 & ~(0x03);							// clr the SW
 	RCC->CFGR0 = tmp32 | RCC_SW_PLL;                       			// Select PLL as system clock source
@@ -1617,6 +1666,7 @@ void SystemInit( void )
 #endif
 }
 
+#if defined(FUNCONF_INIT_ANALOG) && FUNCONF_INIT_ANALOG
 void funAnalogInit( void )
 {
 	//RCC->CFGR0 &= ~(0x1F<<11); // Assume ADCPRE = 0
@@ -1655,6 +1705,7 @@ int funAnalogRead( int nAnalogNumber )
 	// get result
 	return ADC1->RDATAR;
 }
+#endif
 
 // C++ Support
 
diff --git a/ch32fun/ch32fun.h b/ch32fun/ch32fun.h
index 3dc94095..c326b51b 100644
--- a/ch32fun/ch32fun.h
+++ b/ch32fun/ch32fun.h
@@ -128,6 +128,10 @@
 	#define FUNCONF_DEBUG_HARDFAULT 1
 #endif
 
+#if !defined( FUNCONF_INIT_ANALOG )
+	#define FUNCONF_INIT_ANALOG 1
+#endif
+
 #if defined( CH32X03x ) && FUNCONF_USE_PLL
 	#error No PLL on the X03x
 #endif
@@ -160,6 +164,8 @@
 		#endif
 	#elif defined(CH32V30x)
 		#define HSE_VALUE				  (8000000)
+	#elif defined(CH59x)
+		#define HSE_VALUE				  (32000000)
 	#endif
 #endif
 
@@ -202,7 +208,12 @@
 #endif
 
 #ifndef FUNCONF_SYSTEM_CORE_CLOCK
-	#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
+	#if defined(CH59x) // no PLL multiplier, but a divider from the 480 MHz clock
+		#define FUNCONF_SYSTEM_CORE_CLOCK 60000000 // default in ch32fun.c using CLK_SOURCE_PLL_60MHz
+		#if defined(CLK_SOURCE_CH59X)
+			#error Must define FUNCONF_SYSTEM_CORE_CLOCK too if CLK_SOURCE_CH59X is defined
+		#endif
+	#elif defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
 		#define FUNCONF_SYSTEM_CORE_CLOCK ((HSI_VALUE)*(FUNCONF_PLL_MULTIPLIER))
 	#elif defined(FUNCONF_USE_HSE) && FUNCONF_USE_HSE
 		#define FUNCONF_SYSTEM_CORE_CLOCK ((HSE_VALUE)*(FUNCONF_PLL_MULTIPLIER))
@@ -348,6 +359,8 @@ typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
 	#include "ch32v20xhw.h"
 #elif defined( CH32V30x )
 	#include "ch32v30xhw.h"
+#elif defined( CH59x )
+	#include "ch59xhw.h"
 #endif
 
 #if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE )
@@ -817,11 +830,49 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define OFFSET_FOR_GPIOB(pin)         (((pin & PB) >> 31) * (&R32_PB_PIN - &R32_PA_PIN)) // 0 if GPIOA, 0x20 if GPIOB
+#define GPIO_ResetBits(pin)           (*(&R32_PA_CLR + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB))
+#define GPIO_SetBits(pin)             (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB))
+#define GPIO_InverseBits(pin)         (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) ^= (pin & ~PB))
+#define GPIO_ReadPortPin(pin)         (*(&R32_PA_PIN + OFFSET_FOR_GPIOB(pin)) &  (pin & ~PB))
+#define funDigitalRead(pin)           GPIO_ReadPortPin(pin)
+#define funDigitalWrite( pin, value ) { if((value)==FUN_HIGH){GPIO_SetBits(pin);} else if((value)==FUN_LOW){GPIO_ResetBits(pin);} }
+
+RV_STATIC_INLINE void funPinMode(u32 pin, GPIOModeTypeDef mode)
+{
+	switch(mode) {
+	case GPIO_ModeIN_Floating:
+		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
+		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     &= ~(pin & ~PB);
+		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
+		break;
+	case GPIO_ModeIN_PU:
+		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
+		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     |= (pin & ~PB);
+		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
+		break;
+	case GPIO_ModeIN_PD:
+		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
+		*(&R32_PA_PU + OFFSET_FOR_GPIOB(pin))     &= ~(pin & ~PB);
+		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    &= ~(pin & ~PB);
+		break;
+	case GPIO_ModeOut_PP_5mA:
+		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(pin & ~PB);
+		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    |= (pin & ~PB);
+		break;
+	case GPIO_ModeOut_PP_20mA:
+		*(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (pin & ~PB);
+		*(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin))    |= (pin & ~PB);
+		break;
+	}
+}
+#else
 // Arduino-like GPIO Functionality
 #define GpioOf( pin ) ((GPIO_TypeDef *)(GPIOA_BASE + 0x400 * ((pin)>>4)))
 
-#define FUN_HIGH 0x1
-#define FUN_LOW 0x0
 #define FUN_OUTPUT (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)
 #define FUN_INPUT (GPIO_CNF_IN_FLOATING)
 
@@ -846,6 +897,7 @@ extern "C" {
 #define funGpioInitC() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); }
 #define funGpioInitD() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); }
 #define funDigitalRead( pin ) ((int)((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1))
+#endif
 
 
 #define ANALOG_0 0
diff --git a/ch32fun/ch32fun.ld b/ch32fun/ch32fun.ld
index 029a018a..7dd34a08 100644
--- a/ch32fun/ch32fun.ld
+++ b/ch32fun/ch32fun.ld
@@ -65,9 +65,20 @@ MEMORY
 	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
 	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
 #elif TARGET_MCU_LD == 7
-	/* CH32V005, CH32V006, CH32V007 */
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
-	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
+  /* CH32V005, CH32V006, CH32V007 */
+  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
+  RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
+#elif TARGET_MCU_LD == 8
+	/* CH591/2 */
+	#if MCU_PACKAGE == 1
+		FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 192K
+		RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 24K
+	#elif MCU_PACKAGE == 2
+		FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 448K
+		RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 24K
+	#else
+		#error "Unknown MCU package"
+#endif
 #else
 	#error "Unknown MCU target"
 #endif
diff --git a/ch32fun/ch32fun.mk b/ch32fun/ch32fun.mk
index eb76e650..e5b90ccb 100644
--- a/ch32fun/ch32fun.mk
+++ b/ch32fun/ch32fun.mk
@@ -183,6 +183,27 @@ else
 		endif
 
 		TARGET_MCU_LD:=3
+	else ifeq ($(findstring CH59,$(TARGET_MCU)),CH59) # CH592 1
+		TARGET_MCU_PACKAGE?=CH592F
+		CFLAGS_ARCH+=-march=rv32imac \
+			-mabi=ilp32 \
+			-DCH59x=1
+
+		# MCU Flash/RAM split
+		ifeq ($(findstring 591, $(TARGET_MCU_PACKAGE)), 591)
+			MCU_PACKAGE:=1
+		else ifeq ($(findstring 592, $(TARGET_MCU_PACKAGE)), 592)
+			MCU_PACKAGE:=2
+		endif
+
+		# Package
+		ifeq ($(findstring D, $(TARGET_MCU_PACKAGE)), D)
+			CFLAGS+=-DCH59xD
+		else ifeq ($(findstring F, $(TARGET_MCU_PACKAGE)), F)
+			CFLAGS+=-DCH59xF
+		endif
+
+		TARGET_MCU_LD:=8
 	else
 		ERROR:=$(error Unknown MCU $(TARGET_MCU))
 	endif
diff --git a/ch32fun/ch59xhw.h b/ch32fun/ch59xhw.h
new file mode 100644
index 00000000..42ecc7c6
--- /dev/null
+++ b/ch32fun/ch59xhw.h
@@ -0,0 +1,300 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz =  (0x20 |  2),
+    CLK_SOURCE_HSE_8MHz =   (0x20 |  4),
+    CLK_SOURCE_HSE_6_4MHz = (0x20 |  5),
+    CLK_SOURCE_HSE_4MHz =   (0x20 |  8),
+
+    CLK_SOURCE_PLL_60MHz =  (0x40 |  8),
+    CLK_SOURCE_PLL_48MHz =  (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz =  (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz =  (0x40 | 20),
+} SYS_CLKTypeDef;
+
+// For debug writing to the debug interface.
+#define DMDATA0 			((vu32*)0xe0000380)
+#define DMDATA1 			((vu32*)0xe0000384)
+#define DMSTATUS_SENTINEL	((vu32*)0xe0000388)// Reads as 0x00000000 if debugger is attached.
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH59*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+
+/* GPIO PA register */
+#define R32_PA_DIR          (*((vu32*)0x400010A0)) // RW, GPIO PA I/O direction: 0=in, 1=out
+#define R32_PA_PIN          (*((vu32*)0x400010A4)) // RO, GPIO PA input
+#define R32_PA_OUT          (*((vu32*)0x400010A8)) // RW, GPIO PA output
+#define R32_PA_CLR          (*((vu32*)0x400010AC)) // WZ, GPIO PA clear output: 0=keep, 1=clear
+#define R32_PA_PU           (*((vu32*)0x400010B0)) // RW, GPIO PA pullup resistance enable
+#define R32_PA_PD_DRV       (*((vu32*)0x400010B4)) // RW, PA pulldown for input or PA driving capability for output
+
+/* GPIO PB register */
+#define R32_PB_DIR          (*((vu32*)0x400010C0)) // RW, GPIO PB I/O direction: 0=in, 1=out
+#define R32_PB_PIN          (*((vu32*)0x400010C4)) // RO, GPIO PB input
+#define R32_PB_OUT          (*((vu32*)0x400010C8)) // RW, GPIO PB output
+#define R32_PB_CLR          (*((vu32*)0x400010CC)) // WZ, GPIO PB clear output: 0=keep, 1=clear
+#define R32_PB_PU           (*((vu32*)0x400010D0)) // RW, GPIO PB pullup resistance enable
+#define R32_PB_PD_DRV       (*((vu32*)0x400010D4)) // RW, PB pulldown for input or PB driving capability for output
+
+#define PA0      (0x00000001) /*!< Pin 0 selected */
+#define PA1      (0x00000002) /*!< Pin 1 selected */
+#define PA2      (0x00000004) /*!< Pin 2 selected */
+#define PA3      (0x00000008) /*!< Pin 3 selected */
+#define PA4      (0x00000010) /*!< Pin 4 selected */
+#define PA5      (0x00000020) /*!< Pin 5 selected */
+#define PA6      (0x00000040) /*!< Pin 6 selected */
+#define PA7      (0x00000080) /*!< Pin 7 selected */
+#define PA8      (0x00000100) /*!< Pin 8 selected */
+#define PA9      (0x00000200) /*!< Pin 9 selected */
+#define PA10     (0x00000400) /*!< Pin 10 selected */
+#define PA11     (0x00000800) /*!< Pin 11 selected */
+#define PA12     (0x00001000) /*!< Pin 12 selected */
+#define PA13     (0x00002000) /*!< Pin 13 selected */
+#define PA14     (0x00004000) /*!< Pin 14 selected */
+#define PA15     (0x00008000) /*!< Pin 15 selected */
+
+#define PB       (0x80000000) /* Bit mask to indicate bank B */
+#define PB0      (0x80000001) /*!< Pin 0 selected */
+#define PB1      (0x80000002) /*!< Pin 1 selected */
+#define PB2      (0x80000004) /*!< Pin 2 selected */
+#define PB3      (0x80000008) /*!< Pin 3 selected */
+#define PB4      (0x80000010) /*!< Pin 4 selected */
+#define PB5      (0x80000020) /*!< Pin 5 selected */
+#define PB6      (0x80000040) /*!< Pin 6 selected */
+#define PB7      (0x80000080) /*!< Pin 7 selected */
+#define PB8      (0x80000100) /*!< Pin 8 selected */
+#define PB9      (0x80000200) /*!< Pin 9 selected */
+#define PB10     (0x80000400) /*!< Pin 10 selected */
+#define PB11     (0x80000800) /*!< Pin 11 selected */
+#define PB12     (0x80001000) /*!< Pin 12 selected */
+#define PB13     (0x80002000) /*!< Pin 13 selected */
+#define PB14     (0x80004000) /*!< Pin 14 selected */
+#define PB15     (0x80008000) /*!< Pin 15 selected */
+#define PB16     (0x80010000) /*!< Pin 16 selected */
+#define PB17     (0x80020000) /*!< Pin 17 selected */
+#define PB18     (0x80040000) /*!< Pin 18 selected */
+#define PB19     (0x80080000) /*!< Pin 19 selected */
+#define PB20     (0x80100000) /*!< Pin 20 selected */
+#define PB21     (0x80200000) /*!< Pin 21 selected */
+#define PB22     (0x80400000) /*!< Pin 22 selected */
+#define PB23     (0x80800000) /*!< Pin 23 selected */
+#define P_All    (0xFFFFFFFF) /*!< All pins selected */
+
+typedef enum
+{
+    GPIO_ModeIN_Floating,
+    GPIO_ModeIN_PU,
+    GPIO_ModeIN_PD,
+    GPIO_ModeOut_PP_5mA,
+    GPIO_ModeOut_PP_20mA,
+} GPIOModeTypeDef;
+
+/* General Purpose I/O */
+typedef enum
+{
+	GPIO_CFGLR_IN_FLOAT = GPIO_ModeIN_Floating,
+	GPIO_CFGLR_IN_PUPD = GPIO_ModeIN_PU, // is most common
+	GPIO_CFGLR_IN_PU = GPIO_ModeIN_PU,
+	GPIO_CFGLR_IN_PD = GPIO_ModeIN_PD, // to suppress the -Wswitch warning
+	GPIO_CFGLR_OUT_10Mhz_PP = GPIO_ModeOut_PP_20mA,
+	GPIO_CFGLR_OUT_2Mhz_PP = GPIO_ModeOut_PP_5mA,
+	GPIO_CFGLR_OUT_50Mhz_PP = GPIO_ModeOut_PP_20mA,
+} GPIO_CFGLR_PIN_MODE_Typedef;
+
+#define HardFault_IRQn        EXC_IRQn
+
+/* Standard Peripheral Library old definitions (maintained for legacy purpose) */
+#define HSI_Value             HSI_VALUE
+#define HSE_Value             HSE_VALUE
+#define HSEStartUp_TimeOut    HSE_STARTUP_TIMEOUT
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // Header guard
diff --git a/examples_ch59x/blink/Makefile b/examples_ch59x/blink/Makefile
new file mode 100644
index 00000000..f91e0ef0
--- /dev/null
+++ b/examples_ch59x/blink/Makefile
@@ -0,0 +1,10 @@
+all : flash
+
+TARGET:=blink
+TARGET_MCU:=CH592
+TARGET_MCU_PACKAGE:=CH592F
+
+include ../../ch32fun/ch32fun.mk
+
+flash : cv_flash
+clean : cv_clean
diff --git a/examples_ch59x/blink/blink.c b/examples_ch59x/blink/blink.c
new file mode 100644
index 00000000..75b1ea87
--- /dev/null
+++ b/examples_ch59x/blink/blink.c
@@ -0,0 +1,17 @@
+#include "ch32fun.h"
+#include <stdio.h>
+
+int main()
+{
+	SystemInit();
+
+	funPinMode( PA8, GPIO_CFGLR_OUT_2Mhz_PP );
+
+	while(1)
+	{
+		funDigitalWrite( PA8, FUN_LOW );	 // Turn on LED
+		Delay_Ms( 33 );
+		funDigitalWrite( PA8, FUN_HIGH );	 // Turn off LED
+		Delay_Ms( 300 );
+	}
+}
diff --git a/examples_ch59x/blink/funconfig.h b/examples_ch59x/blink/funconfig.h
new file mode 100644
index 00000000..31dec37c
--- /dev/null
+++ b/examples_ch59x/blink/funconfig.h
@@ -0,0 +1,14 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
+
+#define FUNCONF_DEBUG_HARDFAULT   0
+#define FUNCONF_USE_CLK_SEC       0
+#define FUNCONF_USE_DEBUGPRINTF   0 // saves 16 bytes, enable / remove if you want printf over swio
+#define FUNCONF_INIT_ANALOG       0 // ADC is not implemented yet
+
+#endif
diff --git a/examples_ch59x/debugprintfdemo/Makefile b/examples_ch59x/debugprintfdemo/Makefile
new file mode 100644
index 00000000..04239d39
--- /dev/null
+++ b/examples_ch59x/debugprintfdemo/Makefile
@@ -0,0 +1,10 @@
+all : flash
+
+TARGET:=debugprintfdemo
+TARGET_MCU:=CH592
+TARGET_MCU_PACKAGE:=CH592F
+
+include ../../ch32fun/ch32fun.mk
+
+flash : cv_flash
+clean : cv_clean
diff --git a/examples_ch59x/debugprintfdemo/debugprintfdemo.c b/examples_ch59x/debugprintfdemo/debugprintfdemo.c
new file mode 100644
index 00000000..9ae474f1
--- /dev/null
+++ b/examples_ch59x/debugprintfdemo/debugprintfdemo.c
@@ -0,0 +1,34 @@
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
+
+#include "ch32fun.h"
+#include <stdio.h>
+
+uint32_t count;
+
+int last = 0;
+void handle_debug_input( int numbytes, uint8_t * data )
+{
+	last = data[0];
+	count += numbytes;
+}
+
+int main()
+{
+	SystemInit();
+
+	funPinMode( PA8, GPIO_CFGLR_OUT_10Mhz_PP );
+
+	while(1)
+	{
+		funDigitalWrite( PA8, FUN_LOW ); // Turn on LED
+		printf( "+%lu\n", count++ );
+		Delay_Ms(100);
+		int i;
+		for( i = 0; i < 10000; i++ )
+			poll_input();
+		funDigitalWrite( PA8, FUN_HIGH ); // Turn off LED
+		printf( "-%lu[%c]\n", count++, last );
+		Delay_Ms(100);
+	}
+}
diff --git a/examples_ch59x/debugprintfdemo/funconfig.h b/examples_ch59x/debugprintfdemo/funconfig.h
new file mode 100644
index 00000000..3ee74d61
--- /dev/null
+++ b/examples_ch59x/debugprintfdemo/funconfig.h
@@ -0,0 +1,13 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
+
+#define FUNCONF_DEBUG_HARDFAULT   0
+#define FUNCONF_USE_CLK_SEC       0
+#define FUNCONF_INIT_ANALOG       0 // ADC is not implemented yet
+
+#endif


Reviews:
user: login: cnlohr
state: CHANGES_REQUESTED
author_association: OWNER
submitted_at: 2025-02-25T21:27:59Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-25T21:43:49Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-25T21:45:26Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-25T21:49:07Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-25T21:51:39Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-25T23:08:02Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-25T23:09:41Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T14:51:15Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:02:12Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:19:36Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:25:18Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T15:33:03Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:46:44Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T16:53:48Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-26T21:26:48Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-26T21:28:03Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-02-26T21:29:35Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T21:42:01Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T21:42:53Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-26T21:47:29Z
user: login: cnlohr
body: Getting pretty close.  This has me pretty excited!
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-03T01:54:29Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:24:22Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:26:02Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T14:26:46Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-04T21:54:10Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T10:03:25Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:11:04Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:20:36Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:22:35Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:22:54Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:25:22Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:30:46Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:34:54Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:36:56Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:38:13Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:27:14Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T15:03:21Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T16:57:57Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:08:25Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:20:23Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:38:58Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T17:52:37Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T18:39:12Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T18:39:27Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T18:40:08Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T18:40:32Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T20:35:16Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T20:37:49Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T20:42:27Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T20:49:28Z
user: login: cnlohr
state: COMMENTED
author_association: OWNER
submitted_at: 2025-03-11T22:49:16Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T12:40:01Z
user: login: biemster
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T12:40:59Z

Review comments:
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: cnlohr
body: These should go under `ch32fun.h` in the section where other CSRs are read/written.  Maybe we should completely switch to this format, so those functions can just call `read_csr`/`write_csr`.
created_at: 2025-02-25T01:44:25Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: cnlohr
body: These look like they already match the flash definitions on other chips.  Better to use struct'd access instead of the #define access.

Also, please don't use new types, we already have 2 bit-length-type-lists, i.e. uint32_t and `u32`  no need to add a `v` out front.
created_at: 2025-02-25T01:45:36Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: cnlohr
body: Why are these needed?   It looks like the `funPinMode` macro should be able to do the operations as you would need to control IO.
created_at: 2025-02-25T01:47:13Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: cnlohr
body: This section looks overbuilt.  As in this looks really bready, like what's in the EVT.  It looks like it could be paired down a lot and still be fine. 
created_at: 2025-02-25T01:47:58Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: biemster
body: This whole #if should be redone, I was hoping for some pointers where they should go. This is indeed just copied from the EVT, to show what is needed for the ch59x. I could not find a direct ch32 equivalent of sys_safe_access_..., is there?
created_at: 2025-02-25T21:43:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: biemster
body: These switches seem much different from the macros for ch32, so I just copied them in like this. I'll have a second look if they can be consolidated.
created_at: 2025-02-25T21:45:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: biemster
body: Do they? You have a much better trained eye than I on this. It would be great actually if the flash definitions are the same, I'm having great difficulty getting them to work properly at the moment. I'd definitely would like to have structed access here, I'll try again.

I added the `v` in front because it looked most like what the ch59x EVT had (PUINT8V), `v` is for volatile right? That type already existed in `ch32fun`?

edit: yes there is `vu32` already, it's a `__IO uint32_t`. I could leave out the `v`, but it looks like a better fit?
created_at: 2025-02-25T21:49:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: biemster
body: I wanted to use the functions that were there already, but they all directly use `0x804` while the ch59x uses `0x800`. That looked like an important difference to me, but I don't really know what it does though. Should we have two versions of this macro then, or should it take a `reg`? (that would require quite a lot of changes in the already existing codebase I think)
created_at: 2025-02-25T21:51:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: cnlohr
body: I am unfamiliar with sys_safe_access.  Where is it referenced so I can read more? If this is a function that would be used across multiple chips it should appear in ch32fun.h, if it is only used on one or two chips, it should be in the chip-specific header.

For `GPIOA_ModeCfg` this function should if at all possible not exist and the functionality of `funPinMode` should be fixed.
created_at: 2025-02-25T23:07:44Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: cnlohr
body: I honestly had never considered modifying the way the CSR functions in ch32fun.h operate, but I am seriously thinking about cleaning it up now.  It could significantly cut down on the amount of code needed.

For now, I think you're OK doing it as an extra dedicated function.  Or, making the 0x804 to 0x800 depending on the chip architecture.

(I don't have a strong opinion)
created_at: 2025-02-25T23:09:41Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: biemster
body: `sys_safe_access` is detailed in chapter 4.2 of the datasheet (https://www.wch.cn/downloads/CH592DS1_PDF.html)
Certain registers are "RWA" or "WA", to write to those a "safe access mode" has to be activated.
created_at: 2025-02-26T14:51:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: biemster
body: Just noticed now that the datasheet of ch592 also notes csr address as 0x804. Could this be wrong in the SDK? would anything work at all if it's off by 4? (I guess not)
created_at: 2025-02-26T15:02:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: biemster
body: those `sys_safe_access_...` functions also check for a RO bit and try to reinstate that in the `_disable` again, which should not work. I think those functions should just do the `R8_SAFE_ACCESS_SIG` write and nothing else. Then they are fine in a #define
created_at: 2025-02-26T15:19:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: biemster
body: nice that took blinky from 844 bytes to 536! sorry I'm talking to myself
created_at: 2025-02-26T15:25:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: biemster
body: I'd change the csr functions with this then:
```C
// For reading INTSYSCR, for interrupt nesting + hardware stack enable.
#define __get_INTSYSCR()    ({u32 __tmp; __ASM volatile ( ADD_ARCH_ZICSR "csrr %0, 0x804": "=r"(__tmp)); __tmp; })

// For setting INTSYSCR, for interrupt nesting + hardware stack enable.
#define __set_INTSYSCR(val) ({ if (__builtin_constant_p(val) && (u32)(val) < 32) \
        __ASM volatile ( ADD_ARCH_ZICSR "csrw 0x804, %0" :: "i"(val)); \
    else \
        __ASM volatile ( ADD_ARCH_ZICSR "csrw 0x804, %0" :: "r"(val)); })
```
but it's probably best to leave that to a separate PR, so for now I just revert what I did (I don't need it in `SetSysClock` anymore)
created_at: 2025-02-26T15:33:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: biemster
body: Upon looking again they are very different from the flash definitions of other chips. ch59x has only 2 registers (DATA and CONTROL), while the ch32 have 10 fields in the struct. I'm not an expert on this, but I really don't see any way to consolidate these together but I'm definitely open to suggestions.
created_at: 2025-02-26T16:46:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: biemster
body: 
> For `GPIOA_ModeCfg` this function should if at all possible not exist and the functionality of `funPinMode` should be fixed.

The gpio functions in ch32 seems to rely heavily on `RCC`, of which there is no equivalent in ch59x. I could however cook up a `funPinMode` macro that replaces this function, but it will by no means look similar to the ch32 ones I'm afraid.
created_at: 2025-02-26T16:53:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
+{
+  if(read_csr(0x800) & 0x08)
+  {
+    IRQ_STA = read_csr(0x800);
+    write_csr(0x800, (IRQ_STA&(~0x08)));
+  }
+  ADD_N_NOPS(2);
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
+  R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
+  ADD_N_NOPS(2);
+}
+
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_disable(void)
+{
+  R8_SAFE_ACCESS_SIG = 0;
+  write_csr(0x800, read_csr(0x800) | (IRQ_STA & 0x08));
+  IRQ_STA = 0;
+  ADD_N_NOPS(2);
+}
+
+void SetSysClock(SYS_CLKTypeDef sc)
+{
+  sys_safe_access_enable();
+  R8_PLL_CONFIG &= ~(1 << 5); //
+  sys_safe_access_disable();
+  if(sc & 0x20)  // HSE div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (0 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    ADD_N_NOPS(2);
+    R8_FLASH_CFG = 0X51;
+    sys_safe_access_disable();
+  }
+
+  else if(sc & 0x40) // PLL div
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG = (1 << 6) | (sc & 0x1f) | RB_TX_32M_PWR_EN | RB_PLL_PWR_EN;
+    ADD_N_NOPS(4);
+    sys_safe_access_disable();
+    sys_safe_access_enable();
+    R8_FLASH_CFG = 0X52;
+    sys_safe_access_disable();
+  }
+  else
+  {
+    sys_safe_access_enable();
+    R32_CLK_SYS_CFG |= RB_CLK_SYS_MOD;
+    sys_safe_access_disable();
+  }
+  sys_safe_access_enable();
+  R8_PLL_CONFIG |= 1 << 7;
+  sys_safe_access_disable();
+}
+void GPIOA_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
path: ch32fun/ch32fun.c
user: login: cnlohr
body: It's OK if it doesn't look similar.  Everyone has been transitioning to funPinMode and like functions.

Also, sounds great.  I'm really glad you are grinding on this some.  This is the kind of work WCH should have done in their toolchain, so It's always good when we can have something of better quality than the manufacturer. 
created_at: 2025-02-26T21:26:48Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: cnlohr
body: I'm going to hopefully be able to review this more this weekend.  But, there is nothing like sys_safe_access that I am aware of.

Just wondering, do you know if the CH59x uses RVSWIO, RVSWD or something else for it's programming?
created_at: 2025-02-26T21:28:03Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: cnlohr
body: Feel free to leave the `v`

You would need to #ifdef the code in `_write` so that it only uses `DATA0` then.  Do you think the DATA register could be used in the same way DATA0/DATA1 is used on the ch32v line?
created_at: 2025-02-26T21:29:35Z
author_association: OWNER
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: biemster
body: I'm quite confident I got the `sys_safe_access_` stuff correct now, it's just a simple register write now, exactly as written in the datasheet. Just a small #define, so absolute minimum code.
created_at: 2025-02-26T21:42:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: biemster
body: I did not encounter any `RVSW` at all to be honest, so I doubt it's used on ch59x.
created_at: 2025-02-26T21:42:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: biemster
body: I'm battling the flash interface currently, and have not been successful in writing (or reading) anything through this yet. It's in the ISP853.o blob with which ghidra has some issues with, so I think it will take a couple more days before I can add some meaningful code for it here. Is that a blocker for this PR? (I'm a fan of small PRs to add small incremental improvements, but I can accommodate if you prefer a more complete package)
created_at: 2025-02-26T21:47:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,9 +65,20 @@ MEMORY
 	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
 	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
 #elif TARGET_MCU_LD == 7
-	/* CH32V005, CH32V006, CH32V007 */
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
-	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
+  /* CH32V005, CH32V006, CH32V007 */
path: ch32fun/ch32fun.ld
user: login: cnlohr
body: Tabs in this file not spaces.
created_at: 2025-03-03T01:51:24Z
author_association: OWNER
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: cnlohr
body: This is complicated enough, it should be a function (even if a static function).
created_at: 2025-03-03T01:51:53Z
author_association: OWNER
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: cnlohr
body: (Otherwise the code copy pasta will be big)

UNLESS! Did you test it?  Does the compiler compile it down?

Can it do that for switches?  Or only if's?
created_at: 2025-03-03T01:52:22Z
author_association: OWNER
diff_hunk: @@ -183,6 +183,27 @@ else
 		endif
 
 		TARGET_MCU_LD:=3
+	else ifeq ($(findstring CH59,$(TARGET_MCU)),CH59) # CH592 1
+		TARGET_MCU_PACKAGE?=CH592F
+		CFLAGS_ARCH+=-march=rv32imac_zicsr \
path: ch32fun/ch32fun.mk
user: login: cnlohr
body: zicsr should not be specified here, because... older GCC's.  Specify it inline, based on the `ADD_ARCH_ZICSR` macro.
created_at: 2025-03-03T01:53:27Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
+#define FUNCONF_DEBUG_HARDFAULT 0
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: cnlohr
body: Why not?  (Just wondering)?
created_at: 2025-03-03T01:53:48Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: cnlohr
body: How does the CH592 bootup?!?! Does it really boot right into the HSE?!?
created_at: 2025-03-03T01:54:10Z
author_association: OWNER
diff_hunk: @@ -183,6 +183,27 @@ else
 		endif
 
 		TARGET_MCU_LD:=3
+	else ifeq ($(findstring CH59,$(TARGET_MCU)),CH59) # CH592 1
+		TARGET_MCU_PACKAGE?=CH592F
+		CFLAGS_ARCH+=-march=rv32imac_zicsr \
path: ch32fun/ch32fun.mk
user: login: biemster
body: I had this in some macro like that at first, but then it did not work for some reason. I'll try again
created_at: 2025-03-04T14:24:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
+#define FUNCONF_DEBUG_HARDFAULT 0
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: That's based solely on a quick search in the datasheet. There is HSE, LSE and LSI there, but no HSI. It might be just undocumented, but I'm in no way an expert on these things.
created_at: 2025-03-04T14:26:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: How can I check this?
created_at: 2025-03-04T14:26:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: cnlohr
body: What happens if you don't touch clock settings, and boot the chip and short/remove he crystal?  Does the processor seize up?
created_at: 2025-03-04T21:54:10Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: I'll have a try when I bring back alive my board
created_at: 2025-03-05T10:03:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,9 +65,20 @@ MEMORY
 	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
 	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
 #elif TARGET_MCU_LD == 7
-	/* CH32V005, CH32V006, CH32V007 */
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
-	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
+  /* CH32V005, CH32V006, CH32V007 */
path: ch32fun/ch32fun.ld
user: login: biemster
body: The SECTIONS { ... } is almost exclusively spaces, with only 2 lines tabs at the end. Should I convert them all to tabs or leave that to a separate commit? (as those lines will seem changed in the blame of this PR then)
edit: I'll change my changes to tabs, but it's maybe a good idea to convert the whole file to tabs after this goes in (or before, but I might get merge conflicts, or is git smart enough?)
created_at: 2025-03-10T17:11:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -183,6 +183,27 @@ else
 		endif
 
 		TARGET_MCU_LD:=3
+	else ifeq ($(findstring CH59,$(TARGET_MCU)),CH59) # CH592 1
+		TARGET_MCU_PACKAGE?=CH592F
+		CFLAGS_ARCH+=-march=rv32imac_zicsr \
path: ch32fun/ch32fun.mk
user: login: biemster
body: actually removing `_zicsr` works fine now, so that's an easy fix
created_at: 2025-03-10T17:20:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -183,6 +183,27 @@ else
 		endif
 
 		TARGET_MCU_LD:=3
+	else ifeq ($(findstring CH59,$(TARGET_MCU)),CH59) # CH592 1
+		TARGET_MCU_PACKAGE?=CH592F
+		CFLAGS_ARCH+=-march=rv32imac_zicsr \
path: ch32fun/ch32fun.mk
user: login: biemster
body: [ea55eee](https://github.com/cnlohr/ch32fun/pull/534/commits/ea55eeebf7c5cb382c77407d0791805015001375)
created_at: 2025-03-10T17:22:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -65,9 +65,20 @@ MEMORY
 	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
 	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 6K
 #elif TARGET_MCU_LD == 7
-	/* CH32V005, CH32V006, CH32V007 */
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 62K
-	RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
+  /* CH32V005, CH32V006, CH32V007 */
path: ch32fun/ch32fun.ld
user: login: biemster
body: [ea55eee](https://github.com/cnlohr/ch32fun/pull/534/commits/ea55eeebf7c5cb382c77407d0791805015001375)
created_at: 2025-03-10T17:22:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: I tested this, but do you mean check the compiler output assembly? That I did not test. I moved this to a macro following your comment, I thought you did not want this as a function. (or maybe I just got compiler errors having this as a function in the header, I actually do not recall)
created_at: 2025-03-10T17:25:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: actually what do you mean don't touch clock settings? not call `SystemInit()` at all? (that's basically all it does)
Would trying the usb bootloader with a shorted crystal also provide the info you need?
created_at: 2025-03-10T17:30:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1483,6 +1501,144 @@ void DelaySysTick( uint32_t n )
 #endif
 }
 
+#if defined(CH59x)
+/**
+ * @brief Enter safe access mode.
+ * 
+ * @NOTE: After enter safe access mode, about 16 system frequency cycles 
+ * are in safe mode, and one or more secure registers can be rewritten 
+ * within the valid period. The safe mode will be automatically 
+ * terminated after the above validity period is exceeded.
+ */
+vu32 IRQ_STA = 0;
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void sys_safe_access_enable(void)
path: ch32fun/ch32fun.c
user: login: biemster
body: As far as I can see the debug interface is the two wire thing, but I can test it when I receive my linkE
created_at: 2025-03-10T17:34:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
path: ch32fun/ch59xhw.h
user: login: biemster
body: so flash is handled quite differently between v003 and ch59x. This will be a follow up PR, so I'm going to resolve this for now
created_at: 2025-03-10T17:36:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,328 @@
+#ifndef TODO_HARDWARE_H
+#define TODO_HARDWARE_H
+
+#include "ch32fun.h"
+
+#ifndef __ASSEMBLER__  // Things before this can be used in assembly.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+	Ecall_M_Mode_IRQn = 5,   /* 5 Ecall M Mode Interrupt                             */
+	Ecall_U_Mode_IRQn = 8,   /* 8 Ecall U Mode Interrupt                             */
+	Break_Point_IRQn = 9,    /* 9 Break Point Interrupt                              */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+	/******  RISC-V specific Interrupt Numbers *********************************************************/
+	TMR0_IRQn = 16,          /* 0:  TMR0 */
+	GPIOA_IRQn = 17,         /* GPIOA */
+	GPIOB_IRQn = 18,         /* GPIOB */
+	SPI0_IRQn = 19,          /* SPI0 */
+	BB_IRQn = 20,            /* BLEB */
+	LLE_IRQn = 21,           /* BLEL */
+	USB_IRQn = 22,           /* USB */
+	TMR1_IRQn = 24,          /* TMR1 */
+	TMR2_IRQn = 25,          /* TMR2 */
+	UART0_IRQn = 26,         /* UART0 */
+	UART1_IRQn = 27,         /* UART1 */
+	RTC_IRQn = 28,           /* RTC */
+	ADC_IRQn = 29,           /* ADC */
+	I2C_IRQn = 30,           /* I2C */
+	PWMX_IRQn = 31,          /* PWMX */
+	TMR3_IRQn = 32,          /* TMR3 */
+	UART2_IRQn = 33,         /* UART2 */
+	UART3_IRQn = 34,         /* UART3 */
+	WDOG_BAT_IRQn = 35,      /* WDOG_BAT */
+} IRQn_Type;
+
+#define BASE_VECTOR "\n\
+	.balign  2\n\
+	.option   push;\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler                 /* NMI Handler */\n\
+	.word   HardFault_Handler           /* Hard Fault Handler */\n\
+	.word   0xF5F9BDA9\n\
+	.word   Ecall_M_Mode_Handler        /* 5 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   Ecall_U_Mode_Handler		/* 8 */\n\
+	.word   Break_Point_Handler			/* 9 */\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler            /* SysTick Handler */\n\
+	.word   0\n\
+	.word   SW_Handler                 /* SW Handler */\n\
+	.word   0\n\
+	/* External Interrupts */\n\
+	.word   TMR0_IRQHandler            /* 0:  TMR0 */\n\
+	.word   GPIOA_IRQHandler           /* GPIOA */\n\
+	.word   GPIOB_IRQHandler           /* GPIOB */\n\
+	.word   SPI0_IRQHandler            /* SPI0 */\n\
+	.word   BB_IRQHandler              /* BLEB */\n\
+	.word   LLE_IRQHandler             /* BLEL */\n\
+	.word   USB_IRQHandler             /* USB */\n\
+	.word   0\n\
+	.word   TMR1_IRQHandler            /* TMR1 */\n\
+	.word   TMR2_IRQHandler            /* TMR2 */\n\
+	.word   UART0_IRQHandler           /* UART0 */\n\
+	.word   UART1_IRQHandler           /* UART1 */\n\
+	.word   RTC_IRQHandler             /* RTC */\n\
+	.word   ADC_IRQHandler             /* ADC */\n\
+	.word   I2C_IRQHandler             /* I2C */\n\
+	.word   PWMX_IRQHandler            /* PWMX */\n\
+	.word   TMR3_IRQHandler            /* TMR3 */\n\
+	.word   UART2_IRQHandler           /* UART2 */\n\
+	.word   UART3_IRQHandler           /* UART3 */\n\
+	.word   WDOG_BAT_IRQHandler        /* WDOG_BAT */\n"
+
+#define DEFAULT_INTERRUPT_VECTOR_CONTENTS BASE_VECTOR "\n.option pop;\n"
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+	__IO uint32_t CTLR;
+	__IO uint32_t SR;
+	__IO uint64_t CNT;
+	__IO uint64_t CMP;
+} SysTick_Type;
+
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct
+{
+    __I uint32_t  ISR[8];           // 0
+    __I uint32_t  IPR[8];           // 20H
+    __IO uint32_t ITHRESDR;         // 40H
+    uint8_t       RESERVED[4];      // 44H
+    __O uint32_t  CFGR;             // 48H
+    __I uint32_t  GISR;             // 4CH
+    __IO uint8_t  VTFIDR[4];        // 50H
+    uint8_t       RESERVED0[0x0C];  // 54H
+    __IO uint32_t VTFADDR[4];       // 60H
+    uint8_t       RESERVED1[0x90];  // 70H
+    __O uint32_t  IENR[8];          // 100H
+    uint8_t       RESERVED2[0x60];  // 120H
+    __O uint32_t  IRER[8];          // 180H
+    uint8_t       RESERVED3[0x60];  // 1A0H
+    __O uint32_t  IPSR[8];          // 200H
+    uint8_t       RESERVED4[0x60];  // 220H
+    __O uint32_t  IPRR[8];          // 280H
+    uint8_t       RESERVED5[0x60];  // 2A0H
+    __IO uint32_t IACTR[8];         // 300H
+    uint8_t       RESERVED6[0xE0];  // 320H
+    __IO uint8_t  IPRIOR[256];      // 400H
+    uint8_t       RESERVED7[0x810]; // 500H
+    __IO uint32_t SCTLR;            // D10H
+} PFIC_Type;
+#endif /* __ASSEMBLER__*/
+
+#ifdef __ASSEMBLER__
+#define CORE_PERIPH_BASE           (0xE0000000) /* System peripherals base address in the alias region */
+#else
+#define CORE_PERIPH_BASE           ((uint32_t)(0xE0000000))
+#endif /* __ASSEMBLER__*/
+
+#define PFIC_BASE                  (CORE_PERIPH_BASE + 0xE000)
+#define SysTick_BASE               (CORE_PERIPH_BASE + 0xF000)
+
+#define PFIC                       ((PFIC_Type *) PFIC_BASE)
+#define NVIC                       PFIC
+#define NVIC_KEY1                  ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	               ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		           ((uint32_t)0xBEEF0000)
+
+#define SysTick                    ((SysTick_Type *) SysTick_BASE)
+#define SysTick_LOAD_RELOAD_Msk    (0xFFFFFFFFFFFFFFFF)
+#define SysTick_CTLR_SWIE          (1 << 31)
+#define SysTick_CTLR_INIT          (1 << 5)
+#define SysTick_CTLR_MODE          (1 << 4)
+#define SysTick_CTLR_STRE          (1 << 3)
+#define SysTick_CTLR_STCLK         (1 << 2)
+#define SysTick_CTLR_STIE          (1 << 1)
+#define SysTick_CTLR_STE           (1 << 0)
+#define SysTick_SR_CNTIF           (1 << 0)
+
+typedef enum
+{
+    CLK_SOURCE_LSI = 0x00,
+    CLK_SOURCE_LSE,
+
+    CLK_SOURCE_HSE_16MHz = 0x22,
+    CLK_SOURCE_HSE_8MHz = 0x24,
+    CLK_SOURCE_HSE_6_4MHz = 0x25,
+    CLK_SOURCE_HSE_4MHz = 0x28,
+
+    CLK_SOURCE_PLL_60MHz = 0x48,
+    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
+    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
+    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+} SYS_CLKTypeDef;
+
+/* System: clock configuration register */
+#define R32_CLK_SYS_CFG     (*((vu32*)0x40001008)) // RWA, system clock configuration, SAM
+#define  RB_CLK_PLL_DIV     0x1F                      // RWA, output clock divider from PLL or CK32M
+#define  RB_CLK_SYS_MOD     0xC0                      // RWA, system clock source mode: 00=divided from 32MHz, 01=divided from PLL-480MHz, 10=directly from 32MHz, 11=directly from 32KHz
+#define  RB_TX_32M_PWR_EN   0x40000                   // RWA, extern 32MHz HSE power contorl
+#define  RB_XT_FORCE_EN     0x80000                   // RWA, system clock control in Halt mode
+#define  RB_PLL_PWR_EN      0x100000                  // RWA, PLL power control
+
+/* System: safe accessing register */
+#define R32_SAFE_ACCESS     (*((vu32*)0x40001040)) // RW, safe accessing
+#define R8_SAFE_ACCESS_SIG  (*((vu8*)0x40001040))  // WO, safe accessing sign register, must write SAFE_ACCESS_SIG1 then SAFE_ACCESS_SIG2 to enter safe accessing mode
+#define  RB_SAFE_ACC_MODE   0x03                      // RO, current safe accessing mode: 11=safe/unlocked (SAM), other=locked (00..01..10..11)
+#define  RB_SAFE_ACC_ACT    0x08                      // RO, indicate safe accessing status now: 0=locked, read only, 1=safe/unlocked (SAM), write enabled
+#define  RB_SAFE_ACC_TIMER  0x70                      // RO, safe accessing timer bit mask (16*clock number)
+#define SAFE_ACCESS_SIG1    0x57                      // WO: safe accessing sign value step 1
+#define SAFE_ACCESS_SIG2    0xA8                      // WO: safe accessing sign value step 2
+#define SAFE_ACCESS_SIG0    0x00                      // WO: safe accessing sign value for disable
+#define R8_CHIP_ID          (*((vu8*)0x40001041))  // RF, chip ID register, always is ID_CH58*
+
+/*System: Miscellaneous Control register */
+#define R32_MISC_CTRL       (*((vu32*)0x40001048)) // RWA, miscellaneous control register
+#define R8_PLL_CONFIG       (*((vu8*)0x4000104B))  // RWA, PLL configuration control, SAM
+#define  RB_PLL_CFG_DAT     0x7F                      // RWA, PLL configuration control, SAM
+
+/* System: Flash ROM control register */
+#define R32_FLASH_DATA      (*((vu32*)0x40001800)) // RO/WO, flash ROM data
+#define R32_FLASH_CONTROL   (*((vu32*)0x40001804)) // RW, flash ROM control
+#define R8_FLASH_DATA       (*((vu8*)0x40001804))  // RO/WO, flash ROM data buffer
+#define R8_FLASH_CTRL       (*((vu8*)0x40001806))  // RW, flash ROM access control
+#define R8_FLASH_CFG        (*((vu8*)0x40001807))  // RW, flash ROM access config, SAM
+
+#define read_csr(reg)		({unsigned long __tmp; __asm__ volatile ("csrr %0, " #reg : "=r"(__tmp)); __tmp; })
path: ch32fun/ch59xhw.h
user: login: biemster
body: this was taken care of in [17ace98](https://github.com/cnlohr/ch32fun/pull/534/commits/17ace987e2b207bbc395841b3831a770ba52908a)
created_at: 2025-03-10T17:38:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: > How does the CH592 bootup?!?! Does it really boot right into the HSE?!?

Maybe it boots on the LSI? It can run on that using `CLK_SOURCE_LSI`
created_at: 2025-03-11T14:27:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
+#define FUNCONF_DEBUG_HARDFAULT 0
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: Also the CLKType enum does not mention an HSI, so if it's there it's well hidden..
created_at: 2025-03-11T15:03:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+#ifndef _FUNCONFIG_H
+#define _FUNCONFIG_H
+
+#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE         1
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: I did everything I could here that would not break my board, but I was not able to get the processor to stop working whichever pins I shorted on the crystal. As not to block this PR on this, I'm going to resolve this as unresolved, sorry.
created_at: 2025-03-11T16:57:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: Looking at it again I actually find this a very elegant and readable solution. What is exactly your objection? Would it be acceptable if the compiler optimizes it out fully like this?
created_at: 2025-03-11T17:08:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: Ok the compiler uses 8 bytes less when these macros are functions. I'll convert them.
created_at: 2025-03-11T17:20:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: ouch this is why I had them as macros, the linker complains about multiple definitions and if I make them static or inline (or both) it actually does not work at all! Any suggestions how to resolve this?
created_at: 2025-03-11T17:38:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: blast I was being stupid, there are pointers in there. Now it works as a function, but the 8 byte gain is gone again. So we can put a pin in this now since they produce the same assembly, what do you prefer, macros or functions?
The function would be:
```C
RV_STATIC_INLINE void GPIO_ModeCfg(vu32* pd_drv, vu32* pu, vu32* dir, u32 pin, GPIOModeTypeDef mode)
{
	switch(mode) {
	case GPIO_ModeIN_Floating:
		*pd_drv &= ~pin;
		*pu &= ~pin;
		*dir &= ~pin;
		break;
	case GPIO_ModeIN_PU:
		*pd_drv &= ~pin;
		*pu |= pin;
		*dir &= ~pin;
		break;
	case GPIO_ModeIN_PD:
		*pd_drv |= pin;
		*pu &= ~pin;
		*dir &= ~pin;
		break;
	case GPIO_ModeOut_PP_5mA:
		*pd_drv &= ~pin;
		*dir |= pin;
		break;
	case GPIO_ModeOut_PP_20mA:
		*pd_drv |= pin;
		*dir |= pin;
		break;
	}
}

RV_STATIC_INLINE void funPinMode( u32 pin, GPIOModeTypeDef mode )
{
	if(pin & PB) {
		GPIO_ModeCfg(&R32_PB_PD_DRV, &R32_PB_PU, &R32_PB_DIR, pin, mode);
	}
	else {
		GPIO_ModeCfg(&R32_PA_PD_DRV, &R32_PA_PU, &R32_PA_DIR, pin, mode);
	}
}
```
created_at: 2025-03-11T17:52:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -208,7 +208,12 @@
 #endif
 
 #ifndef FUNCONF_SYSTEM_CORE_CLOCK
-	#if defined(FUNCONF_USE_HSI) && FUNCONF_USE_HSI
+	#if defined(CH59x) // no PLL multiplier, but a divider from the 480 MHz clock
+		#define FUNCONF_SYSTEM_CORE_CLOCK 60000000 // default in ch32fun.c using CLK_SOURCE_PLL_60MHz
path: ch32fun/ch32fun.h
user: login: cnlohr
body: Excellent.
created_at: 2025-03-11T18:39:12Z
author_association: OWNER
diff_hunk: @@ -157,15 +157,15 @@ typedef enum
     CLK_SOURCE_LSI = 0x00,
     CLK_SOURCE_LSE,
 
-    CLK_SOURCE_HSE_16MHz = 0x22,
-    CLK_SOURCE_HSE_8MHz = 0x24,
-    CLK_SOURCE_HSE_6_4MHz = 0x25,
-    CLK_SOURCE_HSE_4MHz = 0x28,
-
-    CLK_SOURCE_PLL_60MHz = 0x48,
-    CLK_SOURCE_PLL_48MHz = (0x40 | 10),
-    CLK_SOURCE_PLL_32MHz = (0x40 | 15),
-    CLK_SOURCE_PLL_24MHz = (0x40 | 20),
+    CLK_SOURCE_HSE_16MHz =  (0x20 |  2),
+    CLK_SOURCE_HSE_8MHz =   (0x20 |  4),
+    CLK_SOURCE_HSE_6_4MHz = (0x20 |  5),
+    CLK_SOURCE_HSE_4MHz =   (0x20 |  8),
path: ch32fun/ch59xhw.h
user: login: cnlohr
body: This is fair.
created_at: 2025-03-11T18:39:26Z
author_association: OWNER
diff_hunk: @@ -1,11 +1,14 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_USE_DEBUGPRINTF 0 // saves 16 bytes, enable / remove if you want printf over swio
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/blink/funconfig.h
user: login: cnlohr
body: I would, here, comment any of the thing that default and just say // defaults are commented out.

It's very helpful to have this reference though!
created_at: 2025-03-11T18:40:07Z
author_association: OWNER
diff_hunk: @@ -1,10 +1,13 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: cnlohr
body: Same here, don't need these #define'd here.  Just #define anything that's different or needs to be #defined.
created_at: 2025-03-11T18:40:32Z
author_association: OWNER
diff_hunk: @@ -1,10 +1,13 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: this actually is the minimum of #defines needed. The clocks default to HSI if not given, and the others are ifdefing out unsupported features. Only the CLK_SOURCE_CH59X is not strictly needed indeed, but since it is unique to the ch59x and also quite different from the ch32's I thought it would be good to notify the end user about it.

If it's not here it definitely would have to go in the documentation i think (which will only happen in a PR further down the line)
created_at: 2025-03-11T20:35:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,11 +1,14 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_USE_DEBUGPRINTF 0 // saves 16 bytes, enable / remove if you want printf over swio
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/blink/funconfig.h
user: login: biemster
body: After this work I am slightly inclined to have the `funconfig.h` in the examples have more references like this actually (I much more often read code + comments than documentation), but it's totally your call of course.
created_at: 2025-03-11T20:37:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,10 +1,13 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: cnlohr
body: So that balance would be between adding extra #ifdef  cruft to the ch32fun header or here... My vote is here if you are willing to keep this in the examples.
created_at: 2025-03-11T20:42:26Z
author_association: OWNER
diff_hunk: @@ -1,10 +1,13 @@
 #ifndef _FUNCONFIG_H
 #define _FUNCONFIG_H
 
-#define FUNCONF_USE_HSI         0 // CH592 does not have HSI
-#define FUNCONF_USE_HSE         1
-#define FUNCONF_DEBUG_HARDFAULT 0
-#define FUNCONF_USE_CLK_SEC     0
-#define FUNCONF_INIT_ANALOG     0 // ADC is not implemented yet
+#define FUNCONF_USE_HSI           0 // CH592 does not have HSI
+#define FUNCONF_USE_HSE           1
+#define CLK_SOURCE_CH59X          CLK_SOURCE_PLL_60MHz // default so not really needed
+#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000     // keep in line with CLK_SOURCE_CH59X
path: examples_ch59x/debugprintfdemo/funconfig.h
user: login: biemster
body: yes that's my vote too, I'll keep the funconfigs as they are now then.
created_at: 2025-03-11T20:49:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +830,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
+																										case GPIO_ModeIN_Floating: \
+																											pd_drv &= ~pin; pu &= ~pin; dir &= ~pin; break; \
+																										case GPIO_ModeIN_PU: \
+																											pd_drv &= ~pin; pu |= pin; dir &= ~pin; break; \
+																										case GPIO_ModeIN_PD: \
+																											pd_drv |= pin; pu &= ~pin; dir &= ~pin; break; \
+																										case GPIO_ModeOut_PP_5mA: \
+																											pd_drv &= ~pin; dir |= pin; break; \
+																										case GPIO_ModeOut_PP_20mA: \
+																											pd_drv |= pin; dir |= pin; break; \
+																									} }
+#define funPinMode( pin, mode ) { if(pin & PB) GPIO_ModeCfg(R32_PB_PD_DRV, R32_PB_PU, R32_PB_DIR, pin, mode) \
path: ch32fun/ch32fun.h
user: login: cnlohr
body: This looks like it could be simplified where you would have something like R32_PA_PD_DRV+((pin&0xF0)>>1)

Logic: 
PA = 0x400010B4
PB = 0x400010D4
Difference = 0x20.
Type: uint32_t
so they are 8 units apart
The port number is stored in 0xF0, so 16 units apart.

You can check my logic.
created_at: 2025-03-11T22:49:14Z
author_association: OWNER
diff_hunk: @@ -817,11 +825,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
path: ch32fun/ch32fun.h
user: login: biemster
body: It's a single function now, and simplified as much as I could (f475b81)
created_at: 2025-03-12T12:40:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -817,11 +830,41 @@ extern "C" {
 // and take two cycles, so you typically would use 0, 2, 4, etc.
 #define ADD_N_NOPS( n ) asm volatile( ".rept " #n "\nc.nop\n.endr" );
 
+#define FUN_HIGH 0x1
+#define FUN_LOW 0x0
+#if defined(CH59x)
+#define GPIOA_ResetBits(pin)      (R32_PA_CLR |= pin)
+#define GPIOA_SetBits(pin)        (R32_PA_OUT |= pin)
+#define GPIOA_InverseBits(pin)    (R32_PA_OUT ^= pin)
+#define GPIOA_ReadPortPin(pin)    (R32_PA_PIN & (pin))
+#define GPIOB_ResetBits(pin)      (R32_PB_CLR |= pin)
+#define GPIOB_SetBits(pin)        (R32_PB_OUT |= pin)
+#define GPIOB_InverseBits(pin)    (R32_PB_OUT ^= pin)
+#define GPIOB_ReadPortPin(pin)    (R32_PB_PIN & (pin))
+#define GPIO_ResetBits(pin)       { if(pin & PB) GPIOB_ResetBits(pin); else GPIOA_ResetBits(pin); }
+#define GPIO_SetBits(pin)         { if(pin & PB) GPIOB_SetBits(pin); else GPIOA_SetBits(pin); }
+#define GPIO_InverseBits(pin)     { if(pin & PB) GPIOB_InverseBits(pin); else GPIOA_InverseBits(pin); }
+#define funDigitalRead(pin)       ( (pin & PB) ? GPIOB_ReadPortPin(pin) : GPIOA_ReadPortPin(pin) )
+#define funDigitalWrite( pin, value ) { if(value==FUN_HIGH){GPIO_SetBits(pin);} else if(value==FUN_LOW){GPIO_ResetBits(pin);} }
+
+#define GPIO_ModeCfg(pd_drv, pu, dir, pin, mode) { switch(mode) { \
+																										case GPIO_ModeIN_Floating: \
+																											pd_drv &= ~pin; pu &= ~pin; dir &= ~pin; break; \
+																										case GPIO_ModeIN_PU: \
+																											pd_drv &= ~pin; pu |= pin; dir &= ~pin; break; \
+																										case GPIO_ModeIN_PD: \
+																											pd_drv |= pin; pu &= ~pin; dir &= ~pin; break; \
+																										case GPIO_ModeOut_PP_5mA: \
+																											pd_drv &= ~pin; dir |= pin; break; \
+																										case GPIO_ModeOut_PP_20mA: \
+																											pd_drv |= pin; dir |= pin; break; \
+																									} }
+#define funPinMode( pin, mode ) { if(pin & PB) GPIO_ModeCfg(R32_PB_PD_DRV, R32_PB_PU, R32_PB_DIR, pin, mode) \
path: ch32fun/ch32fun.h
user: login: biemster
body: I more or less did exactly this, I don't see any simplifications anymore (f475b81)
created_at: 2025-03-12T12:40:59Z
author_association: CONTRIBUTOR

PR comments:
user: login: cnlohr
created_at: 2025-02-25T01:49:32Z
body: Thanks for doing this work, @biemster , I've added comments, it looks like you're really close, but it needs a little bit of cleanup.  
author_association: OWNER
user: login: biemster
created_at: 2025-02-25T09:17:11Z
body: yeah I basically just copied in the bare necessities, so the reviewer can see what all needs to go in properly. Cleanup is definitely necessary, and I might add a small bit of extra stuff on the gpio side of things to handle GPIOB and interrupts as well. Where did you add your comments?
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-02-25T21:28:09Z
body: Sorry, I forgot to commit the review.
author_association: OWNER
user: login: biemster
created_at: 2025-02-26T17:54:10Z
body: @cnlohr I went through all the comments, I was able to accommodate the changes to `sys_safe_access_` and `GPIOx_ModeCfg` I think. I couldn't struct the `flash` registers since they seem very different from `ch32`. The overbuilt part in `ch32fun.c` is completely gone, as everything lives in #defines now. Could you review again?

edit: those last two force-pushes were to add `funDigitalRead`, just three lines in `ch32fun.h`
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-02-26T21:30:52Z
body: @biemster you will need to make at least one example, even if it's just `blink` but, I would really like it if you also had a `debugprintf` example as well.  It feels like minimum viable product is `blink` and `printf` where both use the ch32fun functions / structure.  I.e. `blink.c` should be an exact copy of `blink.c` from example but maybe with a different IO pin.
author_association: OWNER
user: login: biemster
created_at: 2025-02-26T21:38:37Z
body: Did I forget to commit the `blink`? I definitely made one, let me check. I was also thinking of a `printf` indeed, since writing to flash does not want to play ball at all currently. I'll focus on that coming days, and add it to the PR.

edit: `blink` is there :) it does not have `funGpioInitAll` since there is not really a similar thing on ch59x, and it uses the pin definitions from `ch59xhw.h`. I'm not sure how to translate the ch32 ones to ch5x, they don't have a MHz definition in them, just current like 5mA and 20mA..
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-02-26T22:24:00Z
body: You can "overload" them to the MHz functions, but also have your own that define 0, 1, 2, 3, for the mA modes.

Like you should allow users to say 10MHz PP, and just be like 🤷 I guess I'll just treat it as the 2nd highest current.
author_association: OWNER
user: login: cnlohr
created_at: 2025-02-26T22:25:05Z
body: I do see blink.c Sorry I missed it first time around, but still need to think through printf.
author_association: OWNER
user: login: biemster
created_at: 2025-02-27T14:28:25Z
body: > I do see blink.c Sorry I missed it first time around, but still need to think through printf.

I noticed the printf going through a debug interface on the ch32 chips, but I did not find anything like that on ch59x. Could I just do that over uart?
edit: o wait I just noticed the comments on printf in ch32fun.h, I'll use an uart
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-02-27T14:44:57Z
body: > You can "overload" them to the MHz functions, but also have your own that define 0, 1, 2, 3, for the mA modes.
> 
> Like you should allow users to say 10MHz PP, and just be like 🤷 I guess I'll just treat it as the 2nd highest current.

Should there be a warning emitted when a pin definition is way off? For example this:
```C
typedef enum
{
	...
	GPIO_CFGLR_IN_PUPD = 8,
```
ch59x has `GPIO_ModeIN_PU` and `GPIO_ModeIN_PD`, which are very different as far as I understand. Also ch59x does not seem to have open-drain available, only push-pull so a user might really need open-drain and then I give then push-pull (I don't want to be on the debugging side of that if it causes issues with the user's design :D )
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-02-27T23:48:53Z
body: > > I do see blink.c Sorry I missed it first time around, but still need to think through printf.
> 
> I noticed the printf going through a debug interface on the ch32 chips, but I did not find anything like that on ch59x. Could I just do that over uart? edit: o wait I just noticed the comments on printf in ch32fun.h, I'll use an uart

Please if at all possible make default to go over debug interface.  My comments were just that you may be able to use a two-word debug output. SWIO debugging is soooo much more convenient than UART debugging.
author_association: OWNER
user: login: cnlohr
created_at: 2025-02-27T23:53:27Z
body: > > You can "overload" them to the MHz functions, but also have your own that define 0, 1, 2, 3, for the mA modes.
> > Like you should allow users to say 10MHz PP, and just be like 🤷 I guess I'll just treat it as the 2nd highest current.
> 
> Should there be a warning emitted when a pin definition is way off? For example this:
> 
> ```c
> typedef enum
> {
> 	...
> 	GPIO_CFGLR_IN_PUPD = 8,
> ```
> 
> ch59x has `GPIO_ModeIN_PU` and `GPIO_ModeIN_PD`, which are very different as far as I understand. Also ch59x does not seem to have open-drain available, only push-pull so a user might really need open-drain and then I give then push-pull (I don't want to be on the debugging side of that if it causes issues with the user's design :D )

Do you mind sharing notes with @dwillmore here?  See what his opinions are because the 00x drive mechanism is also different than the ch32vxxx line.

![image](https://github.com/user-attachments/assets/563d8f71-e925-4869-a4e1-38bef737dea6)

I agree that GPIO_CFGLR_IN_PUPD is not possible, so please leave that definition out.

author_association: OWNER
user: login: cnlohr
created_at: 2025-02-27T23:54:38Z
body: About the debug interface, it looks like it should JustWork.  The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.
author_association: OWNER
user: login: biemster
created_at: 2025-02-28T21:37:42Z
body: > About the debug interface, it looks like it should JustWork. The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.

really? that's awesome! i have zero experience with such, but if it's there I'll get it to work
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-03-01T12:40:40Z
body: > About the debug interface, it looks like it should JustWork. The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.

This is going to be a guessing game, as the datasheet does not mention the debug interfaces or a SWIO pin at all! Same for ch32x305 though, which does have a `debugprintfdemo`, so I'm hoping it's on a similar pin
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-03-01T13:02:23Z
body: > > About the debug interface, it looks like it should JustWork. The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.
> 
> This is going to be a guessing game, as the datasheet does not mention the debug interfaces or a SWIO pin at all! Same for ch32x305 though, which does have a `debugprintfdemo`, so I'm hoping it's on a similar pin

@cnlohr how do I test this? My linkE (and linkW) are still on the slow boat, and my ESP32's are all none s2 ones :sob: 
edit: I just found 3 s2mini's on the bottom of my parts bin, I'm back on the horse!
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-03-01T20:06:20Z
body: > > About the debug interface, it looks like it should JustWork. The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.
> 
> This is going to be a guessing game, as the datasheet does not mention the debug interfaces or a SWIO pin at all! Same for ch32x305 though, which does have a `debugprintfdemo`, so I'm hoping it's on a similar pin

It's undocumented.  But should JustWork
author_association: OWNER
user: login: cnlohr
created_at: 2025-03-01T20:07:05Z
body: > > > About the debug interface, it looks like it should JustWork. The CH592 uses a QingKeV4, which has both DMDEBUG0 and DMDEBUG1 interfaces.
> > 
> > 
> > This is going to be a guessing game, as the datasheet does not mention the debug interfaces or a SWIO pin at all! Same for ch32x305 though, which does have a `debugprintfdemo`, so I'm hoping it's on a similar pin
> 
> @cnlohr how do I test this? My linkE (and linkW) are still on the slow boat, and my ESP32's are all none s2 ones 😭 edit: I just found 3 s2mini's on the bottom of my parts bin, I'm back on the horse!

There is no ESP32 programmer other than rvswd that I'm aware of and it's hard-coded to only work with the ch32v003 and not minichlink :(
author_association: OWNER
user: login: biemster
created_at: 2025-03-02T21:25:39Z
body: 
> There is no ESP32 programmer other than rvswd that I'm aware of and it's hard-coded to only work with the ch32v003 and not minichlink :(

so linkE is my only choice to test the `debugprintfdemo`? Or would the ardulink suffice?
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-03-10T17:33:17Z
body: 
> Do you mind sharing notes with @dwillmore here? See what his opinions are because the 00x drive mechanism is also different than the ch32vxxx line.

yes I just quote this here to remind me
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-03-10T17:43:52Z
body: Because I'm still waiting for my linkE to test `debugprintfdemo`, I'm starting to forget things. Here is my summary of what I think still requires attention or a future PR:
- [x] test if there is really no HSI by shorting the 32M crystal (unresolved because inconclusive, I could not bother the crystal enough to stop the mcu without breaking the board)
- [x] see if `GPIO_ModeCfg` should be a function (f475b81)
- [x] discuss with @dwillmore what his opinions are on the gpio mechanism
- [x] `FUNCONF_SYSTEM_CORE_CLOCK` (probably just have to merge in ch59x specific stuff like `CLK_SOURCE_PLL_60MHz`) (4b87983)
- [ ] test `debugprintfdemo` with linkE
- [ ] new PR for flash access
- [ ] new PR for proper interrupt handling (at least gpio, and see which peripherals need it too)
- [ ] plenty of PRs for ADC/TEMP, PWM, SPI, I2C, BLE and whatnot

please comment if I'm missing something here?
author_association: CONTRIBUTOR
user: login: biemster
created_at: 2025-03-12T13:09:54Z
body: Now only testing `debugprintfdemo` is left :tada: my linkE takes ages to arrive :sob: 
author_association: CONTRIBUTOR
user: login: cnlohr
created_at: 2025-03-12T21:39:09Z
body: Merged per @biemster's request.  A new request will be opened to address emergent issues.
author_association: OWNER
user: login: alexandru0-dev
created_at: 2025-03-13T09:58:28Z
body: @biemster sorry to ask but are there any plans for the CH58X?
they should use the same hal, the only main difference that i found is that it uses the QingKe V4A vs QingKe V4C, which supports Extended
Instruction (XW), of the 59X
author_association: NONE
user: login: biemster
created_at: 2025-03-13T10:02:13Z
body: > @biemster sorry to ask but are there any plans for the CH58X? 

I'm doing CH57X currently, which is also very similar. I don't have any ch58x, so as long that that's the case I can't work on that. (but with the ch59x and ch57x as examples it should be very straightforward to add ch58x as well, maybe you dare to do a PR @alexandru0-dev ? I can definitely help out here and there, especially if you join the discord)
author_association: CONTRIBUTOR
user: login: alexandru0-dev
created_at: 2025-03-13T10:23:21Z
body: > maybe you dare to do a PR @alexandru0-dev ?

I don't have a dev board on my hands rn, but I'm going to order one (I'm going to order the CH582F), once it arrives, I will definitely give it a try

> I can definitely help out here and there, especially if you join the discord)

Can you tell me where to join? @biemster 
author_association: NONE
user: login: biemster
created_at: 2025-03-13T12:50:49Z
body: 
> Can you tell me where to join? @biemster

you can ping cnlohr preferably or me on discord for an invite.
author_association: CONTRIBUTOR
user: login: alexandru0-dev
created_at: 2025-03-13T14:13:06Z
body: 
> > Can you tell me where to join? @biemster
> 
> you can ping cnlohr preferably or me on discord for an invite.

@cnlohr i've sent you a friend request on discord


author_association: NONE