Bootloader
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- RogierWeekers
- Posts: 6
- Joined: Wed Jan 26, 2022 8:43 pm
Bootloader
Is it possible to go into bootloader mode via software. My setup is with a touch panel, which is build into a case, now, if I need to change the code I have to open the case so I can push the button twice. It would be convenient if a dedicate button on the touch panel could be used to switch over.
- adafruit_support_carter
- Posts: 29470
- Joined: Tue Nov 29, 2016 2:45 pm
Re: Bootloader
You can with CircuitPython:
https://learn.adafruit.com/circuitpytho ... -resetting
https://learn.adafruit.com/circuitpytho ... -resetting
- RogierWeekers
- Posts: 6
- Joined: Wed Jan 26, 2022 8:43 pm
Re: Bootloader
Is there a library for C++ (visual studio micro) ?
- User_UMjT7KxnxP8YN8
- Posts: 323
- Joined: Tue Jul 17, 2018 1:28 pm
Re: Bootloader
I haven't used the M0 but I force reboots (which involves running the bootloader) on the Metro M4 by setting up the Watchdog Timer (WDT) then entering a tight loop that causes it to time out.
You can find my WDT code at https://github.com/SapientHetero/Watchd ... SAMD51J19A.
You can find my WDT code at https://github.com/SapientHetero/Watchd ... SAMD51J19A.
- RogierWeekers
- Posts: 6
- Joined: Wed Jan 26, 2022 8:43 pm
Re: Bootloader
Thank you however this does not cover the issue. After changing the code for the M0 (see below) it does reboot, but does not get into bootloader mode.
I created this:
a variable
bool Reboot=false;
//in Setup
void SetupWdt() {
// Set up the generic clock (GCLK2) used to clock the watchdog timer at 1.024kHz
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(4) | // Divide the 32.768kHz clock source by divisor 32, where 2^(4 + 1): 32.768kHz/32=1.024kHz
GCLK_GENDIV_ID(2); // Select Generic Clock (GCLK) 2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_DIVSEL | // Set to divide by 2^(GCLK_GENDIV_DIV(4) + 1)
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK2
GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to the ultra low power oscillator (OSCULP32K)
GCLK_GENCTRL_ID(2); // Select GCLK2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK2 to WDT (Watchdog Timer)
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK2 to the WDT
GCLK_CLKCTRL_GEN_GCLK2 | // Select GCLK2
GCLK_CLKCTRL_ID_WDT; // Feed the GCLK2 to the WDT
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CONFIG = WDT_CONFIG_PER_1K; // Set the WDT reset timeout to 1 second
while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CTRL = WDT_CTRL_ENABLE; // Enable the WDT in normal mode
while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
}
in the main loop
if (!WDT->STATUS.bit.SYNCBUSY && Reboot==false) // Check if the WDT registers are synchronized
{
REG_WDT_CLEAR = WDT_CLEAR_CLEAR_KEY; // Clear the watchdog timer
}
I created this:
a variable
bool Reboot=false;
//in Setup
void SetupWdt() {
// Set up the generic clock (GCLK2) used to clock the watchdog timer at 1.024kHz
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(4) | // Divide the 32.768kHz clock source by divisor 32, where 2^(4 + 1): 32.768kHz/32=1.024kHz
GCLK_GENDIV_ID(2); // Select Generic Clock (GCLK) 2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_DIVSEL | // Set to divide by 2^(GCLK_GENDIV_DIV(4) + 1)
GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK2
GCLK_GENCTRL_SRC_OSCULP32K | // Set the clock source to the ultra low power oscillator (OSCULP32K)
GCLK_GENCTRL_ID(2); // Select GCLK2
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK2 to WDT (Watchdog Timer)
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK2 to the WDT
GCLK_CLKCTRL_GEN_GCLK2 | // Select GCLK2
GCLK_CLKCTRL_ID_WDT; // Feed the GCLK2 to the WDT
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CONFIG = WDT_CONFIG_PER_1K; // Set the WDT reset timeout to 1 second
while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_WDT_CTRL = WDT_CTRL_ENABLE; // Enable the WDT in normal mode
while (WDT->STATUS.bit.SYNCBUSY); // Wait for synchronization
}
in the main loop
if (!WDT->STATUS.bit.SYNCBUSY && Reboot==false) // Check if the WDT registers are synchronized
{
REG_WDT_CLEAR = WDT_CLEAR_CLEAR_KEY; // Clear the watchdog timer
}
- User_UMjT7KxnxP8YN8
- Posts: 323
- Joined: Tue Jul 17, 2018 1:28 pm
Re: Bootloader
So, you want it to STAY in the bootloader rather than running the currently-loaded application? Is erasing the current application an option? If so, you could do so in your code, then call this function:
If you don't want to erase your app, uncommenting this line may get you the effect you want:
It's been over a year since I modified the bootloader, so you'll have to look at it to verify my recollection.
Code: Select all
*******************************************************************************************************************************************************************************************/
void reboot(void) {
//*DBL_TAP_PTR = DBL_TAP_MAGIC;
//SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk; // force reboot (I had to modify this as shown below for M4)
__DSB(); // Ensure all outstanding memory accesses included
// buffered write are completed before reset
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); // Keep priority group unchanged
__DSB(); // Ensure completion of memory access
while(1); // wait until reset
} // reboot
Code: Select all
//*DBL_TAP_PTR = DBL_TAP_MAGIC;
- RogierWeekers
- Posts: 6
- Joined: Wed Jan 26, 2022 8:43 pm
Re: Bootloader
Thanks a lot, but cannot get it to compile, and do not have enough info to correct.
My compiler misses "SCB_AIRCR_PRIGROUP_Msk"
and "DBL_TAP_PTR"
Any suggestions ?
My compiler misses "SCB_AIRCR_PRIGROUP_Msk"
and "DBL_TAP_PTR"
Any suggestions ?
- User_UMjT7KxnxP8YN8
- Posts: 323
- Joined: Tue Jul 17, 2018 1:28 pm
Re: Bootloader
I haven't used the M0 but I had to add the register that won't compile in order for it to work on the M4. Perhaps replacing that line with the following will work:
You'll have to look at the bootloader for the M0, figure out where DBL_TAP_PTR is located, create a macro defining a pointer to that address and set it to get the desired behavior.
The bootloader source code is at https://github.com/adafruit/uf2-samdx1 in the /src directory.
Code: Select all
SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk; // force reboot
The bootloader source code is at https://github.com/adafruit/uf2-samdx1 in the /src directory.
Please be positive and constructive with your questions and comments.