diff --git a/inc/uf2.h b/inc/uf2.h index d6d0c37..8ac7173 100644 --- a/inc/uf2.h +++ b/inc/uf2.h @@ -290,6 +290,12 @@ void delay(uint32_t ms); void hidHandoverLoop(int ep); void handoverPrep(void); +// Useful for debugging. +#ifdef BLINK_DEBUG +void blink_n(uint32_t pin, uint32_t n, uint32_t interval); +void blink_n_forever(uint32_t pin, uint32_t n, uint32_t interval); +#endif + #define CONCAT_1(a, b) a##b #define CONCAT_0(a, b) CONCAT_1(a, b) #define STATIC_ASSERT(e) enum { CONCAT_0(_static_assert_, __LINE__) = 1 / ((e) ? 1 : 0) } diff --git a/src/init_samd21.c b/src/init_samd21.c index 3a7c2af..dd4ace9 100644 --- a/src/init_samd21.c +++ b/src/init_samd21.c @@ -7,7 +7,7 @@ volatile bool g_interrupt_enabled = true; -// SAMD51 starts at 1MHz by default. +// SAMD21 starts at 1MHz by default. uint32_t current_cpu_frequency_MHz = 1; static void gclk_sync(void) { diff --git a/src/init_samd51.c b/src/init_samd51.c index 3ec3c9c..a4525ff 100644 --- a/src/init_samd51.c +++ b/src/init_samd51.c @@ -82,7 +82,8 @@ void system_init(void) { MCLK->CPUDIV.reg = MCLK_CPUDIV_DIV_DIV1; SysTick_Config(1000); - current_cpu_frequency_MHz = 48; + // No change from initial frequency. + // current_cpu_frequency_MHz = 48; } void SysTick_Handler(void) { LED_TICK(); } diff --git a/src/main.c b/src/main.c index ec69af5..0df49ea 100644 --- a/src/main.c +++ b/src/main.c @@ -29,11 +29,11 @@ /** * -------------------- - * SAM-BA Implementation on SAMD21 + * SAM-BA Implementation on SAMD21 and SAMD51 * -------------------- * Requirements to use SAM-BA : * - * Supported communication interfaces : + * Supported communication interfaces (SAMD21): * -------------------- * * SERCOM5 : RX:PB23 TX:PB22 @@ -68,8 +68,6 @@ * * 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. * */ @@ -110,7 +108,7 @@ static void check_start_application(void) { 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 will be cleared after successful USB enumeration // this is around 1.5s resetHorizon = timerHigh + 50; return; @@ -150,7 +148,7 @@ extern char _etext; extern char _end; /** - * \brief SAMD21 SAM-BA Main loop. + * \brief SAM-BA Main loop. * \return Unused (ANSI-C compatibility). */ int main(void) { @@ -181,8 +179,17 @@ int main(void) { while (SUPC->STATUS.bit.BOD33DET) { // Wait for voltage to rise above BOD33 value. } - // Wait 100ms for voltage to stabilize. - delay(100); + + // If we are starting from a power-on or a brownout, + // wait for the voltage to stabilize. Don't do this on an + // external reset because it interferes with the timing of double-click. + // "BODVDD" means BOD33. + if (RSTC->RCAUSE.bit.POR || RSTC->RCAUSE.bit.BODVDD) { + do { + // Check again in 100ms. + delay(100); + } while (SUPC->STATUS.bit.BOD33DET); + } // Now enable reset if voltage falls below minimum. SUPC->BOD33.bit.ENABLE = 0; @@ -190,7 +197,6 @@ int main(void) { SUPC->BOD33.bit.ENABLE = 1; #endif - #if USB_VID == 0x239a && USB_PID == 0x0013 // Adafruit Metro M0 // Delay a bit so SWD programmer can have time to attach. delay(15); diff --git a/src/utils.c b/src/utils.c index c8e5775..dce02a2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -4,27 +4,48 @@ static uint32_t timerLow; uint32_t timerHigh, resetHorizon; -void delay(uint32_t ms) { -// These multipliers were determined empirically and are only approximate. -// SAMD21 starts up at 1MHz by default. +void __attribute__ ((noinline)) delay(uint32_t ms) { + // These multipliers were determined empirically and are only approximate. + // After the pulsing LED is enabled (led_tick_on), the multipliers need to change + // due to the interrupt overhead of the pulsing. + // SAMD21 starts up at 1MHz by default. #ifdef SAMD21 - uint32_t count = ms * 167 * (current_cpu_frequency_MHz); + uint32_t count = ms * (current_cpu_frequency_MHz) * (led_tick_on ? 149: 167); #endif #ifdef SAMD51 // SAMD51 starts up at 48MHz by default, and we set the clock to // 48MHz, so we don't need to adjust for current_cpu_frequency_MHz. - uint32_t count = ms * 6000; - // On SAMD51, before the 1ms SysTick interrupts are set up, the - // timing loop will run about twice as fast, so double the count. - if (led_tick_on) { - count *= 2; - } + uint32_t count = ms * (led_tick_on ? 6353 : 6826); #endif - for (int i = 1; i < count; ++i) { + for (uint32_t i = 1; i < count; ++i) { asm volatile(""); } } +// Useful for debugging. +// PIN_PA19 is D12 on Metro M0, D11 on Metro M4 +#ifdef BLINK_DEBUG +void blink_n(uint32_t pin, uint32_t n, uint32_t interval) { + // Start out off. + PINOP(pin, DIRSET); + PINOP(pin, OUTCLR); + delay(interval); + for (int i = 0; i < n; ++i) { + PINOP(pin, OUTSET); + delay(interval); + PINOP(pin, OUTCLR); + delay(interval); + } +} + +void blink_n_forever(uint32_t pin, uint32_t n, uint32_t interval) { + while(1) { + blink_n(pin, n, interval); + delay(interval*5); + } +} +#endif + void timerTick(void) { if (timerLow-- == 0) { timerLow = TIMER_STEP;