From 0a199704e45dedd57fcc98ab03b7113a16f1aeda Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 24 Feb 2016 00:22:49 -0600 Subject: [PATCH] Enter ISP mode on lpc11u35 if button held on boot If the reset button is held on boot then enter ISP mode manually. This allows devices without the ISP pin wired up to enter ISP mode. Also add a delay before reading the reset button to make sure board voltages have stabilized before reading the reset button. This prevents the Switch Science LPC824 from occasionally entering ISP mode when initially connected. --- source/hif_hal/nxp/lpc11u35/gpio.c | 66 ++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/source/hif_hal/nxp/lpc11u35/gpio.c b/source/hif_hal/nxp/lpc11u35/gpio.c index f3440c49e..09fe67375 100644 --- a/source/hif_hal/nxp/lpc11u35/gpio.c +++ b/source/hif_hal/nxp/lpc11u35/gpio.c @@ -34,6 +34,57 @@ COMPILER_ASSERT(DAPLINK_HIF_ID == DAPLINK_HIF_ID_LPC11U35); #define PIN_MSD_LED (1<<20) #define PIN_CDC_LED (1<<11) + +// taken code from the Nxp App Note AN11305 +/* This data must be global so it is not read from the stack */ +typedef void (*IAP)(uint32_t [], uint32_t []); +static IAP iap_entry = (IAP)0x1fff1ff1; +static uint32_t command[5], result[4]; +#define init_msdstate() *((uint32_t *)(0x10000054)) = 0x0 + +/* This function resets some microcontroller peripherals to reset + hardware configuration to ensure that the USB In-System Programming module + will work properly. It is normally called from reset and assumes some reset + configuration settings for the MCU. + Some of the peripheral configurations may be redundant in your specific + project. +*/ +void ReinvokeISP(void) +{ + /* make sure USB clock is turned on before calling ISP */ + LPC_SYSCON->SYSAHBCLKCTRL |= 0x04000; + /* make sure 32-bit Timer 1 is turned on before calling ISP */ + LPC_SYSCON->SYSAHBCLKCTRL |= 0x00400; + /* make sure GPIO clock is turned on before calling ISP */ + LPC_SYSCON->SYSAHBCLKCTRL |= 0x00040; + /* make sure IO configuration clock is turned on before calling ISP */ + LPC_SYSCON->SYSAHBCLKCTRL |= 0x10000; + + /* make sure AHB clock divider is 1:1 */ + LPC_SYSCON->SYSAHBCLKDIV = 1; + + /* Send Reinvoke ISP command to ISP entry point*/ + command[0] = 57; + + init_msdstate(); /* Initialize Storage state machine */ + /* Set stack pointer to ROM value (reset default) This must be the last + piece of code executed before calling ISP, because most C expressions + and function returns will fail after the stack pointer is changed. */ + __set_MSP(*((volatile uint32_t *)0x00000000)); + + /* Enter ISP. We call "iap_entry" to enter ISP because the ISP entry is done + through the same command interface as IAP. */ + iap_entry(command, result); + // Not supposed to come back! +} + +static void busy_wait(uint32_t cycles) +{ + volatile uint32_t i; + i = cycles; + while (i > 0) i--; +} + void gpio_init(void) { // enable clock for GPIO port 0 LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 6); @@ -62,6 +113,21 @@ void gpio_init(void) { /* Enable AHB clock to the FlexInt, GroupedInt domain. */ LPC_SYSCON->SYSAHBCLKCTRL |= ((1<<19) | (1<<23) | (1<<24)); + + // Give the cap on the reset button time to charge + busy_wait(10000); + + if (gpio_get_sw_reset() == 0) { + IRQn_Type irq; + // Disable SYSTICK timer and interrupt before calling into ISP + SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk); + // Disable all nvic interrupts + for (irq = (IRQn_Type)0; irq < (IRQn_Type)32; irq++) { + NVIC_DisableIRQ(irq); + NVIC_ClearPendingIRQ(irq); + } + ReinvokeISP(); + } } void gpio_set_hid_led(gpio_led_state_t state) {