bootloader/main.c

Go to the documentation of this file.
00001 /* Name: main.c
00002  * Project: USBaspLoader
00003  * Author: Christian Starkjohann
00004  * Creation Date: 2007-12-08
00005  * Tabsize: 4
00006  * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
00007  * License: GNU GPL v2 (see License.txt)
00008  * This Revision: $Id: main.c,v 1.1 2008-07-09 20:47:11 rschaten Exp $
00009  */
00010 
00011 #include <avr/io.h>
00012 #include <avr/interrupt.h>
00013 #include <avr/pgmspace.h>
00014 #include <avr/wdt.h>
00015 #include <avr/boot.h>
00016 #include <avr/eeprom.h>
00017 #include <util/delay.h>
00018 #include <string.h>
00019 
00020 static void leaveBootloader() __attribute__((__noreturn__));
00021 
00022 #include "bootloaderconfig.h"
00023 #include "usbdrv/usbdrv.c"
00024 
00025 /* ------------------------------------------------------------------------ */
00026 
00027 /* Request constants used by USBasp */
00028 #define USBASP_FUNC_CONNECT         1
00029 #define USBASP_FUNC_DISCONNECT      2
00030 #define USBASP_FUNC_TRANSMIT        3
00031 #define USBASP_FUNC_READFLASH       4
00032 #define USBASP_FUNC_ENABLEPROG      5
00033 #define USBASP_FUNC_WRITEFLASH      6
00034 #define USBASP_FUNC_READEEPROM      7
00035 #define USBASP_FUNC_WRITEEEPROM     8
00036 #define USBASP_FUNC_SETLONGADDRESS  9
00037 
00038 /* ------------------------------------------------------------------------ */
00039 
00040 #ifndef ulong
00041 #   define ulong    unsigned long
00042 #endif
00043 #ifndef uint
00044 #   define uint     unsigned int
00045 #endif
00046 
00047 /* defaults if not in config file: */
00048 #ifndef HAVE_EEPROM_PAGED_ACCESS
00049 #   define HAVE_EEPROM_PAGED_ACCESS 0
00050 #endif
00051 #ifndef HAVE_EEPROM_BYTE_ACCESS
00052 #   define HAVE_EEPROM_BYTE_ACCESS  0
00053 #endif
00054 #ifndef BOOTLOADER_CAN_EXIT
00055 #   define  BOOTLOADER_CAN_EXIT     0
00056 #endif
00057 
00058 /* allow compatibility with avrusbboot's bootloaderconfig.h: */
00059 #ifdef BOOTLOADER_INIT
00060 #   define bootLoaderInit()         BOOTLOADER_INIT
00061 #   define bootLoaderExit()
00062 #endif
00063 #ifdef BOOTLOADER_CONDITION
00064 #   define bootLoaderCondition()    BOOTLOADER_CONDITION
00065 #endif
00066 
00067 /* device compatibility: */
00068 #ifndef GICR    /* ATMega*8 don't have GICR, use MCUCR instead */
00069 #   define GICR     MCUCR
00070 #endif
00071 
00072 /* ------------------------------------------------------------------------ */
00073 
00074 typedef union longConverter{
00075     ulong   l;
00076     uint    w[2];
00077     uchar   b[4];
00078 }longConverter_t;
00079 
00080 static uchar            requestBootLoaderExit;
00081 static longConverter_t  currentAddress; /* in bytes */
00082 static uchar            bytesRemaining;
00083 static uchar            isLastPage;
00084 #if HAVE_EEPROM_PAGED_ACCESS
00085 static uchar            currentRequest;
00086 #else
00087 static const uchar      currentRequest = 0;
00088 #endif
00089 
00090 static const uchar  signatureBytes[4] = {
00091 #ifdef SIGNATURE_BYTES
00092     SIGNATURE_BYTES
00093 #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8HVA__)
00094     0x1e, 0x93, 0x07, 0
00095 #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__)
00096     0x1e, 0x92, 0x05, 0
00097 #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__)
00098     0x1e, 0x93, 0x0a, 0
00099 #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
00100     0x1e, 0x94, 0x06, 0
00101 #elif defined (__AVR_ATmega328P__)
00102     0x1e, 0x95, 0x0f, 0
00103 #elif defined (__AVR_ATmega32__)
00104     0x1e, 0x95, 0x02, 0
00105 #else
00106 #   error "Device signature is not known, please edit main.c!"
00107 #endif
00108 };
00109 
00110 #if (FLASHEND) > 0xffff /* we need long addressing */
00111 #   define CURRENT_ADDRESS  currentAddress.l
00112 #else
00113 #   define CURRENT_ADDRESS  currentAddress.w[0]
00114 #endif
00115 
00116 /* ------------------------------------------------------------------------ */
00117 
00118 static void (*nullVector)(void) __attribute__((__noreturn__));
00119 
00120 static void leaveBootloader()
00121 {
00122     DBG1(0x01, 0, 0);
00123     bootLoaderExit();
00124     cli();
00125     GICR = (1 << IVCE);  /* enable change of interrupt vectors */
00126     GICR = (0 << IVSEL); /* move interrupts to application flash section */
00127 /* We must go through a global function pointer variable instead of writing
00128  *  ((void (*)(void))0)();
00129  * because the compiler optimizes a constant 0 to "rcall 0" which is not
00130  * handled correctly by the assembler.
00131  */
00132     nullVector();
00133 }
00134 
00135 /* ------------------------------------------------------------------------ */
00136 
00137 uchar   usbFunctionSetup(uchar data[8])
00138 {
00139 usbRequest_t    *rq = (void *)data;
00140 uchar           len = 0;
00141 static uchar    replyBuffer[4];
00142 
00143     usbMsgPtr = replyBuffer;
00144     if(rq->bRequest == USBASP_FUNC_TRANSMIT){   /* emulate parts of ISP protocol */
00145         uchar rval = 0;
00146         usbWord_t address;
00147         address.bytes[1] = rq->wValue.bytes[1];
00148         address.bytes[0] = rq->wIndex.bytes[0];
00149         if(rq->wValue.bytes[0] == 0x30){        /* read signature */
00150             rval = rq->wIndex.bytes[0] & 3;
00151             rval = signatureBytes[rval];
00152 #if HAVE_EEPROM_BYTE_ACCESS
00153         }else if(rq->wValue.bytes[0] == 0xa0){  /* read EEPROM byte */
00154             rval = eeprom_read_byte((void *)address.word);
00155         }else if(rq->wValue.bytes[0] == 0xc0){  /* write EEPROM byte */
00156             eeprom_write_byte((void *)address.word, rq->wIndex.bytes[1]);
00157 #endif
00158         }else{
00159             /* ignore all others, return default value == 0 */
00160         }
00161         replyBuffer[3] = rval;
00162         len = 4;
00163     }else if(rq->bRequest == USBASP_FUNC_ENABLEPROG){
00164         /* replyBuffer[0] = 0; is never touched and thus always 0 which means success */
00165         len = 1;
00166     }else if(rq->bRequest >= USBASP_FUNC_READFLASH && rq->bRequest <= USBASP_FUNC_SETLONGADDRESS){
00167         currentAddress.w[0] = rq->wValue.word;
00168         if(rq->bRequest == USBASP_FUNC_SETLONGADDRESS){
00169 #if (FLASHEND) > 0xffff
00170             currentAddress.w[1] = rq->wIndex.word;
00171 #endif
00172         }else{
00173             bytesRemaining = rq->wLength.bytes[0];
00174             /* if(rq->bRequest == USBASP_FUNC_WRITEFLASH) only evaluated during writeFlash anyway */
00175             isLastPage = rq->wIndex.bytes[1] & 0x02;
00176 #if HAVE_EEPROM_PAGED_ACCESS
00177             currentRequest = rq->bRequest;
00178 #endif
00179             len = 0xff; /* hand over to usbFunctionRead() / usbFunctionWrite() */
00180         }
00181 #if BOOTLOADER_CAN_EXIT
00182     }else if(rq->bRequest == USBASP_FUNC_DISCONNECT){
00183         requestBootLoaderExit = 1;      /* allow proper shutdown/close of connection */
00184 #endif
00185     }else{
00186         /* ignore: USBASP_FUNC_CONNECT */
00187     }
00188     return len;
00189 }
00190 
00191 uchar usbFunctionWrite(uchar *data, uchar len)
00192 {
00193 uchar   isLastWrite;
00194 
00195     DBG1(0x31, (void *)&currentAddress.l, 4);
00196     if(len > bytesRemaining)
00197         len = bytesRemaining;
00198     bytesRemaining -= len;
00199     isLastWrite = bytesRemaining == 0;
00200     if(currentRequest >= USBASP_FUNC_READEEPROM){
00201         eeprom_write_block(data, (void *)currentAddress.w[0], len);
00202         currentAddress.w[0] += len;
00203     }else{
00204         char i = len;
00205         while(i > 0){
00206             i -= 2;
00207             if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0){    /* if page start: erase */
00208                 DBG1(0x33, 0, 0);
00209 #ifndef NO_FLASH_WRITE
00210                 cli();
00211                 boot_page_erase(CURRENT_ADDRESS);   /* erase page */
00212                 sei();
00213                 boot_spm_busy_wait();               /* wait until page is erased */
00214 #endif
00215             }
00216             DBG1(0x32, 0, 0);
00217             cli();
00218             boot_page_fill(CURRENT_ADDRESS, *(short *)data);
00219             sei();
00220             CURRENT_ADDRESS += 2;
00221             data += 2;
00222             /* write page when we cross page boundary or we have the last partial page */
00223             if((currentAddress.w[0] & (SPM_PAGESIZE - 1)) == 0 || (i <= 0 && isLastWrite && isLastPage)){
00224                 DBG1(0x34, 0, 0);
00225 #ifndef NO_FLASH_WRITE
00226                 cli();
00227                 boot_page_write(CURRENT_ADDRESS - 2);
00228                 sei();
00229                 boot_spm_busy_wait();
00230                 cli();
00231                 boot_rww_enable();
00232                 sei();
00233 #endif
00234             }
00235         }
00236         DBG1(0x35, (void *)&currentAddress.l, 4);
00237     }
00238     return isLastWrite;
00239 }
00240 
00241 uchar usbFunctionRead(uchar *data, uchar len)
00242 {
00243     if(len > bytesRemaining)
00244         len = bytesRemaining;
00245     bytesRemaining -= len;
00246     if(currentRequest >= USBASP_FUNC_READEEPROM){
00247         eeprom_read_block(data, (void *)currentAddress.w[0], len);
00248     }else{
00249         memcpy_P(data, (PGM_VOID_P)CURRENT_ADDRESS, len);
00250     }
00251     CURRENT_ADDRESS += len;
00252     return len;
00253 }
00254 
00255 /* ------------------------------------------------------------------------ */
00256 
00257 static void initForUsbConnectivity(void)
00258 {
00259 uchar   i = 0;
00260 
00261     usbInit();
00262     /* enforce USB re-enumerate: */
00263     usbDeviceDisconnect();  /* do this while interrupts are disabled */
00264     while(--i){         /* fake USB disconnect for > 250 ms */
00265         wdt_reset();
00266         _delay_ms(1);
00267     }
00268     usbDeviceConnect();
00269     sei();
00270 }
00271 
00272 int main(void)
00273 {
00274     /* initialize  */
00275     bootLoaderInit();
00276     odDebugInit();
00277     DBG1(0x00, 0, 0);
00278 #ifndef NO_FLASH_WRITE
00279     GICR = (1 << IVCE);  /* enable change of interrupt vectors */
00280     GICR = (1 << IVSEL); /* move interrupts to boot flash section */
00281 #endif
00282     if(bootLoaderCondition()){
00283         uint i = 0;
00284         initForUsbConnectivity();
00285         do{
00286             usbPoll();
00287 #if BOOTLOADER_CAN_EXIT
00288             if(requestBootLoaderExit){
00289                 if(--i == 0)
00290                     break;
00291             }
00292 #endif
00293         }while(bootLoaderCondition());  /* main event loop */
00294     }
00295     leaveBootloader();
00296     return 0;
00297 }
00298 
00299 /* ------------------------------------------------------------------------ */

Generated on Sat Jul 12 22:27:14 2008 for Dulcimer by  doxygen 1.5.4