diff options
Diffstat (limited to 'firmware/main.c')
-rw-r--r-- | firmware/main.c | 134 |
1 files changed, 69 insertions, 65 deletions
diff --git a/firmware/main.c b/firmware/main.c index 6f7f180..a7deccc 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -16,7 +16,6 @@ // how many milliseconds should host wait till it sends another erase or write? // 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__ @@ -26,8 +25,6 @@ #include <avr/boot.h> #include <util/delay.h> -static void leaveBootloader() __attribute__((__noreturn__)); - #include "bootloaderconfig.h" #include "usbdrv/usbdrv.c" @@ -50,7 +47,9 @@ static void leaveBootloader() __attribute__((__noreturn__)); #endif // events system schedules functions to run in the main loop -static uchar events = 0; // bitmap of events to run +// static uint8_t events = 0; // bitmap of events to run +register uint8_t events asm( "r3" ); // register saves many bytes + #define EVENT_ERASE_APPLICATION 1 #define EVENT_WRITE_PAGE 2 #define EVENT_EXECUTE 4 @@ -77,8 +76,8 @@ static uint16_t currentAddress; // current progmem address, used for erasing and static inline void eraseApplication(void); static void writeFlashPage(void); static void writeWordToPageBuffer(uint16_t data); -static uchar usbFunctionSetup(uchar data[8]); -static uchar usbFunctionWrite(uchar *data, uchar length); +static uint8_t usbFunctionSetup(uint8_t data[8]); +static uint8_t usbFunctionWrite(uint8_t *data, uint8_t length); static inline void leaveBootloader(void); // erase any existing application and write in jumps for usb interrupt and reset to bootloader @@ -92,14 +91,14 @@ static inline void eraseApplication(void) { // during upload uint8_t i; - uint16_t ptr = BOOTLOADER_ADDRESS; + uint16_t ptr = BOOTLOADER_ADDRESS; cli(); while (ptr) { ptr -= SPM_PAGESIZE; boot_page_erase(ptr); } - currentAddress = 0; + currentAddress = 0; for (i=0; i<8; i++) writeWordToPageBuffer(0xFFFF); // Write first 8 words to fill in vectors. writeFlashPage(); // enables interrupts } @@ -150,16 +149,12 @@ static void writeWordToPageBuffer(uint16_t data) { #if (!OSCCAL_RESTORE) && OSCCAL_16_5MHz } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) { data = OSCCAL; -#endif +#endif } previous_sreg=SREG; cli(); // ensure interrupts are disabled - // 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(); boot_page_fill(currentAddress, data); // increment progmem address by one word @@ -168,11 +163,11 @@ static void writeWordToPageBuffer(uint16_t data) { } /* ------------------------------------------------------------------------ */ -static uchar usbFunctionSetup(uchar data[8]) { +static uint8_t usbFunctionSetup(uint8_t data[8]) { usbRequest_t *rq = (void *)data; ((uint8_t*)&idlePolls)[1] = 0; // reset idle polls when we get usb traffic - - static uchar replyBuffer[4] = { + + static uint8_t replyBuffer[4] = { (((uint16_t)PROGMEM_SIZE) >> 8) & 0xff, ((uint16_t)PROGMEM_SIZE) & 0xff, SPM_PAGESIZE, @@ -184,6 +179,10 @@ static uchar usbFunctionSetup(uchar data[8]) { return 4; } else if (rq->bRequest == 1) { // write 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 = rq->wIndex.word; return USB_NO_MSG; // hands off work to usbFunctionWrite @@ -200,7 +199,7 @@ static uchar usbFunctionSetup(uchar data[8]) { } // read in a page over usb, and write it in to the flash write buffer -static uchar usbFunctionWrite(uchar *data, uchar length) { +static uint8_t usbFunctionWrite(uint8_t *data, uint8_t length) { do { // make sure we don't write over the bootloader! if (currentAddress >= BOOTLOADER_ADDRESS) break; @@ -212,10 +211,10 @@ static uchar usbFunctionWrite(uchar *data, uchar length) { // if we have now reached another page boundary, we're done #if SPM_PAGESIZE<256 - // Hack to reduce code size - uchar isLast = ((((uchar)currentAddress) % SPM_PAGESIZE) == 0); + // Hack to reduce code size + uint8_t isLast = ((((uint8_t)currentAddress) % SPM_PAGESIZE) == 0); #else - uchar isLast = ((currentAddress % SPM_PAGESIZE) == 0); + uint8_t isLast = ((currentAddress % SPM_PAGESIZE) == 0); #endif // definitely need this if! seems usbFunctionWrite gets called again in future usbPoll's in the runloop! @@ -235,15 +234,36 @@ void PushMagicWord (void) { asm volatile("push r16"::); } +static void initHardware (void) +{ + MCUSR=0; /* need this to properly disable watchdog */ + wdt_disable(); + + #if LOW_POWER_MODE + // turn off clock prescalling - chip must run at full speed for usb + // if you might run chip at lower voltages, detect that in bootLoaderStartCondition + CLKPR = 1 << CLKPCE; + CLKPR = 0; + #endif + + + usbDeviceDisconnect(); /* do this while interrupts are disabled */ + _delay_ms(500); + usbDeviceConnect(); + usbInit(); // Initialize INT settings after reconnect + sei(); +} + /* ------------------------------------------------------------------------ */ // reset system to a normal state and launch user program +static void leaveBootloader(void) __attribute__((__noreturn__)); static inline void leaveBootloader(void) { - _delay_ms(10); // removing delay causes USB errors + _delay_ms(10); // removing delay causes USB errors bootLoaderExit(); cli(); - usbDeviceDisconnect(); /* Disconnect micronucleus */ - + usbDeviceDisconnect(); /* Disconnect micronucleus */ + USB_INTR_ENABLE = 0; USB_INTR_CFG = 0; /* also reset config bits */ @@ -255,8 +275,8 @@ static inline void leaveBootloader(void) { // as when it was uploaded originally 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; - asm volatile("nop"); + OSCCAL=stored_osc_calibration; + asm volatile("nop"); } #endif // jump to application reset vector at end of flash @@ -273,56 +293,40 @@ int main(void) { #endif bootLoaderInit(); - -# if AUTO_EXIT_NO_USB_MS - ((uint8_t*)&idlePolls)[1]=((AUTO_EXIT_MS-AUTO_EXIT_NO_USB_MS) * 10UL)>>8; // write only high byte to save 6 bytes -# endif + +# if AUTO_EXIT_NO_USB_MS + ((uint8_t*)&idlePolls)[1]=((AUTO_EXIT_MS-AUTO_EXIT_NO_USB_MS) * 10UL)>>8; // write only high byte to save 6 bytes +# endif if (bootLoaderStartCondition()) { - MCUSR=0; /* need this to properly disable watchdog */ - wdt_disable(); - - #if LOW_POWER_MODE - // turn off clock prescalling - chip must run at full speed for usb - // if you might run chip at lower voltages, detect that in bootLoaderStartCondition - CLKPR = 1 << CLKPCE; - CLKPR = 0; - #endif + initHardware(); # if LED_PRESENT LED_INIT(); -# endif - - usbDeviceDisconnect(); /* do this while interrupts are disabled */ - _delay_ms(500); - usbDeviceConnect(); - usbInit(); // Initialize INT settings after reconnect - sei(); - +# endif do { - usbPoll(); - _delay_us(100); - - // 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 - // needs to wait > 9ms before next usb request - if (isEvent(EVENT_ERASE_APPLICATION)) eraseApplication(); - if (isEvent(EVENT_WRITE_PAGE)) { - _delay_us(2000); // Wait for USB traffic to finish before halting CPU with write- - writeFlashPage(); - } - -# if BOOTLOADER_CAN_EXIT - if (isEvent(EVENT_EXECUTE)) break; // when host requests device run uploaded program -# endif clearEvents(); + usbPoll(); + _delay_us(100); + + // 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 + // needs to wait > 9ms before next usb request + if (isEvent(EVENT_ERASE_APPLICATION)) eraseApplication(); + if (isEvent(EVENT_WRITE_PAGE)) { + _delay_us(2000); // Wait for USB traffic to finish before halting CPU with write- + writeFlashPage(); + } # if LED_PRESENT LED_MACRO( ((uint8_t*)&idlePolls)[1] ) # endif - - } while(bootLoaderCondition()); /* main event loop runs so long as bootLoaderCondition remains truthy */ + + // Only try to execute program if reset vector is set - bootloader will not time out with erased memory + if (!bootLoaderCondition()&&(pgm_read_byte(BOOTLOADER_ADDRESS - TINYVECTOR_RESET_OFFSET + 1)!=0xff)) fireEvent(EVENT_EXECUTE); + + } while(!isEvent(EVENT_EXECUTE)); /* main event loop runs as long as program is not executed */ } // set clock prescaler to desired clock speed (changing from clkdiv8, or no division, depending on fuses) @@ -341,8 +345,8 @@ int main(void) { # endif # if OSCCAL_RESTORE - OSCCAL=osccal_default; - asm volatile("nop"); // NOP to avoid CPU hickup during oscillator stabilization + OSCCAL=osccal_default; + asm volatile("nop"); // NOP to avoid CPU hickup during oscillator stabilization # endif leaveBootloader(); |