Erich
Both the NMI and EzPort enable pins are two catch-me's that often cause problems and, as you have noted, the easiest thing to do is usually to disable them (although EzPort enable can be more serious since it doesn't allow programming at all if it is incorrectly set to '0' on a new layout).
If the NMI is needed it needs to be handled out of reset (as you have noted) but since it is a level sensitive input a continuous '0' will still block the processor if the handler is an empty routine
This is the solution used in the uTasker project:
1. Disable:
Each project has definitions for the flash configurations that are easily readable (not just hex values):
#define KINETIS_FLASH_CONFIGURATION_NONVOL_OPTION (FTFL_FOPT_LPBOOT_CLK_DIV_1 | FTFL_FOPT_RESET_PIN_ENABLED | FTFL_FOPT_BOOTSRC_SEL_FLASH | FTFL_FOPT_BOOTPIN_OPT_DISABLE | FTFL_FOPT_NMI_DISABLED)
whereby the NMI disabled state is the default. The user doesn't need to know which bits means what and where to find the configuration values can be change between DISABLED and ENABLED as required.
2. Handle at reset and use later:
The project enables this with the define NMI_IN_FLASH
const _RESET_VECTOR __vector_table
= {
{
(void *)(RAM_START_ADDRESS + (SIZE_OF_RAM - NON_INITIALISED_RAM_SIZE)), // stack pointer to top of RAM
(void (*)(void))START_CODE, // start address
#if defined NMI_IN_FLASH
irq_NMI // if the NMI is not disabled and the input is 0 out of reset this will be immediately taken
#endif
..
which adds a default handler in the flash based reset vector (later vectors will be moved to SRAM). This is needed by any boot loader that is used since an application can't influence this.
The NI handler reconfigures the NMI pin (note that the actual pin changes with Kinetis part) so that the interrupt is negated and the normal start-up can continue, even if there is initially a continuous '0' on the pin:
static void irq_NMI(void)
{
#if defined PB_4_NMI // set the NMI line to an input to remove the NMI function and allow the processor to continue
_CONFIG_PORT_INPUT_FAST_LOW(B, PORTB_BIT4, PORT_PS_UP_ENABLE);
#elif defined PB_18_NMI // set the NMI line to an input to remove the NMI function and allow the processor to continue
_CONFIG_PORT_INPUT_FAST_HIGH(B, PORTB_BIT18, PORT_PS_UP_ENABLE);
#else
_CONFIG_PORT_INPUT_FAST_LOW(A, PORTA_BIT4, PORT_PS_UP_ENABLE); // set the NMI line to an input to remove the NMI function and allow the processor to continue
#endif
}
Later, when the NMI is to be enabled for its application usage the user enters its handler and re-enables the NMI input function with (the vectors will always be in SRAM)
// Allow the user to enter an NMI handler, ensuring that the NMI pin is configured as NMI function
// - note that the NMI may not have been disabled to allow this to work
//
extern void fnEnterNMI(void (*_NMI_handler)(void))
{
VECTOR_TABLE *ptrVect = (VECTOR_TABLE *)VECTOR_TABLE_OFFSET_REG;
ptrVect->reset_vect.ptrNMI = _NMI_handler; // enter interrupt handler
#if defined PB_4_NMI // set the NMI pin function
_CONFIG_PERIPHERAL(B, 4, (PB_4_NMI | PORT_PS_UP_ENABLE));
#elif defined PB_18_NMI // set the NMI pin function
_CONFIG_PERIPHERAL(B, 18, (PB_18_NMI | PORT_PS_UP_ENABLE));
#elif defined PB_5_NMI // set the NMI pin function
_CONFIG_PERIPHERAL(B, 5, (PB_5_NMI | PORT_PS_UP_ENABLE));
#else
_CONFIG_PERIPHERAL(A, 4, (PA_4_NMI | PORT_PS_UP_ENABLE));
#endif
}
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]