BOOT_FLASH attached to a pin?

I would like to have access to the boot & reset buttons from outside of the enclosure I am using to develop things for the Daisy so I do not have to open up the back to enter DFU mode. I can create another reset button by connecting the DTAG pin 10 (RESET) to ground…but I cannot figure out how to create another boot button, or if it is possible. The schematic here lists the BOOT_RESET being connected to K15 on U2G (and also has a note about PORTG Pin3?), but I don’t know what U2G is, physically where it is, or if it is connected to one of the accessible Daisy pins. I also don’t understand the reference to PORTG Pin3 and if it means GPIOG 3, because I cannot find GPIOG 3 listed anywhere.

1 Like

It is connected to PORTG pin3, accessible via libdaisy as dsy_gpio_pin boot_pin = {DSY_GPIOG, 3};

You should be able to pull that pin high in software, and then do a software reset. The cap in the schematic is there to hold the voltage high during that reset so that it will boot into the bootloader.

pseudocode:

void RebootToBootloader()
{
    // Initialize Boot Pin
    dsy_gpio_pin bootpin = {DSY_GPIOG, 3};
    dsy_gpio pin;
    pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    pin.pin = bootpin;
    dsy_gpio_init(&pin);

    // Pull Pin HIGH
    dsy_gpio_write(&pin, 1);
    // Software Reset
    NVIC_SystemReset();
}

The NVIC_SystemReset comes from the CMSIS libraries not from libdaisy, but we’ll add the above function to the libdaisy library at some point as well.

3 Likes

Okay that is useful to know, thanks for your response.

When you mention PORTG pin3 - that is a pin that is internal to seed though right? It is not attached to one of the inline physical pins around the seed perimeter?

If it is just an internal ‘pin’, I don’t think that will allow me to easily add an off-seed boot button by connecting to an external seed pin. The only way I see to add another boot switch with your response is to put a version of the RebootToBootloader code you included in every version of the code I put on the seed and trigger the RebootToBootloader function by pulling one of the seed’s external pins high or low. Let me know if your response suggested a different solution and I missed something though.

Correct, what I mentioned was how you could trigger that function from any UI action on your hardware instead of having to have a physical connection to the boot and reset pins, which are not readily available on the Daisy pinout.

The caveat is that, yes, you would have to include that function in your code.

Okay thanks again, that is very useful to know!

@shensley, RebootToBootloader() is very interesting! I am not sure though, which file to include to be able to use NVIC_SystemReset()? Tried grep but I don’t understand the results (or rather, which header to include).

This is almost @shensley’s pseudocode, just had to add the #include, “correct” the Reset-call, and add a small delay to let the cap charge (as noted on the schematic: https://github.com/electro-smith/Hardware/blob/master/reference/daisy_seed/ES_Daisy_Seed_Rev4.pdf).

This small program blinks the LED two times then is ready to accept another download:

#include <daisy_seed.h>
#include "stm32h7xx_hal.h"

daisy::DaisySeed hw;

void RebootToBootloader()
{
    // Initialize Boot Pin
    dsy_gpio_pin bootpin = {DSY_GPIOG, 3};
    dsy_gpio pin;
    pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
    pin.pin = bootpin;
    dsy_gpio_init(&pin);

    // Pull Pin HIGH
    dsy_gpio_write(&pin, 1);

	// wait a few ms for cap to charge
	hw.DelayMs(10);

    // Software Reset
	HAL_NVIC_SystemReset();
}

int main()
{

	hw.Configure();
	hw.Init();

	hw.SetLed(1);
	hw.DelayMs(500);
	hw.SetLed(0);
	hw.DelayMs(500);
	hw.SetLed(1);
	hw.DelayMs(500);
	hw.SetLed(0);

	RebootToBootloader();

}

I’ll just add a button to my breadboard and connect it to this function, and speed up my numerous uploads! :slight_smile:

1 Like

So I added a (momentary) button to pin 28 and to ground (remember to connect AGND and DGND too).

And in my main() I added this code:

// Configure and initialize button
Switch button1;
button1.Init(hardware.GetPin(28), 10);

// Loop forever
for(;;)
{

	// Reset to upload

	button1.Debounce();
	if (button1.Pressed())
	{
		RebootToBootloader();
	}

	// wait 1 ms
	System::Delay(1);
}
1 Like

Fantastic!

I should be able to add this as a static system function in libdaisy some time this week: System::ResetToBootloader()

I also want to get something set up to call this from USB to have a simplified reprogram via USB workflow.

2 Likes

I think it’s also necessary to disable interrupts before bootloader jump, i.e. add

  RCC->CIER = 0x00000000;

before the NVIC_SystemReset();

And it may be better to replace the delay with while(1);. That said, CMSIS calls this in reset function:

  for(;;)                                                           /* wait until reset */
  {
    __NOP();
  }

So this would only matter if building with a terribly broken version of CMSIS.

3 Likes

I just tried this - works great! tho I had issues with that #include “stm32h7xx_hal.h”

it’s easier to forget the include and :

extern “C” void HAL_NVIC_SystemReset();

in case the include structure changes e.t.c.

I didn’t know about that, thanks!

Hmmm…I also include “core_cm7.h” for measuring MCU utilization, and that seems to require “stm32h7xx_hal.h”…

With:

//#include "stm32h7xx_hal.h" // for HAL_NVIC_SystemReset();
extern "C" void HAL_NVIC_SystemReset();
#include "core_cm7.h"

I get

../../DaisyExamples/libdaisy/Drivers/CMSIS/Include/core_cm7.h:103:8: error: #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
       #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
        ^~~~~
In file included from main.cpp:18:0:
../../DaisyExamples/libdaisy/Drivers/CMSIS/Include/core_cm7.h:1867:39: error: variable or field '__NVIC_EnableIRQ' declared void
 __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
                                       ^~~~~~~~~

../../DaisyExamples/libdaisy/Drivers/CMSIS/Include/core_cm7.h:103:8: error: #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
       #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
        ^~~~~
In file included from main.cpp:18:0:
../../DaisyExamples/libdaisy/Drivers/CMSIS/Include/core_cm7.h:1867:39: error: variable or field '__NVIC_EnableIRQ' declared void
 __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
                                       ^~~~~~~~~

Looks like you’re missing preprocessors flags that normally get defined by HAL. Building with GCC flags like this may help - -DARM_MATH_CM7 -D__FPU_PRESENT -D__FPU_USED=1. This is what OWL uses to include CMSIS without HAL.

2 Likes

you could extern the other function as well, so there’s no need to include #include “core_cm7.h” e.t.c.

1 Like