Add UF2 bootloader for USB firmware flashing
Vendored and trimmed from microsoft/uf2-samdx1, adapted to the actual ATSAMD21G17D (128 KiB flash / 16 KiB RAM), fixing the flash/RAM-size mismatch that the previously commented-out SAM-BA bootloader target had (it assumed a 256 KiB SAMD21G18A). Builds as a standalone PlatformIO environment (bootloader/platformio.ini), no python2/make dependency. Compiles clean, fits in the 8 KiB bootloader region (7292/8192 bytes). Not yet flashed/verified on real hardware.
This commit is contained in:
parent
ce5db617a1
commit
de52b57041
143 changed files with 69119 additions and 0 deletions
278
bootloader/src/main.c
Normal file
278
bootloader/src/main.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* SAM Software Package License
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2011-2014, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following condition is met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* --------------------
|
||||
* SAM-BA Implementation on SAMD21
|
||||
* --------------------
|
||||
* Requirements to use SAM-BA :
|
||||
*
|
||||
* Supported communication interfaces :
|
||||
* --------------------
|
||||
*
|
||||
* SERCOM5 : RX:PB23 TX:PB22
|
||||
* Baudrate : 115200 8N1
|
||||
*
|
||||
* USB : D-:PA24 D+:PA25
|
||||
*
|
||||
* Pins Usage
|
||||
* --------------------
|
||||
* The following pins are used by the program :
|
||||
* PA25 : input/output
|
||||
* PA24 : input/output
|
||||
* PB23 : input
|
||||
* PB22 : output
|
||||
* PA15 : input
|
||||
*
|
||||
* The application board shall avoid driving the PA25,PA24,PB23,PB22 and PA15
|
||||
* signals
|
||||
* while the boot program is running (after a POR for example)
|
||||
*
|
||||
* Clock system
|
||||
* --------------------
|
||||
* CPU clock source (GCLK_GEN_0) - 8MHz internal oscillator (OSC8M)
|
||||
* SERCOM5 core GCLK source (GCLK_ID_SERCOM5_CORE) - GCLK_GEN_0 (i.e., OSC8M)
|
||||
* GCLK Generator 1 source (GCLK_GEN_1) - 48MHz DFLL in Clock Recovery mode
|
||||
* (DFLL48M)
|
||||
* USB GCLK source (GCLK_ID_USB) - GCLK_GEN_1 (i.e., DFLL in CRM mode)
|
||||
*
|
||||
* Memory Mapping
|
||||
* --------------------
|
||||
* SAM-BA code will be located at 0x0 and executed before any applicative code.
|
||||
*
|
||||
* Applications compiled to be executed along with the bootloader will start at
|
||||
* 0x2000 (samd21) or 0x4000 (samd51)
|
||||
* The bootloader doesn't changes the VTOR register, application code is
|
||||
* taking care of this.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "uf2.h"
|
||||
|
||||
static void check_start_application(void);
|
||||
|
||||
static volatile bool main_b_cdc_enable = false;
|
||||
extern int8_t led_tick_step;
|
||||
|
||||
#ifdef SAMD21
|
||||
#define RESET_CONTROLLER PM
|
||||
#endif
|
||||
#ifdef SAMD51
|
||||
#define RESET_CONTROLLER RSTC
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Check the application startup condition
|
||||
*
|
||||
*/
|
||||
static void check_start_application(void) {
|
||||
uint32_t app_start_address;
|
||||
|
||||
// Check if there is an IO which will hold us inside the bootloader.
|
||||
#if defined(HOLD_PIN) && defined(HOLD_STATE)
|
||||
PORT_PINCFG_Type pincfg = {0};
|
||||
pincfg.bit.PMUXEN = false;
|
||||
pincfg.bit.INEN = true;
|
||||
pincfg.bit.DRVSTR = true;
|
||||
|
||||
PINOP(HOLD_PIN, DIRCLR); // Pin is an input
|
||||
|
||||
#if defined(HOLD_PIN_PULLUP)
|
||||
pincfg.bit.PULLEN = true;
|
||||
PINOP(HOLD_PIN, OUTSET); // Pin is pulled up.
|
||||
#elif defined(HOLD_PIN_PULLDOWN)
|
||||
pincfg.bit.PULLEN = true;
|
||||
PINOP(HOLD_PIN, OUTCLR); // Pin is pulled up.
|
||||
#endif
|
||||
PINCFG(HOLD_PIN) = pincfg.reg;
|
||||
|
||||
if (PINIP(HOLD_PIN) == HOLD_STATE) {
|
||||
/* Stay in bootloader */
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Load the Reset Handler address of the application */
|
||||
app_start_address = *(uint32_t *)(APP_START_ADDRESS + 4);
|
||||
|
||||
/**
|
||||
* Test reset vector of application @APP_START_ADDRESS+4
|
||||
* Sanity check on the Reset_Handler address
|
||||
*/
|
||||
if (app_start_address < APP_START_ADDRESS || app_start_address > FLASH_SIZE) {
|
||||
/* Stay in bootloader */
|
||||
return;
|
||||
}
|
||||
|
||||
#if USE_SINGLE_RESET
|
||||
if (SINGLE_RESET()) {
|
||||
if (RESET_CONTROLLER->RCAUSE.bit.POR || *DBL_TAP_PTR != DBL_TAP_MAGIC_QUICK_BOOT) {
|
||||
// the second tap on reset will go into app
|
||||
*DBL_TAP_PTR = DBL_TAP_MAGIC_QUICK_BOOT;
|
||||
// this will be cleared after succesful USB enumeration
|
||||
// this is around 1.5s
|
||||
resetHorizon = timerHigh + 50;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (RESET_CONTROLLER->RCAUSE.bit.POR) {
|
||||
*DBL_TAP_PTR = 0;
|
||||
} else if (*DBL_TAP_PTR == DBL_TAP_MAGIC) {
|
||||
*DBL_TAP_PTR = 0;
|
||||
return; // stay in bootloader
|
||||
} else {
|
||||
if (*DBL_TAP_PTR != DBL_TAP_MAGIC_QUICK_BOOT) {
|
||||
*DBL_TAP_PTR = DBL_TAP_MAGIC;
|
||||
delay(500);
|
||||
}
|
||||
*DBL_TAP_PTR = 0;
|
||||
}
|
||||
|
||||
LED_MSC_OFF();
|
||||
#if defined(__SAMD21E18A__)
|
||||
RGBLED_set_color(COLOR_LEAVE);
|
||||
#endif
|
||||
|
||||
/* Rebase the Stack Pointer */
|
||||
__set_MSP(*(uint32_t *)APP_START_ADDRESS);
|
||||
|
||||
/* Rebase the vector table base address */
|
||||
SCB->VTOR = ((uint32_t)APP_START_ADDRESS & SCB_VTOR_TBLOFF_Msk);
|
||||
|
||||
/* Jump to application Reset Handler in the application */
|
||||
asm("bx %0" ::"r"(app_start_address));
|
||||
}
|
||||
|
||||
extern char _etext;
|
||||
extern char _end;
|
||||
|
||||
/**
|
||||
* \brief SAMD21 SAM-BA Main loop.
|
||||
* \return Unused (ANSI-C compatibility).
|
||||
*/
|
||||
int main(void) {
|
||||
// if VTOR is set, we're not running in bootloader mode; halt
|
||||
if (SCB->VTOR)
|
||||
while (1) {
|
||||
}
|
||||
|
||||
#if (USB_VID == 0x239a) && (USB_PID == 0x0013) // Adafruit Metro M0
|
||||
// Delay a bit so SWD programmer can have time to attach.
|
||||
delay(15);
|
||||
#endif
|
||||
led_init();
|
||||
|
||||
logmsg("Start");
|
||||
assert((uint32_t)&_etext < APP_START_ADDRESS);
|
||||
// bossac writes at 0x20005000
|
||||
assert(!USE_MONITOR || (uint32_t)&_end < 0x20005000);
|
||||
|
||||
assert(8 << NVMCTRL->PARAM.bit.PSZ == FLASH_PAGE_SIZE);
|
||||
assert(FLASH_PAGE_SIZE * NVMCTRL->PARAM.bit.NVMP == FLASH_SIZE);
|
||||
|
||||
/* Jump in application if condition is satisfied */
|
||||
check_start_application();
|
||||
|
||||
/* We have determined we should stay in the monitor. */
|
||||
/* System initialization */
|
||||
system_init();
|
||||
|
||||
__DMB();
|
||||
__enable_irq();
|
||||
|
||||
#if USE_UART
|
||||
/* UART is enabled in all cases */
|
||||
usart_open();
|
||||
#endif
|
||||
|
||||
logmsg("Before main loop");
|
||||
|
||||
usb_init();
|
||||
|
||||
// not enumerated yet
|
||||
RGBLED_set_color(COLOR_START);
|
||||
led_tick_step = 10;
|
||||
|
||||
/* Wait for a complete enum on usb or a '#' char on serial line */
|
||||
while (1) {
|
||||
if (USB_Ok()) {
|
||||
if (!main_b_cdc_enable) {
|
||||
#if USE_SINGLE_RESET
|
||||
// this might have been set
|
||||
resetHorizon = 0;
|
||||
#endif
|
||||
RGBLED_set_color(COLOR_USB);
|
||||
led_tick_step = 1;
|
||||
|
||||
#if USE_SCREEN
|
||||
screen_init();
|
||||
draw_drag();
|
||||
#endif
|
||||
}
|
||||
|
||||
main_b_cdc_enable = true;
|
||||
}
|
||||
|
||||
#if USE_MONITOR
|
||||
// Check if a USB enumeration has succeeded
|
||||
// And com port was opened
|
||||
if (main_b_cdc_enable) {
|
||||
logmsg("entering monitor loop");
|
||||
// SAM-BA on USB loop
|
||||
while (1) {
|
||||
sam_ba_monitor_run();
|
||||
}
|
||||
}
|
||||
#if USE_UART
|
||||
/* Check if a '#' has been received */
|
||||
if (!main_b_cdc_enable && usart_sharp_received()) {
|
||||
RGBLED_set_color(COLOR_UART);
|
||||
sam_ba_monitor_init(SAM_BA_INTERFACE_USART);
|
||||
/* SAM-BA on UART loop */
|
||||
while (1) {
|
||||
sam_ba_monitor_run();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else // no monitor
|
||||
if (main_b_cdc_enable) {
|
||||
process_msc();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!main_b_cdc_enable) {
|
||||
// get more predictable timings before the USB is enumerated
|
||||
for (int i = 1; i < 256; ++i) {
|
||||
asm("nop");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue