summaryrefslogtreecommitdiffstats
path: root/commandline
diff options
context:
space:
mode:
Diffstat (limited to 'commandline')
-rw-r--r--commandline/Makefile5
-rwxr-xr-xcommandline/builds/OSX/micronucleusbin124292 -> 0 bytes
-rw-r--r--[-rwxr-xr-x]commandline/builds/Windows/micronucleus.exebin26126 -> 27662 bytes
-rw-r--r--commandline/library/micronucleus_lib.c173
-rw-r--r--commandline/library/micronucleus_lib.h16
-rw-r--r--commandline/micronucleus.c66
-rw-r--r--commandline/micronucleus.exebin0 -> 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
deleted file mode 100755
index 3ae62c4..0000000
--- a/commandline/builds/OSX/micronucleus
+++ /dev/null
Binary files differ
diff --git a/commandline/builds/Windows/micronucleus.exe b/commandline/builds/Windows/micronucleus.exe
index bfdb56b..aa4752f 100755..100644
--- a/commandline/builds/Windows/micronucleus.exe
+++ b/commandline/builds/Windows/micronucleus.exe
Binary files differ
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(&current_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
new file mode 100644
index 0000000..c5aeedc
--- /dev/null
+++ b/commandline/micronucleus.exe
Binary files differ