int main(void) { bool try_boot = true; /* try booting before we drop to the bootloader */ unsigned timeout = BOOTLOADER_DELAY; /* if nonzero, drop out of the bootloader after this time */ /* Enable the FPU before we hit any FP instructions */ SCB_CPACR |= ((3UL << 10*2) | (3UL << 11*2)); /* set CP10 Full Access and set CP11 Full Access */ #if defined(BOARD_VRBRAINV40) || defined(BOARD_VRBRAINV45) if(!board_test_force_pin() && !(board_get_rtc_signature() == BOOT_RTC_SIGNATURE)) { jump_to_app(); } #endif /* do board-specific initialisation */ board_init(); /* * Check the force-bootloader register; if we find the signature there, don't * try booting. */ if (board_get_rtc_signature() == BOOT_RTC_SIGNATURE) { /* * Don't even try to boot before dropping to the bootloader. */ try_boot = false; /* * Don't drop out of the bootloader until something has been uploaded. */ timeout = 0; #if defined(BOARD_VRBRAINV40) || defined(BOARD_VRBRAINV45) // force an erase of the first sector because version 4.x // of the board is not able to reset USB after first boot. // This will force the bootloader to stay until a program has been flashed. flash_unlock(); flash_func_erase_sector(0); flash_lock(); #endif /* * Clear the signature so that if someone resets us while we're * in the bootloader we'll try to boot next time. */ board_set_rtc_signature(0); } #ifdef INTERFACE_USB /* * Check for USB connection - if present, don't try to boot, but set a timeout after * which we will fall out of the bootloader. * * If the force-bootloader pins are tied, we will stay here until they are removed and * we then time out. */ #if defined(BOARD_VRBRAINV40) || defined(BOARD_VRBRAINV45) if (gpio_get(BOARD_PRESENCE_PORT, BOARD_PRESENCE_PIN) != 0 && board_test_force_pin()) { /* don't try booting before we set up the bootloader */ try_boot = false; } #else if (gpio_get(BOARD_PRESENCE_PORT, BOARD_PRESENCE_PIN) != 0) { /* don't try booting before we set up the bootloader */ try_boot = false; } #endif #endif /* Try to boot the app if we think we should just go straight there */ if (try_boot) { /* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */ #ifdef BOARD_BOOT_FAIL_DETECT board_set_rtc_signature(BOOT_RTC_SIGNATURE); #endif /* try to boot immediately */ jump_to_app(); /* booting failed, stay in the bootloader forever */ timeout = 0; } /* configure the clock for bootloader activity */ rcc_clock_setup_hse_3v3(&clock_setup); /* start the interface */ cinit(BOARD_INTERFACE_CONFIG); #if 0 // MCO1/02 gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO8); gpio_set_af(GPIOA, GPIO_AF0, GPIO8); gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); gpio_set_af(GPIOC, GPIO_AF0, GPIO9); #endif while (1) { /* run the bootloader, come back after an app is uploaded or we time out */ bootloader(timeout); /* if the force-bootloader pins are strapped, just loop back */ if (board_test_force_pin()) continue; /* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */ #ifdef BOARD_BOOT_FAIL_DETECT board_set_rtc_signature(BOOT_RTC_SIGNATURE); #endif /* look to see if we can boot the app */ jump_to_app(); /* launching the app failed - stay in the bootloader forever */ timeout = 0; } }
void bootloader(unsigned timeout) { int c; int arg = 0; unsigned i; unsigned address = board_info.fw_size; /* force erase before upload will work */ uint32_t first_word = 0xffffffff; static union { uint8_t c[256]; uint32_t w[64]; } flash_buffer; /* (re)start the timer system */ systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB); systick_set_reload(board_info.systick_mhz * 1000); /* 1ms tick, magic number */ systick_interrupt_enable(); systick_counter_enable(); /* if we are working with a timeout, start it running */ if (timeout) timer[TIMER_BL_WAIT] = timeout; while (true) { // Wait for a command byte led_off(LED_ACTIVITY); do { /* if we have a timeout and the timer has expired, return now */ if (timeout && !timer[TIMER_BL_WAIT]) return; /* try to get a byte from the host */ c = cin_wait(0); } while (c < 0); led_on(LED_ACTIVITY); // common argument handling for commands switch (c) { case PROTO_GET_SYNC: case PROTO_CHIP_ERASE: case PROTO_CHIP_VERIFY: case PROTO_DEBUG: /* expect EOC */ if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; break; case PROTO_PROG_MULTI: /* expect count */ arg = cin_wait(1000); if (arg < 0) goto cmd_bad; break; case PROTO_GET_DEVICE: case PROTO_READ_MULTI: /* expect arg/count then EOC */ arg = cin_wait(1000); if (arg < 0) goto cmd_bad; if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; break; } // handle the command byte switch (c) { case PROTO_GET_SYNC: // sync break; case PROTO_GET_DEVICE: // report board info switch (arg) { case PROTO_DEVICE_BL_REV: cout((uint8_t *)&bl_proto_rev, sizeof(bl_proto_rev)); break; case PROTO_DEVICE_BOARD_ID: cout((uint8_t *)&board_info.board_type, sizeof(board_info.board_type)); break; case PROTO_DEVICE_BOARD_REV: cout((uint8_t *)&board_info.board_rev, sizeof(board_info.board_rev)); break; case PROTO_DEVICE_FW_SIZE: cout((uint8_t *)&board_info.fw_size, sizeof(board_info.fw_size)); break; default: goto cmd_bad; } break; case PROTO_CHIP_ERASE: // erase the program area + read for programming flash_unlock(); for (i = 0; flash_func_sector_size(i) != 0; i++) flash_func_erase_sector(i); address = 0; break; case PROTO_CHIP_VERIFY: // reset for verification of the program area address = 0; break; case PROTO_PROG_MULTI: // program bytes if (arg % 4) goto cmd_bad; if ((address + arg) > board_info.fw_size) goto cmd_bad; if (arg > sizeof(flash_buffer.c)) goto cmd_bad; for (i = 0; i < arg; i++) { c = cin_wait(1000); if (c < 0) goto cmd_bad; flash_buffer.c[i] = c; } if (cin_wait(1000) != PROTO_EOC) goto cmd_bad; if (address == 0) { // save the first word and don't program it until // everything else is done first_word = flash_buffer.w[0]; // replace first word with bits we can overwrite later flash_buffer.w[0] = 0xffffffff; } arg /= 4; for (i = 0; i < arg; i++) { flash_func_write_word(address, flash_buffer.w[i]); address += 4; } break; case PROTO_READ_MULTI: // readback bytes if (arg % 4) goto cmd_bad; if ((address + arg) > board_info.fw_size) goto cmd_bad; arg /= 4; /* handle readback of the not-yet-programmed first word */ if ((address == 0) && (first_word != 0xffffffff)) { cout((uint8_t *)&first_word, 4); address += 4; arg--; } while (arg-- > 0) { cout_word(flash_func_read_word(address)); address += 4; } break; case PROTO_BOOT: // program the deferred first word if (first_word != 0xffffffff) { flash_func_write_word(0, first_word); // revert in case the flash was bad... first_word = 0xffffffff; } // quiesce and jump to the app return; case PROTO_DEBUG: // XXX reserved for ad-hoc debugging as required break; default: continue; } // we got a command worth syncing, so kill the timeout because // we are probably talking to the uploader timeout = 0; // send the sync response for this command sync_response(); continue; cmd_bad: // Currently we do nothing & let the programming tool time out // if that's what it wants to do. // Let the initial delay keep counting down so that we ignore // random chatter from a device. while(true); continue; } }