Skip to content

Commit

Permalink
Merge pull request adafruit#47 from stevenj/master
Browse files Browse the repository at this point in the history
Proposal to allow a GPIO to hold the bootloader from running the app, if its in the correct state
  • Loading branch information
mmoskal authored Aug 19, 2022
2 parents b393cb1 + a714932 commit f4c13d5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 [[email protected]](mailto:[email protected]) with any additional questions or comments.
Expand Down
3 changes: 3 additions & 0 deletions inc/uf2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit f4c13d5

Please sign in to comment.