From 568359df2c8ad4293dfc14b57db9b01fb2f1adab Mon Sep 17 00:00:00 2001 From: cpldcpu Date: Sun, 5 Jan 2014 19:35:47 +0100 Subject: commandline: Support for new v2 transmission protocol The block transfer is now done in the address and indexfield of a setup-packet to save a lot of memory in the firmware: This requires twice the number of transmissions, but is effectively faster due to less bus congestion and resends. --- firmware/main.c | 226 ++++++++++++++++++++++++++------------------------------ 1 file changed, 106 insertions(+), 120 deletions(-) (limited to 'firmware/main.c') diff --git a/firmware/main.c b/firmware/main.c index 513a956..246b2f9 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -52,6 +52,7 @@ enum { cmd_device_info=0, cmd_transfer_page=1, cmd_erase_application=2, + cmd_write_data=3, cmd_exit=4, cmd_write_page=64, // internal commands start at 64 }; @@ -66,9 +67,21 @@ static inline void eraseApplication(void); static void writeFlashPage(void); static void writeWordToPageBuffer(uint16_t data); static uint8_t usbFunctionSetup(uint8_t data[8]); -static uint8_t usbFunctionWrite(uint8_t *data, uint8_t length); static inline void leaveBootloader(void); +// clear memory which stores data to be written by next writeFlashPage call +#define __boot_page_fill_clear() \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)(__BOOT_PAGE_FILL | (1 << CTPB))) \ + ); \ +})) + // erase any existing application and write in jumps for usb interrupt and reset to bootloader // - Because flash can be erased once and programmed several times, we can write the bootloader // - vectors in now, and write in the application stuff around them later. @@ -86,34 +99,24 @@ static inline void eraseApplication(void) { ptr -= SPM_PAGESIZE; boot_page_erase(ptr); } + + // clear page buffer as a precaution before filling the buffer in case + // a previous write operation failed and there is still something in the buffer. + __boot_page_fill_clear(); - // Code size is increase if this stuff is removed?!? - currentAddress.w = 0; - for (i=0; i<8; i++) writeWordToPageBuffer(0xFFFF); // Write first 8 words to fill in vectors. - writeFlashPage(); + // Write reset vector into first page. + currentAddress.w = 0; + writeWordToPageBuffer(0xffff); + command=cmd_write_page; } // simply write currently stored page in to already erased flash memory static inline void writeFlashPage(void) { - - boot_page_write(currentAddress.w - 2); // will halt CPU, no waiting required - + if (currentAddress.w<=BOOTLOADER_ADDRESS) + boot_page_write(currentAddress.w - 2); // will halt CPU, no waiting required } -// clear memory which stores data to be written by next writeFlashPage call -#define __boot_page_fill_clear() \ -(__extension__({ \ - __asm__ __volatile__ \ - ( \ - "sts %0, %1\n\t" \ - "spm\n\t" \ - : \ - : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ - "r" ((uint8_t)(__BOOT_PAGE_FILL | (1 << CTPB))) \ - ); \ -})) - // write a word in to the page buffer, doing interrupt table modifications where they're required static void writeWordToPageBuffer(uint16_t data) { @@ -121,10 +124,10 @@ static void writeWordToPageBuffer(uint16_t data) { // the device can not be bricked. // Saving user-reset-vector is done in the host tool, starting with // firmware V2 - - if (currentAddress.w == RESET_VECTOR_OFFSET * 2) { - data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; - } + + if (currentAddress.w == RESET_VECTOR_OFFSET * 2) { + data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; + } #if (!OSCCAL_RESTORE) && OSCCAL_16_5MHz if (currentAddress.w == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) { @@ -134,58 +137,41 @@ static void writeWordToPageBuffer(uint16_t data) { boot_page_fill(currentAddress.w, data); - // increment progmem address by one word currentAddress.w += 2; } // This function is never called, it is just here to suppress a compiler warning. USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) { return 0; } -/* ------------------------------------------------------------------------ */ -static uint8_t usbFunctionSetup(uint8_t data[8]) { - usbRequest_t *rq = (void *)data; - - static uint8_t replyBuffer[4] = { + PROGMEM const uint8_t replyBuffer[4] = { (((uint16_t)PROGMEM_SIZE) >> 8) & 0xff, ((uint16_t)PROGMEM_SIZE) & 0xff, SPM_PAGESIZE, MICRONUCLEUS_WRITE_SLEEP - }; + }; + +/* ------------------------------------------------------------------------ */ +static uint8_t usbFunctionSetup(uint8_t data[8]) { + usbRequest_t *rq = (void *)data; + idlePolls.b[1]=0; // reset idle polls when we get usb traffic if (rq->bRequest == cmd_device_info) { // get device info - usbMsgPtr = replyBuffer; + usbMsgPtr = (usbMsgPtr_t)replyBuffer; return 4; - } else if (rq->bRequest == cmd_transfer_page) { // transfer page - // clear page buffer as a precaution before filling the buffer in case - // a previous write operation failed and there is still something in the buffer. - __boot_page_fill_clear(); - currentAddress.w = rq->wIndex.word; - return USB_NO_MSG; // hands off work to usbFunctionWrite + } else if (rq->bRequest == cmd_transfer_page) { // initialize write page + currentAddress.w = rq->wIndex.word; + } else if (rq->bRequest == cmd_write_data) { // Write data + writeWordToPageBuffer(rq->wValue.word); + writeWordToPageBuffer(rq->wIndex.word); + if ((currentAddress.b[0] % SPM_PAGESIZE) == 0) + command=cmd_write_page; // ask runloop to write our page } else { // Handle cmd_erase_application and cmd_exit command=rq->bRequest; - return 0; } -} - -// read in a page over usb, and write it in to the flash write buffer -static uint8_t usbFunctionWrite(uint8_t *data, uint8_t length) { - do { - // make sure we don't write over the bootloader! - if (currentAddress.w >= BOOTLOADER_ADDRESS) break; - - writeWordToPageBuffer(*(uint16_t *) data); - data += 2; // advance data pointer - length -= 2; - } while(length); - - // if we have now reached another page boundary, we're done - uint8_t isLast = ((currentAddress.b[0] % SPM_PAGESIZE) == 0); - if (isLast) command=cmd_write_page; // ask runloop to write our page - - return isLast; // let V-USB know we're done with this request + return 0; } static void initHardware (void) @@ -235,13 +221,12 @@ static inline void leaveBootloader(void) { } #endif - asm volatile ("rjmp __vectors - 2"); // jump to application reset vector at end of flash + asm volatile ("rjmp __vectors - 2"); // jump to application reset vector at end of flash - for (;;); // Make sure function does not return to help compiler optimize + for (;;); // Make sure function does not return to help compiler optimize } void USB_INTR_VECTOR(void); - int main(void) { uint8_t ackSent=0; bootLoaderInit(); @@ -263,73 +248,74 @@ int main(void) { USB_INTR_PENDING = 1<