diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h index ba320ecf0082e95111d7f9ee4ab39ab5bf0f5223..c6ccd39a2d3b393645577cf9c368c4ab9205b399 100644 --- a/ch32v003fun/ch32v003fun.h +++ b/ch32v003fun/ch32v003fun.h @@ -1302,20 +1302,20 @@ typedef struct #define FLASH_STATR_EOP ((uint8_t)0x20) /* End of operation */ /******************* Bit definition for FLASH_CTLR register *******************/ -#define FLASH_CTLR_PG ((uint16_t)0x0001) /* Programming */ -#define FLASH_CTLR_PER ((uint16_t)0x0002) /* Page Erase 1KByte*/ -#define FLASH_CTLR_MER ((uint16_t)0x0004) /* Mass Erase */ -#define FLASH_CTLR_OPTPG ((uint16_t)0x0010) /* Option Byte Programming */ -#define FLASH_CTLR_OPTER ((uint16_t)0x0020) /* Option Byte Erase */ -#define FLASH_CTLR_STRT ((uint16_t)0x0040) /* Start */ -#define FLASH_CTLR_LOCK ((uint16_t)0x0080) /* Lock */ -#define FLASH_CTLR_OPTWRE ((uint16_t)0x0200) /* Option Bytes Write Enable */ -#define FLASH_CTLR_ERRIE ((uint16_t)0x0400) /* Error Interrupt Enable */ -#define FLASH_CTLR_EOPIE ((uint16_t)0x1000) /* End of operation interrupt enable */ -#define FLASH_CTLR_PAGE_PG ((uint16_t)0x00010000) /* Page Programming 64Byte */ -#define FLASH_CTLR_PAGE_ER ((uint16_t)0x00020000) /* Page Erase 64Byte */ -#define FLASH_CTLR_BUF_LOAD ((uint16_t)0x00040000) /* Buffer Load */ -#define FLASH_CTLR_BUF_RST ((uint16_t)0x00080000) /* Buffer Reset */ +#define FLASH_CTLR_PG (0x0001) /* Programming */ +#define FLASH_CTLR_PER (0x0002) /* Page Erase 1KByte*/ +#define FLASH_CTLR_MER (0x0004) /* Mass Erase */ +#define FLASH_CTLR_OPTPG (0x0010) /* Option Byte Programming */ +#define FLASH_CTLR_OPTER (0x0020) /* Option Byte Erase */ +#define FLASH_CTLR_STRT (0x0040) /* Start */ +#define FLASH_CTLR_LOCK (0x0080) /* Lock */ +#define FLASH_CTLR_OPTWRE (0x0200) /* Option Bytes Write Enable */ +#define FLASH_CTLR_ERRIE (0x0400) /* Error Interrupt Enable */ +#define FLASH_CTLR_EOPIE (0x1000) /* End of operation interrupt enable */ +#define FLASH_CTLR_PAGE_PG (0x00010000) /* Page Programming 64Byte */ +#define FLASH_CTLR_PAGE_ER (0x00020000) /* Page Erase 64Byte */ +#define FLASH_CTLR_BUF_LOAD (0x00040000) /* Buffer Load */ +#define FLASH_CTLR_BUF_RST (0x00080000) /* Buffer Reset */ /******************* Bit definition for FLASH_ADDR register *******************/ #define FLASH_ADDR_FAR ((uint32_t)0xFFFFFFFF) /* Flash Address */ diff --git a/examples/flashtest/Makefile b/examples/flashtest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..89a4c4c409495584772ed6a271dc715d6c6b2143 --- /dev/null +++ b/examples/flashtest/Makefile @@ -0,0 +1,9 @@ +all : flash + +TARGET:=flashtest + +include ../../ch32v003fun/ch32v003fun.mk + +flash : cv_flash +clean : cv_clean + diff --git a/examples/flashtest/flashtest.c b/examples/flashtest/flashtest.c new file mode 100644 index 0000000000000000000000000000000000000000..435dcc1861cfedab59d74c900fed40efcf8e0811 --- /dev/null +++ b/examples/flashtest/flashtest.c @@ -0,0 +1,103 @@ +// DOES NOT WORK HALP!!!!!!!!!!!!!! + +#define SYSTEM_CORE_CLOCK 48000000 +#define SYSTICK_USE_HCLK + +#include "ch32v003fun.h" +#include <stdio.h> + + +int main() +{ + int start; + int stop; + + SETUP_SYSTICK_HCLK + + SystemInit48HSI(); + SetupDebugPrintf(); + + Delay_Ms(100); + + printf( "Starting\n" ); + + // Unkock flash - be aware you need extra stuff for the bootloader. + FLASH->KEYR = 0x45670123; + FLASH->KEYR = 0xCDEF89AB; + + // For option bytes. +// FLASH->OBKEYR = 0x45670123; +// FLASH->OBKEYR = 0xCDEF89AB; + + FLASH->MODEKEYR = 0x45670123; + FLASH->MODEKEYR = 0xCDEF89AB; + + printf( "FLASH->CTLR = %08lx\n", FLASH->CTLR ); + if( FLASH->CTLR & 0x8080 ) + { + printf( "Flash still locked\n" ); + while(1); + } + + uint32_t * ptr = (uint32_t*)0x08003700; + printf( "Memory at: %p: %08lx %08lx\n", ptr, ptr[0], ptr[1] ); + + + printf( "FLASH->CTLR = %08lx\n", FLASH->CTLR ); + + //Erase Page + FLASH->CTLR = CR_PAGE_ER; + FLASH->ADDR = (intptr_t)ptr; + FLASH->CTLR = CR_STRT_Set | CR_PAGE_ER; + start = SysTick->CNT; + while( FLASH->STATR & FLASH_STATR_BSY ); // Takes about 3ms. + stop = SysTick->CNT; + + printf( "FLASH->STATR = %08lx -> %d cycles for page erase\n", FLASH->STATR, stop - start ); + printf( "Erase complete\n" ); + + + printf( "Memory at %p: %08lx %08lx\n", ptr, ptr[0], ptr[1] ); + + // Clear buffer and prep for flashing. + FLASH->CTLR = CR_PAGE_PG; // synonym of FTPG. + FLASH->CTLR = CR_BUF_RST | CR_PAGE_PG; + FLASH->ADDR = (intptr_t)ptr; // This can actually happen about anywhere toward the end here. + + + // Note: It takes about 6 clock cycles for this to finish. + start = SysTick->CNT; + while( FLASH->STATR & FLASH_STATR_BSY ); // No real need for this. + stop = SysTick->CNT; + printf( "FLASH->STATR = %08lx -> %d cycles for buffer reset\n", FLASH->STATR, stop - start ); + + + int i; + start = SysTick->CNT; + for( i = 0; i < 16; i++ ) + { + ptr[i] = 0xabcd1234 + i; //Write to the memory + FLASH->CTLR = CR_PAGE_PG | FLASH_CTLR_BUF_LOAD; // Load the buffer. + while( FLASH->STATR & FLASH_STATR_BSY ); // Only needed if running from RAM. + } + stop = SysTick->CNT; + printf( "Write: %d cycles for writing data in\n", stop - start ); + + // Actually write the flash out. (Takes about 3ms) + FLASH->CTLR = CR_PAGE_PG|CR_STRT_Set; + + start = SysTick->CNT; + while( FLASH->STATR & FLASH_STATR_BSY ); + stop = SysTick->CNT; + printf( "FLASH->STATR = %08lx -> %d cycles for page write\n", FLASH->STATR, stop - start ); + + printf( "FLASH->STATR = %08lx\n", FLASH->STATR ); + + printf( "Memory at: %08lx: %08lx %08lx\n", (uint32_t)ptr, ptr[0], ptr[1] ); + + for( i = 0; i < 16; i++ ) + printf( "%08lx ", ptr[i] ); + printf( "\n" ); + while(1); +} + diff --git a/minichlink/ardulink.c b/minichlink/ardulink.c index cd28635be0d3b4999302c21056d41fb392400c6a..962061945387bb6537d10be21d99274a5f2fe14f 100644 --- a/minichlink/ardulink.c +++ b/minichlink/ardulink.c @@ -14,156 +14,159 @@ static int ArdulinkControl3v3(void * dev, int power_on); static int ArdulinkExit(void * dev); typedef struct { - struct ProgrammerStructBase psb; - serial_dev_t serial; + struct ProgrammerStructBase psb; + serial_dev_t serial; } ardulink_ctx_t; int ArdulinkWriteReg32(void * dev, uint8_t reg_7_bit, uint32_t command) { - uint8_t buf[6]; - buf[0] = 'w'; - buf[1] = reg_7_bit; + uint8_t buf[6]; + buf[0] = 'w'; + buf[1] = reg_7_bit; - //fprintf(stderr, "WriteReg32: 0x%02x = 0x%08x\n", reg_7_bit, command); + //fprintf(stderr, "WriteReg32: 0x%02x = 0x%08x\n", reg_7_bit, command); - buf[2] = command & 0xff; - buf[3] = (command >> 8) & 0xff; - buf[4] = (command >> 16) & 0xff; - buf[5] = (command >> 24) & 0xff; + buf[2] = command & 0xff; + buf[3] = (command >> 8) & 0xff; + buf[4] = (command >> 16) & 0xff; + buf[5] = (command >> 24) & 0xff; - if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, buf, 6) == -1) - return -errno; + if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, buf, 6) == -1) + return -errno; - if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, buf, 1) == -1) - return -errno; + if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, buf, 1) == -1) + return -errno; - return buf[0] == '+' ? 0 : -EPROTO; + return buf[0] == '+' ? 0 : -71; // EPROTO } int ArdulinkReadReg32(void * dev, uint8_t reg_7_bit, uint32_t * commandresp) { - uint8_t buf[4]; - buf[0] = 'r'; - buf[1] = reg_7_bit; + uint8_t buf[4]; + buf[0] = 'r'; + buf[1] = reg_7_bit; - if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, buf, 2) == -1) - return -errno; + if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, buf, 2) == -1) + return -errno; - if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, buf, 4) == -1) - return -errno; + if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, buf, 4) == -1) + return -errno; - *commandresp = (uint32_t)buf[0] | (uint32_t)buf[1] << 8 | \ - (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24; + *commandresp = (uint32_t)buf[0] | (uint32_t)buf[1] << 8 | \ + (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24; - //fprintf(stderr, "ReadReg32: 0x%02x = 0x%08x\n", reg_7_bit, *commandresp); + //fprintf(stderr, "ReadReg32: 0x%02x = 0x%08x\n", reg_7_bit, *commandresp); - return 0; + return 0; } int ArdulinkFlushLLCommands(void * dev) { - return 0; + return 0; } int ArdulinkControl3v3(void * dev, int power_on) { - char c; + char c; - fprintf(stderr, "Ardulink: target power %d\n", power_on); + fprintf(stderr, "Ardulink: target power %d\n", power_on); - c = power_on ? 'p' : 'P'; - if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, &c, 1) == -1) - return -errno; + c = power_on ? 'p' : 'P'; + if (serial_dev_write(&((ardulink_ctx_t*)dev)->serial, &c, 1) == -1) + return -errno; - if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, &c, 1) == -1) - return -errno; + if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, &c, 1) == -1) + return -errno; - if (c != '+') - return -EPROTO; + if (c != '+') + return -71; // EPROTO - usleep(20000); - return 0; + MCF.DelayUS(dev, 20000); + return 0; } int ArdulinkDelayUS(void * dev, int microseconds) { - //fprintf(stderr, "Ardulink: faking delay %d\n", microseconds); - //usleep(microseconds); - return 0; + //fprintf(stderr, "Ardulink: faking delay %d\n", microseconds); + //usleep(microseconds); + return 0; } int ArdulinkExit(void * dev) { - serial_dev_close(&((ardulink_ctx_t*)dev)->serial); - free(dev); - return 0; + serial_dev_close(&((ardulink_ctx_t*)dev)->serial); + free(dev); + return 0; } +int ArdulinkSetupInterface( void * dev ) +{ + char first; + // Let the bootloader do its thing. + MCF.DelayUS(dev, 3UL*1000UL*1000UL); + + if (serial_dev_read(&((ardulink_ctx_t*)dev)->serial, &first, 1) == -1) { + perror("read"); + return -1; + } + + if (first != '!') { + fprintf(stderr, "Ardulink: not the sync character.\n"); + return -1; + } +} void * TryInit_Ardulink(const init_hints_t* hints) { - ardulink_ctx_t *ctx; - char first; - - if (!(ctx = calloc(sizeof(ardulink_ctx_t), 1))) { - perror("calloc"); - return NULL; - } - - const char* serial_to_open = NULL; - // Get the serial port that shall be opened. - // First, if we have a directly set serial port hint, use that. - // Otherwise, use the environment variable MINICHLINK_SERIAL. - // If that also doesn't exist, fall back to the default serial. - if (hints && hints->serial_port != NULL) { - serial_to_open = hints->serial_port; - } - else if ((serial_to_open = getenv("MINICHLINK_SERIAL")) == NULL) { - // fallback - serial_to_open = DEFAULT_SERIAL_NAME; - } - - if (serial_dev_create(&ctx->serial, serial_to_open, 115200) == -1) { - perror("create"); - return NULL; - } - - if (serial_dev_open(&ctx->serial) == -1) { - perror("open"); - return NULL; - } - - // Arduino DTR reset. - if (serial_dev_do_dtr_reset(&ctx->serial) == -1) { - perror("dtr reset"); - return NULL; - } - - // Flush anything that might be in the RX buffer, we need the sync char. - if (serial_dev_flush_rx(&ctx->serial) == -1) { - perror("flush rx"); - return NULL; - } - - // Let the bootloader do its thing. - usleep(3UL*1000UL*1000UL); - - if (serial_dev_read(&ctx->serial, &first, 1) == -1) { - perror("read"); - return NULL; - } - - if (first != '!') { - fprintf(stderr, "Ardulink: not the sync character.\n"); - return NULL; - } - - fprintf(stderr, "Ardulink: synced.\n"); - - MCF.WriteReg32 = ArdulinkWriteReg32; + ardulink_ctx_t *ctx; + + if (!(ctx = calloc(sizeof(ardulink_ctx_t), 1))) { + perror("calloc"); + return NULL; + } + + const char* serial_to_open = NULL; + // Get the serial port that shall be opened. + // First, if we have a directly set serial port hint, use that. + // Otherwise, use the environment variable MINICHLINK_SERIAL. + // If that also doesn't exist, fall back to the default serial. + if (hints && hints->serial_port != NULL) { + serial_to_open = hints->serial_port; + } + else if ((serial_to_open = getenv("MINICHLINK_SERIAL")) == NULL) { + // fallback + serial_to_open = DEFAULT_SERIAL_NAME; + } + + if (serial_dev_create(&ctx->serial, serial_to_open, 115200) == -1) { + perror("create"); + return NULL; + } + + if (serial_dev_open(&ctx->serial) == -1) { + perror("open"); + return NULL; + } + + // Arduino DTR reset. + if (serial_dev_do_dtr_reset(&ctx->serial) == -1) { + perror("dtr reset"); + return NULL; + } + + // Flush anything that might be in the RX buffer, we need the sync char. + if (serial_dev_flush_rx(&ctx->serial) == -1) { + perror("flush rx"); + return NULL; + } + + fprintf(stderr, "Ardulink: synced.\n"); + + MCF.WriteReg32 = ArdulinkWriteReg32; MCF.ReadReg32 = ArdulinkReadReg32; - MCF.FlushLLCommands = ArdulinkFlushLLCommands; - MCF.Control3v3 = ArdulinkControl3v3; - MCF.DelayUS = ArdulinkDelayUS; + MCF.FlushLLCommands = ArdulinkFlushLLCommands; + MCF.Control3v3 = ArdulinkControl3v3; + MCF.DelayUS = ArdulinkDelayUS; MCF.Exit = ArdulinkExit; + MCF.SetupInterface = ArdulinkSetupInterface; return ctx; } diff --git a/minichlink/hidapi.c b/minichlink/hidapi.c index 1056c56104437fa54021e88f0fd33c20c8751f4a..04c6dced558f81fddba17a240c6dee98aa1c4e2d 100644 --- a/minichlink/hidapi.c +++ b/minichlink/hidapi.c @@ -2202,6 +2202,8 @@ int main(void) #include "hidapi.h" +int g_hidapiSuppress; + /* Definitions from linux/hidraw.h. Since these are new, some distros may not have header files which contain them. */ #ifndef HIDIOCSFEATURE @@ -2796,14 +2798,14 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path) /* Get Report Descriptor Size */ res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size); - if (res < 0) + if (res < 0 && !g_hidapiSuppress) perror("HIDIOCGRDESCSIZE"); /* Get Report Descriptor */ rpt_desc.size = desc_size; res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc); - if (res < 0) { + if (res < 0 && !g_hidapiSuppress) { perror("HIDIOCGRDESC"); } else { /* Determine if this device uses numbered reports. */ @@ -2899,7 +2901,7 @@ int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char int res; res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data); - if (res < 0) + if (res < 0 && !g_hidapiSuppress) perror("ioctl (SFEATURE)"); return res; @@ -2910,7 +2912,7 @@ int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, int res; res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data); - if (res < 0) + if (res < 0 && !g_hidapiSuppress) perror("ioctl (GFEATURE)"); diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index efbda9d45331da8595d35d04766adeec56318295..0abb1ff5441d6c34c3593b22a156d198a2628e00 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -20,7 +20,6 @@ void Sleep(uint32_t dwMilliseconds); static int64_t StringToMemoryAddress( const char * number ) __attribute__((used)); static void StaticUpdatePROGBUFRegs( void * dev ) __attribute__((used)); -static int InternalUnlockBootloader( void * dev ) __attribute__((used)); int DefaultReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob ); void TestFunction(void * v ); @@ -55,7 +54,16 @@ void * MiniCHLinkInitAsDLL( struct MiniChlinkFunctions ** MCFO, const init_hints return 0; } + struct InternalState * iss = calloc( 1, sizeof( struct InternalState ) ); + ((struct ProgrammerStructBase*)dev)->internal = iss; + iss->ram_base = 0x20000000; + iss->ram_size = 2048; + iss->sector_size = 64; + iss->flash_size = 16384; + iss->target_chip_type = 0; + SetupAutomaticHighLevelFunctions( dev ); + if( MCFO ) { *MCFO = &MCF; @@ -63,37 +71,30 @@ void * MiniCHLinkInitAsDLL( struct MiniChlinkFunctions ** MCFO, const init_hints return dev; } -void parse_possible_init_hints(int argc, char **argv, init_hints_t *hints) -{ - if (!hints) - return; - int c; - opterr = 0; - /* we're only interested in the value for the COM port, given in a -c parameter */ - /* the '-' is really important so that getopt does not permutate the argv array and messes up parsing later */ - while ((c = getopt(argc, argv, "-c:")) != -1) - { - switch (c) - { - case 'c': - // we can use the pointer as-is because it points in our - // argv array and that is stable. - hints->serial_port = optarg; - break; - } - } -} - #if !defined( MINICHLINK_AS_LIBRARY ) && !defined( MINICHLINK_IMPORT ) int main( int argc, char ** argv ) { + int i; + if( argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h' ) { goto help; } init_hints_t hints; memset(&hints, 0, sizeof(hints)); - parse_possible_init_hints(argc, argv, &hints); + + // Scan for possible hints. + for( i = 0; i < argc; i++ ) + { + char * v = argv[i]; + if( strncmp( v, "-c", 2 ) == 0 ) + { + i++; + if( i < argc ) + hints.serial_port = argv[i]; + } + } + void * dev = MiniCHLinkInitAsDLL( 0, &hints ); if( !dev ) { @@ -194,55 +195,55 @@ keep_going: goto unimplemented; break; case 'b': //reBoot - if( !MCF.HaltMode || MCF.HaltMode( dev, 1 ) ) + if( !MCF.HaltMode || MCF.HaltMode( dev, HALT_MODE_REBOOT ) ) goto unimplemented; break; case 'B': //reBoot into Bootloader - if( !MCF.HaltMode || MCF.HaltMode( dev, 3 ) ) + if( !MCF.HaltMode || MCF.HaltMode( dev, HALT_MODE_GO_TO_BOOTLOADER ) ) goto unimplemented; break; case 'e': //rEsume - if( !MCF.HaltMode || MCF.HaltMode( dev, 2 ) ) + if( !MCF.HaltMode || MCF.HaltMode( dev, HALT_MODE_RESUME ) ) goto unimplemented; break; case 'E': //Erase whole chip. - if( MCF.HaltMode ) MCF.HaltMode( dev, 0 ); + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ); if( !MCF.Erase || MCF.Erase( dev, 0, 0, 1 ) ) goto unimplemented; break; case 'a': - if( !MCF.HaltMode || MCF.HaltMode( dev, 0 ) ) + if( !MCF.HaltMode || MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ) ) goto unimplemented; break; case 'A': // Halt without reboot - if( !MCF.HaltMode || MCF.HaltMode( dev, 5 ) ) + if( !MCF.HaltMode || MCF.HaltMode( dev, HALT_MODE_HALT_BUT_NO_RESET ) ) goto unimplemented; break; // disable NRST pin (turn it into a GPIO) case 'd': // see "RSTMODE" in datasheet - if( MCF.HaltMode ) MCF.HaltMode( dev, 0 ); + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ); if( MCF.ConfigureNRSTAsGPIO ) MCF.ConfigureNRSTAsGPIO( dev, 0 ); else goto unimplemented; break; case 'D': // see "RSTMODE" in datasheet - if( MCF.HaltMode ) MCF.HaltMode( dev, 0 ); + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ); if( MCF.ConfigureNRSTAsGPIO ) MCF.ConfigureNRSTAsGPIO( dev, 1 ); else goto unimplemented; break; case 'p': - if( MCF.HaltMode ) MCF.HaltMode( dev, 0 ); + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ); if( MCF.ConfigureReadProtection ) MCF.ConfigureReadProtection( dev, 0 ); else goto unimplemented; break; case 'P': - if( MCF.HaltMode ) MCF.HaltMode( dev, 0 ); + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_AND_RESET ); if( MCF.ConfigureReadProtection ) MCF.ConfigureReadProtection( dev, 1 ); else @@ -263,11 +264,10 @@ keep_going: { printf( "GDBServer Running\n" ); } - else + else if( argchar[1] == 'T' ) { // In case we aren't running already. - //MCF.HaltMode( dev, 2 ); - //XXX TODO: Why do some programmers start automatically, and others don't? + MCF.HaltMode( dev, 2 ); } do @@ -385,7 +385,7 @@ keep_going: } case 'r': { - if( MCF.HaltMode ) MCF.HaltMode( dev, 5 ); //No need to reboot. + if( MCF.HaltMode ) MCF.HaltMode( dev, HALT_MODE_HALT_BUT_NO_RESET ); //No need to reboot. if( argchar[2] != 0 ) { @@ -463,6 +463,7 @@ keep_going: } case 'w': { + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); if( argchar[2] != 0 ) goto help; iarg++; argchar = 0; // Stop advancing @@ -543,14 +544,14 @@ keep_going: fprintf( stderr, "Error: File I/O Fault.\n" ); exit( -10 ); } - if( len > 16384 ) + if( len > iss->flash_size ) { fprintf( stderr, "Error: Image for CH32V003 too large (%d)\n", len ); exit( -9 ); } - int is_flash = ( offset & 0xff000000 ) == 0x08000000 || ( offset & 0x1FFFF800 ) == 0x1FFFF000; - if( MCF.HaltMode ) MCF.HaltMode( dev, is_flash?0:5 ); + int is_flash = IsAddressFlash( offset ); + if( MCF.HaltMode ) MCF.HaltMode( dev, is_flash ? HALT_MODE_HALT_AND_RESET : HALT_MODE_HALT_BUT_NO_RESET ); if( MCF.WriteBinaryBlob ) { @@ -593,6 +594,7 @@ help: fprintf( stderr, " -f Disable 5V\n" ); fprintf( stderr, " -c [serial port for Ardulink, try /dev/ttyACM0 or COM11 etc]\n" ); fprintf( stderr, " -u Clear all code flash - by power off (also can unbrick)\n" ); + fprintf( stderr, " -E Erase chip\n" ); fprintf( stderr, " -b Reboot out of Halt\n" ); fprintf( stderr, " -e Resume from halt\n" ); fprintf( stderr, " -a Reboot into Halt\n" ); @@ -624,8 +626,6 @@ unimplemented: #define strtoll _strtoi64 #endif -static int StaticUnlockFlash( void * dev, struct InternalState * iss ); - int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber ) { if( !number || !number[0] ) return defaultNumber; @@ -680,7 +680,7 @@ static int DefaultWaitForFlash( void * dev ) rw = 0; MCF.ReadWord( dev, (intptr_t)&FLASH->STATR, &rw ); // FLASH_STATR => 0x4002200C if( timeout++ > 100 ) return -1; - } while(rw & 1); // BSY flag. + } while(rw & 3); // BSY flag for 003, or WRBSY for other processors. if( rw & FLASH_STATR_WRPRTERR ) { @@ -734,7 +734,7 @@ int DefaultSetupInterface( void * dev ) struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); if( MCF.Control3v3 ) MCF.Control3v3( dev, 1 ); - if( MCF.DelayUS ) MCF.DelayUS( dev, 16000 ); + MCF.DelayUS( dev, 16000 ); MCF.WriteReg32( dev, DMSHDWCFGR, 0x5aa50000 | (1<<10) ); // Shadow Config Reg MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // CFGR (1<<10 == Allow output from slave) MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // Bug in silicon? If coming out of cold boot, and we don't do our little "song and dance" this has to be called. @@ -780,7 +780,7 @@ static void StaticUpdatePROGBUFRegs( void * dev ) MCF.WriteReg32( dev, DMCOMMAND, 0x0023100d ); // Copy data to x13 } -static int InternalUnlockBootloader( void * dev ) +int InternalUnlockBootloader( void * dev ) { if( !MCF.WriteWord ) return -99; int ret = 0; @@ -805,6 +805,23 @@ static int InternalUnlockBootloader( void * dev ) } +int InternalIsMemoryErased( struct InternalState * iss, uint32_t address ) +{ + if(( address & 0xff000000 ) != 0x08000000 ) return 0; + int sector = (address & 0xffffff) / iss->sector_size; + if( sector >= MAX_FLASH_SECTORS ) + return 0; + else + return iss->flash_sector_status[sector]; +} + +void InternalMarkMemoryNotErased( struct InternalState * iss, uint32_t address ) +{ + if(( address & 0xff000000 ) != 0x08000000 ) return; + int sector = (address & 0xffffff) / iss->sector_size; + if( sector < MAX_FLASH_SECTORS ) + iss->flash_sector_status[sector] = 0; +} static int DefaultWriteHalfWord( void * dev, uint32_t address_to_write, uint16_t data ) { @@ -924,12 +941,7 @@ static int DefaultWriteWord( void * dev, uint32_t address_to_write, uint32_t dat struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); int ret = 0; - int is_flash = 0; - if( ( address_to_write & 0xff000000 ) == 0x08000000 || ( address_to_write & 0x1FFFF800 ) == 0x1FFFF000 ) - { - // Is flash. - is_flash = 1; - } + int is_flash = IsAddressFlash( address_to_write ); if( iss->statetag != STTAG( "WRSQ" ) || is_flash != iss->lastwriteflags ) { @@ -1023,17 +1035,24 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob uint32_t rw; struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); - int is_flash = 0; + int sectorsize = iss->sector_size; + + // We can't write into flash when mapped to 0x00000000 + if( address_to_write < 0x01000000 ) + address_to_write |= 0x08000000; + + int is_flash = IsAddressFlash( address_to_write ); if( blob_size == 0 ) return 0; - if( (address_to_write & 0xff000000) == 0x08000000 || (address_to_write & 0xff000000) == 0x00000000 || (address_to_write & 0x1FFFF800) == 0x1FFFF000 ) - is_flash = 1; - // We can't write into flash when mapped to 0x00000000 - if( is_flash ) - address_to_write |= 0x08000000; + if( is_flash && !iss->flash_unlocked ) + { + if( ( rw = InternalUnlockFlash( dev, iss ) ) ) + return rw; + } + // Regardless of sector size, allow block write to do its thing if it can. if( is_flash && MCF.BlockWrite64 && ( address_to_write & 0x3f ) == 0 && ( blob_size & 0x3f ) == 0 ) { int i; @@ -1049,50 +1068,48 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob return 0; } - if( is_flash && !iss->flash_unlocked ) - { - if( ( rw = StaticUnlockFlash( dev, iss ) ) ) - return rw; - } - - - uint8_t tempblock[64]; - int sblock = address_to_write >> 6; - int eblock = ( address_to_write + blob_size + 0x3f) >> 6; + uint8_t tempblock[sectorsize]; + int sblock = address_to_write / sectorsize; + int eblock = ( address_to_write + blob_size + (sectorsize-1) ) / sectorsize; int b; int rsofar = 0; for( b = sblock; b < eblock; b++ ) { - int offset_in_block = address_to_write - (b * 64); + int offset_in_block = address_to_write - (b * sectorsize); if( offset_in_block < 0 ) offset_in_block = 0; - int end_o_plus_one_in_block = ( address_to_write + blob_size ) - (b*64); - if( end_o_plus_one_in_block > 64 ) end_o_plus_one_in_block = 64; - int base = b * 64; + int end_o_plus_one_in_block = ( address_to_write + blob_size ) - (b*sectorsize); + if( end_o_plus_one_in_block > sectorsize ) end_o_plus_one_in_block = sectorsize; + int base = b * sectorsize; - if( offset_in_block == 0 && end_o_plus_one_in_block == 64 ) + if( offset_in_block == 0 && end_o_plus_one_in_block == sectorsize ) { - if( MCF.BlockWrite64 ) + if( MCF.BlockWrite64 ) { - int r = MCF.BlockWrite64( dev, base, blob + rsofar ); - rsofar += 64; - if( r ) + int i; + for( i = 0; i < sectorsize/64; i++ ) { - fprintf( stderr, "Error writing block at memory %08x (error = %d)\n", base, r ); - return r; + int r = MCF.BlockWrite64( dev, base + i*64, blob + rsofar+i*64 ); + rsofar += 64; + if( r ) + { + fprintf( stderr, "Error writing block at memory %08x (error = %d)\n", base, r ); + return r; + } } } else // Block Write not avaialble { if( is_flash ) { - MCF.Erase( dev, base, 64, 0 ); + if( !InternalIsMemoryErased( iss, base ) ) + MCF.Erase( dev, base, sectorsize, 0 ); MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG ); // THIS IS REQUIRED, (intptr_t)&FLASH->CTLR = 0x40022010 MCF.WriteWord( dev, 0x40022010, CR_BUF_RST | CR_PAGE_PG ); // (intptr_t)&FLASH->CTLR = 0x40022010 } int j; - for( j = 0; j < 16; j++ ) + for( j = 0; j < sectorsize/4; j++ ) { uint32_t writeword; memcpy( &writeword, blob + rsofar, 4 ); @@ -1103,8 +1120,10 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob if( is_flash ) { MCF.WriteWord( dev, 0x40022014, base ); //0x40022014 -> FLASH->ADDR + if( MCF.PrepForLongOp ) MCF.PrepForLongOp( dev ); // Give the programmer a headsup this next operation could take a while. MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG|CR_STRT_Set ); // 0x40022010 -> FLASH->CTLR if( MCF.WaitForFlash ) MCF.WaitForFlash( dev ); + InternalMarkMemoryNotErased( iss, base ); } } } @@ -1113,7 +1132,7 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob //Ok, we have to do something wacky. if( is_flash ) { - MCF.ReadBinaryBlob( dev, base, 64, tempblock ); + MCF.ReadBinaryBlob( dev, base, sectorsize, tempblock ); // Permute tempblock int tocopy = end_o_plus_one_in_block - offset_in_block; @@ -1122,23 +1141,29 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob if( MCF.BlockWrite64 ) { - int r = MCF.BlockWrite64( dev, base, tempblock ); - if( r ) return r; + int i; + for( i = 0; i < sectorsize/64; i++ ) + { + int r = MCF.BlockWrite64( dev, base+i*64, tempblock+i*64 ); + if( r ) return r; + } } else { - MCF.Erase( dev, base, 64, 0 ); + if( !InternalIsMemoryErased( iss, base ) ) + MCF.Erase( dev, base, sectorsize, 0 ); MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG ); // THIS IS REQUIRED, (intptr_t)&FLASH->CTLR = 0x40022010 MCF.WriteWord( dev, 0x40022010, CR_BUF_RST | CR_PAGE_PG ); // (intptr_t)&FLASH->CTLR = 0x40022010 int j; - for( j = 0; j < 16; j++ ) + for( j = 0; j < sectorsize/4; j++ ) { MCF.WriteWord( dev, j*4+base, *(uint32_t*)(tempblock + j * 4) ); rsofar += 4; } MCF.WriteWord( dev, 0x40022014, base ); //0x40022014 -> FLASH->ADDR MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG|CR_STRT_Set ); // 0x40022010 -> FLASH->CTLR + InternalMarkMemoryNotErased( iss, base ); } if( MCF.WaitForFlash && MCF.WaitForFlash( dev ) ) goto timedout; } @@ -1146,7 +1171,7 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob { // Accessing RAM. Be careful to only do the needed operations. int j; - for( j = 0; j < 16; j++ ) + for( j = 0; j < sectorsize; j++ ) { uint32_t taddy = j*4; if( offset_in_block <= taddy && end_o_plus_one_in_block >= taddy + 4 ) @@ -1206,7 +1231,7 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob } #endif - if(MCF.DelayUS) MCF.DelayUS( dev, 100 ); // Why do we need this? (We seem to need this on the WCH programmers?) + MCF.DelayUS( dev, 100 ); // Why do we need this? (We seem to need this on the WCH programmers?) return 0; timedout: fprintf( stderr, "Timed out\n" ); @@ -1277,21 +1302,29 @@ static int DefaultReadWord( void * dev, uint32_t address_to_read, uint32_t * dat return r; } -static int StaticUnlockFlash( void * dev, struct InternalState * iss ) +int InternalUnlockFlash( void * dev, struct InternalState * iss ) { + int ret = 0; uint32_t rw; - MCF.ReadWord( dev, 0x40022010, &rw ); // FLASH->CTLR = 0x40022010 + ret = MCF.ReadWord( dev, 0x40022010, &rw ); // FLASH->CTLR = 0x40022010 if( rw & 0x8080 ) { + ret = MCF.WriteWord( dev, 0x40022004, 0x45670123 ); // FLASH->KEYR = 0x40022004 + if( ret ) goto reterr; + ret = MCF.WriteWord( dev, 0x40022004, 0xCDEF89AB ); + if( ret ) goto reterr; + ret = MCF.WriteWord( dev, 0x40022008, 0x45670123 ); // OBKEYR = 0x40022008 + if( ret ) goto reterr; + ret = MCF.WriteWord( dev, 0x40022008, 0xCDEF89AB ); + if( ret ) goto reterr; + ret = MCF.WriteWord( dev, 0x40022024, 0x45670123 ); // MODEKEYR = 0x40022024 + if( ret ) goto reterr; + ret = MCF.WriteWord( dev, 0x40022024, 0xCDEF89AB ); + if( ret ) goto reterr; + + ret = MCF.ReadWord( dev, 0x40022010, &rw ); // FLASH->CTLR = 0x40022010 + if( ret ) goto reterr; - MCF.WriteWord( dev, 0x40022004, 0x45670123 ); // FLASH->KEYR = 0x40022004 - MCF.WriteWord( dev, 0x40022004, 0xCDEF89AB ); - MCF.WriteWord( dev, 0x40022008, 0x45670123 ); // OBKEYR = 0x40022008 - MCF.WriteWord( dev, 0x40022008, 0xCDEF89AB ); - MCF.WriteWord( dev, 0x40022024, 0x45670123 ); // MODEKEYR = 0x40022024 - MCF.WriteWord( dev, 0x40022024, 0xCDEF89AB ); - - MCF.ReadWord( dev, 0x40022010, &rw ); // FLASH->CTLR = 0x40022010 if( rw & 0x8080 ) { fprintf( stderr, "Error: Flash is not unlocked (CTLR = %08x)\n", rw ); @@ -1300,6 +1333,9 @@ static int StaticUnlockFlash( void * dev, struct InternalState * iss ) } iss->flash_unlocked = 1; return 0; +reterr: + fprintf( stderr, "Error unlocking flash, got code %d from underlying system\n", ret ); + return ret; } int DefaultErase( void * dev, uint32_t address, uint32_t length, int type ) @@ -1309,9 +1345,8 @@ int DefaultErase( void * dev, uint32_t address, uint32_t length, int type ) if( !iss->flash_unlocked ) { - if( ( rw = StaticUnlockFlash( dev, iss ) ) ) + if( ( rw = InternalUnlockFlash( dev, iss ) ) ) return rw; - printf( "Flash unlocked\n" ); } if( type == 1 ) @@ -1319,37 +1354,47 @@ int DefaultErase( void * dev, uint32_t address, uint32_t length, int type ) // Whole-chip flash iss->statetag = STTAG( "XXXX" ); printf( "Whole-chip erase\n" ); - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, 0 ); - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, FLASH_CTLR_MER ); - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_STRT_Set|FLASH_CTLR_MER ); + if( MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, 0 ) ) goto flashoperr; + if( MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, FLASH_CTLR_MER ) ) goto flashoperr; + if( MCF.PrepForLongOp ) MCF.PrepForLongOp( dev ); // Give the programmer a headsup this next operation could take a while. + if( MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_STRT_Set|FLASH_CTLR_MER ) ) goto flashoperr; rw = MCF.WaitForDoneOp( dev, 0 ); if( MCF.WaitForFlash && MCF.WaitForFlash( dev ) ) { fprintf( stderr, "Error: Wait for flash error.\n" ); return -11; } - rw = MCF.WaitForDoneOp( dev, 0 ); - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, 0 ); - rw = MCF.WaitForDoneOp( dev, 0 ); - fprintf( stderr, "Whole Chip Erase Code: %d\n", rw ); + MCF.VoidHighLevelState( dev ); + memset( iss->flash_sector_status, 1, sizeof( iss->flash_sector_status ) ); } else { // 16.4.7, Step 3: Check the BSY bit of the FLASH_STATR register to confirm that there are no other programming operations in progress. // skip (we make sure at the end) - int chunk_to_erase = address; - while( chunk_to_erase < address + length ) { + if( ( chunk_to_erase & 0xff000000 ) == 0x08000000 ) + { + int sector = ( chunk_to_erase & 0x00ffffff ) / iss->sector_size; + if( sector < MAX_FLASH_SECTORS ) + { + iss->flash_sector_status[sector] = 1; + } + } + // Step 4: set PAGE_ER of FLASH_CTLR(0x40022010) - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_PAGE_ER ); // Actually FTER + if( MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_PAGE_ER ) ) goto flashoperr; // Actually FTER // Step 5: Write the first address of the fast erase page to the FLASH_ADDR register. - MCF.WriteWord( dev, (intptr_t)&FLASH->ADDR, chunk_to_erase ); - + if( MCF.WriteWord( dev, (intptr_t)&FLASH->ADDR, chunk_to_erase ) ) goto flashoperr; // Step 6: Set the STAT bit of FLASH_CTLR register to '1' to initiate a fast page erase (64 bytes) action. - MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_STRT_Set | CR_PAGE_ER ); + if( MCF.PrepForLongOp ) MCF.PrepForLongOp( dev ); // Give the programmer a headsup this next operation could take a while. + if( MCF.WriteWord( dev, (intptr_t)&FLASH->CTLR, CR_STRT_Set | CR_PAGE_ER ) ) goto flashoperr; if( MCF.WaitForFlash && MCF.WaitForFlash( dev ) ) return -99; - chunk_to_erase+=64; + chunk_to_erase+=iss->sector_size; } } + return 0; +flashoperr: + fprintf( stderr, "Error: Flash operation error\n" ); + return -93; } int DefaultReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob ) @@ -1518,27 +1563,26 @@ static int DefaultHaltMode( void * dev, int mode ) struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); switch ( mode ) { - case 5: // Don't reboot. - case 0: + case HALT_MODE_HALT_BUT_NO_RESET: // Don't reboot. + case HALT_MODE_HALT_AND_RESET: MCF.WriteReg32( dev, DMSHDWCFGR, 0x5aa50000 | (1<<10) ); // Shadow Config Reg MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // CFGR (1<<10 == Allow output from slave) MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // Bug in silicon? If coming out of cold boot, and we don't do our little "song and dance" this has to be called. MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. if( mode == 0 ) MCF.WriteReg32( dev, DMCONTROL, 0x80000003 ); // Reboot. MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Re-initiate a halt request. - // MCF.WriteReg32( dev, DMCONTROL, 0x00000001 ); // Clear Halt Request. This is recommended, but not doing it seems more stable. // Sometimes, even if the processor is halted but the MSB is clear, it will spuriously start? MCF.FlushLLCommands( dev ); break; - case 1: + case HALT_MODE_REBOOT: MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request. MCF.WriteReg32( dev, DMCONTROL, 0x80000003 ); // Reboot. MCF.WriteReg32( dev, DMCONTROL, 0x40000001 ); // resumereq MCF.FlushLLCommands( dev ); break; - case 2: + case HALT_MODE_RESUME: MCF.WriteReg32( dev, DMSHDWCFGR, 0x5aa50000 | (1<<10) ); // Shadow Config Reg MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // CFGR (1<<10 == Allow output from slave) MCF.WriteReg32( dev, DMCFGR, 0x5aa50000 | (1<<10) ); // Bug in silicon? If coming out of cold boot, and we don't do our little "song and dance" this has to be called. @@ -1546,7 +1590,7 @@ static int DefaultHaltMode( void * dev, int mode ) MCF.WriteReg32( dev, DMCONTROL, 0x40000001 ); // resumereq MCF.FlushLLCommands( dev ); break; - case 3: + case HALT_MODE_GO_TO_BOOTLOADER: MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request. @@ -1564,18 +1608,13 @@ static int DefaultHaltMode( void * dev, int mode ) default: fprintf( stderr, "Error: Unknown halt mode %d\n", mode ); } -#if 0 - int i; - for( i = 0; i < 100; i++ ) - { - uint32_t temp = 0; - MCF.ReadReg32( dev, DMSTATUS, &temp ); - fprintf( stderr, "DMSTATUS: %08x\n", temp ); - usleep( 20000); - } -#endif + iss->flash_unlocked = 0; iss->processor_in_mode = mode; + + // In case processor halt process needs to complete, i.e. if it was in the middle of a flash op. + MCF.DelayUS( dev, 3000 ); + return 0; } @@ -1596,7 +1635,6 @@ int DefaultPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leav } r = MCF.ReadReg32( dev, DMDATA0, &rr ); if( r < 0 ) return r; - if( maxlen < 8 ) return -9; // DMDATA1: @@ -1632,10 +1670,9 @@ int DefaultPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leav int DefaultUnbrick( void * dev ) { - // TODO: Why doesn't this work on the ESP32S2? - printf( "Entering Unbrick Mode\n" ); MCF.Control3v3( dev, 0 ); + MCF.DelayUS( dev, 60000 ); MCF.DelayUS( dev, 60000 ); MCF.DelayUS( dev, 60000 ); @@ -1673,16 +1710,7 @@ int DefaultUnbrick( void * dev ) // After more experimentation, it appaers to work best by not clearing the halt request. MCF.FlushLLCommands( dev ); - if( MCF.DelayUS ) - MCF.DelayUS( dev, 20000 ); - else - { -#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32) - Sleep(20); -#else - usleep(20000); -#endif - } + MCF.DelayUS( dev, 20000 ); if( timeout == max_timeout ) { @@ -1698,138 +1726,6 @@ 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, 0 ); - 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, 0 ); - ret |= MCF.WaitForFlash( dev ); - ctlr |= CR_OPTPG_Set; - MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 - ret |= MCF.WaitForDoneOp( dev, 0 ); - ret |= MCF.WaitForFlash( dev ); - ctlr &=~CR_OPTPG_Reset; - MCF.WriteWord( dev, 0x40022010, ctlr ); // FLASH->CTLR = 0x40022010 - ret |= MCF.WaitForDoneOp( dev, 0 ); - 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, 0 ); - 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, 0 ); - 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, 0 ); - 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, 0 ); - 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 DefaultConfigureReadProtection( void * dev, int one_if_yes_protect ) @@ -1841,7 +1737,7 @@ int DefaultConfigureReadProtection( void * dev, int one_if_yes_protect ) int DefaultPrintChipInfo( void * dev ) { uint32_t reg; - MCF.HaltMode( dev, 5 ); + MCF.HaltMode( dev, HALT_MODE_HALT_BUT_NO_RESET ); if( MCF.ReadWord( dev, 0x1FFFF800, ® ) ) goto fail; printf( "USER/RDPR : %04x/%04x\n", reg>>16, reg&0xFFFF ); @@ -1872,10 +1768,20 @@ int DefaultVoidHighLevelState( void * dev ) return 0; } +int DefaultDelayUS( void * dev, int us ) +{ +#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32) + Sleep( (us+9999) / 1000 ); +#else + usleep( us ); +#endif + return 0; +} + int SetupAutomaticHighLevelFunctions( void * dev ) { // Will populate high-level functions from low-level functions. - if( MCF.WriteReg32 == 0 || MCF.ReadReg32 == 0 ) return -5; + if( MCF.WriteReg32 == 0 && MCF.ReadReg32 == 0 && MCF.WriteWord == 0 ) return -5; // Else, TODO: Build the high level functions from low level functions. // If a high-level function alrady exists, don't override. @@ -1926,12 +1832,9 @@ int SetupAutomaticHighLevelFunctions( void * dev ) MCF.ConfigureNRSTAsGPIO = DefaultConfigureNRSTAsGPIO; if( !MCF.VoidHighLevelState ) MCF.VoidHighLevelState = DefaultVoidHighLevelState; + if( !MCF.DelayUS ) + MCF.DelayUS = DefaultDelayUS; - struct InternalState * iss = calloc( 1, sizeof( struct InternalState ) ); - iss->ram_base = 0x20000000; - iss->ram_size = 2048; - - ((struct ProgrammerStructBase*)dev)->internal = iss; return 0; } @@ -1988,3 +1891,5 @@ void TestFunction(void * dev ) } } + + diff --git a/minichlink/minichlink.exe b/minichlink/minichlink.exe index a52fdbc65872c0fc70a1facfb7fa9cbe22a35552..d3404712091bdd8dcc125d58deeb556c528a3c93 100644 Binary files a/minichlink/minichlink.exe and b/minichlink/minichlink.exe differ diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h index c5f3bcba8fa1c2bf29f10a44a306f736a37ed4a3..dfdb2447ec9661a1af0ed0a095a6a9a600257d53 100644 --- a/minichlink/minichlink.h +++ b/minichlink/minichlink.h @@ -50,18 +50,15 @@ struct MiniChlinkFunctions int (*SetEnableBreakpoints)( void * dev, int halt_on_break, int single_step ); + int (*PrepForLongOp)( void * dev ); // Called before the command that will take a while. int (*WaitForFlash)( void * dev ); int (*WaitForDoneOp)( void * dev, int ignore ); int (*PrintChipInfo)( void * dev ); - // Geared for flash, but could be anything. + // Geared for flash, but could be anything. Note: If in flash, must also erase. int (*BlockWrite64)( void * dev, uint32_t address_to_write, uint8_t * data ); - // TODO: What about 64-byte block-reads? - // TODO: What about byte read/write? - // TODO: What about half read/write? - // Returns positive if received text. // Returns negative if error. // Returns 0 if no text waiting. @@ -86,6 +83,14 @@ struct MiniChlinkFunctions FlushLLCommands */ +inline static int IsAddressFlash( uint32_t addy ) { return ( addy & 0xff000000 ) == 0x08000000 || ( addy & 0x1FFFF800 ) == 0x1FFFF000; } + +#define HALT_MODE_HALT_AND_RESET 0 +#define HALT_MODE_REBOOT 1 +#define HALT_MODE_RESUME 2 +#define HALT_MODE_GO_TO_BOOTLOADER 3 +#define HALT_MODE_HALT_BUT_NO_RESET 5 + // Convert a 4-character string to an int. #define STTAG( x ) (*((uint32_t*)(x))) @@ -97,6 +102,8 @@ struct ProgrammerStructBase // You can put other things here. }; +#define MAX_FLASH_SECTORS 262144 + struct InternalState { uint32_t statetag; @@ -107,6 +114,10 @@ struct InternalState int autoincrement; uint32_t ram_base; uint32_t ram_size; + int sector_size; + int flash_size; + int target_chip_type; // 0 for unknown (or 003), otherwise a part number. + uint8_t flash_sector_status[MAX_FLASH_SECTORS]; // 0 means unerased/unknown. 1 means erased. }; @@ -168,6 +179,10 @@ int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber ); // For drivers to call int DefaultVoidHighLevelState( void * dev ); +int InternalUnlockBootloader( void * dev ); +int InternalIsMemoryErased( struct InternalState * iss, uint32_t address ); +void InternalMarkMemoryNotErased( struct InternalState * iss, uint32_t address ); +int InternalUnlockFlash( void * dev, struct InternalState * iss ); // GDBSever Functions int SetupGDBServer( void * dev ); diff --git a/minichlink/pgm-b003fun.c b/minichlink/pgm-b003fun.c index 5e37aea3fc5b653577934ccb4fa626c0865592a9..a1681087a842e39d941c19a61872bb26cf8b13de 100644 --- a/minichlink/pgm-b003fun.c +++ b/minichlink/pgm-b003fun.c @@ -1,26 +1,224 @@ -#if 0 #include <stdint.h> #include "hidapi.h" #include "minichlink.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "../ch32v003fun/ch32v003fun.h" + +//#define DEBUG_B003 + +#if defined(WINDOWS) || defined(WIN32) || defined(_WIN32) +void Sleep(uint32_t dwMilliseconds); +#define usleep( x ) Sleep( x / 1000 ); +#else +#include <unistd.h> +#endif struct B003FunProgrammerStruct { - void * internal; + void * internal; // Part of struct ProgrammerStructBase + hid_device * hd; uint8_t commandbuffer[128]; + uint8_t respbuffer[128]; int commandplace; + int prepping_for_erase; +}; + +static const unsigned char byte_wise_read_blob[] = { // No alignment restrictions. + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x94, 0x21, 0x14, 0xa3, 0x85, 0x05, 0x05, 0x07, + 0xe3, 0xcc, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, 0x14, 0xc1, 0x82, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char half_wise_read_blob[] = { // size and address must be aligned by 2. + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x96, 0x21, 0x16, 0xa3, 0x89, 0x05, 0x09, 0x07, + 0xe3, 0xcc, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, 0x14, 0xc1, 0x82, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char word_wise_read_blob[] = { // size and address must be aligned by 4. + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x94, 0x41, 0x14, 0xc3, 0x91, 0x05, 0x11, 0x07, + 0xe3, 0xcc, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, 0x14, 0xc1, 0x82, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static const unsigned char word_wise_write_blob[] = { // size and address must be aligned by 4. + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x14, 0x43, 0x94, 0xc1, 0x91, 0x05, 0x11, 0x07, + 0xe3, 0xcc, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, 0x14, 0xc1, 0x82, 0x80, // NOTE: No readback! + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* - uint32_t state; - uint8_t reply[256]; - int replylen; -*/ + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x14, 0x43, 0x94, 0xc1, 0x94, 0x41, 0x14, 0xc3, // With readback. + 0x91, 0x05, 0x11, 0x07, 0xe3, 0xca, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, + 0x14, 0xc1, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 */ +}; + +static const unsigned char write64_flash[] = { // size and address must be aligned by 4. + 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x13, 0x86, 0x05, 0x04, 0x5c, 0x43, + 0x8c, 0xc7, 0x14, 0x47, 0x94, 0xc1, 0xb7, 0x06, 0x05, 0x00, 0xd4, 0xc3, + 0x94, 0x41, 0x91, 0x05, 0x11, 0x07, 0xe3, 0xc8, 0xc5, 0xfe, 0xc1, 0x66, + 0x93, 0x86, 0x06, 0x04, 0xd4, 0xc3, 0xfd, 0x56, 0x14, 0xc1, 0x82, 0x80 +}; + +static const unsigned char half_wise_write_blob[] = { // size and address must be aligned by 2 + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x16, 0x23, 0x96, 0xa1, 0x96, 0x21, 0x16, 0xa3, + 0x89, 0x05, 0x09, 0x07, 0xe3, 0xca, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, + 0x14, 0xc1, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char byte_wise_write_blob[] = { // no division requirements. + 0x23, 0xa0, 0x05, 0x00, 0x13, 0x07, 0x45, 0x03, 0x0c, 0x43, 0x50, 0x43, + 0x2e, 0x96, 0x21, 0x07, 0x14, 0x23, 0x94, 0xa1, 0x94, 0x21, 0x14, 0xa3, + 0x85, 0x05, 0x05, 0x07, 0xe3, 0xca, 0xc5, 0xfe, 0x93, 0x06, 0xf0, 0xff, + 0x14, 0xc1, 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// Just set the countdown to 0 to avoid any issues. +// li a3, 0; sw a3, 0(a1); li a3, -1; sw a3, 0(a0); ret; +static const unsigned char halt_wait_blob[] = { + 0x81, 0x46, 0x94, 0xc1, 0xfd, 0x56, 0x14, 0xc1, 0x82, 0x80 }; + +// Set the countdown to -1 to cause main system to execute. +// li a3, -1; sw a3, 0(a1); li a3, -1; sw a3, 0(a0); ret; +//static const unsigned char run_app_blob[] = { +// 0xfd, 0x56, 0x94, 0xc1, 0xfd, 0x56, 0x14, 0xc1, 0x82, 0x80 }; +// +// Alternatively, we do it ourselves. +static const unsigned char run_app_blob[] = { + 0x37, 0x07, 0x67, 0x45, 0xb7, 0x27, 0x02, 0x40, 0x13, 0x07, 0x37, 0x12, + 0x98, 0xd7, 0x37, 0x97, 0xef, 0xcd, 0x13, 0x07, 0xb7, 0x9a, 0x98, 0xd7, + 0x23, 0xa6, 0x07, 0x00, 0x13, 0x07, 0x00, 0x08, 0x98, 0xcb, 0xb7, 0xf7, + 0x00, 0xe0, 0x37, 0x07, 0x00, 0x80, 0x23, 0xa8, 0xe7, 0xd0, 0x82, 0x80, }; +static void ResetOp( struct B003FunProgrammerStruct * eps ) +{ + memset( eps->commandbuffer, 0, sizeof( eps->commandbuffer ) ); + memcpy( eps->commandbuffer, "\xaa\x00\x00\x00", 4 ); + eps->commandplace = 4; +} + +static void WriteOp4( struct B003FunProgrammerStruct * eps, uint32_t opsend ) +{ + int place = eps->commandplace; + int newend = place + 4; + if( newend < sizeof( eps->commandbuffer ) ) + { + memcpy( eps->commandbuffer + place, &opsend, 4 ); + } + eps->commandplace = newend; +} + + +static void WriteOpArb( struct B003FunProgrammerStruct * eps, const uint8_t * data, int len ) +{ + int place = eps->commandplace; + int newend = place + len; + if( newend < sizeof( eps->commandbuffer ) ) + { + memcpy( eps->commandbuffer + place, data, len ); + } + eps->commandplace = newend; +} + +static int CommitOp( struct B003FunProgrammerStruct * eps ) +{ + int retries = 0; + int r; + + uint32_t magic_go = 0x1234abcd; + memcpy( eps->commandbuffer + 124, &magic_go, 4 ); + + #ifdef DEBUG_B003 + { + int i; + printf( "Commit TX: %lu bytes\n", sizeof(eps->commandbuffer) ); + for( i = 0; i < sizeof(eps->commandbuffer) ; i++ ) + { + printf( "%02x ", eps->commandbuffer[i] ); + if( ( i & 0xf ) == 0xf ) printf( "\n" ); + } + if( ( i & 0xf ) != 0xf ) printf( "\n" ); + } + #endif + +resend: + r = hid_send_feature_report( eps->hd, eps->commandbuffer, sizeof(eps->commandbuffer) ); + #ifdef DEBUG_B003 + printf( "hid_send_feature_report = %d\n", r ); + #endif + if( r < 0 ) + { + fprintf( stderr, "Warning: Issue with hid_send_feature_report. Retrying\n" ); + if( retries++ > 10 ) + return r; + else + goto resend; + } + + + if( eps->prepping_for_erase ) + { + usleep(4000); + } + + int timeout = 0; + + do + { + eps->respbuffer[0] = 0xaa; + r = hid_get_feature_report( eps->hd, eps->respbuffer, sizeof(eps->respbuffer) ); + + #ifdef DEBUG_B003 + { + int i; + printf( "Commit RX: %d bytes\n", r ); + for( i = 0; i < r; i++ ) + { + printf( "%02x ", eps->respbuffer[i] ); + if( ( i & 0xf ) == 0xf ) printf( "\n" ); + } + if( ( i & 0xf ) != 0xf ) printf( "\n" ); + } + #endif + + if( r < 0 ) + { + if( retries++ > 10 ) return r; + continue; + } + + if( eps->respbuffer[1] == 0xff ) break; + + if( timeout++ > 20 ) + { + printf( "Error: Timed out waiting for stub to complete\n" ); + return -99; + } + } while( 1 ); + return 0; +} + static int B003FunFlushLLCommands( void * dev ) { + // All commands are synchronous anyway. + return 0; +} + + +static int B003FunWaitForDoneOp( void * dev, int ignore ) +{ + // It's synchronous, so no issue here. return 0; } @@ -30,78 +228,314 @@ static int B003FunDelayUS( void * dev, int microseconds ) return 0; } -static int B003FunSetupInterface( void * dev ) +// Does not handle erasing +static int InternalB003FunWriteBinaryBlob( void * dev, uint32_t address_to_write_to, uint32_t write_size, const uint8_t * blob ) { + struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct *)dev; + + int is_flash = IsAddressFlash( address_to_write_to ); + + if( ( address_to_write_to & 0x1 ) && write_size > 0 ) + { + // Need to do byte-wise writing in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, byte_wise_write_blob, sizeof(byte_wise_write_blob) ); + WriteOp4( eps, address_to_write_to ); // Base address to write. + WriteOp4( eps, 1 ); // write 1 bytes. + memcpy( &eps->commandbuffer[60], blob, 1 ); + if( CommitOp( eps ) ) return -5; + if( is_flash && memcmp( &eps->commandbuffer[60], blob, 1 ) ) goto verifyfail; + blob++; + write_size --; + address_to_write_to++; + } + if( ( address_to_write_to & 0x2 ) && write_size > 1 ) + { + // Need to do byte-wise writing in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, half_wise_write_blob, sizeof(half_wise_write_blob) ); + WriteOp4( eps, address_to_write_to ); // Base address to write. + WriteOp4( eps, 2 ); // write 2 bytes. + memcpy( &eps->commandbuffer[60], blob, 2 ); + if( CommitOp( eps ) ) return -5; + if( is_flash && memcmp( &eps->commandbuffer[60], blob, 2 ) ) goto verifyfail; + blob += 2; + write_size -= 2; + address_to_write_to+=2; + } + while( write_size > 3 ) + { + int to_write_this_time = write_size & (~3); + if( to_write_this_time > 64 ) to_write_this_time = 64; + + // Need to do byte-wise writing in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, word_wise_write_blob, sizeof(word_wise_write_blob) ); + WriteOp4( eps, address_to_write_to ); // Base address to write. + WriteOp4( eps, to_write_this_time ); // write 4 bytes. + memcpy( &eps->commandbuffer[60], blob, to_write_this_time ); + if( CommitOp( eps ) ) return -5; + if( is_flash && memcmp( &eps->commandbuffer[60], blob, to_write_this_time ) ) goto verifyfail; + blob += to_write_this_time; + write_size -= to_write_this_time; + address_to_write_to += to_write_this_time; + } + if( write_size > 1 ) + { + // Need to do byte-wise writing in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, half_wise_write_blob, sizeof(half_wise_write_blob) ); + WriteOp4( eps, address_to_write_to ); // Base address to write. + WriteOp4( eps, 2 ); // write 2 bytes. + memcpy( &eps->commandbuffer[60], blob, 2 ); + if( CommitOp( eps ) ) return -5; + if( is_flash && memcmp( &eps->commandbuffer[60], blob, 2 ) ) goto verifyfail; + blob += 2; + write_size -= 2; + address_to_write_to += 2; + } + if( write_size ) + { + // Need to do byte-wise writing in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, byte_wise_write_blob, sizeof(byte_wise_write_blob) ); + WriteOp4( eps, address_to_write_to ); // Base address to write. + WriteOp4( eps, 1 ); // write 1 byte. + memcpy( &eps->commandbuffer[60], blob, 1 ); + if( CommitOp( eps ) ) return -5; + if( is_flash && memcmp( &eps->commandbuffer[60], blob, 1 ) ) goto verifyfail; + blob += 1; + write_size -= 1; + address_to_write_to+=1; + } + eps->prepping_for_erase = 0; return 0; +verifyfail: + fprintf( stderr, "Error: Write Binary Blob: %d bytes to %08x\n", write_size, address_to_write_to ); + return -6; } -static int B003FunExit( void * dev ) +static int B003FunReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob ) { + struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct *)dev; + +#ifdef DEBUG_B003 + printf( "Read Binary Blob: %d bytes from %08x\n", read_size, address_to_read_from ); +#endif + + if( ( address_to_read_from & 0x1 ) && read_size > 0 ) + { + // Need to do byte-wise reading in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, byte_wise_read_blob, sizeof(byte_wise_read_blob) ); + WriteOp4( eps, address_to_read_from ); // Base address to read. + WriteOp4( eps, 1 ); // Read 1 bytes. + if( CommitOp( eps ) ) return -5; + memcpy( blob, &eps->respbuffer[60], 1 ); + blob++; + read_size --; + address_to_read_from++; + } + if( ( address_to_read_from & 0x2 ) && read_size > 1 ) + { + // Need to do byte-wise reading in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, half_wise_read_blob, sizeof(half_wise_read_blob) ); + WriteOp4( eps, address_to_read_from ); // Base address to read. + WriteOp4( eps, 2 ); // Read 2 bytes. + if( CommitOp( eps ) ) return -5; + memcpy( blob, &eps->respbuffer[60], 2 ); + blob += 2; + read_size -= 2; + address_to_read_from+=2; + } + while( read_size > 3 ) + { + int to_read_this_time = read_size & (~3); + if( to_read_this_time > 64 ) to_read_this_time = 64; + + // Need to do byte-wise reading in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, word_wise_read_blob, sizeof(word_wise_read_blob) ); + WriteOp4( eps, address_to_read_from ); // Base address to read. + WriteOp4( eps, to_read_this_time ); // Read 4 bytes. + if( CommitOp( eps ) ) return -5; + memcpy( blob, &eps->respbuffer[60], to_read_this_time ); + blob += to_read_this_time; + read_size -= to_read_this_time; + address_to_read_from += to_read_this_time; + } + if( read_size > 1 ) + { + // Need to do byte-wise reading in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, half_wise_read_blob, sizeof(half_wise_read_blob) ); + WriteOp4( eps, address_to_read_from ); // Base address to read. + WriteOp4( eps, 2 ); // Read 2 bytes. + if( CommitOp( eps ) ) return -5; + memcpy( blob, &eps->respbuffer[60], 2 ); + blob += 2; + read_size -= 2; + address_to_read_from += 2; + } + if( read_size ) + { + // Need to do byte-wise reading in front to line up with word alignment. + ResetOp( eps ); + WriteOpArb( eps, byte_wise_read_blob, sizeof(byte_wise_read_blob) ); + WriteOp4( eps, address_to_read_from ); // Base address to read. + WriteOp4( eps, 1 ); // Read 1 byte. + if( CommitOp( eps ) ) return -5; + memcpy( blob, &eps->respbuffer[60], 1 ); + blob += 1; + read_size -= 1; + address_to_read_from+=1; + } return 0; } -// MUST be 4-byte-aligned. -static int B003FunWriteWord( void * dev, uint32_t address_to_write, uint32_t data ) +static int InternalB003FunBoot( void * dev ) { + struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct*) dev; + + printf( "Booting\n" ); + ResetOp( eps ); + WriteOpArb( eps, run_app_blob, sizeof(run_app_blob) ); + if( CommitOp( eps ) ) return -5; return 0; } -static int B003FunReadWord( void * dev, uint32_t address_to_read, uint32_t * data ) +static int B003FunSetupInterface( void * dev ) { + struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct*) dev; + printf( "Halting Boot Countdown\n" ); + ResetOp( eps ); + WriteOpArb( eps, halt_wait_blob, sizeof(halt_wait_blob) ); + if( CommitOp( eps ) ) return -5; return 0; } -static int B003FunWaitForDoneOp( void * dev, int ignore ) -{ - // ... Need this. +static int B003FunExit( void * dev ) +{ return 0; } +// MUST be 4-byte-aligned. +static int B003FunWriteWord( void * dev, uint32_t address_to_write, uint32_t data ) +{ + return InternalB003FunWriteBinaryBlob( dev, address_to_write, 4, (uint8_t*)&data ); +} + +static int B003FunReadWord( void * dev, uint32_t address_to_read, uint32_t * data ) +{ + return B003FunReadBinaryBlob( dev, address_to_read, 4, (uint8_t*)data ); +} static int B003FunBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data ) { + struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct*) dev; + struct InternalState * iss = eps->internal; + + if( IsAddressFlash( address_to_write ) ) + { + if( !iss->flash_unlocked ) + { + int rw; + if( ( rw = InternalUnlockFlash( dev, iss ) ) ) + return rw; + } + + if( !InternalIsMemoryErased( iss, address_to_write ) ) + { + if( MCF.Erase( dev, address_to_write, 64, 0 ) ) + { + fprintf( stderr, "Error: Failed to erase sector at %08x\n", address_to_write ); + return -9; + } + } + + // Not actually needed. + MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG ); // (intptr_t)&FLASH->CTLR = 0x40022010 + MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG | CR_BUF_RST); // (intptr_t)&FLASH->CTLR = 0x40022010 + + ResetOp( eps ); + WriteOpArb( eps, write64_flash, sizeof(write64_flash) ); + WriteOp4( eps, address_to_write ); // Base address to write. @52 + WriteOp4( eps, 0x4002200c ); // FLASH STATR base address. @ 56 + memcpy( &eps->commandbuffer[60], data, 64 ); // @60 + if( MCF.PrepForLongOp ) MCF.PrepForLongOp( dev ); // Give the programmer a headsup this next operation could take a while. + if( CommitOp( eps ) ) return -5; + + // This is actually built-in. +// MCF.WriteWord( dev, 0x40022010, CR_PAGE_PG|CR_STRT_Set); // (intptr_t)&FLASH->CTLR = 0x40022010 (actually commit) + } + else + { + return InternalB003FunWriteBinaryBlob( dev, address_to_write, 64, data ); + } + return 0; } static int B003FunWriteHalfWord( void * dev, uint32_t address_to_write, uint16_t data ) { + return InternalB003FunWriteBinaryBlob( dev, address_to_write, 2, (uint8_t*)&data ); } static int B003FunReadHalfWord( void * dev, uint32_t address_to_read, uint16_t * data ) { + return B003FunReadBinaryBlob( dev, address_to_read, 2, (uint8_t*)data ); } static int B003FunWriteByte( void * dev, uint32_t address_to_write, uint8_t data ) { + return InternalB003FunWriteBinaryBlob( dev, address_to_write, 1, &data ); } static int B003FunReadByte( void * dev, uint32_t address_to_read, uint8_t * data ) { + return B003FunReadBinaryBlob( dev, address_to_read, 1, data ); } -static void ResetOp( struct B003FunProgrammerStruct * eps ) +static int B003FunHaltMode( void * dev, int mode ) { - memcpy( eps->commandbuffer, "\xaa\x00\x00\x00", 4 ); - eps->commandplace = 4; -} - -static void WriteOp4( struct B003FunProgrammerStruct * eps, uint32_t opsend ) -{ - int place = eps->commandplace; - int newend = place + 4; - if( newend < sizeof( eps->commandbuffer ) ) + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); + switch ( mode ) { - memcpy( eps->commandbuffer + place, &opsend, 4 ); + case HALT_MODE_HALT_BUT_NO_RESET: // Don't reboot. + case HALT_MODE_HALT_AND_RESET: // Reboot and halt + // This programmer is always halted anyway. + break; + + case HALT_MODE_REBOOT: // Actually boot? + InternalB003FunBoot( dev ); + break; + + case HALT_MODE_RESUME: + fprintf( stderr, "Warning: this programmer cannot resume\n" ); + // We can't do this. + break; + + case HALT_MODE_GO_TO_BOOTLOADER: + fprintf( stderr, "Warning: this programmer is already a bootloader. Can't go into bootloader\n" ); + break; + + default: + fprintf( stderr, "Error: Unknown halt mode %d\n", mode ); } - eps->commandplace = newend; + + iss->processor_in_mode = mode; + return 0; } -static void CommitOp( struct B003FunProgrammerStruct * eps ) + +int B003FunPrepForLongOp( void * dev ) { + struct B003FunProgrammerStruct * d = (struct B003FunProgrammerStruct*)dev; + d->prepping_for_erase = 1; + return 0; } - CommitOp( eps ); - void * TryInit_B003Fun() @@ -112,6 +546,9 @@ void * TryInit_B003Fun() hid_device * hd = hid_open( VID, PID, 0); // third parameter is "serial" if( !hd ) return 0; + //extern int g_hidapiSuppress; + //g_hidapiSuppress = 1; // Suppress errors for this device. (don't do this yet) + struct B003FunProgrammerStruct * eps = malloc( sizeof( struct B003FunProgrammerStruct ) ); memset( eps, 0, sizeof( *eps ) ); eps->hd = hd; @@ -133,18 +570,208 @@ void * TryInit_B003Fun() MCF.WriteWord = B003FunWriteWord; MCF.ReadWord = B003FunReadWord; - MCF.WaitForDoneOp = B003FunWaitForDoneOp; + MCF.WriteHalfWord = B003FunWriteHalfWord; + MCF.ReadHalfWord = B003FunReadHalfWord; + + MCF.WriteByte = B003FunWriteByte; + MCF.ReadByte = B003FunReadByte; + MCF.WaitForDoneOp = B003FunWaitForDoneOp; MCF.BlockWrite64 = B003FunBlockWrite64; + MCF.ReadBinaryBlob = B003FunReadBinaryBlob; - // Alert programmer. - ResetOp( eps ) - WriteOp4( eps, 0x00b02023 ); //sw a1, 0 ; stop execution - WriteOp4( eps, 0x00008067 ); //jalr x0, x1, 0 ; ret - CommitOp( eps ); + MCF.PrepForLongOp = B003FunPrepForLongOp; + + MCF.HaltMode = B003FunHaltMode; return eps; } -#else -void * TryInit_B003Fun() { return 0; } -#endif + + + + + +// Utility for generating bootloader code: + +// make rv003usb.bin && xxd -i -s 100 -l 44 rv003usb.bin + +/* +// Read data, arbitrarily from memory. (byte-wise) +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + XW_C_LBU(a3, a1, 0); //lbu a3, 0(a1) // Read from RAM + XW_C_SB(a3, a4, 0); //sb a3, 0(a4) // Store into scratchpad + c.addi a1, 1 // Advance pointers + c.addi a4, 1 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0,0 +*/ + +/* +// Read data, arbitrarily from memory. (half-wise) + +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + XW_C_LHU(a3, a1, 0); //lhu a3, 0(a1) // Read from RAM + XW_C_SH(a3, a4, 0); //sh a3, 0(a4) // Store into scratchpad + c.addi a1, 2 // Advance pointers + c.addi a4, 2 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0,0 +*/ + +/* +// Read data, arbitrarily from memory. (word-wise) +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + lw a3, 0(a1); //lw a3, 0(a1) // Read from RAM + sw a3, 0(a4); //sw a3, 0(a4) // Store into scratchpad + c.addi a1, 4 // Advance pointers + c.addi a4, 4 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0,0 +*/ +/* +// Write data, arbitrarily to memory. (word-wise) +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + lw a3, 0(a4); //lw a3, 0(a1) // Read from RAM + sw a3, 0(a1); //sw a3, 0(a4) // Store into scratchpad + lw a3, 0(a1); // Read-back + sw a3, 0(a4); + c.addi a1, 4 // Advance pointers + c.addi a4, 4 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0 +*/ + +/* +// Write data, arbitrarily to memory. (word-wise) +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + XW_C_LHU(a3, a4, 0); //lbu a3, 0(a4) // Read from scratchpad + XW_C_SH(a3, a1, 0); //sb a3, 0(a1) // Store into RAM + XW_C_LHU(a3, a1, 0); //lbu a3, 0(a4) // Read back + XW_C_SH(a3, a4, 0); //sb a3, 0(a1) + c.addi a1, 2 // Advance pointers + c.addi a4, 2 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0 +*/ + +/* +// Write data, arbitrarily to memory. (byte-wise) +. = 0x66 + sw x0, 0(a1); // Stop Countdown + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // Get starting address to read + c.lw a2, 4(a4); // Get length to read. + c.add a2, a1 // a2 is now ending address. + c.addi a4, 8 // start writing back at byte 60. +1: + XW_C_LBU(a3, a4, 0); //lbu a3, 0(a4) // Read from scratchpad + XW_C_SB(a3, a1, 0); //sb a3, 0(a1) // Store into RAM + XW_C_LBU(a3, a1, 0); //Read back + XW_C_SB(a3, a4, 0); + c.addi a1, 1 // Advance pointers + c.addi a4, 1 + blt a1, a2, 1b // Loop til all read. + addi a3, x0, -1 + sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret + .long 0,0,0,0,0,0 +*/ + + +/* Run app blob + 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; +*/ + + +/* Write flash block 64. + +. = 0x66 + addi a4, a0, 52; // Start reading properties, starting from scratchpad + 52. + c.lw a1, 0(a4); // a1 = Address to write to. + addi a2, a1, 64 // a2 = end of section to write to + c.lw a5, 4(a4); // a5 = Get flash address (0x40022010) + + // Must be done outside. +// li a3, 0x00080000 | 0x00010000; + //c.sw a3, 0(a5); //FLASH->CTLR = CR_BUF_RST | CR_PAGE_PG + c.sw a1, 8(a5); //FLASH->ADDR = writing location. + + 1: + c.lw a3, 8(a4); //lw a3, 0(a1) // Read from RAM (Starting @60) + c.sw a3, 0(a1); //sw a3, 0(a4) // Store into flash + + li a3, 0x00010000 | 0x00040000; // CR_PAGE_PG | FLASH_CTLR_BUF_LOAD + c.sw a3, 4(a5); // Load into flash write buffer. + + c.lw a3, 0(a1); //Tricky: By reading from flash here, we force it to wait for completion. + c.addi a1, 4 // Advance pointers + c.addi a4, 4 + + // // Wait for write to complete. + // 2: c.lw a3, 0(a5) // read FLASH->STATR + // c.andi a3, 1 // Mask off BUSY bit. + // c.bnez a3, 2b + + + blt a1, a2, 1b // Loop til all read. + + li a3, 0x00010000 | 0x00000040 //CR_PAGE_PG|CR_STRT_Set + c.sw a3, 4(a5); //FLASH->CTRL = CR_PAGE_PG|CR_STRT_Set + li a3, -1 + c.sw a3, 0(a0) // Write -1 into 0x00 indicating all done. + ret +*/ diff --git a/minichlink/pgm-esp32s2-ch32xx.c b/minichlink/pgm-esp32s2-ch32xx.c index ef8a721e7c3cbfbaf335c47bb353c666c2156d39..090da555ff10f8cd2b1945d671a6e4861f9aaf9d 100644 --- a/minichlink/pgm-esp32s2-ch32xx.c +++ b/minichlink/pgm-esp32s2-ch32xx.c @@ -12,6 +12,8 @@ struct ESP32ProgrammerStruct int commandplace; uint8_t reply[256]; int replylen; + + int dev_version; }; int ESPFlushLLCommands( void * dev ); @@ -243,12 +245,18 @@ int ESPBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data ) retry: - Write2LE( eps, 0x0bfe ); + if( eps->dev_version >= 2 && InternalIsMemoryErased( (struct InternalState*)eps->internal, address_to_write ) ) + Write2LE( eps, 0x0efe ); + else + Write2LE( eps, 0x0bfe ); Write4LE( eps, address_to_write ); + int i; int timeout = 0; for( i = 0; i < 64; i++ ) Write1( eps, data[i] ); + InternalMarkMemoryNotErased( (struct InternalState*)eps->internal, address_to_write ); + do { ESPFlushLLCommands( dev ); @@ -409,6 +417,7 @@ void * TryInit_ESP32S2CHFUN() memset( eps, 0, sizeof( *eps ) ); eps->hd = hd; eps->commandplace = 1; + eps->dev_version = 0; memset( &MCF, 0, sizeof( MCF ) ); MCF.WriteReg32 = ESPWriteReg32; @@ -431,9 +440,16 @@ void * TryInit_ESP32S2CHFUN() MCF.BlockWrite64 = ESPBlockWrite64; MCF.VendorCommand = ESPVendorCommand; + // Reset internal programmer state. Write2LE( eps, 0x0afe ); - + ESPFlushLLCommands( eps ); + Write2LE( eps, 0xfefe ); + ESPFlushLLCommands( eps ); + if( eps->replylen > 1 ) + { + eps->dev_version = eps->reply[1]; + } return eps; } diff --git a/minichlink/pgm-wch-linke.c b/minichlink/pgm-wch-linke.c index 2a3e516906f7ca4593bda13fc0cbd99a82d303d6..e618135aab4d804281491a2a06fc15519ae052e9 100644 --- a/minichlink/pgm-wch-linke.c +++ b/minichlink/pgm-wch-linke.c @@ -18,8 +18,8 @@ struct LinkEProgrammerStruct // For non-ch32v003 chips. //static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t * readbuff ); -//static int InternalLinkEHaltMode( void * d, int mode ); -//static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob ); +static int InternalLinkEHaltMode( void * d, int mode ); +static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob ); #define WCHTIMEOUT 5000 #define WCHCHECK(x) if( (status = x) ) { fprintf( stderr, "Bad USB Operation on " __FILE__ ":%d (%d)\n", __LINE__, status ); exit( status ); } @@ -191,6 +191,7 @@ int LEFlushLLCommands( void * dev ) static int LESetupInterface( void * d ) { libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh; + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)d)->internal); uint8_t rbuff[1024]; uint32_t transferred = 0; @@ -223,6 +224,10 @@ static int LESetupInterface( void * d ) // TODO: What in the world is this? It doesn't appear to be needed. wch_link_command( dev, "\x81\x0c\x02\x09\x01", 5, 0, 0, 0 ); //Reply is: 820c0101 + // Note from further debugging: + // My capture differs in this case: \x05 instead of \x09 -> But does not seem to be needed + //wch_link_command( dev, "\x81\x0c\x02\x05\x01", 5, 0, 0, 0 ); //Reply is: 820c0101 + // This puts the processor on hold to allow the debugger to run. wch_link_command( dev, "\x81\x0d\x01\x02", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500 if (rbuff[0] == 0x81 && rbuff[1] == 0x55 && rbuff[2] == 0x01 && rbuff[3] == 0x01) @@ -230,8 +235,18 @@ static int LESetupInterface( void * d ) fprintf(stderr, "link error, nothing connected to linker\n"); return -1; } - uint32_t target_chip_type = ( rbuff[4] << 4) + (rbuff[5] >> 4); - fprintf(stderr, "Chip Type: %03x\n", target_chip_type); + + uint32_t target_chip_type = ( rbuff[4] << 4) + (rbuff[5] >> 4); + fprintf(stderr, "Chip Type: %03x\n", target_chip_type); + if( target_chip_type == 0x307 || target_chip_type == 0x203 ) + { + fprintf( stderr, "CH32V307 or CH32V203 Detected. Allowing old-flash-mode for operation.\n" ); + MCF.WriteBinaryBlob = LEWriteBinaryBlob; + + iss->sector_size = 256; + + wch_link_command( dev, "\x81\x0d\x01\x03", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Ignored, 820d050900300500 + } // For some reason, if we don't do this sometimes the programmer starts in a hosey mode. MCF.WriteReg32( d, DMCONTROL, 0x80000001 ); // Make the debug module work properly. @@ -254,17 +269,36 @@ static int LESetupInterface( void * d ) } // This puts the processor on hold to allow the debugger to run. - wch_link_command( dev, "\x81\x11\x01\x09", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below) + // Recommended to switch to 05 from 09 by Alexander M + // wch_link_command( dev, "\x81\x11\x01\x09", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below) + wch_link_command( dev, "\x81\x11\x01\x05", 4, (int*)&transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below) + if( transferred != 20 ) { fprintf( stderr, "Error: could not get part status\n" ); return -1; } - fprintf( stderr, "Part Type (A): 0x%02x%02x (This is the capacity code, in KB)\n", rbuff[2], rbuff[3] ); // Is this Flash size? + fprintf( stderr, "Flash Storage: %d kB\n", (rbuff[2]<<8) | rbuff[3] ); // Is this Flash size? fprintf( stderr, "Part UUID : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", rbuff[4], rbuff[5], rbuff[6], rbuff[7], rbuff[8], rbuff[9], rbuff[10], rbuff[11] ); fprintf( stderr, "PFlags : %02x-%02x-%02x-%02x\n", rbuff[12], rbuff[13], rbuff[14], rbuff[15] ); fprintf( stderr, "Part Type (B): %02x-%02x-%02x-%02x\n", rbuff[16], rbuff[17], rbuff[18], rbuff[19] ); - + + // Check for read protection + wch_link_command( dev, "\x81\x06\x01\x01", 4, (int*)&transferred, rbuff, 1024 ); + if(transferred != 4) { + fprintf(stderr, "Error: could not get read protection status\n"); + return -1; + } + + if(rbuff[3] == 0x01) { + fprintf(stderr, "Read protection: enabled\n"); + } else { + fprintf(stderr, "Read protection: disabled\n"); + } + + iss->flash_size = ((rbuff[2]<<8) | rbuff[3])*1024; + iss->target_chip_type = target_chip_type; + return 0; } @@ -365,49 +399,47 @@ void * TryInit_WCHLinkE() }; -#if 0 +#if 1 // In case you are using a non-CH32V003 board. - const uint8_t * bootloader = (const uint8_t*) -"\x21\x11\x22\xca\x26\xc8\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45" \ -"\xb7\x27\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07" \ -"\xb7\x9a\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27" \ -"\x02\x40\x98\x4b\xad\x66\x37\x33\x00\x40\x13\x67\x47\x00\x98\xcb" \ -"\x98\x4b\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b" \ -"\x63\x16\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb" \ -"\x93\x07\xf6\x03\x99\x83\x2e\xc0\x2d\x63\x81\x76\x3e\xc4\xb7\x32" \ -"\x00\x40\xb7\x27\x02\x40\x13\x03\xa3\xaa\xfd\x16\x98\x4b\xb7\x03" \ -"\x02\x00\x33\x67\x77\x00\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67" \ -"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb" \ -"\x02\x47\x13\x07\x07\x04\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x79\xf7" \ -"\x93\x77\x85\x00\xf1\xcf\x93\x07\xf6\x03\x2e\xc0\x99\x83\x37\x27" \ -"\x02\x40\x3e\xc4\x1c\x4b\xc1\x66\x2d\x63\xd5\x8f\x1c\xcb\x37\x07" \ -"\x00\x20\x13\x07\x07\x20\xb7\x27\x02\x40\xb7\x03\x08\x00\xb7\x32" \ -"\x00\x40\x13\x03\xa3\xaa\x94\x4b\xb3\xe6\x76\x00\x94\xcb\xd4\x47" \ -"\x85\x8a\xf5\xfe\x82\x46\xba\x84\x37\x04\x04\x00\x36\xc2\xc1\x46" \ -"\x36\xc6\x92\x46\x84\x40\x11\x07\x84\xc2\x94\x4b\xc1\x8e\x94\xcb" \ -"\xd4\x47\x85\x8a\xb1\xea\x92\x46\xba\x84\x91\x06\x36\xc2\xb2\x46" \ -"\xfd\x16\x36\xc6\xf9\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6\x06\x04" \ -"\x94\xcb\xd4\x47\x85\x8a\x85\xee\xd4\x47\xc1\x8a\x85\xce\xd8\x47" \ -"\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b\x21\x45" \ -"\x75\x8f\x98\xcb\x52\x44\xc2\x44\x61\x01\x02\x90\x23\x20\xd3\x00" \ -"\xf5\xb5\x23\xa0\x62\x00\x3d\xb7\x23\xa0\x62\x00\x55\xb7\x23\xa0" \ -"\x62\x00\xc1\xb7\x82\x46\x93\x86\x06\x04\x36\xc0\xa2\x46\xfd\x16" \ -"\x36\xc4\xb5\xf2\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb" \ -"\x41\x89\x05\xcd\x2e\xc0\x0d\x06\x02\xc4\x09\x82\xb7\x07\x00\x20" \ -"\x32\xc6\x93\x87\x07\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46" \ -"\x8a\x07\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4" \ -"\xa2\x46\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x61\xb7\x41\x45" \ -"\x51\xb7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ +"\x93\x77\x15\x00\x41\x11\x99\xcf\xb7\x06\x67\x45\xb7\x27\x02\x40" \ +"\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07\xb7\x9a\xd8\xc3" \ +"\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x95\xc7\xb7\x27\x02\x40\x98\x4b" \ +"\xad\x66\x37\x38\x00\x40\x13\x67\x47\x00\x98\xcb\x98\x4b\x93\x86" \ +"\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b\x61\xeb\x98\x4b" \ +"\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb\x93\x07\xf6\x0f\xa1\x83" \ +"\x2e\xc0\x2d\x68\x81\x76\x3e\xc4\xb7\x08\x02\x00\xb7\x27\x02\x40" \ +"\x37\x33\x00\x40\x13\x08\xa8\xaa\xfd\x16\x98\x4b\x33\x67\x17\x01" \ +"\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67\x07\x04\x98\xcb\xd8\x47" \ +"\x05\x8b\x41\xeb\x98\x4b\x75\x8f\x98\xcb\x02\x47\x13\x07\x07\x10" \ +"\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x69\xfb\x93\x77\x85\x00\xd5\xcb" \ +"\x93\x07\xf6\x0f\x2e\xc0\xa1\x83\x3e\xc4\x37\x27\x02\x40\x1c\x4b" \ +"\xc1\x66\x41\x68\xd5\x8f\x1c\xcb\xb7\x16\x00\x20\xb7\x27\x02\x40" \ +"\x93\x08\x00\x04\x37\x03\x20\x00\x98\x4b\x33\x67\x07\x01\x98\xcb" \ +"\xd8\x47\x05\x8b\x75\xff\x02\x47\x3a\xc2\x46\xc6\x32\x47\x0d\xef" \ +"\x98\x4b\x33\x67\x67\x00\x98\xcb\xd8\x47\x05\x8b\x75\xff\xd8\x47" \ +"\x41\x8b\x39\xc3\xd8\x47\xc1\x76\xfd\x16\x13\x67\x07\x01\xd8\xc7" \ +"\x98\x4b\x21\x45\x75\x8f\x98\xcb\x41\x01\x02\x90\x23\x20\xd8\x00" \ +"\x25\xb7\x23\x20\x03\x01\xa5\xb7\x12\x47\x13\x8e\x46\x00\x94\x42" \ +"\x14\xc3\x12\x47\x11\x07\x3a\xc2\x32\x47\x7d\x17\x3a\xc6\xd8\x47" \ +"\x09\x8b\x75\xff\xf2\x86\x5d\xb7\x02\x47\x13\x07\x07\x10\x3a\xc0" \ +"\x22\x47\x7d\x17\x3a\xc4\x49\xf3\x98\x4b\xc1\x76\xfd\x16\x75\x8f" \ +"\x98\xcb\x41\x89\x15\xc9\x2e\xc0\x0d\x06\x02\xc4\x09\x82\x32\xc6" \ +"\xb7\x17\x00\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46\x8a\x07" \ +"\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4\xa2\x46" \ +"\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\xbd\xbf\x41\x45\xad\xbf" \ +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; int bootloader_len = 512; #endif -#if 0 static int InternalLinkEHaltMode( void * d, int mode ) { libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh; @@ -432,7 +464,6 @@ static int InternalLinkEHaltMode( void * d, int mode ) } return 0; } -#endif #if 0 static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t * readbuff ) @@ -494,10 +525,10 @@ static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t } #endif -#if 0 static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob ) { libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh; + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); InternalLinkEHaltMode( d, 0 ); @@ -506,7 +537,7 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t rbuff[1024]; int transferred; - int padlen = ((len-1) & (~0x3f)) + 0x40; + int padlen = ((len-1) & (~(iss->sector_size-1))) + iss->sector_size; wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 ); wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 ); // Not sure why but it seems to work better when we request twice. @@ -521,9 +552,9 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x05", 4, 0, 0, 0 ); int pplace = 0; - for( pplace = 0; pplace < bootloader_len; pplace += 64 ) + for( pplace = 0; pplace < bootloader_len; pplace += iss->sector_size ) { - WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, (uint8_t*)(bootloader+pplace), 64, &transferred, WCHTIMEOUT ) ); + WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, (uint8_t*)(bootloader+pplace), iss->sector_size, &transferred, WCHTIMEOUT ) ); } for( i = 0; i < 10; i++ ) @@ -542,24 +573,23 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x02", 4, 0, 0, 0 ); - for( pplace = 0; pplace < padlen; pplace += 64 ) + for( pplace = 0; pplace < padlen; pplace += iss->sector_size ) { - if( pplace + 64 > len ) + if( pplace + iss->sector_size > len ) { - uint8_t paddeddata[64]; - int gap = pplace + 64 - len; + uint8_t paddeddata[iss->sector_size]; + int gap = pplace + iss->sector_size - len; int okcopy = len - pplace; memcpy( paddeddata, blob + pplace, okcopy ); memset( paddeddata + okcopy, 0xff, gap ); - WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, paddeddata, 64, &transferred, WCHTIMEOUT ) ); + WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, paddeddata, iss->sector_size, &transferred, WCHTIMEOUT ) ); } else { - WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, 64, &transferred, WCHTIMEOUT ) ); + WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, iss->sector_size, &transferred, WCHTIMEOUT ) ); } } return 0; } -#endif diff --git a/minichlink/serial_dev.c b/minichlink/serial_dev.c index f39780fa580f833a47a6ecb8ee756957937637fc..af5543118357662082d8b7b257322bdd2ff54355 100644 --- a/minichlink/serial_dev.c +++ b/minichlink/serial_dev.c @@ -1,173 +1,173 @@ #include "serial_dev.h" int serial_dev_create(serial_dev_t *dev, const char* port, unsigned baud) { - if (!dev) - return -1; - dev->port = port; - dev->baud = baud; - #ifdef IS_WINDOWS - dev->handle = INVALID_HANDLE_VALUE; - #else - dev->fd = -1; - #endif - return 0; + if (!dev) + return -1; + dev->port = port; + dev->baud = baud; + #ifdef IS_WINDOWS + dev->handle = INVALID_HANDLE_VALUE; + #else + dev->fd = -1; + #endif + return 0; } int serial_dev_open(serial_dev_t *dev) { - fprintf(stderr, "Opening serial port %s at %u baud.\n", dev->port, dev->baud); + fprintf(stderr, "Opening serial port %s at %u baud.\n", dev->port, dev->baud); #ifdef IS_WINDOWS - // Windows quirk: port = "COM10" is invalid, has to be encoded as "\\.\COM10". - // This also works for COM below 9. So, let's give the user the ability to use - // any "COMx" string and just prepend the "\\.\". - char winPortName[64]; - if(dev->port[0] != '\\') { - snprintf(winPortName, sizeof(winPortName), "\\\\.\\%s", dev->port); - } else { - // copy verbatim if string already starts with a '\' - snprintf(winPortName, sizeof(winPortName), "%s", dev->port); - } - dev->handle = CreateFileA(winPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0,0); - if (dev->handle == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) { - fprintf(stderr, "Serial port %s not found.\n", dev->port); - // weird: without this, errno = 0 (no error). - _set_errno(ERROR_FILE_NOT_FOUND); - return -1; // Device not found - } - // Error while opening the device - return -1; - } - DCB dcbSerialParams; - dcbSerialParams.DCBlength = sizeof(dcbSerialParams); - if (!GetCommState(dev->handle, &dcbSerialParams)) { - return -1; - } - // set baud and 8N1 serial formatting - dcbSerialParams.BaudRate = dev->baud; - dcbSerialParams.ByteSize = 8; - dcbSerialParams.StopBits = ONESTOPBIT; - dcbSerialParams.Parity = NOPARITY; - // write back - if (!SetCommState(dev->handle, &dcbSerialParams)){ - return -1; - } - // Set the timeout parameters to "no timeout" (blocking). - // see https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts - COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = 0; - timeouts.ReadTotalTimeoutConstant = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = MAXDWORD; - timeouts.WriteTotalTimeoutMultiplier = 0; - // Write the parameters - if (!SetCommTimeouts(dev->handle, &timeouts)) { - return -1; - } + // Windows quirk: port = "COM10" is invalid, has to be encoded as "\\.\COM10". + // This also works for COM below 9. So, let's give the user the ability to use + // any "COMx" string and just prepend the "\\.\". + char winPortName[64]; + if(dev->port[0] != '\\') { + snprintf(winPortName, sizeof(winPortName), "\\\\.\\%s", dev->port); + } else { + // copy verbatim if string already starts with a '\' + snprintf(winPortName, sizeof(winPortName), "%s", dev->port); + } + dev->handle = CreateFileA(winPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0,0); + if (dev->handle == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) { + fprintf(stderr, "Serial port %s not found.\n", dev->port); + // weird: without this, errno = 0 (no error). + _set_errno(ERROR_FILE_NOT_FOUND); + return -1; // Device not found + } + // Error while opening the device + return -1; + } + DCB dcbSerialParams; + dcbSerialParams.DCBlength = sizeof(dcbSerialParams); + if (!GetCommState(dev->handle, &dcbSerialParams)) { + return -1; + } + // set baud and 8N1 serial formatting + dcbSerialParams.BaudRate = dev->baud; + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = ONESTOPBIT; + dcbSerialParams.Parity = NOPARITY; + // write back + if (!SetCommState(dev->handle, &dcbSerialParams)){ + return -1; + } + // Set the timeout parameters to "no timeout" (blocking). + // see https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts + COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutConstant = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = MAXDWORD; + timeouts.WriteTotalTimeoutMultiplier = 0; + // Write the parameters + if (!SetCommTimeouts(dev->handle, &timeouts)) { + return -1; + } #else - struct termios attr; - if ((dev->fd = open(dev->port, O_RDWR | O_NOCTTY)) == -1) { - perror("open"); - return -1; - } + struct termios attr; + if ((dev->fd = open(dev->port, O_RDWR | O_NOCTTY)) == -1) { + perror("open"); + return -1; + } - if (tcgetattr(dev->fd, &attr) == -1) { - perror("tcgetattr"); - return -1; - } + if (tcgetattr(dev->fd, &attr) == -1) { + perror("tcgetattr"); + return -1; + } - cfmakeraw(&attr); - cfsetspeed(&attr, dev->baud); + cfmakeraw(&attr); + cfsetspeed(&attr, dev->baud); - if (tcsetattr(dev->fd, TCSANOW, &attr) == -1) { - perror("tcsetattr"); - return -1; - } + if (tcsetattr(dev->fd, TCSANOW, &attr) == -1) { + perror("tcsetattr"); + return -1; + } #endif - // all okay if we get here - return 0; + // all okay if we get here + return 0; } int serial_dev_write(serial_dev_t *dev, const void* data, size_t len) { #ifdef IS_WINDOWS - DWORD dwBytesWritten; - if (!WriteFile(dev->handle, data, len, &dwBytesWritten,NULL)) { - return -1; - } - return (int) dwBytesWritten; + DWORD dwBytesWritten; + if (!WriteFile(dev->handle, data, len, &dwBytesWritten,NULL)) { + return -1; + } + return (int) dwBytesWritten; #else - return write(dev->fd, data, len); + return write(dev->fd, data, len); #endif } int serial_dev_read(serial_dev_t *dev, void* data, size_t len) { #ifdef IS_WINDOWS - DWORD dwBytesRead = 0; - if (!ReadFile(dev->handle, data, len, &dwBytesRead, NULL)) { - return -1; - } - return (int) dwBytesRead; + DWORD dwBytesRead = 0; + if (!ReadFile(dev->handle, data, len, &dwBytesRead, NULL)) { + return -1; + } + return (int) dwBytesRead; #else - return read(dev->fd, data, len); + return read(dev->fd, data, len); #endif } int serial_dev_do_dtr_reset(serial_dev_t *dev) { #ifdef IS_WINDOWS - // EscapeCommFunction returns 0 on fail - if(EscapeCommFunction(dev->handle, SETDTR) == 0) { - return -1; - } - if(EscapeCommFunction(dev->handle, CLRDTR) == 0) { - return -1; - } + // EscapeCommFunction returns 0 on fail + if(EscapeCommFunction(dev->handle, SETDTR) == 0) { + return -1; + } + if(EscapeCommFunction(dev->handle, CLRDTR) == 0) { + return -1; + } #else - int argp = TIOCM_DTR; - // Arduino DTR reset. - if (ioctl(dev->fd, TIOCMBIC, &argp) == -1) { - perror("ioctl"); - return -1; - } + int argp = TIOCM_DTR; + // Arduino DTR reset. + if (ioctl(dev->fd, TIOCMBIC, &argp) == -1) { + perror("ioctl"); + return -1; + } - if (tcdrain(dev->fd) == -1) { - perror("tcdrain"); - return -1; - } + if (tcdrain(dev->fd) == -1) { + perror("tcdrain"); + return -1; + } - if (ioctl(dev->fd, TIOCMBIS, &argp) == -1) { - perror("ioctl"); - return -1; - } + if (ioctl(dev->fd, TIOCMBIS, &argp) == -1) { + perror("ioctl"); + return -1; + } #endif - return 0; + return 0; } int serial_dev_flush_rx(serial_dev_t *dev) { #ifdef IS_WINDOWS - // PurgeComm returns 0 on fail - if (PurgeComm(dev->handle, PURGE_RXCLEAR) == 0) { - return -1; - } + // PurgeComm returns 0 on fail + if (PurgeComm(dev->handle, PURGE_RXCLEAR) == 0) { + return -1; + } #else - if (tcflush(dev->fd, TCIFLUSH) == -1) { - perror("tcflush"); - return -1; - } + if (tcflush(dev->fd, TCIFLUSH) == -1) { + perror("tcflush"); + return -1; + } #endif - return 0; + return 0; } int serial_dev_close(serial_dev_t *dev) { #ifdef IS_WINDOWS - if(!CloseHandle(dev->handle)) { - return -1; - } - dev->handle = INVALID_HANDLE_VALUE; + if(!CloseHandle(dev->handle)) { + return -1; + } + dev->handle = INVALID_HANDLE_VALUE; #else - int ret = 0; - if((ret = close(dev->fd)) != 0) { - return ret; - } - dev->fd = -1; + int ret = 0; + if((ret = close(dev->fd)) != 0) { + return ret; + } + dev->fd = -1; #endif - return 0; + return 0; } \ No newline at end of file diff --git a/minichlink/serial_dev.h b/minichlink/serial_dev.h index a75733f41870308408ce0b2f5b82d20ef7ccfe54..7c7e4f1eea1f1b369b08f0508739112a84c60ca5 100644 --- a/minichlink/serial_dev.h +++ b/minichlink/serial_dev.h @@ -9,6 +9,7 @@ #define IS_WINDOWS #define DEFAULT_SERIAL_NAME "\\\\.\\COM3" #else +#include <unistd.h> #include <termios.h> #include <fcntl.h> #include <sys/ioctl.h> @@ -17,7 +18,6 @@ #endif /* these are available on all platforms */ #include <errno.h> -#include <unistd.h> #include <stdio.h> typedef struct { diff --git a/minichlink/winbuild.bat b/minichlink/winbuild.bat index 785472441f6d5d1db88cd6282afe61fc9f21a39b..9c4095bc4ce65dcea556e50f2dc1a094cc04f303 100644 --- a/minichlink/winbuild.bat +++ b/minichlink/winbuild.bat @@ -1 +1 @@ -tcc minichlink.c pgm-esp32s2-ch32xx.c pgm-wch-linke.c minichgdb.c nhc-link042.c -DWIN32 -lws2_32 -lsetupapi libusb-1.0.dll +tcc minichlink.c pgm-esp32s2-ch32xx.c serial_dev.c ardulink.c pgm-b003fun.c pgm-wch-linke.c minichgdb.c nhc-link042.c -DWIN32 -lws2_32 -lsetupapi libusb-1.0.dll