/* Copyright (c) 2015 Arduino LLC. All right reserved. Copyright (c) 2015 Atmel Corporation/Thibaut VIARD. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "sam_ba_monitor.h" #include "sam_ba_serial.h" #include "board_definitions.h" #include "board_driver_led.h" #include "sam_ba_usb.h" #include "sam_ba_cdc.h" extern uint32_t __sketch_vectors_ptr; // Exported value from linker script extern void board_init(void); #if (defined DEBUG) && (DEBUG == 1) volatile uint32_t* pulSketch_Start_Address; #endif static volatile bool main_b_cdc_enable = false; /** * \brief Check the application startup condition * */ static void check_start_application(void) { // LED_init(); // LED_off(); #if defined(BOOT_DOUBLE_TAP_ADDRESS) #define DOUBLE_TAP_MAGIC 0x07738135 if (PM->RCAUSE.bit.POR) { /* On power-on initialize double-tap */ BOOT_DOUBLE_TAP_DATA = 0; } else { if (BOOT_DOUBLE_TAP_DATA == DOUBLE_TAP_MAGIC) { /* Second tap, stay in bootloader */ BOOT_DOUBLE_TAP_DATA = 0; return; } /* First tap */ BOOT_DOUBLE_TAP_DATA = DOUBLE_TAP_MAGIC; /* Wait 0.5sec to see if the user tap reset again. * The loop value is based on SAMD21 default 1MHz clock @ reset. */ for (uint32_t i=0; i<125000; i++) /* 500ms */ /* force compiler to not optimize this... */ __asm__ __volatile__(""); /* Timeout happened, continue boot... */ BOOT_DOUBLE_TAP_DATA = 0; } #endif #if (!defined DEBUG) || ((defined DEBUG) && (DEBUG == 0)) uint32_t* pulSketch_Start_Address; #endif /* * Test sketch stack pointer @ &__sketch_vectors_ptr * Stay in SAM-BA if value @ (&__sketch_vectors_ptr) == 0xFFFFFFFF (Erased flash cell value) */ if (__sketch_vectors_ptr == 0xFFFFFFFF) { /* Stay in bootloader */ return; } /* * Load the sketch Reset Handler address * __sketch_vectors_ptr is exported from linker script and point on first 32b word of sketch vector table * First 32b word is sketch stack * Second 32b word is sketch entry point: Reset_Handler() */ pulSketch_Start_Address = &__sketch_vectors_ptr ; pulSketch_Start_Address++ ; /* * Test vector table address of sketch @ &__sketch_vectors_ptr * Stay in SAM-BA if this function is not aligned enough, ie not valid */ if ( ((uint32_t)(&__sketch_vectors_ptr) & ~SCB_VTOR_TBLOFF_Msk) != 0x00) { /* Stay in bootloader */ return; } /* #if defined(BOOT_LOAD_PIN) volatile PortGroup *boot_port = (volatile PortGroup *)(&(PORT->Group[BOOT_LOAD_PIN / 32])); volatile bool boot_en; // Enable the input mode in Boot GPIO Pin boot_port->DIRCLR.reg = BOOT_PIN_MASK; boot_port->PINCFG[BOOT_LOAD_PIN & 0x1F].reg = PORT_PINCFG_INEN | PORT_PINCFG_PULLEN; boot_port->OUTSET.reg = BOOT_PIN_MASK; // Read the BOOT_LOAD_PIN status boot_en = (boot_port->IN.reg) & BOOT_PIN_MASK; // Check the bootloader enable condition if (!boot_en) { // Stay in bootloader return; } #endif */ // LED_on(); /* Rebase the Stack Pointer */ __set_MSP( (uint32_t)(__sketch_vectors_ptr) ); /* Rebase the vector table base address */ SCB->VTOR = ((uint32_t)(&__sketch_vectors_ptr) & SCB_VTOR_TBLOFF_Msk); /* Jump to application Reset Handler in the application */ asm("bx %0"::"r"(*pulSketch_Start_Address)); } #if DEBUG_ENABLE # define DEBUG_PIN_HIGH port_pin_set_output_level(BOOT_LED, 1) # define DEBUG_PIN_LOW port_pin_set_output_level(BOOT_LED, 0) #else # define DEBUG_PIN_HIGH do{}while(0) # define DEBUG_PIN_LOW do{}while(0) #endif /** * \brief SAMD21 SAM-BA Main loop. * \return Unused (ANSI-C compatibility). */ int main(void) { #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES P_USB_CDC pCdc; #endif DEBUG_PIN_HIGH; /* Jump in application if condition is satisfied */ check_start_application(); /* We have determined we should stay in the monitor. */ /* System initialization */ board_init(); __enable_irq(); #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES /* UART is enabled in all cases */ serial_open(); #endif #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES pCdc = usb_init(); #endif DEBUG_PIN_LOW; /* Wait for a complete enum on usb or a '#' char on serial line */ while (1) { #if SAM_BA_INTERFACE == SAM_BA_USBCDC_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES if (pCdc->IsConfigured(pCdc) != 0) { main_b_cdc_enable = true; } /* Check if a USB enumeration has succeeded and if comm port has been opened */ if (main_b_cdc_enable) { sam_ba_monitor_init(SAM_BA_INTERFACE_USBCDC); /* SAM-BA on USB loop */ while( 1 ) { sam_ba_monitor_run(); } } #endif #if SAM_BA_INTERFACE == SAM_BA_UART_ONLY || SAM_BA_INTERFACE == SAM_BA_BOTH_INTERFACES /* Check if a '#' has been received */ if (!main_b_cdc_enable && serial_sharp_received()) { sam_ba_monitor_init(SAM_BA_INTERFACE_USART); /* SAM-BA on Serial loop */ while(1) { sam_ba_monitor_run(); } } #endif } }