summaryrefslogtreecommitdiffstats
path: root/commandline/library/micronucleus_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'commandline/library/micronucleus_lib.c')
-rw-r--r--commandline/library/micronucleus_lib.c69
1 files changed, 62 insertions, 7 deletions
diff --git a/commandline/library/micronucleus_lib.c b/commandline/library/micronucleus_lib.c
index 6e574f5..76594d8 100644
--- a/commandline/library/micronucleus_lib.c
+++ b/commandline/library/micronucleus_lib.c
@@ -28,7 +28,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;
@@ -62,15 +62,22 @@ micronucleus* micronucleus_connect() {
// get nucleus info
unsigned char buffer[4];
- int res = usb_control_msg(nucleus->device, 0xC0, 0, 0, 0, (char *)buffer, 4, MICRONUCLEUS_USB_TIMEOUT);
+ 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);
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)&&(!fast_mode)) {
+ // firmware v2 reports more aggressive write times. Add 2ms if fast mode is not used.
+ nucleus->write_sleep = buffer[3]+2;
+ nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages;
+ } else {
+ nucleus->write_sleep = buffer[3];
+ nucleus->erase_sleep = nucleus->write_sleep * nucleus->pages;
+ }
}
}
}
@@ -80,7 +87,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 +129,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 +150,59 @@ 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)
+ userReset = page_buffer [1] * 0x100 + page_buffer [0];
+
+ if ( address >= deviceHandle->flash_size - deviceHandle->page_size )
+ {
+ // move user reset vector to end of last page
+ // The reset vector is always the last vector in the tinyvectortable
+ unsigned user_reset_addr = (deviceHandle->pages*deviceHandle->page_size)-2;
+ unsigned data = (userReset + 0x1000 - user_reset_addr/2) & ~0x1000;
+
+ 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 )
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 +211,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 +229,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;