diff --git a/inc/ch32fun.h b/inc/ch32fun.h index d1a0ba5..e30fddc 100644 --- a/inc/ch32fun.h +++ b/inc/ch32fun.h @@ -24,7 +24,11 @@ 4. Delays Delay_Us(n) Delay_Ms(n) - DelaySysTick( uint32_t n ); + DelaySysTick( uint32_t n ) + TimeElapsed32( uint32_t now, uint32_t start); + TimeElapsed32U( now, start ); // For if events could be in the future. + funSysTick32() + funSysTick64() 5. printf printf, _write may be semihosted, or printed to UART. @@ -85,6 +89,7 @@ #define FUNCONF_ISR_IN_RAM 0 // Put the interrupt vector in RAM. #define FUNCONF_SUPPORT_CONSTRUCTORS 0 // Call functions with __attribute__((constructor)) in SystemInit() #define FUNCONF_ICACHE_EN 1 // Enables ICache on cores that support it, may require power-down + power up to work properly at flash time. +#define FUNCONF_OVERRIDE_STARTUP 0 // User code will have its own `handle_reset` and `InterruptVector` */ // Sanity check for when porting old code. @@ -139,6 +144,10 @@ #define FUNCONF_ENABLE_HPE 0 #endif +#ifndef FUNCONF_TINYVECTOR + #define FUNCONF_TINYVECTOR 0 +#endif + #if FUNCONF_ENABLE_HPE == 1 #define INTERRUPT_DECORATOR __attribute__((interrupt("WCH-Interrupt-fast"))) #else @@ -278,6 +287,10 @@ #endif #endif +#ifndef FUNCONF_OVERRIDE_STARTUP +#define FUNCONF_OVERRIDE_STARTUP 0 +#endif + ///////////////////////////////////////////////////////////////////////////////////////////////// // Legacy, for EVT, CMSIS @@ -884,7 +897,8 @@ extern "C" { #define Ticks_from_Us(n) ((n) * DELAY_US_TIME) #define Ticks_from_Ms(n) ((n) * DELAY_MS_TIME) -#define TimeElapsed32(now,start) ((uint32_t)((uint32_t)(now)-(uint32_t)(start))) +#define TimeElapsed32(now,start) ((int32_t)((uint32_t)(now)-(uint32_t)(start))) +#define TimeElapsed32u(now,start) ((uint32_t)((uint32_t)(now)-(uint32_t)(start))) // Add a certain number of nops. Note: These are usually executed in pairs // and take two cycles, so you typically would use 0, 2, 4, etc. @@ -893,17 +907,23 @@ extern "C" { #define FUN_HIGH 0x1 #define FUN_LOW 0x0 #if defined(CH57x) || defined(CH58x) || defined(CH59x) + #if defined( PB ) && defined( R32_PB_PIN ) #define OFFSET_FOR_GPIOB(pin) (((pin & PB) >> 31) * (&R32_PB_PIN - &R32_PA_PIN)) // 0 if GPIOA, 0x20 if GPIOB #else #define PB 0 #define OFFSET_FOR_GPIOB(pin) 0 #endif -#define GPIO_ResetBits(pin) (*(&R32_PA_CLR + OFFSET_FOR_GPIOB(pin)) = (pin & ~PB)) -#define GPIO_SetBits(pin) (*(&R32_PA_SET + 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) + +#if defined(CH571_CH573) || defined(CH582_CH583) // 582/3 doesn't have _SET +#define GPIO_SetBits(pin) (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) |= (1<<(pin & ~PB))) +#else +#define GPIO_SetBits(pin) (*(&R32_PA_SET + OFFSET_FOR_GPIOB(pin)) = (1<<(pin & ~PB))) +#endif +#define GPIO_ResetBits(pin) (*(&R32_PA_CLR + OFFSET_FOR_GPIOB(pin)) = (1<<(pin & ~PB))) +#define GPIO_InverseBits(pin) (*(&R32_PA_OUT + OFFSET_FOR_GPIOB(pin)) ^= (1<<(pin & ~PB))) +#define GPIO_ReadPortPin(pin) (*(&R32_PA_PIN + OFFSET_FOR_GPIOB(pin)) & (1<<(pin & ~PB))) +#define funDigitalRead(pin) !!GPIO_ReadPortPin(pin) #define funDigitalWrite( pin, value ) do{ if((value)==FUN_HIGH){GPIO_SetBits(pin);} else if((value)==FUN_LOW){GPIO_ResetBits(pin);} }while(0) #define funGpioInitAll() // funGpioInitAll() does not do anything on ch5xx, put here for consistency @@ -911,27 +931,27 @@ 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); + *(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(pin & ~PB)); + *(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(pin & ~PB)); + *(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(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); + *(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(pin & ~PB)); + *(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) |= (1<<(pin & ~PB)); + *(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(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); + *(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (1<<(pin & ~PB)); + *(&R32_PA_PU + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(pin & ~PB)); + *(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(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); + *(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) &= ~(1<<(pin & ~PB)); + *(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) |= (1<<(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); + *(&R32_PA_PD_DRV + OFFSET_FOR_GPIOB(pin)) |= (1<<(pin & ~PB)); + *(&R32_PA_DIR + OFFSET_FOR_GPIOB(pin)) |= (1<<(pin & ~PB)); break; } } @@ -948,14 +968,14 @@ RV_STATIC_INLINE void funPinMode(u32 pin, GPIOModeTypeDef mode) #define funDigitalWrite( pin, value ) do{ GpioOf( pin )->BSHR = 1<<((!(value))*16 + ((pin) & 0xf)); }while(0) #if defined(CH32X03x) -#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ); } -#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); } +#define funGpioInitAll() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ); }while(0) +#define funPinMode( pin, mode ) do{ *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }while(0) #elif defined(CH32V10x) || defined(CH32V20x) || defined(CH32V30x) || defined(CH32L103) -#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); } -#define funPinMode( pin, mode ) { *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); } -#define funGpioInitB() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB ); } +#define funGpioInitAll() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE ); }while(0) +#define funPinMode( pin, mode ) do{ *((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3)) = ( (*((&GpioOf(pin)->CFGLR)+((pin&0x8)>>3))) & (~(0xf<<(4*((pin)&0x7))))) | ((mode)<<(4*((pin)&0x7))); }while(0) +#define funGpioInitB() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB ); }while(0) #elif defined(CH32H41x) -#define funGpioInitAll() { RCC->HB2PCENR |= ( RCC_HB2Periph_AFIO | RCC_HB2Periph_GPIOA | RCC_HB2Periph_GPIOB | RCC_HB2Periph_GPIOC | RCC_HB2Periph_GPIOD | RCC_HB2Periph_GPIOE | RCC_HB2Periph_GPIOF ); } +#define funGpioInitAll() do{ RCC->HB2PCENR |= ( RCC_HB2Periph_AFIO | RCC_HB2Periph_GPIOA | RCC_HB2Periph_GPIOB | RCC_HB2Periph_GPIOC | RCC_HB2Periph_GPIOD | RCC_HB2Periph_GPIOE | RCC_HB2Periph_GPIOF ); }while(0) RV_STATIC_INLINE void funPinMode(u32 pin, GPIOMode_TypeDef mode, GPIOSpeed_TypeDef speed) { @@ -971,13 +991,13 @@ RV_STATIC_INLINE void funPinAF(u32 pin, u32 af) } #else -#define funGpioInitAll() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); } -#define funPinMode( pin, mode ) { GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf<<(4*((pin)&0xf))))) | ((mode)<<(4*((pin)&0xf))); } +#define funGpioInitAll() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD ); }while(0) +#define funPinMode( pin, mode ) do{ GpioOf(pin)->CFGLR = (GpioOf(pin)->CFGLR & (~(0xf<<(4*((pin)&0xf))))) | ((mode)<<(4*((pin)&0xf))); }while(0) #endif -#define funGpioInitA() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA ); } -#define funGpioInitC() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); } -#define funGpioInitD() { RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); } +#define funGpioInitA() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA ); }while(0) +#define funGpioInitC() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC ); }while(0) +#define funGpioInitD() do{ RCC->APB2PCENR |= ( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD ); }while(0) #define funDigitalRead( pin ) ((int)((GpioOf(pin)->INDR >> ((pin)&0xf)) & 1)) #endif @@ -999,7 +1019,6 @@ RV_STATIC_INLINE void funPinAF(u32 pin, u32 af) #if defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE ) - // Stuff that can only be compiled on device (not for the programmer, or other host programs) // Initialize the ADC calibrate it and set some sane defaults. @@ -1009,28 +1028,48 @@ void funAnalogInit( void ); // Be sure to call funAnalogInit first. int funAnalogRead( int nAnalogNumber ); -void handle_reset() __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used)); +#if FUNCONF_CUSTOM_MTVEC + void handle_reset( void ) __attribute__((naked)) __attribute__((section(".init"))) __attribute__((used)); +#else + void handle_reset( void ) __attribute__((naked)) __attribute__((section(".text.handle_reset"))) __attribute__((used)); +#endif + + void DefaultIRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used)); // used to clear the CSS flag in case of clock fail switch #if defined(FUNCONF_USE_CLK_SEC) && FUNCONF_USE_CLK_SEC void NMI_RCC_CSS_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute__((naked)) __attribute__((used)); #endif +void funRebootToBootloader(); + void DelaySysTick( uint32_t n ); +// #define funSysTick32() is defined per-architecture. + +// Get a 64-bit timestamp. Please in general try to use 32-bit timestamps +// whenever possible. Use functions that automatically handle rollover +// correctly like TimeElapsed32( start, end ). Only use this in cases where +// you must act on time periods exceeding 2^31 ticks. +// +// Also, if you are on a platform without a hardware 64-bit timer, you must +// call this function at least once every 2^32 ticks to make sure MSBs aren't +// lost. +uint64_t funSysTick64( void ); // Depending on a LOT of factors, it's about 6 cycles per n. // **DO NOT send it zero or less.** #ifndef __MACOSX__ #ifndef __DELAY_TINY_DEFINED__ #define __DELAY_TINY_DEFINED__ + static inline void Delay_Tiny( int n ) { - __ASM volatile( "\ - mv a5, %[n]\n\ + asm volatile( "\ 1: \ - c.addi a5, -1\n\ - c.bnez a5, 1b" : : [n]"r"(n) : "a5" ); + c.addi %[n], -1\n\ + c.bnez %[n], 1b" : [n]"+r"(n) ); } + #endif #endif #endif //defined(__riscv) || defined(__riscv__) || defined( CH32V003FUN_BASE ) diff --git a/src/ch32fun.c b/src/ch32fun.c index f4d93a7..d76e7a0 100644 --- a/src/ch32fun.c +++ b/src/ch32fun.c @@ -92,6 +92,12 @@ void __libc_init_array(void) #include #include +#ifdef putchar +// Host stdio headers may define putchar as a macro. The firmware provides its +// own weak implementation below, so remove the host macro on every toolchain. +#undef putchar +#endif + #if defined(CH32H41x) volatile v5f_main v5f_start_function = NULL; static int start_v5f(void) @@ -920,6 +926,7 @@ void I2C2_ER_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION) void SPI2_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void USART1_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void USART2_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); +void OPCM_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void USART3_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void EXTI15_10_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void RTCAlarm_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); @@ -1067,9 +1074,12 @@ void USART_WKUP_IRQHandler( void ) __attribute__((section(VECTOR_HANDLER_SECTIO void handle_reset( void ) __attribute__((section(".text.handle_reset"))); +#if !FUNCONF_OVERRIDE_STARTUP #if FUNCONF_ISR_IN_RAM void Init() __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("InitDefault"))) __attribute((naked)); void InitDefault() __attribute__((naked)) __attribute((section(".init"))) __attribute((naked)); + +#if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR void InitDefault( void ) { asm volatile( "\n\ @@ -1079,6 +1089,9 @@ void handle_reset( void ) __attribute__((section(".text.handle_reset"))); j handle_reset\n\ .option pop;\n" ); } +#else + void InitDefault() __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("handle_reset"))); +#endif void InterruptVector() __attribute__((naked)) __attribute((section(VECTOR_HANDLER_SECTION))) __attribute((weak,alias("InterruptVectorDefault"))) __attribute((naked)); void InterruptVectorDefault() __attribute__((naked)) __attribute((section(VECTOR_HANDLER_SECTION))) __attribute((naked)); @@ -1089,6 +1102,7 @@ void handle_reset( void ) __attribute__((section(".text.handle_reset"))); #else void InterruptVector() __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("InterruptVectorDefault"))) __attribute((naked)); void InterruptVectorDefault() __attribute__((naked)) __attribute((section(".init"))) __attribute((naked)); + void InterruptVectorDefault( void ) { #if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR @@ -1103,7 +1117,7 @@ void handle_reset( void ) __attribute__((section(".text.handle_reset"))); #endif } #endif - +#endif #if FUNCONF_ISR_IN_RAM #define VECTOR_HANDLER_SECTION ".data.vector_handler" @@ -1112,6 +1126,7 @@ void handle_reset( void ) __attribute__((section(".text.handle_reset"))); #endif +#if !FUNCONF_OVERRIDE_STARTUP #if defined( CH32V003 ) || defined( CH32X03x ) || defined(CH32V00x) @@ -1129,18 +1144,19 @@ void handle_reset( void ) // Setup the interrupt vector, processor status and INTSYSCR. #if FUNCONF_ENABLE_HPE // Enabled nested and hardware (HPE) stack, since it's really good on the x035. -" li t0, 0x1888\n\ - csrs mstatus, t0\n" -" li t0, 0x0b\n\ - csrw 0x804, t0\n" +" li a3, 0x1888\n\ + csrs mstatus, a3\n" +" li a3, 0x0b\n\ + csrw 0x804, a3\n" #else " li a0, 0x1880\n\ csrw mstatus, a0\n" #endif -" li a3, 0x3\n\ - la a0, InterruptVector\n\ - or a0, a0, a3\n\ - csrw mtvec, a0\n" +#if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR +" la a3, InterruptVector\n\ + ori a3, a3, 3\n\ + csrw mtvec, a3\n" +#endif : : : "a0", "a3", "memory"); // Careful: Use registers to prevent overwriting of self-data. @@ -1218,8 +1234,8 @@ void handle_reset( void ) la a1, _highcode_vma_start\n\ la a2, _highcode_vma_end\n\ bgeu a1, a2, 2f\n\ -1: lw t0, (a0)\n\ - sw t0, (a1)\n\ +1: lw a3, (a0)\n\ + sw a3, (a1)\n\ addi a0, a0, 4\n\ addi a1, a1, 4\n\ bltu a1, a2, 1b\n\ @@ -1230,8 +1246,8 @@ void handle_reset( void ) la a1, _data_vma\n\ la a2, _edata\n\ beq a1, a2, 2f\n\ -1: lw t0, 0(a0)\n\ - sw t0, 0(a1)\n\ +1: lw a3, 0(a0)\n\ + sw a3, 0(a1)\n\ addi a0, a0, 4\n\ addi a1, a1, 4\n\ bltu a1, a2, 1b\n\ @@ -1248,27 +1264,33 @@ void handle_reset( void ) // Setup the interrupt vector, processor status and INTSYSCR. asm volatile( -" li t0, 0x1f\n\ - csrw 0xbc0, t0\n" +" li a3, 0x1f\n\ + csrw 0xbc0, a3\n" #if defined(CH32V30x) && !defined( DISABLED_FLOAT ) -" li t0, 0x7888\n\ - csrs mstatus, t0\n" +" li a3, 0x7888\n\ + csrs mstatus, a3\n" #else -" li t0, 0x1888\n\ - csrs mstatus, t0\n" +" li a3, 0x1888\n\ + csrs mstatus, a3\n" #endif #if FUNCONF_ENABLE_HPE // Enabled nested and hardware (HPE) stack, since it's really good on the x035. -" li t0, 0x0b\n\ - csrw 0x804, t0\n" +" li a3, 0x0b\n\ + csrw 0x804, a3\n" #endif -" la t0, InterruptVector\n\ - ori t0, t0, 3\n\ - csrw mtvec, t0\n" - : : [InterruptVector]"r"(InterruptVector) : "t0", "memory" + : : : "a3", "memory" ); +#if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR + asm volatile( +" la a3, InterruptVector\n\ + ori a3, a3, 3\n\ + csrw mtvec, a3\n" + : : [InterruptVector]"r"(InterruptVector) : "a3", "memory" + ); +#endif + #if defined( FUNCONF_SYSTICK_USE_HCLK ) && FUNCONF_SYSTICK_USE_HCLK && !defined(CH32V10x) SysTick->CTLR = 5; #else @@ -1302,19 +1324,19 @@ void handle_reset( void ) .option push\n\ .option norelax\n\ la gp, __global_pointer$\n\ -.option pop\n\ - csrr a7, mhartid\n\ - bnez a7, 5f\n\ - la sp, _v3f_stack\n\ - j 3f\n\ -5: la sp, _v5f_stack\n" -"3:\n" +.option pop\n" ); asm volatile( #if __GNUC__ > 10 " .option arch, +zicsr\n" #endif +" csrr a7, mhartid\n\ + bnez a7, 5f\n\ + la sp, _v3f_stack\n\ + j 3f\n\ +5: la sp, _v5f_stack\n" +"3:\n" ); // Careful: Use registers to prevent overwriting of self-data. @@ -1335,8 +1357,8 @@ void handle_reset( void ) la a1, _itcm_vma_start\n\ la a2, _itcm_vma_end\n\ bgeu a1, a2, 2f\n\ -1: lw t0, (a0)\n\ - sw t0, (a1)\n\ +1: lw a3, (a0)\n\ + sw a3, (a1)\n\ addi a0, a0, 4\n\ addi a1, a1, 4\n\ bltu a1, a2, 1b\n\ @@ -1346,8 +1368,8 @@ void handle_reset( void ) la a1, _dtcm_vma_start\n\ la a2, _dtcm_vma_end\n\ bgeu a1, a2, 2f\n\ -1: lw t0, (a0)\n\ - sw t0, (a1)\n\ +1: lw a3, (a0)\n\ + sw a3, (a1)\n\ addi a0, a0, 4\n\ addi a1, a1, 4\n\ bltu a1, a2, 1b\n\ @@ -1357,8 +1379,8 @@ void handle_reset( void ) la a1, _data_vma\n\ la a2, _edata\n\ beq a1, a2, 2f\n\ -1: lw t0, 0(a0)\n\ - sw t0, 0(a1)\n\ +1: lw a3, 0(a0)\n\ + sw a3, 0(a1)\n\ addi a0, a0, 4\n\ addi a1, a1, 4\n\ bltu a1, a2, 1b\n\ @@ -1376,40 +1398,47 @@ void handle_reset( void ) // Setup the interrupt vector, processor status and INTSYSCR. asm volatile( " bnez a7, 5f\n\ - la t0, 0x12370303\n\ - csrw 0xbc0, t0\n\ + la a3, 0x12370303\n\ + csrw 0xbc0, a3\n\ j 3f\n\ -5: la t0, 0x12378400\n\ - csrw 0xbc0, t0\n\ +5: la a3, 0x12378400\n\ + csrw 0xbc0, a3\n\ 3:\n" #if !defined( DISABLED_FLOAT ) -" li t0, 0x7888\n\ - csrs mstatus, t0\n" +" li a3, 0x7888\n\ + csrs mstatus, a3\n" #else -" li t0, 0x1888\n\ - csrs mstatus, t0\n" +" li a3, 0x1888\n\ + csrs mstatus, a3\n" #endif #if FUNCONF_ENABLE_HPE " bnez a7, 5f\n\ - li t0, 0x01\n\ - csrw 0xBC1, t0\n\ - li t0, 0x0b\n\ - csrw 0x804, t0\n\ + li a3, 0x01\n\ + csrw 0xBC1, a3\n\ + li a3, 0x0b\n\ + csrw 0x804, a3\n\ j 3f\n\ -5: li t0, 0x07\n\ - csrw 0xBC1, t0\n\ - li t0, 0x0b\n\ - csrw 0x804, t0\n\ +5: li a3, 0x07\n\ + csrw 0xBC1, a3\n\ + li a3, 0x0b\n\ + csrw 0x804, a3\n\ 3:\n" #endif -" la t0, InterruptVector\n\ - ori t0, t0, 3\n\ - csrw mtvec, t0\n" - : : [InterruptVector]"r"(InterruptVector) : "t0", "memory" + : : : "a3", "memory" ); + +#if !defined(FUNCONF_TINYVECTOR) || !FUNCONF_TINYVECTOR + asm volatile( +" la a3, InterruptVector\n\ + ori a3, a3, 3\n\ + csrw mtvec, a3\n" + : : [InterruptVector]"r"(InterruptVector) : "a3", "memory" + ); +#endif + #if defined( FUNCONF_SYSTICK_USE_HCLK ) && FUNCONF_SYSTICK_USE_HCLK SysTick->CTLR = 5; #else @@ -1431,6 +1460,7 @@ void handle_reset( void ) : : [main]"r"(main), [start_v5f]"r"(start_v5f) ); } #endif +#endif #if defined( __riscv_float_abi_double ) #define FLOAD( src, offset, dst ) \ @@ -1651,14 +1681,22 @@ WEAK int putchar(int c) extern int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy); WEAK int _write(int fd, const char *buf, int size) { - while(USBFS_SendEndpointNEW(3, (uint8_t*)buf, size, 1) == -1); // -1 == busy + if(USBFS_SendEndpointNEW(3, (uint8_t*)buf, size, /*copy*/1) == -1) { // -1 == busy + // wait for 1ms to try again once more + Delay_Ms(1); + USBFS_SendEndpointNEW(3, (uint8_t*)buf, size, /*copy*/1); + } return size; } WEAK int putchar(int c) { uint8_t single = c; - while(USBFS_SendEndpointNEW(3, &single, 1, 1) == -1); // -1 == busy + if(USBFS_SendEndpointNEW(3, &single, 1, /*copy*/1) == -1) { // -1 == busy + // wait for 1ms to try again once more + Delay_Ms(1); + USBFS_SendEndpointNEW(3, &single, 1, /*copy*/1); + } return 1; } #endif @@ -1850,10 +1888,10 @@ void DelaySysTick( uint32_t n ) #if defined(CH32V003) || defined(CH32V00x) uint32_t targend = SysTick->CNT + n; while( ((int32_t)( SysTick->CNT - targend )) < 0 ); -#elif defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x) || defined(CH32L103) || defined(CH582_CH583) || defined(CH591_CH592) || defined(CH32H41x) +#elif defined(CH32V20x) || defined(CH32V30x) || defined(CH32X03x) || defined(CH32L103) || defined(CH582_CH583) || defined(CH591_CH592) uint64_t targend = SysTick->CNT + n; while( ((int64_t)( SysTick->CNT - targend )) < 0 ); -#elif defined(CH32V10x) || defined(CH570_CH572) || defined(CH584_CH585) +#elif defined(CH32V10x) || defined(CH570_CH572) || defined(CH584_CH585) || defined(CH32H41x) uint32_t targend = SysTick->CNTL + n; while( ((int32_t)( SysTick->CNTL - targend )) < 0 ); #elif defined(CH571_CH573) @@ -1865,6 +1903,44 @@ void DelaySysTick( uint32_t n ) #endif } + +// Computes a 64-bit SysTick timestamp from the current CPU. +// If the CPU supports a 64-bit SysTick, then it will make sure it +// did not race condition. If it's a 32-bit SysTick, a virtual +// high word will be generated and incremented any time a wraparound +// is detected. +// +// In general, please do not use this function. In 99% of cases, using 32-bit +// functions with proper rollover is better. For instance you can use +// TimeElapsed32( start, end ). +// +// This should only be used when you must act on time periods exceeding 2^31 +// ticks. +// +uint64_t funSysTick64( void ) +{ + uint32_t base = funSysTick32(); +#ifdef funSysTickHigh + + uint32_t high = funSysTickHigh(); + uint32_t check = funSysTick32(); + + // If and only if check is higher than base can we guarantee high is + // valid and matches the check. + if( check >= base ) + return ((uint64_t)high<<32) | check; + + // Else we need a new high. + return (((uint64_t)(funSysTickHigh()))<<32) | check; +#else + static uint32_t lastBase; + static uint32_t high; + if( base < lastBase ) { high++; } + lastBase = base; + return ((uint64_t)high<<32) | base; +#endif +} + #if defined(CH32H41x) void StartV5F(v5f_main function) { @@ -1956,6 +2032,14 @@ void SystemInit( void ) #define CLK_SOURCE_CH5XX CLK_SOURCE_PLL_60MHz #endif #if (defined(CH570_CH572) || defined(CH584_CH585)) +#if (defined(CH584_CH585) && CLK_SOURCE_CH5XX == 0xff) +#warning "The ch584/5 does not support an exact 60MHz setting. Please pick an availabe clock source from the SYS_CLKTypeDef enum in ch5xxhw.h" +#warning "Choosing CLK_SOURCE_HSE_PLL_62_4MHz for now" +#undef CLK_SOURCE_CH5XX +#define CLK_SOURCE_CH5XX CLK_SOURCE_HSE_PLL_62_4MHz +#undef FUNCONF_SYSTEM_CORE_CLOCK +#define FUNCONF_SYSTEM_CORE_CLOCK 62400000 +#endif SYS_CLKTypeDef sc = CLK_SOURCE_CH5XX; if(sc == RB_CLK_SYS_MOD) // LSI @@ -1966,6 +2050,7 @@ void SystemInit( void ) } else { +#if defined(CH570_CH572) if((sc & RB_CLK_SYS_MOD) == 0x40) // PLL div { SYS_SAFE_ACCESS( @@ -1980,6 +2065,56 @@ void SystemInit( void ) R8_FLASH_CFG = (sc & 0x1F) ? 0x02 : 0x07; ); } +#else + if( sc & 0x100) // PLL + { + if( (sc&0x1F) == 0 ) // HSI@16MHz, HSE@32MHz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK|(1<<4); + R8_FLASH_CFG = 0x07; + ); + } + else if( (sc&0x1F) < 10 ) // HSI/HSE+PLL>=39MHz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK & (~(1<<4)); + R8_FLASH_CFG = 0x01; // Probably a divider value for flash clock + ); + } + else if( (sc&0x1F) < 16 ) // HSI/HSE+PLL>19.5MHz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK & (~(1<<4)); + R8_FLASH_CFG = 0x02; + ); + } + else // HSI/HSE+PLL<=19.5MHz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK|(1<<4); + R8_FLASH_CFG = 0x03; + ); + } + } + else + { + if( (sc&0x1F) < 8 ) //HSI>=4MHz, HSE>=6.4Mhz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK & (~(1<<4)); + R8_FLASH_CFG = 0x51; + ); + } + else // HSI=2MHz,1MHz, HSE=4Mhz,2Mhz + { + SYS_SAFE_ACCESS( + R8_FLASH_SCK = R8_FLASH_SCK & (~(1<<4)); + R8_FLASH_CFG = 0x57; + ); + } + } +#endif SYS_SAFE_ACCESS( #ifdef CH570_CH572 R8_CLK_SYS_CFG = sc; @@ -2176,6 +2311,22 @@ int funAnalogRead( int nAnalogNumber ) } #endif +void funRebootToBootloader() +{ +#if defined(CH32V003) || defined(CH32V00x) || defined(CH32X03x) + FLASH->BOOT_MODEKEYR = FLASH_KEY1; + FLASH->BOOT_MODEKEYR = FLASH_KEY2; + FLASH->STATR = 1<<14; + RCC->RSTSCKR |= 0x1000000; + PFIC->SCTLR = 1<<31; +#elif defined(CH5xx) + SYS_SAFE_ACCESS( + R8_RESET_STATUS = 1<<7; + R8_RST_WDOG_CTRL = 5; + ); +#endif +} + // C++ Support #ifdef CPLUSPLUS