diff options
Diffstat (limited to 'firmware/main.c')
-rw-r--r-- | firmware/main.c | 122 |
1 files changed, 72 insertions, 50 deletions
diff --git a/firmware/main.c b/firmware/main.c index e56de62..ad08895 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -15,6 +15,9 @@ // needs to be above 4.5 (and a whole integer) as avr freezes for 4.5ms #define MICRONUCLEUS_WRITE_SLEEP 8 +// Use the old delay routines without NOP padding. This saves memory. +#define __DELAY_BACKWARD_COMPATIBLE__ + #include <avr/io.h> #include <avr/interrupt.h> @@ -96,20 +99,14 @@ static uchar events = 0; // bitmap of events to run #define isEvent(event) (events & (event)) #define clearEvents() events = 0 -// length of bytes to write in to flash memory in upcomming usbFunctionWrite calls -//static unsigned char writeLength; - -// becomes 1 when some programming happened -// lets leaveBootloader know if needs to finish up the programming -static uchar didWriteSomething = 0; - uint16_t idlePolls = 0; // how long have we been idle? - - static uint16_t vectorTemp[2]; // remember data to create tinyVector table before BOOTLOADER_ADDRESS static addr_t currentAddress; // current progmem address, used for erasing and writing +#ifdef RESTORE_OSCCAL + static uint8_t osccal_default; // due to compiler insanity, having this as global actually saves memory +#endif /* ------------------------------------------------------------------------ */ static inline void eraseApplication(void); @@ -127,21 +124,23 @@ static inline void leaveBootloader(void); // 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. -// - if vectors weren't written back in immidately, usb would fail. +// - if vectors weren't written back in immediately, usb would fail. static inline void eraseApplication(void) { // erase all pages until bootloader, in reverse order (so our vectors stay in place for as long as possible) // while the vectors don't matter for usb comms as interrupts are disabled during erase, it's important // to minimise the chance of leaving the device in a state where the bootloader wont run, if there's power failure // during upload - currentAddress = BOOTLOADER_ADDRESS; + addr_t ptr = BOOTLOADER_ADDRESS; + cli(); - while (currentAddress) { - currentAddress -= SPM_PAGESIZE; + while (ptr) { + ptr -= SPM_PAGESIZE; - boot_page_erase(currentAddress); + boot_page_erase(ptr); boot_spm_busy_wait(); } + currentAddress = 0; fillFlashWithVectors(); sei(); } @@ -149,7 +148,6 @@ static inline void eraseApplication(void) { // simply write currently stored page in to already erased flash memory static void writeFlashPage(void) { uint8_t previous_sreg = SREG; // backup current interrupt setting - didWriteSomething = 1; cli(); boot_page_write(currentAddress - 2); boot_spm_busy_wait(); // Wait until the memory is written. @@ -185,8 +183,10 @@ static void writeWordToPageBuffer(uint16_t data) { data = vectorTemp[0] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 2 + RESET_VECTOR_OFFSET; } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) { data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET; +#ifndef RESTORE_OSCCAL } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) { data = OSCCAL; +#endif } @@ -221,9 +221,18 @@ static void fillFlashWithVectors(void) { //} // TODO: Or more simply: + + +#if SPM_PAGESIZE<256 do { - writeWordToPageBuffer(0xFFFF); + writeWordToPageBuffer(0xFFFF); + } while ((uchar)currentAddress % SPM_PAGESIZE); +#else + do { + writeWordToPageBuffer(0xFFFF); } while (currentAddress % SPM_PAGESIZE); +#endif + writeFlashPage(); } @@ -292,7 +301,14 @@ static uchar usbFunctionWrite(uchar *data, uchar length) { // if we have now reached another page boundary, we're done //uchar isLast = (writeLength == 0); + +#if SPM_PAGESIZE<256 + // Hack to reduce code size + uchar isLast = ((((uchar)currentAddress) % SPM_PAGESIZE) == 0); +#else uchar isLast = ((currentAddress % SPM_PAGESIZE) == 0); +#endif + // 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 @@ -326,12 +342,9 @@ static inline void tiny85FlashInit(void) { // check for erased first page (no bootloader interrupt vectors), add vectors if missing // this needs to happen for usb communication to work later - essential to first run after bootloader // being installed - if(pgm_read_word(RESET_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1 || - pgm_read_word(USBPLUS_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1) { - - fillFlashWithVectors(); - } - + + if(pgm_read_byte(RESET_VECTOR_OFFSET * 2+1) == 0xff) fillFlashWithVectors(); // write vectors if flash is empty + // TODO: necessary to reset currentAddress? currentAddress = 0; } @@ -341,24 +354,21 @@ static inline void tiny85FlashWrites(void) { // write page to flash, interrupts will be disabled for > 4.5ms including erase // TODO: Do we need this? Wouldn't the programmer always send full sized pages? - if (currentAddress % SPM_PAGESIZE) { // when we aren't perfectly aligned to a flash page boundary + +#if SPM_PAGESIZE<256 + // Hack to reduce code size + if ((uchar)currentAddress % SPM_PAGESIZE) +#else + if (currentAddress % SPM_PAGESIZE) +#endif + { + // when we aren't perfectly aligned to a flash page boundary fillFlashWithVectors(); // fill up the rest of the page with 0xFFFF (unprogrammed) bits } else { writeFlashPage(); // otherwise just write it } } -// finishes up writing to the flash, including adding the tinyVector tables at the end of memory -// TODO: can this be simplified? EG: currentAddress = PROGMEM_SIZE; fillFlashWithVectors(); -// static inline void tiny85FinishWriting(void) { -// // make sure remainder of flash is erased and write checksum and application reset vectors -// if (didWriteSomething) { -// while (currentAddress < BOOTLOADER_ADDRESS) { -// fillFlashWithVectors(); -// } -// } -// } - // reset system to a normal state and launch user program static inline void leaveBootloader(void) { _delay_ms(10); // removing delay causes USB errors @@ -366,24 +376,25 @@ static inline void leaveBootloader(void) { //DBG1(0x01, 0, 0); bootLoaderExit(); cli(); + usbDeviceDisconnect(); /* Disconnect micronucleus */ + USB_INTR_ENABLE = 0; USB_INTR_CFG = 0; /* also reset config bits */ // clear magic word from bottom of stack before jumping to the app - *(uint8_t*)(RAMEND) = 0x00; - *(uint8_t*)(RAMEND-1) = 0x00; + *(uint8_t*)(RAMEND) = 0x00; // A single write is sufficient to invalidate magic word + // *(uint8_t*)(RAMEND-1) = 0x00; +#ifndef RESTORE_OSCCAL // adjust clock to previous calibration value, so user program always starts with same calibration // as when it was uploaded originally // TODO: Test this and find out, do we need the +1 offset? unsigned char stored_osc_calibration = pgm_read_byte(BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET); if (stored_osc_calibration != 0xFF && stored_osc_calibration != 0x00) { - //OSCCAL = stored_osc_calibration; // this should really be a gradual change, but maybe it's alright anyway? - // do the gradual change - failed to score extra free bytes anyway in 1.06 - while (OSCCAL > stored_osc_calibration) OSCCAL--; - while (OSCCAL < stored_osc_calibration) OSCCAL++; + OSCCAL=stored_osc_calibration; + asm volatile("nop"); } - +#endif // jump to application reset vector at end of flash asm volatile ("rjmp __vectors - 4"); } @@ -391,17 +402,18 @@ static inline void leaveBootloader(void) { int main(void) { /* initialize */ #ifdef RESTORE_OSCCAL - uint8_t osccal_default = OSCCAL; + osccal_default = OSCCAL; #endif #if (!SET_CLOCK_PRESCALER) && LOW_POWER_MODE uint8_t prescaler_default = CLKPR; #endif - + + + MCUSR=0; /* clean wdt reset bit if reset occured due to wdt */ wdt_disable(); /* main app may have enabled watchdog */ tiny85FlashInit(); bootLoaderInit(); - - + if (bootLoaderStartCondition()) { #if LOW_POWER_MODE // turn off clock prescalling - chip must run at full speed for usb @@ -410,11 +422,14 @@ int main(void) { CLKPR = 0; #endif + #ifdef NANITE + PORTB &=~_BV(NANITE_CTRLPIN); + #endif initForUsbConnectivity(); do { - usbPoll(); + + usbPoll(); _delay_us(100); - idlePolls++; // these next two freeze the chip for ~ 4.5ms, breaking usb protocol // and usually both of these will activate in the same loop, so host @@ -422,6 +437,11 @@ int main(void) { if (isEvent(EVENT_ERASE_APPLICATION)) eraseApplication(); if (isEvent(EVENT_WRITE_PAGE)) tiny85FlashWrites(); + #ifdef NANITE + DDRB |= _BV(NANITE_CTRLPIN); + if (((unsigned char*)&idlePolls)[1]&0xd) DDRB &=~_BV(NANITE_CTRLPIN); + #endif + # if BOOTLOADER_CAN_EXIT if (isEvent(EVENT_EXECUTE)) { // when host requests device run uploaded program break; @@ -429,7 +449,7 @@ int main(void) { # endif clearEvents(); - + } while(bootLoaderCondition()); /* main event loop runs so long as bootLoaderCondition remains truthy */ } @@ -443,10 +463,12 @@ int main(void) { CLKPR = prescaler_default; #endif #endif + - // slowly bring down OSCCAL to it's original value before launching in to user program #ifdef RESTORE_OSCCAL - while (OSCCAL > osccal_default) { OSCCAL -= 1; } + + OSCCAL=osccal_default; + asm volatile("nop"); // NOP to avoid CPU hickup during osccillator stabilization #endif leaveBootloader(); } |