Introduction The KSDK provides a high level API for peripheral drivers and OS functions in MQX. A key aspect of the peripheral driver implementation involves the use of interrupts. These interrupt events are handled by specific IRQ handlers in the KSDK peripheral driver. However, the standard CMSIS style IRQ hander naming cannot be used by an application running in MQX because those names are reserved. This document provides a guide to implementing the IRQ handlers provided by the KSDK in MQX. IRQ Naming The device startup assembly code provided in KSDK defines weak instances of the IRQHandlers for each of the interrupt vectors on the device. In bare metal applications, when using KSDK peripheral drivers these IRQHandler names are re-declared in the associated ‘fsl_xxx_irq.c’ file. This then points the NVIC to use those functions over the weak functions with the same name. However, when using MQX this is no longer possible as the MQX kernel requires those IRQHandler names for its own interrupt handling. It is therefore necessary for the application developer to use a different name for the peripheral driver IRQ handler. The convention used in KSDK is pre-append the IRQHandler name with MQX_. For example, /* IRQ Handler prototypes */ void MQX_SPI0_IRQHandler(void); The function prototype above can now be installed in MQX by the application developer to handle peripheral driver interrupts. We will cover interrupt handler installation in the next section. IRQ Handler Installation In MQX it is required for the application to install IRQ handlers. KSDK provides a function to handle this in the OSA (Operating System Abstraction) layer. The following function allows the application developer to install the appropriate IRQ handler to the interrupt that will be triggered. //Install IRQ handlers OSA_InstallIntHandler(SPI0_IRQn, MQX_SPI0_IRQHandler); The ‘OSA_InstallIntHandler’ function requires the vector table number for the interrupt in question, as well as the name of the IRQ handler that will be used in the application. Once installed, MQX will execute this handler when the related interrupt is triggered. IRQ Priorities Setting appropriate interrupt priorities is important in MQX applications. MQX uses 8 priority levels that are mapped to the interrupt priority levels in the Cortex-M4 core. Table 1 illustrates the mapping between MQX and hardware. Table 1: MQX to Hardware priority mapping. MQX Priority BASEPRI 0 Not Allowed 1 0x20 (Priority 2 in NVIC_SetPriority) 2 0x40 (Priority 4 in NVIC_SetPriority) 3 0x60 (Priority 6 in NVIC_SetPriority) 4 0x80 (Priority 8 in NVIC_SetPriority) 5 0xA0 (Priority 10 in NVIC_SetPriority) 6 0xC0 (Priority 12 in NVIC_SetPriority) 7 0xE0 (Priority 14 in NVIC_SetPriority) >7 0x00 (Lowest priority) To ensure proper MQX application behavior it is recommended to adhere to the following when using NVIC_SetPriority to set interrupt priorities: Priority should be an even number Priority level should be greater or equal to 2 times the value of MQX_HARDWARE_INTERUPT_LEVEL_MAX MQX_HARDWARE_INTERRUPT_LEVEL_MAX is located in the MQX_init_struct structure. In the MQX examples provided by the KSDK installation the MQX_init_struct structure is defined in ‘mqx_main.c’ as follows: const _WEAK_SYMBOL(MQX_INITIALIZATION_STRUCT MQX_init_struct) = /*! \endcond */ { /* PROCESSOR_NUMBER */ BSP_DEFAULT_PROCESSOR_NUMBER, /* [KPSDK-2559] Workaround to make TAD happy. With new version of TAD START_OF_KERNEL_MEMORY and END_OF_KERNEL_MEMORY can be removed */ /* START_OF_KERNEL_MEMORY */ &kernel_data_prv, /* END_OF_KERNEL_MEMORY */ BSP_DEFAULT_END_OF_HEAP, /* INTERRUPT_STACK_SIZE */ BSP_DEFAULT_INTERRUPT_STACK_SIZE, #if MQX_CUSTOM_MAIN /* TASK_TEMPLATE_LIST */ NULL, #else /* TASK_TEMPLATE_LIST */ MQX_template_list, #endif /* MQX_CUSTOM_MAIN */ /* MQX_HARDWARE_INTERRUPT_LEVEL_MAX*/ BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX, /* MAX_MSGPOOLS */ BSP_DEFAULT_MAX_MSGPOOLS, /* MAX_MSGQS */ BSP_DEFAULT_MAX_MSGQS, /* IO_CHANNEL */ BSP_DEFAULT_IO_CHANNEL, /* IO_OPEN_MODE */ BSP_DEFAULT_IO_OPEN_MODE, #if MQXCFG_PREALLOCATED_SYSTEM_STACKS /* INTERRUPT_STACK_LOCATION */ mqx_interrupt_stack, #else 0, #endif /* START_OF_HEAP */ BSP_DEFAULT_START_OF_HEAP, /* END_OF_HEAP */ BSP_DEFAULT_END_OF_HEAP, }; The MQX_HARDWARE_INTERUPT_LEVEL_MAX constant is defined as BSP_DEFAULT_ MQX_HARDWARE_INTERUPT_LEVEL_MAX in this MQX_init_struct structure. Where BSP_DEFAULT_ MQX_HARDWARE_INTERUPT_LEVEL_MAX is defined in ‘bsp_config.h’ as: #ifndef BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX #define BSP_DEFAULT_MQX_HARDWARE_INTERRUPT_LEVEL_MAX (2L) #endif For the interrupt we have shown examples for above, the interrupt priority would be set as such: //Set IRQ priorities NVIC_SetPriority(SPI0_IRQn, 6U); Priority 6 is greater than 2 times the value set in the MQX_init_struct by BSP_DEFAULT_ MQX_HARDWARE_INTERUPT_LEVEL_MAX. Example Included with this document is a source file called ‘hello.c’. This file is a direct replacement for the ‘hello.c’ source file in the ‘hello’ example provided by the KSDK installation of MQX. The project can be located in the following directories (based on default installation settings): Windows C:\Freescale\KSDK_1.1.0\rtos\mqx\mqx\examples\hello Linux ~/Freescale/KSDK_1.1.0/rtos/mqx/mqx/examples/hello All that is required to run the new demo is to replace the ‘hello.c’ located in the directory above with the ‘hello.c’ included with document and a rebuild of the project. The concepts we have touched in this document are implemented in the new ‘hello.c’. Interrupt handler prototypes are declared near the top of the file, and the functions are defined at the end of the file. The OSA layer of KSDK is used to install interrupt handlers in the ‘dspi_task’ function. In addition, the ‘NVIC_SetPriority’ function is also used in ‘dspi_task’ to properly configure the interrupt priorities. The new ‘hello.c’ will work in IAR EWARM, Keil MDK-ARM, Kinetis Design Studio, Atollic TrueSTUDIO, and with command line ARM GCC tools. No changes are made to the serial connection configuration. Successful completion of the example should show the following in the terminal window. Figure 1: Example of successful execution. NOTE: The demo uses the DSPI_DRV_EdmaMaster driver. Therefore, it is necessary to have a Kinetis device that supports this driver. The new source code was tested on FRDM-K64F. To successfully complete the DSPI eDMA loopback pins J2-8 and J2-10 need to be connected together on the FRDM-K64F. Conclusion This document should serve to help MQX application developers configure their code to make effective use of the interrupt driven KSDK peripheral drivers.
View full article