.Sect1 .Endnote_20_Symbol .Footnote_20_Symbol { } -->
  1. 1./* Name: main.c 

  2. 2. * Title: AVR bootloader HID 

  3. 3. * Author: Christian Starkjohann 

  4. 4. * Creation Date: 2007-03-19 

  5. 5. * Tabsize: 4 

  6. 6. * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 

  7. 7. * License: GNU GPL v2 (see License.txt) 

  8. 8. * This Revision: $Id: main.c 693 2008-11-14 15:09:37Z cs $ 

  9. 9. */ 

  10. 10.#include <avr/io.h> 

  11. 11.#include <avr/interrupt.h> 

  12. 12.#include <avr/pgmspace.h> 

  13. 13.#include <avr/wdt.h> 

  14. 14.#include <avr/boot.h> 

  15. 15.#include <string.h> 

  16. 16.#include <util/delay.h> 

  17. 17. 

  18. 18.static void leaveBootloader() __attribute__((__noreturn__)); 

GNU C Compiler attribut noreturn

  1. 19.#include "bootloaderconfig.h" 

  2. 20.#include "usbdrv.c" 

  3. 21. 

  4. 22./* ------------------------------------------------------------------------ */ 

  5. 23. 

  6. 24.#ifndef ulong 

  7. 25.#   define ulong    unsigned long 

  8. 26.#endif 

  9. 27.#ifndef uint 

  10. 28.#   define uint     unsigned int 

  11. 29.#endif 

  12. 30. 

  13. 31.#if (FLASHEND) > 0xffff /* we need long addressing */ 

  14. 32.#   define addr_t           ulong 

  15. 33.#else 

  16. 34.#   define addr_t           uint 

  17. 35.#endif 

  18. 36. 

  19. 37.static addr_t           currentAddress; /* in bytes */ 

  20. 38.static uchar            offset;         /* data already processed in current transfer */ 

  21. 39.#if BOOTLOADER_CAN_EXIT 

  22. 40.static uchar            exitMainloop; 

  23. 41.#endif 

  24. 42. 

Report Deskriptoren beschreiben, was ein Gerät kann; Deskriptoren können mit einer Software, die auf usb.org verfügbar ist, erzeugt werden

HID Descriptor Info

