diff options
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/main.c | 246 | 
1 files changed, 122 insertions, 124 deletions
| diff --git a/firmware/main.c b/firmware/main.c index 48ac399..bec0305 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -70,7 +70,7 @@ static uint16_t vectorTemp[2]; // remember data to create tinyVector table befor  static uint16_t currentAddress; // current progmem address, used for erasing and writing  #if OSCCAL_RESTORE - static uint8_t osccal_default;  // due to compiler insanity, having this as global actually saves memory +  static uint8_t osccal_default;  // due to compiler insanity, having this as global actually saves memory  #endif   /* ------------------------------------------------------------------------ */ @@ -86,142 +86,140 @@ static inline void leaveBootloader(void);  //  - vectors in now, and write in the application stuff around them later.  //  - 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 -     -    uint8_t i; -	uint16_t ptr = BOOTLOADER_ADDRESS; -    cli(); -    while (ptr) { -        ptr -= SPM_PAGESIZE;         -        boot_page_erase(ptr); -    } +  // 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 +   +  uint8_t i; +  uint16_t ptr = BOOTLOADER_ADDRESS; +  cli(); + +  while (ptr) { +    ptr -= SPM_PAGESIZE;         +    boot_page_erase(ptr); +  }  	currentAddress = 0; -    for (i=0; i<8; i++) writeWordToPageBuffer(0xFFFF);  // Write first 8 words to fill in vectors. -    writeFlashPage();  // enables interrupts +  for (i=0; i<8; i++) writeWordToPageBuffer(0xFFFF);  // Write first 8 words to fill in vectors. +  writeFlashPage();  // enables interrupts  }  // simply write currently stored page in to already erased flash memory  static void writeFlashPage(void) { -    cli(); -    boot_page_write(currentAddress - 2);   // will halt CPU, no waiting required -    sei(); +  cli(); +  boot_page_write(currentAddress - 2);   // will halt CPU, no waiting required +  sei();  }  // 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)))     \ -    );                                           \ +  __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) { -    uint8_t previous_sreg; +  uint8_t previous_sreg; +   +  // first two interrupt vectors get replaced with a jump to the bootloader's vector table +  // remember vectors or the tinyvector table  +    if (currentAddress == RESET_VECTOR_OFFSET * 2) { +      vectorTemp[0] = data; +      data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; +    } +     +    if (currentAddress == USBPLUS_VECTOR_OFFSET * 2) { +      vectorTemp[1] = data; +      data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; +    } -    // first two interrupt vectors get replaced with a jump to the bootloader's vector table -    // remember vectors or the tinyvector table  -        if (currentAddress == RESET_VECTOR_OFFSET * 2) { -            vectorTemp[0] = data; -            data = 0xC000 + (BOOTLOADER_ADDRESS/2) - 1; -        } -         -        if (currentAddress == USBPLUS_VECTOR_OFFSET * 2) { -            vectorTemp[1] = data; -            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; -    } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) { -        data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET; +  // 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; +  } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_USBPLUS_OFFSET) { +      data = vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS)/2 + 1 + USBPLUS_VECTOR_OFFSET;  #if (!OSCCAL_RESTORE) && OSCCAL_16_5MHz    -    } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) { -        data = OSCCAL; +  } else if (currentAddress == BOOTLOADER_ADDRESS - TINYVECTOR_OSCCAL_OFFSET) { +      data = OSCCAL;  #endif		 -    } +  } -    previous_sreg=SREG;     -    cli(); // ensure interrupts are disabled -     -    boot_page_fill(currentAddress, data); -     -    // increment progmem address by one word -    currentAddress += 2; -    SREG=previous_sreg; +  previous_sreg=SREG;     +  cli(); // ensure interrupts are disabled +   +  boot_page_fill(currentAddress, data); +   +  // increment progmem address by one word +  currentAddress += 2; +  SREG=previous_sreg;  }  /* ------------------------------------------------------------------------ */  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 uint8_t replyBuffer[4] = { -        (((uint16_t)PROGMEM_SIZE) >> 8) & 0xff, -        ((uint16_t)PROGMEM_SIZE) & 0xff, -        SPM_PAGESIZE, -        MICRONUCLEUS_WRITE_SLEEP -    }; +  usbRequest_t *rq = (void *)data; +  ((uint8_t*)&idlePolls)[1] = 0;              // reset idle polls when we get usb traffic + +  static uint8_t replyBuffer[4] = { +    (((uint16_t)PROGMEM_SIZE) >> 8) & 0xff, +    ((uint16_t)PROGMEM_SIZE) & 0xff, +    SPM_PAGESIZE, +    MICRONUCLEUS_WRITE_SLEEP +  }; -    if (rq->bRequest == 0) { // get device info -        usbMsgPtr = replyBuffer; -        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 -         -    } else if (rq->bRequest == 2) { // erase application -        fireEvent(EVENT_ERASE_APPLICATION); -         -    } else { // exit bootloader -#       if BOOTLOADER_CAN_EXIT -            fireEvent(EVENT_EXECUTE); -#       endif -    } +  if (rq->bRequest == 0) { // get device info +    usbMsgPtr = replyBuffer; +    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 -    return 0; +  } else if (rq->bRequest == 2) { // erase application +    fireEvent(EVENT_ERASE_APPLICATION); +       +  } else { // exit bootloader +    fireEvent(EVENT_EXECUTE); +  } +   +  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 >= BOOTLOADER_ADDRESS) break; -         -        writeWordToPageBuffer(*(uint16_t *) data); -        data += 2; // advance data pointer -        length -= 2; -    } while(length); +  do {      +    // make sure we don't write over the bootloader! +    if (currentAddress >= BOOTLOADER_ADDRESS) break; -    // if we have now reached another page boundary, we're done +    writeWordToPageBuffer(*(uint16_t *) data); +    data += 2; // advance data pointer +    length -= 2; +  } while(length); +   +  // if we have now reached another page boundary, we're done  #if SPM_PAGESIZE<256  	// Hack to reduce code size -    uint8_t isLast = ((((uint8_t)currentAddress) % SPM_PAGESIZE) == 0); +  uint8_t isLast = ((((uint8_t)currentAddress) % SPM_PAGESIZE) == 0);  #else -    uint8_t 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! -    if (isLast) fireEvent(EVENT_WRITE_PAGE); // ask runloop to write our page -     -    return isLast; // let vusb know we're done with this request +  // 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  }  /* ------------------------------------------------------------------------ */ @@ -229,10 +227,10 @@ void PushMagicWord (void) __attribute__ ((naked)) __attribute__ ((section (".ini  // put the word "B007" at the bottom of the stack (RAMEND - RAMEND-1)  void PushMagicWord (void) { -    asm volatile("ldi r16, 0xB0"::); -    asm volatile("push r16"::); -    asm volatile("ldi r16, 0x07"::); -    asm volatile("push r16"::); +  asm volatile("ldi r16, 0xB0"::); +  asm volatile("push r16"::); +  asm volatile("ldi r16, 0x07"::); +  asm volatile("push r16"::);  }  static void initHardware (void) @@ -252,29 +250,29 @@ static void initHardware (void)  // 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 -     -    bootLoaderExit(); -    cli(); + _delay_ms(10); // removing delay causes USB errors +   +  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; // A single write is sufficient to invalidate magic word +  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; // A single write is sufficient to invalidate magic word  #if (!OSCCAL_RESTORE) && OSCCAL_16_5MHz    -    // adjust clock to previous calibration value, so user program always starts with same calibration -    // 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; -		nop(); -    } +  // adjust clock to previous calibration value, so user program always starts with same calibration +  // 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; +  nop(); +  }  #endif -    // jump to application reset vector at end of flash -    asm volatile ("rjmp __vectors - 4"); +  // jump to application reset vector at end of flash +  asm volatile ("rjmp __vectors - 4");  }  int main(void) { | 
