/** @(#)vectors.c <11-Mar-2015 13:34:42 bob p> * \date Last Time-stamp: <21-Feb-2022 13:02:19 bob p> * * \file vectors.c * \brief Startup file, that copies code to RAM and default interrupt vectors. * */ /*lint -save */ #include "includes.h" #include "hardware.h" #include "leds_blink.h" #include "delay.h" #include "uart1.h" #include "uart2.h" extern char __StackTop[]; /* Top of the Stack */ extern void _start( void ); /* newlib C lib initialization */ #if 0 void hardware_init_hook( void ); /* Called by crt0.S at reset if exists. Called from _start after the bss is zeroed */ void hardware_init_hook( void ) { } void software_init_hook( void ); /* Called by crt0.S at reset if exists. Called from _start after the bss is zeroed */ void software_init_hook( void ) { } #endif /* * Weak definitions of handlers point to a default_handler or empty * handler if not implemented. * * A weak definition can be used to resolve any reference to that * symbol in the same way as a normal definition. However, if another * non-weak definition of that symbol exists in the build, the linker * uses that definition instead of the weak definition, and does not * produce an error due to multiply-defined symbols. */ void Reset_Handler( void ) __attribute__( ( noreturn, naked, aligned( 8U ), section( ".after_vectors" ) ) ); /* Where execution will start */ void vectors_reset_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void HardFault_Handler( void ) __attribute__( ( weak, alias( "hardfault_default" ) ) ); void HardFault_Handler_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void fault_soft_handler( uint32_t const value_u32 ) __attribute__( ( weak, alias( "empty_handler_u32" ) ) ); void fault_soft_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void bootloader_mr_setup( void ) __attribute__( ( weak, alias( "vectors_bootloader_mr_setup" ) ) ); void clock_cpu_init_after_c_setup( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void clock_cpu_init_b4_c_setup( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void hardware_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void hardware_init_b4_var_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void serial_io_init( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void vectors_b4_newlib_start( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void watchdog_init( void ) __attribute__( ( weak, alias( "watchdog_turn_off" ) ) ); void empty1_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty2_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty3_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty4_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty5_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty6_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty7_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty8_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); void empty9_handler_void( void ) __attribute__( ( weak, alias( "empty_handler_void" ) ) ); /* ---------------------------------------------------------------------------------- * Default handlers: */ #ifndef SCB_ICSR #define SCB_ICSR (*(volatile uint32_t*)(0xE000ED04)) #endif /** * Default handler for interrupts * * Most of the vector table is initialized to point at this handler. * * If you end up here it probably means: * - You have accidentally enabled an interrupt source in a peripheral * - Enabled the wrong interrupt source * - Failed to install or create a handler for an interrupt you intended using e.g. misspelled the name. * Compare your handler (C function) name to that used in the vector table. * * You can check 'vectorNum' below to determine the interrupt source. Look this up in the vector table below. */ static void irq_default_handler( void ) __attribute__( ( interrupt( "IRQ" ), section( ".after_vectors" ) ) ); static void irq_default_handler( void ) { debug_uart_init( DEBUG_EMB_ASSERT_BAUD ); /* UART may have been shutdown as part of shutdown sequence */ #if 0 const volatile uint32_t vectorNum = ( ( SCB_ICSR & SCB_ICSR_VECTACTIVE_MASK ) >> SCB_ICSR_VECTACTIVE_Pos ); DEBUG_FUNC( vectorNum ); #endif fault_soft_handler( 0xAAAAAAAAUL ); /* Do something like blink LED then halt */ } static void hardfault_default( void ) __attribute__( ( used, __aligned__( 4U ), section( ".after_vectors" ) ) ); static void hardfault_default( void ) { debug_uart_init( DEBUG_EMB_ASSERT_BAUD ); /* UART may have been shutdown as part of shutdown sequence */ DEBUG_FUNC(); for( ;; ) { leds_blink( 1U, 5U, 500U ); delay_ms( 5000U ); } } static void empty_handler_void( void ) __attribute__( ( used, __aligned__( 4U ), section( ".after_vectors" ) ) ); static void empty_handler_void( void ) { /* Normal power up comes through here. Why? */ } static void empty_handler_u32( uint32_t const value_u32 ) __attribute__( ( used, __aligned__( 4U ), section( ".after_vectors" ) ) ); static void empty_handler_u32( uint32_t const value_u32 ) { UNUSED( value_u32 ); debug_uart_init( DEBUG_EMB_ASSERT_BAUD ); /* UART may have been shutdown as part of shutdown sequence */ DEBUG_FUNC(); fault_soft_handler( 0x01UL ); /* Do something like blink LED then halt */ } static void watchdog_turn_off( void ) __attribute__( ( used, __aligned__( 4U ), section( ".after_vectors" ) ) ); /* The watchdog register may only be written to a single time after reset. Default to turning it off */ static void watchdog_turn_off( void ) /* Make sure to override this in a real shipping product. Also account for Bootloader, in MKL43/MKL27 etc, turned it off so need to from Flash */ { SIM_COPC = 0U; /* Disable the watchdog timer */ } /* ---------------------------------------------------------------------------------- */ /* * Weak definitions of handlers point to IRQ_default_handler if not implemented. * Name format follows the Non-C CMSIS convention: */ void NMI_Handler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void SVC_Handler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void PendSV_Handler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); /* * CMSIS considers SysTick_Handler a system setting so it should be * grouped above, however it is a interrupt so it could be grouped * below. So just make it, its own group and move on with life and * stop worrying about such minutia: */ void SysTick_Handler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void DMA0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void DMA1_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void DMA2_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void DMA3_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void FTFA_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void LVD_LVW_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void LLW_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void I2C0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void I2C1_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void SPI0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void SPI1_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void LPUART0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void LPUART1_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void UART2_FLEXIO_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void ADC0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void CMP0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void TPM0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void TPM1_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void TPM2_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void RTC_Alarm_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void RTC_Seconds_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void PIT_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void USB_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void DAC0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void I2S0_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void MCG_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void LPTimer_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void PORTA_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void PORTCD_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void Reserved39_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void Reserved42_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void Reserved43_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); void Reserved45_IRQHandler( void ) __attribute__( ( weak, alias( "irq_default_handler" ) ) ); /* ---------------------------------------------------------------------------------- * Interrupt vector table (loaded into flash memory at 0x0000) */ #if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */ #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wcast-align" /* Cast increases required alignment of __StackTop */ void ( * const interrupt_vector_table[] )( void ) __attribute__( ( used, section( ".isr_vector" ) ) ) = { /* Cast increases required alignment of target type: */ /* No. Address Pri */ ( void( * )( void ) ) __StackTop, /* 0x00 0x00000000 - Initial stack pointer */ Reset_Handler, /* 0x01 0x00000004 - Reset handler */ NMI_Handler, /* 0x02 0x00000008 -2 Non-Maskable Interrupt */ HardFault_Handler, /* 0x03 0x0000000C -1 Unrecoverable hard fault */ empty1_handler_void, /* 0x04 0x00000010 - */ empty2_handler_void, /* 0x05 0x00000014 - */ empty3_handler_void, /* 0x06 0x00000018 - */ empty4_handler_void, /* 0x07 0x0000001C - */ empty5_handler_void, /* 0x08 0x00000020 - */ empty6_handler_void, /* 0x09 0x00000024 - */ empty7_handler_void, /* 0x0A 0x00000028 - */ SVC_Handler, /* 0x0B 0x0000002C - Supervisor call (SVCall) */ empty8_handler_void, /* 0x0C 0x00000030 - */ empty9_handler_void, /* 0x0D 0x00000034 - */ PendSV_Handler, /* 0x0E 0x00000038 - Pendable request for system service */ /* Interrupts: */ SysTick_Handler, /* 0x0F 0x0000003C - System tick timer (SysTick) */ DMA0_IRQHandler, /* 0x10 0x00000040 - DMA Channel 0 Transfer Complete and Error */ DMA1_IRQHandler, /* 0x11 0x00000044 - DMA Channel 1 Transfer Complete and Error */ DMA2_IRQHandler, /* 0x12 0x00000048 - DMA Channel 2 Transfer Complete and Error */ DMA3_IRQHandler, /* 0x13 0x0000004C - DMA Channel 3 Transfer Complete and Error */ Reserved39_IRQHandler, /* 0x14 0x00000050 - Reserved interrupt 39/23 */ FTFA_IRQHandler, /* 0x15 0x00000054 - Command complete and read collision */ LVD_LVW_IRQHandler, /* 0x16 0x00000058 - Low-voltage detect, low-voltage warning */ LLW_IRQHandler, /* 0x17 0x0000005C - Low Leakage Wake-up */ I2C0_IRQHandler, /* 0x18 0x00000060 - I2C0 interrupt */ I2C1_IRQHandler, /* 0x19 0x00000064 - I2C1 interrupt */ SPI0_IRQHandler, /* 0x1A 0x00000068 - SPI0 Interrupt, for all sources */ SPI1_IRQHandler, /* 0x1B 0x0000006C - SPI1 Interrupt, for all sources */ LPUART0_IRQHandler, /* 0x1C 0x00000070 - LPUART0 Status and Error interrupt */ LPUART1_IRQHandler, /* 0x1D 0x00000074 - LPUART1 Status and Error interrupt */ UART2_FLEXIO_IRQHandler, /* 0x1E 0x00000078 - UART2 Status or FLEXIO */ ADC0_IRQHandler, /* 0x1F 0x0000007C - ADC0 interrupt */ CMP0_IRQHandler, /* 0x20 0x00000080 - CMP0 interrupt */ TPM0_IRQHandler, /* 0x21 0x00000084 - TPM0 fault, overflow and channels interrupt */ TPM1_IRQHandler, /* 0x22 0x00000088 - TPM1 fault, overflow and channels interrupt */ TPM2_IRQHandler, /* 0x23 0x0000008C - TPM2 fault, overflow and channels interrupt */ RTC_Alarm_IRQHandler, /* 0x24 0x00000090 - RTC Alarm interrupt */ RTC_Seconds_IRQHandler, /* 0x25 0x00000094 - RTC Seconds interrupt */ PIT_IRQHandler, /* 0x26 0x00000098 - PIT timer all channels interrupt */ I2S0_IRQHandler, /* 0x27 0x0000009C - I2S */ USB_IRQHandler, /* 0x28 0x000000A0 - USB interrupt */ DAC0_IRQHandler, /* 0x29 0x000000A4 - DAC0 interrupt */ Reserved42_IRQHandler, /* 0x2A 0x000000A8 - 42 */ Reserved43_IRQHandler, /* 0x2A 0x000000A8 - 43 */ LPTimer_IRQHandler, /* 0x2C 0x000000B0 - LPTimer interrupt */ Reserved45_IRQHandler, /* 0x2D 0x000000B4 - Reserved interrupt 45/29 */ PORTA_IRQHandler, /* 0x2E 0x000000B8 - Port A interrupt */ PORTCD_IRQHandler /* 0x2F 0x000000BC - Port D interrupt [BEWARE THIS VECTOR MAY BE A DIFFERENT PORT ON DIFFERENT PARTS!] */ }; #if( __GCC_VERSION__ >= 40700U ) /* GCC 4.7.0 or later */ #pragma GCC diagnostic pop #else #pragma GCC diagnostic error "-Wcast-align" #endif /* ---------------------------------------------------------------------------------- */ static void vectors_bootloader_mr_setup( void ) __attribute__( ( used, __aligned__( 4U ), section( ".after_vectors" ) ) ); static void vectors_bootloader_mr_setup( void ) { /* * RCM_MR Indicates the boot source, the boot source remains set * until the next System Reset or software can write logic one to * clear the corresponding mode bit. While either bit is set the * NMI input is disabled and the vector table is relocated to the * ROM base address at 0x1C00_0000. These bits should be cleared by * writing logic one before executing any code from either Flash or * SRAM. * * A reset is forced to clear out anything that the ROM * bootloader did, so we are sure we have the data sheet reset * values. * This method works around the buggy KL43/27/17 bootloaders as * described in: "Problem Analysis and solutions for booting from * ROM BOOTLOADER in KL series". */ if( 0U != ( RCM_MR & RCM_MR_BOOTROM_MASK ) ) { RCM_MR = RCM_MR_BOOTROM_MASK; /* Clear the bits that indicated a bootlaoder boot via ROM */ RCM_FM = 0U; /* Boot from Flash not ROM on next reset */ SCB_AIRCR = ( SCB_AIRCR_VECTKEY( 0x05FAU ) | SCB_AIRCR_SYSRESETREQ_MASK ); /* Force a Software Reset */ } } /* ---------------------------------------------------------------------------------- * * Reset_Handler() -- Reset entry point. * * The CPU reset vector points here. Initialize the CPU, and jump * to the C runtime start, which will eventually invoke main() */ #if 0 /* Zeroing of the BSS happens in crt0.S, only need this if zeroing something else */ typedef struct { uint32_t* dest; uint32_t wlen; } __zero_table_t; extern const __zero_table_t __zero_table_start__; extern const __zero_table_t __zero_table_end__; #endif typedef struct { uint32_t const* src; uint32_t* dest; uint32_t wlen; } __copy_table_t; extern const __copy_table_t __copy_table_start__; extern const __copy_table_t __copy_table_end__; void Reset_Handler( void ) { irq_disable(); /* Did bootloader leave IRQs on perhaps? */ BUT_TOP_INIT(); /* Give capacitor time to charge from the pull-up before testing the input */ bootloader_mr_setup(); SCB_VTOR = ( uint32_t ) interrupt_vector_table; sync_barrier_data(); psp_set( sp_get() ); /* Set the unused Multitask Stack Pointer to a known value */ lr_set( 0UL ); /* Set to known zero value in case of Hardware Fault at boot */ if( BUT_TOP_ASSERTED() ) { uint16_t const wdt_src_u16 = (((uint16_t) RCM_SSRS1 << 8U) | ((uint16_t) RCM_SSRS0) ); /* MISRA */ if( ( 0x82U == wdt_src_u16) || /* POR */ ( 0x20U == wdt_src_u16) || /* WDOG */ ( 0x40U == wdt_src_u16) || /* PIN */ ( 0x60U == wdt_src_u16) || /* PIN & WDOG */ (0x860U == wdt_src_u16) /* PIN & WDOG & MDM_AP (Debugger reset request) */ ) { RCM_FM = RCM_FM_FORCEROM_MASK; /* Force next reset to jump to Bootloader ROM, */ SCB_AIRCR = (SCB_AIRCR_VECTKEY(0x05FAU) | SCB_AIRCR_SYSRESETREQ_MASK); /* with this reset */ } } /* * The watchdog and power mode registers may only be written to a single time after * reset. Default to turning it off. Override these function in a * shipping product if needed: */ watchdog_init(); /* * Depending on the amount of data to be copied it may make sense to * initialize the clocks before copying the data to RAM, if the new * clock speed is faster than the default CPU clock. However such * code must not use any preinitialized data. */ hardware_init_b4_var_init(); #if( PWR_OFF_TEST_DBG > 1000U ) sync_barrier_data(); /* One time write - allow VLPR, LLS and VLLS modes */ /* Setup Power mode protection register */ SMC_PMPROT = SMC_PMPROT_AVLP_MASK | /* Allow Very-Low-Power Modes */ SMC_PMPROT_AVLLS_MASK | /* Allow Very-Low-Leakage Stop Mode */ SMC_PMPROT_ALLS_MASK; /* Allow Low-Leakage Stop Mode */ /* SIM_SCGC5 = Clocks left on and set in hardware_setup */ SIM_SCGC6 = SIM_SCGC6_FTF_MASK; /* Flash Clock must remain on, as we are running form Flash right here */ SIM_SCGC7 = 0UL; SCB_SCR = SCB_SCR_SLEEPDEEP_MASK; /* Deep Sleep = 1, SLEEPONEXIT = 0 = do not sleep when returning to Thread mode */ SMC_PMCTRL = SMC_PMCTRL_STOPM( 4U ); /* 4 = Very Low Lekage Stop VLLSx */ SMC_STOPCTRL = SMC_STOPCTRL_VLLSM( 0U ); /* 3 = VLLS3 LPTMR runs, SRAM Preserved, 1 = VLLS1 SRAM Powered Off, 0 = VLLS0 LPO disabled, SRAM Powered Off! */ ( volatile uint8_t ) SMC_STOPCTRL; /* Dummy read to ensure the register is written before entering low power mode */ /* * Before executing the WFI instruction, the last register * written to must be read back. This ensures that all register * writes associated with setting up the low power mode being * entered have completed before the MCU enters the low power * mode. Failure to do this may result in the low power mode * not being entered correctly. */ wait4irq(); for(;;) { ; } #endif vectors_reset_init(); hardware_init(); clock_cpu_init_b4_c_setup(); /* Do before UART or baud rate will be wrong */ serial_io_init(); /* Setup UART output, if such a function exists, to output any hardware exception messages. MAKE SURE CORRECT UART CLOCK IS ENABLED IN clock.c! */ HardFault_Handler_init(); fault_soft_init(); hardware_init(); #if 0 /* Zeroing of the BSS happens in crt0.S, only need this if zeroing something else */ for( __zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable ) /* Zero the BSS */ { watchdog_service(); for( uint32_t i = 0UL; i < pTable->wlen; ++i ) { pTable->dest[i] = 0UL; } } #endif /* Copy values from flash to initialize RAM such as the .data segment: */ for( __copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable ) { watchdog_service(); for( uint32_t i =0UL; i < pTable->wlen; ++i ) { pTable->dest[ i ] = pTable->src[ i ]; } } watchdog_service(); clock_cpu_init_after_c_setup(); vectors_b4_newlib_start(); watchdog_service(); _start(); /* Goto newlib/nanolib C lib startup to zero BBS and start main() */ /* * Can never get here due to _start() ending in infinite loop, via "swi SWI_Exit". * * If using a non-standard _start() trigger a hardware break-point in * the hopes there is a debugger 'out there'. */ brkpt(); } /*lint -restore */