das erste Byte ist eine Kennung, das zweite/dritte Byte sind der Wert
z.B: 6  (Usage-Page) 0xff00  (Vendor specific Page)

  1. 43.PROGMEM char usbHidReportDescriptor[33] = { 

  2. 44.    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop) 

  3. 45.    0x09, 0x01,                    // USAGE (Vendor Usage 1) 

  4. 46.    0xa1, 0x01,                    // COLLECTION (Application) 

  5. 47.    0x15, 0x00,                    //   LOGICAL_MINIMUM (0) 

  6. 48.    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255) 

  7. 49.    0x75, 0x08,                    //   REPORT_SIZE (8) 

  8. 50. 

  9. 51.    0x85, 0x01,                    //   REPORT_ID (1) 

  10. 52.    0x95, 0x06,                    //   REPORT_COUNT (6) 

  11. 53.    0x09, 0x00,                    //   USAGE (Undefined) 

  12. 54.    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf) 

  13. 55. 

  14. 56.    0x85, 0x02,                    //   REPORT_ID (2) 

  15. 57.    0x95, 0x83,                    //   REPORT_COUNT (131) 

  16. 58.    0x09, 0x00,                    //   USAGE (Undefined) 

  17. 59.    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf) 

  18. 60.    0xc0                           // END_COLLECTION 

  19. 61.}; 

  20. 62. 

  21. 63./* allow compatibility with avrusbboot's bootloaderconfig.h: */ 

  22. 64.#ifdef BOOTLOADER_INIT 

  23. 65.#   define bootLoaderInit()         BOOTLOADER_INIT 

  24. 66.#endif 

  25. 67.#ifdef BOOTLOADER_CONDITION 

  26. 68.#   define bootLoaderCondition()    BOOTLOADER_CONDITION 

  27. 69.#endif 

  28. 70. 

  29. 71./* compatibility with ATMega88 and other new devices: */ 

  30. 72.#ifndef TCCR0 

  31. 73.#define TCCR0   TCCR0B 

  32. 74.#endif 

  33. 75.#ifndef GICR 

  34. 76.#define GICR    MCUCR 

  35. 77.#endif 

  36. 78. 

  37. 79.static void (*nullVector)(void) __attribute__((__noreturn__)); 

  38. 80. 

  39. 81.static void leaveBootloader() 

  40. 82.{ 

  41. 83.    DBG1(0x01, 0, 0); 

oddebug.h  ==>   This module implements a function for debug logs on the serial line of the

AVR microcontroller. Debugging can be configured with the define

'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging

calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is

2, DBG1 and DBG2 logs will be printed.

  1. 84.    cli(); 

  2. 85.    boot_rww_enable(); 

boot.h  ==>  boot_rww_enable ();

    // Re-enable interrupts (if they were ever enabled).

  1. 86. 

  2. 87.    USB_INTR_ENABLE = 0; 

  3. 88.    USB_INTR_CFG = 0;       /* also reset config bits */ 

Substitution für die Konfig-Register für Prozessorunabhängigkeit

  1. 89.#if F_CPU == 12800000 

  2. 90.    TCCR0 = 0;              /* default value */ 

  3. 91.#endif 

  4. 92.    GICR = (1 << IVCE);     /* enable change of interrupt vectors */ 

  5. 93.    GICR = (0 << IVSEL);    /* move interrupts to application flash section */ 

  6. 94./* We must go through a global function pointer variable instead of writing 

  7. 95. * because the compiler optimizes a constant 0 to "rcall 0" which is not 

  8. 96. * handled correctly by the assembler. 

  9. 97. */ 

((void (*)(void))0)();  

hier wird die Adresse 0 in einen Funktionszeiger umgewandelt und dieser dann aufgerufen; der Aufruf erfolgt mit rcall (zu kurz)

ein long-Call wird so gemacht:static void (*nullVector)(void) __attribute__((__noreturn__));

der Aufruf erfolgt mit icall

  1. 98.    nullVector(); 

  2. 99.} 

  3. 100. 

  1. 101.{ 

  2. 102.usbRequest_t    *rq = (void *)data; 

  3. 103.static uchar    replyBuffer[7] = { 

  4. 104.        1,                              /* report ID */ 

  5. 105.        SPM_PAGESIZE & 0xff, 

  6. 106.        SPM_PAGESIZE >> 8, 

  7. 107.        ((long)FLASHEND + 1) & 0xff, 

  8. 108.        (((long)FLASHEND + 1) >> 8) & 0xff, 

  9. 109.        (((long)FLASHEND + 1) >> 16) & 0xff, 

  10. 110.        (((long)FLASHEND + 1) >> 24) & 0xff 

  11. 111.    }; 

  12. 112. 

  13. 113.    if(rq->bRequest == USBRQ_HID_SET_REPORT){ 

  14. 114.        if(rq->wValue.bytes[0] == 2){ 

  15. 115.            offset = 0; 

  16. 116.            return USB_NO_MSG; 

  17. 117.        } 

  18. 118.#if BOOTLOADER_CAN_EXIT 

  19. 119.        else{ 

  20. 120.            exitMainloop = 1; 

  21. 121.        } 

  22. 122.#endif 

  23. 123.    }else if(rq->bRequest == USBRQ_HID_GET_REPORT){ 

  24. 124.        usbMsgPtr = replyBuffer; 

  25. 125.        return 7; 

  26. 126.    } 

  27. 127.    return 0; 

  28. 128.} 

  29. 129. 

