diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c index 4363ed3a115f529e739dd67457b4c0e9d18fa331..f25595f66cde4f1debce05d487a311d514fc721e 100644 --- a/ch32v003fun/ch32v003fun.c +++ b/ch32v003fun/ch32v003fun.c @@ -854,7 +854,6 @@ int _write(int fd, const char *buf, int size) #define DMDATA0 ((volatile uint32_t*)0xe00000f4) #define DMDATA1 ((volatile uint32_t*)0xe00000f8) - char buffer[4] = { 0 }; int place = 0; while( place < size ) diff --git a/examples/bootload/bootload.c b/examples/bootload/bootload.c index aa107360e5ce3b6789c65d1b125256b86ef26b34..02b2385b74f0562f307f28b882b7dc12138c1fba 100644 --- a/examples/bootload/bootload.c +++ b/examples/bootload/bootload.c @@ -46,13 +46,23 @@ int main() count = marker[0]; int i; + + // Make a clear signature. + for( i = 0; i < 10; i++ ) + { + GPIOD->BSHR = 1 | (1<<4); // Turn on GPIOD0 + D4 + GPIOC->BSHR = 1; // Turn on GPIOC0 + GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIOD0 + D4 + GPIOC->BSHR = 1<<16; // Turn off GPIOC0 + } + for( i = 0; i < 5; i++ ) { - GPIOD->BSHR = 1 | (1<<4); // Turn on GPIOD0 + D4 - GPIOC->BSHR = 1; // Turn on GPIOC0 + GPIOD->BSHR = 1 | (1<<4); + GPIOC->BSHR = 1; Delay_Ms( 250 ); GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIOD0 + D4 - GPIOC->BSHR = 1; // Turn off GPIOC0 + GPIOC->BSHR = 1<<16; // Turn off GPIOC0 Delay_Ms( 20 ); count++; } diff --git a/examples/debugprintfdemo/debugprintfdemo.c b/examples/debugprintfdemo/debugprintfdemo.c index f5a801d6ae39a298e64ce9485eb7b4cd74df5f6a..297d2b8d640e1d1ac0aaa9202aaad30d39be630e 100644 --- a/examples/debugprintfdemo/debugprintfdemo.c +++ b/examples/debugprintfdemo/debugprintfdemo.c @@ -1,9 +1,5 @@ -// Really basic self-contained demo for the ch32v003 -// Doesn't rely on any of the weird HAL stuff from CH -// Final executable is ~1/4th the size. - -// Could be defined here, or in the processor defines. -#define SYSTEM_CORE_CLOCK 48000000 +/* Small example showing how to use the SWIO programming pin to + do printf through the debug interface */ #include "ch32v003fun.h" #include <stdio.h> diff --git a/examples/optionbytes/optionbytes.c b/examples/optionbytes/optionbytes.c index 25aaf5c9178eeae2dd395a1380a329ddb888d42d..fbec69aa3fadb2217ebacf4d07462e46e626e1ff 100644 --- a/examples/optionbytes/optionbytes.c +++ b/examples/optionbytes/optionbytes.c @@ -1,6 +1,17 @@ -// Really basic self-contained demo for the ch32v003 -// Doesn't rely on any of the weird HAL stuff from CH -// Final executable is ~1/4th the size. +/* This shows how to use the option bytes. I.e. how do you disable NRST? + WARNING Portions of this code are under the following copyright. +*/ +/********************************** (C) COPYRIGHT ******************************* + * File Name : ch32v00x_flash.c + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/08 + * Description : This file provides all the FLASH firmware functions. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ // Could be defined here, or in the processor defines. #define SYSTEM_CORE_CLOCK 48000000 diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index e31c7b9a836c419651fac200631e9e9626e5d230..b4cb47a24f5298637caebeda62c0acc2470398d6 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -385,8 +385,7 @@ help: fprintf( stderr, " -b Reboot out of Halt\n" ); fprintf( stderr, " -e Resume from halt\n" ); fprintf( stderr, " -h Place into Halt\n" ); - fprintf( stderr, " -D Configure NRST as GPIO **WARNING** If you do this and you reconfig\n" ); - fprintf( stderr, " the SWIO pin (PD1) on boot, your part can never again be programmed!\n" ); + fprintf( stderr, " -D Configure NRST as GPIO\n" ); fprintf( stderr, " -d Configure NRST as NRST\n" ); // fprintf( stderr, " -P Enable Read Protection (UNTESTED)\n" ); // fprintf( stderr, " -p Disable Read Protection (UNTESTED)\n" ); @@ -562,6 +561,61 @@ static int InternalUnlockBootloader( void * dev ) return ret; } + + +static int DefaultWriteHalfWord( void * dev, uint32_t address_to_write, uint32_t data ) +{ + int ret = 0; + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); + if( MCF.VoidHighLevelState ) MCF.VoidHighLevelState( dev ); + iss->statetag = STTAG( "XXXX" ); + + MCF.WriteReg32( dev, DMABSTRACTAUTO, 0x00000000 ); // Disable Autoexec. + + // Different address, so we don't need to re-write all the program regs. + // sh x8,0(x9) // Write to the address. + MCF.WriteReg32( dev, DMPROGBUF0, 0x00849023 ); + MCF.WriteReg32( dev, DMPROGBUF1, 0x00100073 ); // c.ebreak + + MCF.WriteReg32( dev, DMDATA0, address_to_write ); + MCF.WriteReg32( dev, DMCOMMAND, 0x00231009 ); // Copy data to x9 + MCF.WriteReg32( dev, DMDATA0, data ); + MCF.WriteReg32( dev, DMCOMMAND, 0x00271008 ); // Copy data to x8, and execute program. + + ret |= MCF.WaitForDoneOp( dev ); + iss->currentstateval = -1; + + + return ret; +} + +static int DefaultReadHalfWord( void * dev, uint32_t address_to_write, uint32_t * data ) +{ + int ret = 0; + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); + if( MCF.VoidHighLevelState ) MCF.VoidHighLevelState( dev ); + iss->statetag = STTAG( "XXXX" ); + + MCF.WriteReg32( dev, DMABSTRACTAUTO, 0x00000000 ); // Disable Autoexec. + + // Different address, so we don't need to re-write all the program regs. + // lh x8,0(x9) // Write to the address. + MCF.WriteReg32( dev, DMPROGBUF0, 0x00049403 ); + MCF.WriteReg32( dev, DMPROGBUF1, 0x00100073 ); // c.ebreak + + MCF.WriteReg32( dev, DMDATA0, address_to_write ); + MCF.WriteReg32( dev, DMCOMMAND, 0x00231009 ); // Copy data to x9 + MCF.WriteReg32( dev, DMCOMMAND, 0x00241000 ); // Only execute. + MCF.WriteReg32( dev, DMCOMMAND, 0x00221008 ); // Read x8 into DATA0. + + ret |= MCF.WaitForDoneOp( dev ); + iss->currentstateval = -1; + + + return ret | MCF.ReadReg32( dev, DMDATA0, data ); +} + + static int DefaultWriteWord( void * dev, uint32_t address_to_write, uint32_t data ) { struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); @@ -764,13 +818,11 @@ timedout: static int DefaultReadWord( void * dev, uint32_t address_to_read, uint32_t * data ) { struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); - if( iss->statetag != STTAG( "RDSQ" ) || address_to_read != iss->currentstateval ) { if( iss->statetag != STTAG( "RDSQ" ) ) { MCF.WriteReg32( dev, DMABSTRACTAUTO, 0 ); // Disable Autoexec. - // c.lw x8,0(x11) // Pull the address from DATA1 // c.lw x9,0(x8) // Read the data at that location. MCF.WriteReg32( dev, DMPROGBUF0, 0x40044180 ); @@ -1021,7 +1073,7 @@ int DefaultUnbrick( void * dev ) if( timeout == max_timeout ) { - printf( "Timed out trying to unbrick\n" ); + fprintf( stderr, "Timed out trying to unbrick\n" ); return -5; } MCF.Erase( dev, 0, 0, 1); @@ -1029,6 +1081,144 @@ int DefaultUnbrick( void * dev ) return -5; } +int DefaultConfigureNRSTAsGPIO( void * dev, int one_if_yes_gpio ) +{ + fprintf( stderr, "Error: DefaultConfigureNRSTAsGPIO does not work via the programmer here. Please see the demo \"optionbytes\"\n" ); + return -5; +#if 0 + int ret = 0; + uint32_t csw; + + + if( MCF.ReadWord( dev, 0x1FFFF800, &csw ) ) + { + fprintf( stderr, "Error: failed to get user word\n" ); + return -5; + } + + printf( "CSW WAS : %08x\n", csw ); + + MCF.WriteWord( dev, 0x40022008, 0x45670123 ); // OBKEYR = 0x40022008 + MCF.WriteWord( dev, 0x40022008, 0xCDEF89AB ); + MCF.WriteWord( dev, 0x40022004, 0x45670123 ); // FLASH->KEYR = 0x40022004 + MCF.WriteWord( dev, 0x40022004, 0xCDEF89AB ); + MCF.WriteWord( dev, 0x40022024, 0x45670123 ); // MODEKEYR = 0x40022024 + MCF.WriteWord( dev, 0x40022024, 0xCDEF89AB ); + +//XXXX THIS DOES NOT WORK IT CANNOT ERASE. + uint32_t ctlr; + if( MCF.ReadWord( dev, 0x40022010, &ctlr ) ) // FLASH->CTLR = 0x40022010 + { + return -9; + } + ctlr |= CR_OPTER_Set | CR_STRT_Set; // OBER + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + + MCF.WriteHalfWord( dev, (intptr_t)&OB->RDPR, RDP_Key ); + + ctlr &=~CR_OPTER_Reset; + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + ctlr |= CR_OPTPG_Set; + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + ctlr &=~CR_OPTPG_Reset; + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + + +// This does work to write the option bytes, but does NOT work to erase. + + if( MCF.ReadWord( dev, 0x40022010, &ctlr ) ) // FLASH->CTLR = 0x40022010 + { + return -9; + } + ctlr |= CR_OPTPG_Set; //OBPG + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + + uint32_t config = OB_IWDG_HW | OB_STOP_NoRST | OB_STDBY_NoRST | (one_if_yes_gpio?OB_RST_NoEN:OB_RST_EN_DT1ms) | (uint16_t)0xE0; + printf( "Config (%08x): %08x\n", (intptr_t)&OB->USER, config ); + MCF.WriteHalfWord( dev, (intptr_t)&OB->USER, config ); + + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + + ctlr &= CR_OPTPG_Reset; + MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 + + + if( MCF.ReadWord( dev, 0x1FFFF800, &csw ) ) + { + fprintf( stderr, "Error: failed to get user word\n" ); + return -5; + } + + //csw >>= 16; // Only want bottom part of word. + printf( "CSW: %08x\n", csw ); + +#if 0 + uint32_t prevuser; + if( MCF.ReadWord( dev, 0x1FFFF800, &prevuser ) ) + { + fprintf( stderr, "Error: failed to get user word\n" ); + return -5; + } + + ret |= MCF.WaitForFlash( dev ); + + // Erase. + MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010 + csw |= 1<<5;//OBER; + MCF.WriteWord( dev, 0x40022010, csw ); // FLASH->CTLR = 0x40022010 + MCF.WriteHalfWord( dev, 0x1FFFF802, 0xffff ); + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + + MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010 + printf( "CTLR: %08x\n", csw ); + csw |= 1<<9;//OBPG, OBWRE + MCF.WriteWord( dev, 0x40022010, csw ); + + int j; + for( j = 0; j < 5; j++ ) + { + if( MCF.ReadWord( dev, 0x1FFFF800, &prevuser ) ) + { + fprintf( stderr, "Error: failed to get user word\n" ); + return -5; + } + + //csw >>= 16; // Only want bottom part of word. + printf( "CSW was: %08x\n", prevuser ); + csw = prevuser >> 16; + csw = csw & 0xe7e7; + csw |= (one_if_yes_gpio?0b11:0b00)<<(3+0); + csw |= (one_if_yes_gpio?0b00:0b11)<<(3+8); + printf( "CSW writing: %08x\n", csw ); + MCF.WriteHalfWord( dev, 0x1FFFF802, csw ); + ret |= MCF.WaitForDoneOp( dev ); + ret |= MCF.WaitForFlash( dev ); + } + + + MCF.ReadWord( dev, 0x40022010, &csw ); // FLASH->CTLR = 0x40022010 + printf( "CTLR: %08x\n", csw ); + csw &= ~(1<<9);//OBPG, OBWRE + MCF.WriteWord( dev, 0x40022010, csw ); + +#endif + printf( "RET: %d\n", ret ); + return 0; +#endif +} + int DefaultPrintChipInfo( void * dev ) { uint32_t reg; @@ -1072,8 +1262,12 @@ int SetupAutomaticHighLevelFunctions( void * dev ) MCF.ReadBinaryBlob = DefaultReadBinaryBlob; if( !MCF.WriteWord ) MCF.WriteWord = DefaultWriteWord; + if( !MCF.WriteHalfWord ) + MCF.WriteHalfWord = DefaultWriteHalfWord; if( !MCF.ReadWord ) MCF.ReadWord = DefaultReadWord; + if( !MCF.ReadHalfWord ) + MCF.ReadHalfWord = DefaultReadHalfWord; if( !MCF.Erase ) MCF.Erase = DefaultErase; if( !MCF.HaltMode ) @@ -1088,6 +1282,8 @@ int SetupAutomaticHighLevelFunctions( void * dev ) MCF.PrintChipInfo = DefaultPrintChipInfo; if( !MCF.Unbrick ) MCF.Unbrick = DefaultUnbrick; + if( !MCF.ConfigureNRSTAsGPIO ) + MCF.ConfigureNRSTAsGPIO = DefaultConfigureNRSTAsGPIO; struct InternalState * iss = malloc( sizeof( struct InternalState ) ); iss->statetag = 0; diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h index de5302a76dd9847e9ea4c7a8d4b823f4668069a0..d10f1ffb20722357851caa5e8dbd5209b3932d94 100644 --- a/minichlink/minichlink.h +++ b/minichlink/minichlink.h @@ -31,7 +31,8 @@ struct MiniChlinkFunctions int (*Erase)( void * dev, uint32_t address, uint32_t length, int type ); //type = 0 for fast, 1 for whole-chip // MUST be 4-byte-aligned. - int (*WriteWord)( void * dev, uint32_t address_to_write, uint32_t data ); // Flags = 1 for "doing a fast FLASH write." + int (*VoidHighLevelState)( void * dev ); + int (*WriteWord)( void * dev, uint32_t address_to_write, uint32_t data ); int (*ReadWord)( void * dev, uint32_t address_to_read, uint32_t * data ); int (*WaitForFlash)( void * dev ); @@ -52,6 +53,10 @@ struct MiniChlinkFunctions int (*PollTerminal)( void * dev, uint8_t * buffer, int maxlen ); int (*PerformSongAndDance)( void * dev ); + + // Do Not override these. they are cursed. + int (*WriteHalfWord)( void * dev, uint32_t address_to_write, uint32_t data ); + int (*ReadHalfWord)( void * dev, uint32_t address_to_read, uint32_t * data ); }; /** If you are writing a driver, the minimal number of functions you can implement are: diff --git a/minichlink/pgm-esp32s2-ch32xx.c b/minichlink/pgm-esp32s2-ch32xx.c index 2b3c67d5574832dab892fdf1ef44316b6725be01..6f7b7fa041cc4fa3d58af3cb09033108784e2659 100644 --- a/minichlink/pgm-esp32s2-ch32xx.c +++ b/minichlink/pgm-esp32s2-ch32xx.c @@ -105,7 +105,7 @@ int ESPFlushLLCommands( void * dev ) if( r < 0 ) { fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r ); - return r; + exit( -9 ); } retry: eps->reply[0] = 0xad; // Key report ID @@ -247,6 +247,13 @@ int ESPPerformSongAndDance( void * dev ) return 0; } +int ESPVoidHighLevelState( void * dev ) +{ + struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev; + Write2LE( eps, 0x05fe ); + ESPFlushLLCommands( dev ); + return 0; +} void * TryInit_ESP32S2CHFUN() { @@ -268,6 +275,7 @@ void * TryInit_ESP32S2CHFUN() MCF.DelayUS = ESPDelayUS; MCF.Control3v3 = ESPControl3v3; MCF.Exit = ESPExit; + MCF.VoidHighLevelState = ESPVoidHighLevelState; // These are optional. Disabling these is a good mechanismto make sure the core functions still work. MCF.WriteWord = ESPWriteWord;