diff --git a/README.md b/README.md index 265e21ed..814aad54 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,30 @@ Thus, it's best to set the USB ID to one for which there are no drivers. The bootloader sits at 0x00000000, and the application starts at 0x00002000 (SAMD21) or 0x00004000 (SAMD51). +#### Bootloader Hold Switch + +A Board can be configured to sense the state of a GPIO and to hold the bootloader from running an application if it is in the appropriate state. To enable this, add the following to your board configuration header file. + +```C +// The Pin that will tell us to stay in the bootloader or not. +#define HOLD_PIN PIN_PA02 + +// Optional, define if a Pull up or pulldown is needed. +#define HOLD_PIN_PULLUP +//#define HOLD_PIN_PULLDOWN + +// What is the Hold state of the GPIO, 0 or 1. +#define HOLD_STATE 1 +``` + +Set `HOLD_PIN` to the appropriate GPIO and `HOLD_STATE` to the logic level which will hold the bootloader from running the application. + +The definition of _BOTH_ `HOLD_PIN` and `HOLD_STATE` triggers the inclusion of this feature. If either of these is undefined, this feature is not enabled. + +If an internal pullup/pulldown is required for the IO, it can be enabled with the _OPTIONAL_ `HOLD_PIN_PULLUP` or `HOLD_PIN_PULLDOWN` macros. If neither are defined, then no pullup/pulldown will be enabled for the io pin. + +This switch is NOT dynamic. Once the bootloader has sensed this pin and decided not to run the application, then a change in this IO will not, itself, then cause the Application to run, without also resetting the board. + ## Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/inc/uf2.h b/inc/uf2.h index 56aba541..63df870a 100644 --- a/inc/uf2.h +++ b/inc/uf2.h @@ -265,6 +265,9 @@ void system_init(void); #define LED_TICK led_tick #define PINOP(pin, OP) (PORT->Group[(pin) / 32].OP.reg = (1 << ((pin) % 32))) +#define PINIP(pin) (((PORT->Group[(pin) / 32].IN.reg) >> ((pin) % 32)) & 0x1) +#define PINCFG(pin) (PORT->Group[(pin) / 32].PINCFG[(pin) % 32].reg) +#define PINMUX(pin) (PORT->Group[(pin) / 32].PMUX[((pin) % 32)/2].reg) void led_tick(void); void led_signal(void); diff --git a/src/main.c b/src/main.c index dec6fcf2..c4f6f9a7 100644 --- a/src/main.c +++ b/src/main.c @@ -94,6 +94,30 @@ extern int8_t led_tick_step; 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);