uchar usbFunctionWrite(uchar *data, uchar len)

  1. 130.{ 

  2. 131.union { 

  3. 132.    addr_t  l; 

  4. 133.    uint    s[sizeof(addr_t)/2]; 

  5. 134.    uchar   c[sizeof(addr_t)]; 

  6. 135.}       address; 

  7. 136.uchar   isLast; 

  8. 137. 

  9. 138.    address.l = currentAddress; 

  10. 139.    if(offset == 0){ 

  11. 140.        DBG1(0x30, data, 3); 

  12. 141.        address.c[0] = data[1]; 

  13. 142.        address.c[1] = data[2]; 

  14. 143.#if (FLASHEND) > 0xffff /* we need long addressing */ 

  15. 144.        address.c[2] = data[3]; 

  16. 145.        address.c[3] = 0; 

  17. 146.#endif 

  18. 147.        data += 4; 

  19. 148.        len -= 4; 

  20. 149.    } 

  21. 150.    DBG1(0x31, (void *)&currentAddress, 4); 

  22. 151.    offset += len; 

  23. 152.    isLast = offset & 0x80; /* != 0 if last block received */ 

  24. 153.    do{ 

  25. 154.        addr_t prevAddr; 

  26. 155.#if SPM_PAGESIZE > 256 

  27. 156.        uint pageAddr; 

  28. 157.#else 

  29. 158.        uchar pageAddr; 

  30. 159.#endif 

  31. 160.        DBG1(0x32, 0, 0); 

  32. 161.        pageAddr = address.s[0] & (SPM_PAGESIZE - 1); 

  33. 162.        if(pageAddr == 0){              /* if page start: erase */ 

  34. 163.            DBG1(0x33, 0, 0); 

  35. 164.#ifndef TEST_MODE 

  36. 165.            cli(); 

  37. 166.            boot_page_erase(address.l); /* erase page */ 

  38. 167.            sei(); 

  39. 168.            boot_spm_busy_wait();       /* wait until page is erased */ 

  40. 169.#endif 

  41. 170.        } 

  42. 171.        cli(); 

  43. 172.        boot_page_fill(address.l, *(short *)data); 

  44. 173.        sei(); 

  45. 174.        prevAddr = address.l; 

  46. 175.        address.l += 2; 

  47. 176.        data += 2; 

  48. 177.        /* write page when we cross page boundary */ 

  49. 178.        pageAddr = address.s[0] & (SPM_PAGESIZE - 1); 

  50. 179.        if(pageAddr == 0){ 

  51. 180.            DBG1(0x34, 0, 0); 

  52. 181.#ifndef TEST_MODE 

  53. 182.            cli(); 

  54. 183.            boot_page_write(prevAddr); 

  55. 184.            sei(); 

  56. 185.            boot_spm_busy_wait(); 

  57. 186.#endif 

  58. 187.        } 

  59. 188.        len -= 2; 

  60. 189.    }while(len); 

  61. 190.    currentAddress = address.l; 

  62. 191.    DBG1(0x35, (void *)&currentAddress, 4); 

  63. 192.    return isLast; 

  64. 193.} 

  65. 194. 

  1. 195.{ 

  2. 196.uchar   i = 0; 

  3. 197. 

  4. 198.#if F_CPU == 12800000 

  5. 199.    TCCR0 = 3;          /* 1/64 prescaler */ 

  6. 200.#endif 

  7. 201.    usbInit(); 

  8. 202.    /* enforce USB re-enumerate: */ 

  9. 203.    usbDeviceDisconnect();  /* do this while interrupts are disabled */ 

  10. 204.    do{             /* fake USB disconnect for > 250 ms */ 

  11. 205.        wdt_reset(); 

  12. 206.        _delay_ms(1); 

  13. 207.    }while(--i); 

  14. 208.    usbDeviceConnect(); 

  15. 209.    sei(); 

  16. 210.} 

  17. 211. 

  1. 212.{ 

  2. 213.    /* initialize hardware */ 

  3. 214.    bootLoaderInit(); 

  4. 215.    odDebugInit(); 

  5. 216.    DBG1(0x00, 0, 0); 

  6. 217.    /* jump to application if jumper is set */ 

  7. 218.    if(bootLoaderCondition()){ 

ist der Bootloader-Jumper gesetzt?

  1. 219.        uchar i = 0, j = 0; 

  2. 220.#ifndef TEST_MODE 

Das IVSEL-Bit kann allerdings nicht auf beliebige Art und Weise verän-

dert werden. Eine Modifikation ist nur durch folgenden Ablauf möglich:

• IVCE auf ’1’ setzen

• Innerhalb von 4 Takten IVSEL auf den gewünschten Wert setzen,

gleichzeitig IVCE auf ’0’ setzen

  1. 221.        GICR = (1 << IVCE);  /* enable change of interrupt vectors */ 

  2. 222.        GICR = (1 << IVSEL); /* move interrupts to boot flash section */ 

  3. 223.#endif 

  4. 224.        initForUsbConnectivity(); 

  5. 225.        do{ /* main event loop */ 

  6. 226.            wdt_reset(); 

  7. 227.            usbPoll(); 

  8. 228.#if BOOTLOADER_CAN_EXIT 

  9. 229.            if(exitMainloop){ 

oder Endlosschleife und  Ausstieg durch Reset

  1. 230.#if F_CPU == 12800000 

  2. 231.                break;  /* memory is tight at 12.8 MHz, save exit delay below */ 

  3. 232.#endif 

  4. 233.                if(--i == 0){ 

  5. 234.                    if(--j == 0) 

  6. 235.                        break; 

  7. 236.                } 

  8. 237.            } 

  9. 238.#endif 

  10. 239.        }while(bootLoaderCondition()); 

  11. 240.    } 

  12. 241.    leaveBootloader(); 

  13. 242.    return 0; 

  14. 243.}