⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bootrom.c

📁 at91的一个bootloader
💻 C
字号:
//-----------------------------------------------------------------------------
// The bootrom proper; the piece of code that runs from RAM and can program
// flash. If we are loaded over JTAG, then we go directly into RAM; otherwise
// we are copied from some location in flash into RAM by the routines in
// fromflash.c. In any case, we start up the USB driver and either load
// new code (if the downloader connects) or give up waiting and jump to
// the application.
//
// Jonathan Westhues, split Aug 14 2005, public release May 26 2006
//-----------------------------------------------------------------------------
#include <bootrom.h>

static void ConfigClocks(void)
{
    volatile int i;

    // we are using a 16 MHz crystal as the basis for everything
    PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROCESSOR_CLK | PMC_SYS_CLK_UDP_CLK;

    PMC_PERIPHERAL_CLK_ENABLE =
        (1<<PERIPH_PIOA) |
        (1<<PERIPH_ADC) |
        (1<<PERIPH_SPI) |
        (1<<PERIPH_SSC) |
        (1<<PERIPH_PWMC) |
        (1<<PERIPH_UDP);

    PMC_MAIN_OSCILLATOR = PMC_MAIN_OSCILLATOR_ENABLE |
        PMC_MAIN_OSCILLATOR_STARTUP_DELAY(0x40);

    // TODO: THIS DEPENDS ON THE CRYSTAL FREQUENCY THAT YOU CHOOSE. Make
    // the ARM run at some reasonable speed, and make the USB peripheral
    // run at exactly 48 MHz.

    // minimum PLL clock frequency is 80 MHz in range 00 (96 here so okay)
    PMC_PLL = PMC_PLL_DIVISOR(2) | PMC_PLL_COUNT_BEFORE_LOCK(0x40) |
        PMC_PLL_FREQUENCY_RANGE(0) | PMC_PLL_MULTIPLIER(12) |
        PMC_PLL_USB_DIVISOR(1);

    // let the PLL spin up, plenty of time
    for(i = 0; i < 100; i++)
        ;

    PMC_MASTER_CLK = PMC_CLK_SELECTION_SLOW_CLOCK | PMC_CLK_PRESCALE_DIV_2;

    for(i = 0; i < 100; i++)
        ;

    PMC_MASTER_CLK = PMC_CLK_SELECTION_PLL_CLOCK | PMC_CLK_PRESCALE_DIV_2;

    for(i = 0; i < 100; i++)
        ;
}

static void Fatal(void)
{
    for(;;);
}

void UsbPacketReceived(BYTE *packet, int len)
{
    int i;
    UsbCommand *c = (UsbCommand *)packet;
    volatile DWORD *p;

    if(len != sizeof(*c)) {
        Fatal();
    }

    switch(c->cmd) {
        case CMD_DEVICE_INFO:
            break;

        case CMD_SETUP_WRITE:
            p = (volatile DWORD *)0;
            for(i = 0; i < 12; i++) {
                p[i+c->ext1] = c->d.asDwords[i];
            }
            break;

        case CMD_FINISH_WRITE:
            p = (volatile DWORD *)0;
            for(i = 0; i < 4; i++) {
                p[i+60] = c->d.asDwords[i];
            }

            MC_FLASH_COMMAND = MC_FLASH_COMMAND_KEY |
                MC_FLASH_COMMAND_PAGEN(c->ext1/FLASH_PAGE_SIZE_BYTES) |
                FCMD_WRITE_PAGE;
            while(!(MC_FLASH_STATUS & MC_FLASH_STATUS_READY))
                ;
            break;

        case CMD_HARDWARE_RESET:
            break;

        default:
            Fatal();
            break;
    }

    c->cmd = CMD_ACK;
    UsbSendPacket(packet, len);
}

void Bootrom(void)
{
    //------------
    // First set up all the I/O pins; GPIOs configured directly, other ones
    // just need to be assigned to the appropriate peripheral.

    // Kill all the pullups, especially the one on USB D+; leave them for
    // the unused pins, though.
    PIO_NO_PULL_UP_ENABLE =     (1 << GPIO_USB_PU)          | 
                                (1 << GPIO_LED);

    PIO_OUTPUT_ENABLE =         (1 << GPIO_LED);

    PIO_ENABLE =                (1 << GPIO_USB_PU)          |
                                (1 << GPIO_LED);

    USB_D_PLUS_PULLUP_OFF();
    LED_OFF();

    LED_ON();

    // Configure the flash that we are running out of.
    MC_FLASH_MODE = MC_FLASH_MODE_FLASH_WAIT_STATES(0) | 
        MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48);

    // Careful, a lot of peripherals can't be configured until the PLL clock
    // comes up; you write to the registers but it doesn't stick.
    ConfigClocks();

    UsbStart();

    // Borrow a PWM unit for my real-time clock
    PWM_ENABLE = PWM_CHANNEL(0);
    // 48 MHz / 1024 gives 46.875 kHz
    PWM_CH_MODE(0) = PWM_CH_MODE_PRESCALER(10);
    PWM_CH_DUTY_CYCLE(0) = 0;
    PWM_CH_PERIOD(0) = 0xffff;

    WORD start = (SWORD)PWM_CH_COUNTER(0);

    for(;;) {
        WORD now = (SWORD)PWM_CH_COUNTER(0);

        if(UsbPoll()) {
            // It did something; reset the clock that would jump us to the
            // applications.
            start = now;
        }

        WDT_HIT();

        if((SWORD)(now - start) > 30000) {
            USB_D_PLUS_PULLUP_OFF();

            // This is a function call to 0x00002001, which is equal to
            // (1 << 13) | 1. The application is at address 0x00002000, and
            // we want to set the LSb in order to switch in to Thumb mode
            // when we bx. 
            //
            // I would have thought that I could write this as a cast to
            // a function pointer and a call, but I can't seem to get that
            // to work. I also can't figure out how to make the assembler
            // load pc relative a constant in flash, thus the ugly way
            // to specify the address.
            asm("mov r3, #1\n");
            asm("lsl r3, r3, #13\n");
            asm("mov r4, #1\n");
            asm("orr r3, r4\n");
            asm("bx r3\n");
        }
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -