// read in a page over usb, and write it in to the flash write buffer static uchar usbFunctionWrite(uchar *data, uchar length) { //if (length > writeLength) length = writeLength; // test for missing final page bug writeLength -= length; do { // remember vectors or the tinyvector table if (currentAddress == RESET_VECTOR_OFFSET * 2) { vectorTemp[0] = *(short *)data; } if (currentAddress == USBPLUS_VECTOR_OFFSET * 2) { vectorTemp[1] = *(short *)data; } // make sure we don't write over the bootloader! if (currentAddress >= PROGMEM_SIZE) { __boot_page_fill_clear(); break; } writeWordToPageBuffer(*(uint16_t *) data); data += 2; // advance data pointer length -= 2; } while(length); // TODO: Isn't this always last? // if we have now reached another page boundary, we're done uchar isLast = (writeLength == 0); // definitely need this if! seems usbFunctionWrite gets called again in future usbPoll's in the runloop! if (isLast) fireEvent(EVENT_WRITE_PAGE); // ask runloop to write our page return isLast; // let vusb know we're done with this request }
// write a word in to the page buffer, doing interrupt table modifications where they're required static void writeWordToPageBuffer(uint16_t data) { // first two interrupt vectors get replaced with a jump to the bootloader's vector table if (currentAddress == (RESET_VECTOR_OFFSET * 2) || currentAddress == (USBPLUS_VECTOR_OFFSET * 2)) { data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; } // at end of page just before bootloader, write in tinyVector table // see http://embedded-creations.com/projects/attiny85-usb-bootloader-overview/avr-jtag-programmer/ // for info on how the tiny vector table works if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET) { data = vectorTemp[0] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 2 + RESET_VECTOR_OFFSET; } if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) { data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET; } // clear page buffer as a precaution before filling the buffer on the first page // in case the bootloader somehow ran after user program and there was something // in the page buffer already if (currentAddress == 0x0000) __boot_page_fill_clear(); cli(); boot_page_fill(currentAddress, data); sei(); // only need to erase if there is data already in the page that doesn't match what we're programming // TODO: what about this: if (pgm_read_word(currentAddress) & data != data) { ??? should work right? //if (pgm_read_word(currentAddress) != data && pgm_read_word(currentAddress) != 0xFFFF) { //if ((pgm_read_word(currentAddress) & data) != data) { // fireEvent(EVENT_PAGE_NEEDS_ERASE); //} // increment progmem address by one word currentAddress += 2; }
static void writeWordToPageBuffer(uint16_t data) { // first two interrupt vectors get replaced with a jump to the bootloader vector table if(CURRENT_ADDRESS == (RESET_VECTOR_OFFSET * 2) || CURRENT_ADDRESS == (USBPLUS_VECTOR_OFFSET * 2)) data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; // write 2's complement of checksum #ifdef APPCHECKSUM if(CURRENT_ADDRESS == BOOTLOADER_ADDRESS - APPCHECKSUM_POSITION) data = (uint8_t)(~checksum + 1); #endif if(CURRENT_ADDRESS == BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET) data = vectorTemp[0] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 2 + RESET_VECTOR_OFFSET; if(CURRENT_ADDRESS == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET; #ifdef APPCHECKSUM // only calculate checksum when we are writing new data to flash (ignore when writing vectors after bootloader programming) checksum += (uint8_t)(data/256) + (uint8_t)(data); #endif // clear page buffer as a precaution before filling the buffer on the first page // TODO: maybe clear on the first byte of every page? if(CURRENT_ADDRESS == 0x0000) __boot_page_fill_clear(); boot_page_fill(CURRENT_ADDRESS, data); // only need to erase if there is data already in the page that doesn't match what we're programming if(pgm_read_word(CURRENT_ADDRESS) != data && pgm_read_word(CURRENT_ADDRESS) != 0xFFFF) needToErase = 1; CURRENT_ADDRESS += 2; }
uchar usbFunctionWrite(uchar *data, uchar len) { uchar isLast; DBG1(0x31, (void *)¤tAddress.l, 4); if(len > bytesRemaining) len = bytesRemaining; bytesRemaining -= len; isLast = bytesRemaining == 0; if(currentRequest >= USBASP_FUNC_READEEPROM){ uchar i; for(i = 0; i < len; i++){ eeprom_write_byte((void *)(currentAddress.w[0]++), *data++); } }else { uchar i; for(i = 0; i < len;){ #ifdef TINY85MODE #if 1 if(CURRENT_ADDRESS == RESET_VECTOR_OFFSET * 2) { vectorTemp[0] = *(short *)data; } if(CURRENT_ADDRESS == USBPLUS_VECTOR_OFFSET * 2) { vectorTemp[1] = *(short *)data; } #else if(CURRENT_ADDRESS == RESET_VECTOR_OFFSET * 2 || CURRENT_ADDRESS == USBPLUS_VECTOR_OFFSET * 2) { vectorTemp[CURRENT_ADDRESS ? 1:0] = *(short *)data; } #endif #else # if !HAVE_CHIP_ERASE if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0){ /* if page start: erase */ DBG1(0x33, 0, 0); # ifndef NO_FLASH_WRITE cli(); boot_page_erase(CURRENT_ADDRESS); /* erase page */ sei(); boot_spm_busy_wait(); /* wait until page is erased */ # endif # endif #endif i += 2; DBG1(0x32, 0, 0); #ifdef TINY85MODE if(CURRENT_ADDRESS >= BOOTLOADER_ADDRESS - 6) { // stop writing data to flash if the application is too big, and clear any leftover data in the page buffer __boot_page_fill_clear(); return isLast; } writeWordToPageBuffer(*(short *)data); #else cli(); boot_page_fill(CURRENT_ADDRESS, *(short *)data); sei(); CURRENT_ADDRESS += 2; #endif data += 2; /* write page when we cross page boundary or we have the last partial page */ if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0 || (isLast && i >= len && isLastPage)){ DBG1(0x34, 0, 0); #ifdef TINY85MODE flashPageLoaded = 1; #else # ifndef NO_FLASH_WRITE cli(); boot_page_write(CURRENT_ADDRESS - 2); sei(); boot_spm_busy_wait(); cli(); boot_rww_enable(); sei(); # endif #endif } } DBG1(0x35, (void *)¤tAddress.l, 4); } return isLast; } uchar usbFunctionRead(uchar *data, uchar len) { uchar i; if(len > bytesRemaining) len = bytesRemaining; bytesRemaining -= len; for(i = 0; i < len; i++){ if(currentRequest >= USBASP_FUNC_READEEPROM){ *data = eeprom_read_byte((void *)currentAddress.w[0]); }else{ *data = pgm_read_byte((void *)CURRENT_ADDRESS); // read back original vectors #ifdef TINY85MODE #if 1 if(CURRENT_ADDRESS == RESET_VECTOR_OFFSET * 2) *data = vectorTemp[0]; if(CURRENT_ADDRESS == (RESET_VECTOR_OFFSET * 2) + 1) *data = vectorTemp[0]/256; if(CURRENT_ADDRESS == (USBPLUS_VECTOR_OFFSET * 2)) *data = vectorTemp[1]; if(CURRENT_ADDRESS == (USBPLUS_VECTOR_OFFSET * 2) + 1) *data = vectorTemp[1]/256; #else if(CURRENT_ADDRESS == RESET_VECTOR_OFFSET * 2 || CURRENT_ADDRESS == USBPLUS_VECTOR_OFFSET * 2) { *(short *)data = vectorTemp[CURRENT_ADDRESS ? 1:0]; data++; CURRENT_ADDRESS++; } #endif #endif } data++; CURRENT_ADDRESS++; } return len; }