diff options
Diffstat (limited to 'commandline')
-rw-r--r-- | commandline/Makefile | 5 | ||||
-rwxr-xr-x | commandline/builds/OSX/micronucleus | bin | 124292 -> 0 bytes | |||
-rw-r--r--[-rwxr-xr-x] | commandline/builds/Windows/micronucleus.exe | bin | 26126 -> 27662 bytes | |||
-rw-r--r-- | commandline/library/micronucleus_lib.c | 173 | ||||
-rw-r--r-- | commandline/library/micronucleus_lib.h | 16 | ||||
-rw-r--r-- | commandline/micronucleus.c | 66 | ||||
-rw-r--r-- | commandline/micronucleus.exe | bin | 0 -> 27662 bytes |
7 files changed, 208 insertions, 52 deletions
diff --git a/commandline/Makefile b/commandline/Makefile index 3c52cb4..e8aadfd 100644 --- a/commandline/Makefile +++ b/commandline/Makefile @@ -20,6 +20,11 @@ else ifeq ($(shell uname), Darwin) # USBLIBS += -framework IOKit # Uncomment these to create a dual architecture binary: # OSFLAG += -arch x86_64 -arch i386 +else ifeq ($(shell uname), OpenBSD) + USBFLAGS=$(shell libusb-config --cflags || libusb-legacy-config --cflags) + USBLIBS=$(shell libusb-config --libs || libusb-legacy-config --libs) + EXE_SUFFIX = + OSFLAG = -D OPENBSD else USBFLAGS = -I C:\MinGW\include USBLIBS = -L C:\MinGW\lib -lusb diff --git a/commandline/builds/OSX/micronucleus b/commandline/builds/OSX/micronucleus Binary files differdeleted file mode 100755 index 3ae62c4..0000000 --- a/commandline/builds/OSX/micronucleus +++ /dev/null diff --git a/commandline/builds/Windows/micronucleus.exe b/commandline/builds/Windows/micronucleus.exe Binary files differindex bfdb56b..aa4752f 100755..100644 --- a/commandline/builds/Windows/micronucleus.exe +++ b/commandline/builds/Windows/micronucleus.exe diff --git a/commandline/library/micronucleus_lib.c b/commandline/library/micronucleus_lib.c index 6e574f5..0569dbe 100644 --- a/commandline/library/micronucleus_lib.c +++ b/commandline/library/micronucleus_lib.c @@ -1,8 +1,10 @@ /* Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> - + (c) 2012 by ihsan Kehribar <ihsan@kehribar.me> + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to @@ -28,7 +30,7 @@ #include "micronucleus_lib.h" #include "littleWire_util.h" -micronucleus* micronucleus_connect() { +micronucleus* micronucleus_connect(int fast_mode) { micronucleus *nucleus = NULL; struct usb_bus *busses; @@ -60,17 +62,64 @@ micronucleus* micronucleus_connect() { nucleus->device = usb_open(dev); - // get nucleus info - unsigned char buffer[4]; - int res = usb_control_msg(nucleus->device, 0xC0, 0, 0, 0, (char *)buffer, 4, MICRONUCLEUS_USB_TIMEOUT); - assert(res >= 4); - - nucleus->flash_size = (buffer[0]<<8) + buffer[1]; - nucleus->page_size = buffer[2]; - nucleus->pages = (nucleus->flash_size / nucleus->page_size); - if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; - nucleus->write_sleep = buffer[3]; - nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + if (nucleus->version.major>=2) { // Version 2.x + // get nucleus info + unsigned char buffer[6]; + int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 6, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + assert(res >= 6); + + nucleus->flash_size = (buffer[0]<<8) + buffer[1]; + nucleus->page_size = buffer[2]; + nucleus->pages = (nucleus->flash_size / nucleus->page_size); + if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; + + nucleus->bootloader_start = nucleus->pages*nucleus->page_size; + + if ((nucleus->version.major>=2)&&(!fast_mode)) { + // firmware v2 reports more aggressive write times. Add 2ms if fast mode is not used. + nucleus->write_sleep = (buffer[3] & 127) + 2; + } else { + nucleus->write_sleep = (buffer[3] & 127); + } + + // if bit 7 of write sleep time is set, divide the erase time by four to + // accomodate to the 4*page erase of the ATtiny841/441 + if (buffer[3]&128) { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages / 4; + } else { + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + } + + nucleus->signature1 = buffer[4]; + nucleus->signature2 = buffer[5]; + + } else { // Version 1.x + // get nucleus info + unsigned char buffer[4]; + int res = usb_control_msg(nucleus->device, USB_ENDPOINT_IN| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, 0, (char *)buffer, 4, MICRONUCLEUS_USB_TIMEOUT); + + // Device descriptor was found, but talking to it was not succesful. This can happen when the device is being reset. + if (res<0) return NULL; + + assert(res >= 4); + + nucleus->flash_size = (buffer[0]<<8) + buffer[1]; + nucleus->page_size = buffer[2]; + nucleus->pages = (nucleus->flash_size / nucleus->page_size); + if (nucleus->pages * nucleus->page_size < nucleus->flash_size) nucleus->pages += 1; + + nucleus->bootloader_start = nucleus->pages*nucleus->page_size; + + nucleus->write_sleep = (buffer[3] & 127); + nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages; + + nucleus->signature1 = 0; + nucleus->signature2 = 0; + } } } } @@ -80,7 +129,7 @@ micronucleus* micronucleus_connect() { int micronucleus_eraseFlash(micronucleus* deviceHandle, micronucleus_callback progress) { int res; - res = usb_control_msg(deviceHandle->device, 0xC0, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); // give microcontroller enough time to erase all writable pages and come back online float i = 0; @@ -122,6 +171,7 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz unsigned int page_address; // address within this page when copying buffer unsigned int res; unsigned int pagecontainsdata; + unsigned int userReset; for (address = 0; address < deviceHandle->flash_size; address += deviceHandle->page_size) { // work around a bug in older bootloader versions @@ -142,12 +192,99 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz } } + // Reset vector patching is done in the host tool in micronucleus >=2 + if (deviceHandle->version.major >=2) + { + if ( address == 0 ) { + // save user reset vector (bootloader will patch with its vector) + unsigned int word0,word1; + word0 = page_buffer [1] * 0x100 + page_buffer [0]; + word1 = page_buffer [3] * 0x100 + page_buffer [2]; + + if (word0==0x940c) { // long jump + userReset = word1; + } else if ((word0&0xf000)==0xc000) { // rjmp + userReset = (word0 & 0x0fff) - 0 + 1; + } else { + fprintf(stderr, + "The reset vector of the user program does not contain a branch instruction,\n" + "therefore the bootloader can not be inserted. Please rearrage your code.\n" + ); + return -1; + } + + // Patch in jmp to bootloader. + if (deviceHandle->bootloader_start > 0x2000) { + // jmp + unsigned data = 0x940c; + page_buffer [ 0 ] = data >> 0 & 0xff; + page_buffer [ 1 ] = data >> 8 & 0xff; + page_buffer [ 2 ] = deviceHandle->bootloader_start >> 0 & 0xff; + page_buffer [ 3 ] = deviceHandle->bootloader_start >> 8 & 0xff; + } else { + // rjmp + unsigned data = 0xc000 | ((deviceHandle->bootloader_start/2 - 1) & 0x0fff); + page_buffer [ 0 ] = data >> 0 & 0xff; + page_buffer [ 1 ] = data >> 8 & 0xff; + } + + } + + if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) { + // move user reset vector to end of last page + // The reset vector is always the last vector in the tinyvectortable + unsigned int user_reset_addr = (deviceHandle->pages*deviceHandle->page_size) - 4; + + if (user_reset_addr > 0x2000) { + // jmp + unsigned data = 0x940c; + page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; + page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; + page_buffer [user_reset_addr - address + 2] = userReset >> 0 & 0xff; + page_buffer [user_reset_addr - address + 3] = userReset >> 8 & 0xff; + } else { + // rjmp + unsigned data = 0xc000 | ((userReset - user_reset_addr/2 - 1) & 0x0fff); + page_buffer [user_reset_addr - address + 0] = data >> 0 & 0xff; + page_buffer [user_reset_addr - address + 1] = data >> 8 & 0xff; + } + } + } + + // always write last page so bootloader can insert the tiny vector table - if ( address >= deviceHandle->flash_size - deviceHandle->page_size ) + if ( address >= deviceHandle->bootloader_start - deviceHandle->page_size ) pagecontainsdata = 1; // ask microcontroller to write this page's data if (pagecontainsdata) { + + if (deviceHandle->version.major == 1) { + // Firmware rev.1 transfers a page as a single block + // ask microcontroller to write this page's data + res = usb_control_msg(deviceHandle->device, + USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, + page_length, address, + page_buffer, page_length, + MICRONUCLEUS_USB_TIMEOUT); + } else if (deviceHandle->version.major >= 2) { + // Firmware rev.2 uses individual set up packets to transfer data + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, page_length, address, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + if (res) return -1; + int i; + + for (i=0; i< page_length; i+=4) + { + int w1,w2; + w1=(page_buffer[i+1]<<8)+(page_buffer[i+0]<<0); + w2=(page_buffer[i+3]<<8)+(page_buffer[i+2]<<0); + + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 3, w1, w2, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + if (res) return -1; + } + } + /* res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1, @@ -156,7 +293,7 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz MICRONUCLEUS_USB_TIMEOUT); if (res != page_length) return -1; - + */ // give microcontroller enough time to write this page and come back online delay(deviceHandle->write_sleep); } @@ -174,7 +311,7 @@ int micronucleus_writeFlash(micronucleus* deviceHandle, unsigned int program_siz int micronucleus_startApp(micronucleus* deviceHandle) { int res; - res = usb_control_msg(deviceHandle->device, 0xC0, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); + res = usb_control_msg(deviceHandle->device, USB_ENDPOINT_OUT| USB_TYPE_VENDOR | USB_RECIP_DEVICE, 4, 0, 0, NULL, 0, MICRONUCLEUS_USB_TIMEOUT); if(res!=0) return -1; diff --git a/commandline/library/micronucleus_lib.h b/commandline/library/micronucleus_lib.h index 9118ace..b691fa4 100644 --- a/commandline/library/micronucleus_lib.h +++ b/commandline/library/micronucleus_lib.h @@ -3,7 +3,9 @@ /* Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> + (c) 2012 by ihsan Kehribar <ihsan@kehribar.me> + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -44,11 +46,12 @@ #define MICRONUCLEUS_VENDOR_ID 0x16D0 #define MICRONUCLEUS_PRODUCT_ID 0x0753 #define MICRONUCLEUS_USB_TIMEOUT 0xFFFF -#define MICRONUCLEUS_MAX_MAJOR_VERSION 1 +#define MICRONUCLEUS_MAX_MAJOR_VERSION 2 + /*******************************************************************************/ /******************************************************************************** -* Declearations +* Declarations ********************************************************************************/ //typedef usb_dev_handle micronucleus; // representing version number of micronucleus device @@ -57,6 +60,8 @@ typedef struct _micronucleus_version { unsigned char minor; } micronucleus_version; +#define MICRONUCLEUS_COMMANDLINE_VERSION "Commandline tool version: 2.0a5" + // handle representing one micronucleus device typedef struct _micronucleus { usb_dev_handle *device; @@ -64,9 +69,12 @@ typedef struct _micronucleus { micronucleus_version version; unsigned int flash_size; // programmable size (in bytes) of progmem unsigned int page_size; // size (in bytes) of page + unsigned int bootloader_start; // Start of the bootloader unsigned int pages; // total number of pages to program unsigned int write_sleep; // milliseconds unsigned int erase_sleep; // milliseconds + unsigned char signature1; // only used in protocol v2 + unsigned char signature2; // only used in protocol v2 } micronucleus; typedef void (*micronucleus_callback)(float progress); @@ -77,7 +85,7 @@ typedef void (*micronucleus_callback)(float progress); * Try to connect to the device * Returns: device handle for success, NULL for fail ********************************************************************************/ -micronucleus* micronucleus_connect(); +micronucleus* micronucleus_connect(int fast_mode); /*******************************************************************************/ /******************************************************************************** diff --git a/commandline/micronucleus.c b/commandline/micronucleus.c index b7d49ab..14c1761 100644 --- a/commandline/micronucleus.c +++ b/commandline/micronucleus.c @@ -1,7 +1,9 @@ /* - Created: September 2012 - by ihsan Kehribar <ihsan@kehribar.me> - +Created: September 2012 + (c) 2012 by ihsan Kehribar <ihsan@kehribar.me> + Changes for Micronucleus protocol version V2.x + (c) 2014 T. Bo"scke + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to @@ -54,6 +56,7 @@ static char* progress_friendly_name; // name of progress section static int dump_progress = 0; // output computer friendly progress info static int use_ansi = 0; // output ansi control character stuff static int erase_only = 0; // only erase, dont't write file +static int fast_mode = 0; // normal mode adds 2ms to page writing times and waits longer for connect. static int timeout = 0; /*****************************************************************************/ @@ -69,17 +72,22 @@ int main(int argc, char **argv) { int run = 0; int file_type = FILE_TYPE_INTEL_HEX; int arg_pointer = 1; - char* usage = "usage: micronucleus [--run] [--dump-progress] [--type intel-hex|raw] [--no-ansi] [--timeout integer] [--erase-only] filename"; + #if defined(WIN) + char* usage = "usage: micronucleus [--help] [--run] [--dump-progress] [--fast-mode] [--type intel-hex|raw] [--timeout integer] [--erase-only] filename"; + #else + char* usage = "usage: micronucleus [--help] [--run] [--dump-progress] [--fast-mode] [--type intel-hex|raw] [--timeout integer] [--erase-only] filename [--no-ansi]"; + #endif progress_step = 0; progress_total_steps = 5; // steps: waiting, connecting, parsing, erasing, writing, (running)? dump_progress = 0; erase_only = 0; + fast_mode=0; timeout = 0; // no timeout by default - //#if defined(WIN) - // use_ansi = 0; - //#else + #if defined(WIN) + use_ansi = 0; + #else use_ansi = 1; - //#endif + #endif while (arg_pointer < argc) { if (strcmp(argv[arg_pointer], "--run") == 0) { @@ -104,19 +112,25 @@ int main(int argc, char **argv) { puts(" for driving GUIs"); puts(" --erase-only: Erase the device without programming. Fills the"); puts(" program memory with 0xFFFF. Any files are ignored."); + puts(" --fast-mode: Speed up the timing of micronucleus. Do not use if"); + puts(" you encounter USB errors. "); puts(" --run: Ask bootloader to run the program when finished"); puts(" uploading provided program"); - //#ifndef WIN + #ifndef WIN puts(" --no-ansi: Don't use ANSI in terminal output"); - //#endif + #endif puts(" --timeout [integer]: Timeout after waiting specified number of seconds"); puts(" filename: Path to intel hex or raw data file to upload,"); puts(" or \"-\" to read from stdin"); + puts(""); + puts(MICRONUCLEUS_COMMANDLINE_VERSION); return EXIT_SUCCESS; } else if (strcmp(argv[arg_pointer], "--dump-progress") == 0) { dump_progress = 1; } else if (strcmp(argv[arg_pointer], "--no-ansi") == 0) { use_ansi = 0; + } else if (strcmp(argv[arg_pointer], "--fast-mode") == 0) { + fast_mode = 1; } else if (strcmp(argv[arg_pointer], "--erase-only") == 0) { erase_only = 1; progress_total_steps -= 1; @@ -149,7 +163,7 @@ int main(int argc, char **argv) { while (my_device == NULL) { delay(100); - my_device = micronucleus_connect(); + my_device = micronucleus_connect(fast_mode); time(¤t_time); if (timeout && start_time + timeout < current_time) { @@ -164,28 +178,20 @@ int main(int argc, char **argv) { printf("> Device is found!\n"); - // wait for CONNECT_WAIT milliseconds with progress output - float wait = 0.0f; - setProgressData("connecting", 2); - while (wait < CONNECT_WAIT) { - printProgress((wait / ((float) CONNECT_WAIT)) * 0.9f); - wait += 50.0f; - delay(50); + if (!fast_mode) { + // wait for CONNECT_WAIT milliseconds with progress output + float wait = 0.0f; + setProgressData("connecting", 2); + while (wait < CONNECT_WAIT) { + printProgress((wait / ((float) CONNECT_WAIT)) * 0.9f); + wait += 50.0f; + delay(50); + } } - - //my_device = micronucleus_connect(); printProgress(1.0); - // if (my_device->page_size == 64) { - // printf("> Device looks like ATtiny85!\n"); - // } else if (my_device->page_size == 32) { - // printf("> Device looks like ATtiny45!\n"); - // } else { - // printf("> Unsupported device!\n"); - // return EXIT_FAILURE; - // } - printf("> Device has firmware version %d.%d\n",my_device->version.major,my_device->version.minor); + if (my_device->signature1) printf("> Device signature: 0x1e%02x%02x \n",(int)my_device->signature1,(int)my_device->signature2); printf("> Available space for user applications: %d bytes\n", my_device->flash_size); printf("> Suggested sleep time between sending pages: %ums\n", my_device->write_sleep); printf("> Whole page count: %d page size: %d\n", my_device->pages,my_device->page_size); @@ -239,7 +245,7 @@ int main(int argc, char **argv) { int deciseconds_till_reconnect_notice = 50; // notice after 5 seconds while (my_device == NULL) { delay(100); - my_device = micronucleus_connect(); + my_device = micronucleus_connect(fast_mode); deciseconds_till_reconnect_notice -= 1; if (deciseconds_till_reconnect_notice == 0) { diff --git a/commandline/micronucleus.exe b/commandline/micronucleus.exe Binary files differnew file mode 100644 index 0000000..c5aeedc --- /dev/null +++ b/commandline/micronucleus.exe |