Controlling Peripheral Interrupts with Harmony v2 System Services

 Summary

MPLAB® Harmony Interrupt System Services provides a set of APIs allowing the system developers to monitor and control the operation of peripheral interrupts.

The elements controlled by the Interrupt System Services include:

  • Enabling and disabling an individual interrupt
  • Setting a Peripheral's Interrupt Priority and Sub-Priority
  • Clearing an interrupt flag
  • Assigning an ISR to a Peripheral with a Dynamic Driver


Interrupts are controlled by Harmony's Interrupt System Services but they are defined when the individual peripheral drivers are selected. To effectively implement interrupts, the system developer must work with both Interrupt System Services and the individual peripheral setup. This page demonstrates Interrupt System Services.


Enabling Interrupt System Services

To enable Interrupt System Services from MPLAB Harmony Configurator (MHC), select the box Use Interrupt System Service? under Harmony Framework Configuration > System Services > Interrupts.

sys-int-setup.png

When you click the Generate button, MHC will add the source files to the project to enable Interrupt System Services.

Peripheral Interrupt Setup

Peripheral interrupts are set up under the Driver section of MHC. For each peripheral capable of generating an interrupt, MHC will present you with an option of enabling the interrupt. When configuring the interrupt in MHC, you have the opportunity to set the initial priority level of the individual interrupt.

When the project is generated, MHC inserts code to:

  • Initialize the MCU interrupt system: SYS_INT_Initialize()
  • Enable Global Interrupts: SYS_INT_Enable()
  • Set the selected interrupt priority levels
  • Enable the peripheral interrupts
  • Create "Stub" Interrupt Service routines for either Static or Dynamic Drivers

Enabling and Disabling an Interrupt

Individual peripheral interrupts can be enabled or disabled by calling the functions SYS_INT_SourceEnable() and SYS_INT_SourceDisable().


void SYS_INT_SourceEnable(INT_SOURCE source);

void SYS_INT_SourceDisable(INT_SOURCE#* source);

. . .

/ Enable interrupts from Timer 3
SYS_INT_SourceEnable(INT_SOURCE_TIMER_3);

// Disable interrupts from ADC 1
SYS_INT_SourceEnable(INT_SOURCE_ADC_1);

The data type for the input parameter for these functions, INT_SOURCE, is an enumeration defined in the processor's Harmony interrupt header file.

Setting an ISR Priority

Application programs can change the priority, and sub-priority, of individual peripherals using the functions SYS_INT_VectorPrioritySet and SYS_INT_VectorSubprioritySet.


void SYS_INT_VectorPrioritySet( INT_VECTOR vector,
INT_PRIORITY_LEVELpriority);

void SYS_INT_VectorSubprioritySet( INT_VECTOR vector,
INT_SUBPRIORITY_LEVEL subpriority);

SYS_INT_VectorPrioritySet(INT_VECTOR_UART1,
INT_PRIORITY_LEVEL2); // Set UART1's interrupt priority level to 2
SYS_INT_VectorSubrioritySet(INT_VECTOR_UART1,
INT_SUBPRIORITY_LEVEL1); // Set UART1's interrupt SUB priority level to 1

The data types for the input parameters to these functions, INT_VECTOR, ]INT_PRIORITY, and INT_SUBPRIORITY_LEVEL are enumerations defined in the processor's Harmony interrupt header file.

Clearing an Interrupt's Request Flag

Peripherals announce an interrupt condition by setting the Peripheral Interrupt Request flag associated with the peripheral. The interrupt request flags are located in the MCU's special function registers (SFRs). The ISR needs to clear the request flag before returning control to the main program. The Harmony supplied function to clear the flags is SYS_INT_SourceStatusClear.


void SYS_INT_SourceStatusClear( INT_SOURCE source);


// Clear Timer1 interrupt request
SYS_INT_SourceStatusClear(INT_SOURCE_TIMER1);

The data type for the input parameter, INT_SOURCE, is an enumeration defined in the processor's Harmony interrupt header file.

Dynamic vs Static Drivers

Peripherals are configured with either a Static or Dynamic driver. MHC provides the developer with the ability to select the driver type from a drop down menu.

Static drivers are intended to be used in applications in which the peripheral's parameters remain unchanged (i.e., static) and in applications where the peripheral is not shared with multiple tasks. Dynamic Drivers offer the ability to easily alter the peripheral's performance at run-time. One of the features which can be changed for Dynamic Drivers is the Interrupt Service Routine (ISR). Changing the ISR at run-time can be essential in sharing one peripheral among several tasks.

For Static Drivers, Harmony inserts a "stub" ISR at the interrupt vector. The Harmony supplied static ISR contains code to clear the Peripheral Interrupt Request flag. You will need to complete the ISR by adding code to the ISR function.

For Dynamic Drivers, Harmony inserts a call to a Harmony-supplied Peripheral Task function at the interrupt vector. The Peripheral Task does some parameter testing then calls, via a function pointer, the ISR to handle the interrupt.

Implementing an ISR for a Static Driver

static-stub.png

When a peripheral is configured to use an interrupt, MHC creates a C file called the SYSTEM_INTERRUPT. This file is placed in the current project. For peripherals with static drivers, a stub ISR is created.

To implement application-specific ISR, a code needs to be inserted in the stub ISR.

Implementing an ISR for a Dynamic Driver

dynamic-stub.png

ISRs for Dynamic Drivers are implemented using call-back functions. MHC places a call to a Peripheral-Task into the interrupt vector for each peripheral defined with a Dynamic Driver. There is one Peripheral-Task function for each peripheral type. The Peripheral Task functions have names such as DRV_TMR_Tasks_ISR for Timers and DRV_USART_TasksTransmit for the UART transmit function.

The lone parameter passed to the Peripheral-Task function is a pointer to a data structure containing the information for the individual peripheral. (This data structure is commonly called a System Object.) One of the parameters in the System Object data structure is the address of the designated ISR.

The Peripheral-Task function performs some error checking and then invokes the functions specified in the System Object data structure. Loading the System Object with the address of the ISR establishes which user-written function will eventually be executed upon an interrupt.

The default selection of the ISR for a peripheral with a dynamic driver varies among the peripherals. For basic I/O peripherals such as SPI, MHC inserts a call to the specific transfer functions based upon whether or not the enhanced buffer is being used. The SPI interrupt handler ensures the data is transferred to and from the SPI SFRs and the user-designated data buffer.

The default ISR for interrupts requiring user-written function is NULL. For peripherals where a specific code needs to be inserted, Harmony provides two support functions, SYS_INT_DynamicRegister and SYS_INT_DynamicDeregister. These functions enable to set or remove their custom function as the ISR callback function.


void SYS_INT_DynamicDeregister( INT_SOURCE source);

void SYS_INT_DynamicRegister( INT_SOURCE source, ISR_POINTER,
SYSTEM_MODULE_OBJECT Object);


// Deregisters the ISR for Timer_4 interrupt
SYS_INT_DynamicDeragister(INT_SOUTCE_TIMER_4);


/* Sets the user-written MyISR as the interrupt service routine for Timer 1 where Timer 1 has been set as Timer instance 0 */
SYS_INT_DynamicRegister(INT_SORCE_TIMER_1, MyISR , sysObj.drvTmr0);

NOTE:

Early versions of Harmony do not support nor include SYS_INT_DynamicRegister or SYS_INT_DynamicDeregister.

Some peripheral drivers, such as Timers, offer their own functions to set their ISRs. Refer to the Harmony Peripheral documentation for how to set or clear the dynamic ISR for the selected peripheral.

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.