diff --git a/ch32v003fun/ch32v003fun-bootloader.ld b/ch32v003fun/ch32v003fun-bootloader.ld new file mode 100644 index 0000000000000000000000000000000000000000..39d6580e88a0b572317c6a1821d730df795735a3 --- /dev/null +++ b/ch32v003fun/ch32v003fun-bootloader.ld @@ -0,0 +1,148 @@ +ENTRY( InterruptVector ) + +MEMORY +{ + /* Actually at 0x1FFFF000 but the system maps it to 0x00000000 */ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1920 + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K +} + +SECTIONS +{ + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .text : + { + . = ALIGN(4); + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dalign : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + } >RAM AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + . = ALIGN(4); + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.sdata2*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + PROVIDE( _eusrstack = ORIGIN(RAM) + LENGTH(RAM)); +} + + + diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c index c800f905c9ef3ffd812bc2f8666a04149aa074c1..4363ed3a115f529e739dd67457b4c0e9d18fa331 100644 --- a/ch32v003fun/ch32v003fun.c +++ b/ch32v003fun/ch32v003fun.c @@ -664,10 +664,6 @@ mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt int main() __attribute__((used)); void SystemInit( void ) __attribute__((used)); -void InterruptVector() __attribute__((naked)) __attribute((section(".init"))) __attribute__((used)) __attribute((weak)); -void handle_reset() __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used)); -void DefaultIRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute__((naked)) __attribute__((used)); - extern uint32_t * _sbss; extern uint32_t * _ebss; extern uint32_t * _data_lma; @@ -712,7 +708,11 @@ void TIM1_TRG_COM_IRQHandler( void ) __attribute__((section(".text.vector_ha void TIM1_CC_IRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); void TIM2_IRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used)); -void InterruptVector() +void InterruptVector() __attribute__((naked)) __attribute((section(".init"))) __attribute((weak,alias("InterruptVectorDefault"))); +void InterruptVectorDefault() __attribute__((naked)) __attribute((section(".init"))); + + +void InterruptVectorDefault() { asm volatile( "\n\ .align 2\n\ @@ -759,7 +759,6 @@ void InterruptVector() .word TIM2_IRQHandler /* TIM2 */ \n"); } - void handle_reset() { asm volatile( "\n\ diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h index 9f25a84910c83e962c15c1fb5b860606776e0e24..56393414e1432ea9d3b1da24a4fd7cf98b19e023 100644 --- a/ch32v003fun/ch32v003fun.h +++ b/ch32v003fun/ch32v003fun.h @@ -4819,6 +4819,9 @@ extern "C" { #define DELAY_US_TIME (SYSTEM_CORE_CLOCK / 8000000) #define DELAY_MS_TIME (SYSTEM_CORE_CLOCK / 8000) +void handle_reset() __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used)); +void DefaultIRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute__((naked)) __attribute__((used)); + void DelaySysTick( uint32_t n ); #define Delay_Us(n) DelaySysTick( n * DELAY_US_TIME ) diff --git a/examples/blink/blink.bin b/examples/blink/blink.bin index b1c36a5c828db912241513fd46ac9f0fae76f4d5..f5244807298493f49c777f4e01a93a19666c80c3 100755 Binary files a/examples/blink/blink.bin and b/examples/blink/blink.bin differ diff --git a/examples/bootload/Makefile b/examples/bootload/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d39497d767c87bed9dd45d735f0758813c72142d --- /dev/null +++ b/examples/bootload/Makefile @@ -0,0 +1,51 @@ +TARGET:=bootload + +all : flash + +PREFIX:=riscv64-unknown-elf + +GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User + +EVT:=../../ch32v003evt + +MINICHLINK:=../../minichlink + +ifeq ($(OS),Windows_NT) +# On Windows, all the major RISC-V GCC installs are missing the -ec libgcc. +LIB_GCC=../../misc/libgcc.a +else +LIB_GCC=-lgcc +endif + +CH32V003FUN:=../../ch32v003fun + +CFLAGS:= \ + -g -Os -flto -ffunction-sections \ + -static-libgcc $(LIB_GCC) \ + -march=rv32ec \ + -mabi=ilp32e \ + -I/usr/include/newlib \ + -I$(CH32V003FUN) \ + -nostdlib \ + -I. -DCUSTOM_INTERRUPT_VECTOR + +LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun-bootloader.ld -Wl,--gc-sections + +SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c + +$(TARGET).elf : $(SYSTEM_C) $(TARGET).c + $(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) + +$(TARGET).bin : $(TARGET).elf + $(PREFIX)-size $^ + $(PREFIX)-objdump -S $^ > $(TARGET).lst + $(PREFIX)-objdump -t $^ > $(TARGET).map + $(PREFIX)-objcopy -O binary $< $(TARGET).bin + $(PREFIX)-objcopy -O ihex $< $(TARGET).hex + +flash : $(TARGET).bin + $(MINICHLINK)/minichlink -h -U -w $< bootloader -B + +clean : + rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex + diff --git a/examples/bootload/bootload.c b/examples/bootload/bootload.c new file mode 100644 index 0000000000000000000000000000000000000000..aa107360e5ce3b6789c65d1b125256b86ef26b34 --- /dev/null +++ b/examples/bootload/bootload.c @@ -0,0 +1,74 @@ +// Could be defined here, or in the processor defines. +#define SYSTEM_CORE_CLOCK 48000000 + +#include "ch32v003fun.h" +#include <stdio.h> + +#define APB_CLOCK SYSTEM_CORE_CLOCK + +uint32_t count; + +// You can override the interrupt vector this way: +void InterruptVector() __attribute__((naked)) __attribute((section(".init"))); +void InterruptVector() +{ + asm volatile( "\n\ + .align 2\n\ + .option norvc;\n\ + j handle_reset"); +} + +uint32_t count; + +int main() +{ + SystemInit48HSI(); + + // From here, you can do whatever you'd like! + // This code will live up at 0x1ffff000. + + // Enable GPIOD. + RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC; + + // GPIO D0 Push-Pull, 10MHz Output + GPIOD->CFGLR &= ~(0xf<<(4*0)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0); + + // GPIO D0 Push-Pull, 10MHz Output + GPIOD->CFGLR &= ~(0xf<<(4*4)); + GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); + + // GPIO D0 Push-Pull, 10MHz Output + GPIOC->CFGLR &= ~(0xf<<(4*0)); + GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4); + + static const uint32_t marker[] = { 0xaaaaaaaa }; + count = marker[0]; + + int i; + for( i = 0; i < 5; i++ ) + { + GPIOD->BSHR = 1 | (1<<4); // Turn on GPIOD0 + D4 + GPIOC->BSHR = 1; // Turn on GPIOC0 + Delay_Ms( 250 ); + GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIOD0 + D4 + GPIOC->BSHR = 1; // Turn off GPIOC0 + Delay_Ms( 20 ); + count++; + } + + // Exit bootloader after 5 blinks. + + // Note we have to do this if we ended up in the bootloader because + // the main system booted us here. If you don't care, you don't need + // to turn OBTKEYR back off. + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + FLASH->BOOT_MODEKEYR = FLASH_KEY1; + FLASH->BOOT_MODEKEYR = FLASH_KEY2; + FLASH->STATR = 0; // 1<<14 is zero, so, boot user code. + FLASH->CTLR = CR_LOCK_Set; + + PFIC->SCTLR = 1<<31; + while(1); +} diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index 3160afaf05fbcdb4dc03e2f1dcb7f8eb717bef33..e31c7b9a836c419651fac200631e9e9626e5d230 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -14,6 +14,7 @@ static int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber ); static int64_t StringToMemoryAddress( const char * number ); static void StaticUpdatePROGBUFRegs( void * dev ); +static int InternalUnlockBootloader( void * dev ); void TestFunction(void * v ); struct MiniChlinkFunctions MCF; @@ -108,10 +109,19 @@ keep_going: else goto unimplemented; break; + case 'U': + // Unlock Bootloader + if( InternalUnlockBootloader( dev ) ) + goto unimplemented; + break; case 'b': //reBoot if( !MCF.HaltMode || MCF.HaltMode( dev, 1 ) ) goto unimplemented; break; + case 'B': //reBoot into Bootloader + if( !MCF.HaltMode || MCF.HaltMode( dev, 3 ) ) + goto unimplemented; + break; case 'e': //rEsume if( !MCF.HaltMode || MCF.HaltMode( dev, 2 ) ) goto unimplemented; @@ -345,7 +355,7 @@ keep_going: goto unimplemented; } - printf( "Image written successfully\n" ); + printf( "Image written.\n" ); free( image ); break; @@ -528,6 +538,30 @@ static void StaticUpdatePROGBUFRegs( void * dev ) MCF.WriteReg32( dev, DMCOMMAND, 0x0023100d ); // Copy data to x13 } +static int InternalUnlockBootloader( void * dev ) +{ + if( !MCF.WriteWord ) return -99; + int ret = 0; + uint32_t OBTKEYR; + ret |= MCF.WriteWord( dev, 0x40022028, 0x45670123 ); //(FLASH_BOOT_MODEKEYP) + ret |= MCF.WriteWord( dev, 0x40022028, 0xCDEF89AB ); //(FLASH_BOOT_MODEKEYP) + ret |= MCF.ReadWord( dev, 0x40022008, &OBTKEYR ); //(FLASH_OBTKEYR) + if( ret ) + { + fprintf( stderr, "Error operating with OBTKEYR\n" ); + return -1; + } + if( OBTKEYR & (1<<15) ) + { + fprintf( stderr, "Error: Could not unlock boot section (%08x)\n", OBTKEYR ); + } + OBTKEYR |= (1<<14); // Configure for boot-to-bootload. + ret |= MCF.WriteWord( dev, 0x40022008, OBTKEYR ); + ret |= MCF.ReadWord( dev, 0x40022008, &OBTKEYR ); //(FLASH_OBTKEYR) + printf( "FLASH_OBTKEYR = %08x (%d)\n", OBTKEYR, ret ); + return ret; +} + static int DefaultWriteWord( void * dev, uint32_t address_to_write, uint32_t data ) { struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); @@ -633,7 +667,7 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob if( blob_size == 0 ) return 0; - if( (address_to_write & 0xff000000) == 0x08000000 || (address_to_write & 0xff000000) == 0x00000000 ) + if( (address_to_write & 0xff000000) == 0x08000000 || (address_to_write & 0xff000000) == 0x00000000 || (address_to_write & 0x1FFFF800) == 0x1FFFF000 ) is_flash = 1; if( is_flash && MCF.BlockWrite64 && ( address_to_write & 0x3f ) == 0 ) @@ -880,6 +914,21 @@ static int DefaultHaltMode( void * dev, int mode ) MCF.WriteReg32( dev, DMCONTROL, 0x40000001 ); // resumereq MCF.FlushLLCommands( dev ); break; + case 3: + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request. + + MCF.WriteWord( dev, (intptr_t)&FLASH->KEYR, FLASH_KEY1 ); + MCF.WriteWord( dev, (intptr_t)&FLASH->KEYR, FLASH_KEY2 ); + MCF.WriteWord( dev, (intptr_t)&FLASH->BOOT_MODEKEYR, FLASH_KEY1 ); + MCF.WriteWord( dev, (intptr_t)&FLASH->BOOT_MODEKEYR, FLASH_KEY2 ); + MCF.WriteWord( dev, (intptr_t)&FLASH->STATR, 1<<14 ); + MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_LOCK_Set ); + + MCF.WriteReg32( dev, DMCONTROL, 0x80000003 ); // Reboot. + MCF.WriteReg32( dev, DMCONTROL, 0x40000001 ); // resumereq + MCF.FlushLLCommands( dev ); + break; } iss->processor_in_mode = mode; return 0;