Summary
This page illustrates the steps needed to configure a timer and associated interrupt vector using static drive function calls. When a timer is configured to use a static driver, a unique interrupt vector is created for the timer.
This example uses a Timer1 generated interrupt.
Steps demonstrated on this page include:
- Using MPLAB® Harmony Configurator (MHC) to create the project structure with a static driver for Timer1.
- Verifying the function DRV_TMR0_Initialize() establishes Timer1's operating parameters.
- Implementing the Interrupt Service Routine (ISR) in the file system_interrupt.c.
- Modifying the function APP_Init() to enable the MCU to accept Timer1 interrupts.
- Modifying the main application program, APP_Tasks() to start Timer1.
Using MHC to Create a Project
Under the Driver section check the Use Timer Driver? box. Ensure a STATIC timer driver is used. When STATIC is selected you will have the option of configuring the timer settings as well as the interrupt priority levels.
Under the System Service section of the MHC, you should observe the Clock and Ports system services have been selected by default. Leave the Timer system services unchecked.
Below is the project directory and file structure generated by the MHC.
The illustration shows the source file (or file directory) of the functions needed to be modified in order to use a static timer driver.
Configuring the Timer
- The code for the timer's configuration parameters and interrupt levels are generated by the MHC and placed in the function DRV_TMR_Initialize.
- For a system using a static driver, the driver initialization function is placed in the file drv-tmr-static.c.
- The drv_tmr_static.c file is placed within the system configuration directory structure as shown in the picture below.
drv-tmr-static.c
void DRV_TMR0_Initialize(void)
{
/* Initialize Timer Instance0 */
/* Disable Timer */
PLIB_TMR_Stop(TMR_ID_1);
/* Select clock source */
PLIB_TMR_ClockSourceSelect(TMR_ID_1,
TMR_CLOCK_SOURCE_PERIPHERAL_CLOCK);
/* Select prescalar value */
PLIB_TMR_PrescaleSelect(TMR_ID_1, TMR_PRESCALE_VALUE_256);
/* Enable 16 bit mode */
PLIB_TMR_Mode16BitEnable(TMR_ID_1);
/* Clear counter */
PLIB_TMR_Counter16BitClear(TMR_ID_1);
h/*Set period */
PLIB_TMR_Period16BitSet(TMR_ID_1, 0);
/* Setup Interrupt */
PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_TIMER_1);
PLIB_INT_VectorPrioritySet(INT_ID_0, INT_VECTOR_T1,
INT_PRIORITY_LEVEL5);
PLIB_INT_VectorSubPrioritySet(INT_ID_0, INT_VECTOR_T1,
INT_SUBPRIORITY_LEVEL0);
}
- You should examine DRV_TMR_Initialize() to ensure the timer is configured to your specifications.
- During the applications start-up phase, DRV_TMR_Initialize() is called by the system initialization function SYS_Initialize().
- Static driver functions are implemented using Peripheral Libraries.
Adding Code to the Interrupt Service Routine
- The MHC will generate separate interrupt vectors for each driver instance defined.
- The drivers will be placed in system_interrupt.c.
- Each interrupt vector will contain code which clears the interrupt flag (PLIB_INt_Sourceflagclear(..)).
- You are responsible for adding code to execute the task required of the ISR. In this example, you are asked to enter your own ISR functionality.
system-interrupt.c
void __ISR(_TIMER_1_VECTOR, ipl5) _IntHandlerDrvTmrInstance0(void)
{
// User-Written ISR code goes here!
PLIB_INT_SourceFlagClear(INT_ID_0,INT_SOURCE_TIMER_1);
}
Enabling Timer Interrupts
- The function to initialize the application, APP_Initialize() is located in app.c.
- In this example, a line of code was added to enable interrupts from Timer1.
app.c
void APP_Initialize (void)
{
appData.state = APP_STATE_INIT;
PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_TIMER_1);
}
Starting the Timers
- The main application function, APP_Tasks(), is located in app.c.
- In this example, during the initial state of the application (APP_STATE_INIT), the timer is started.
app.c
void APP_Tasks (void)
{
switch ( appData.state )
{
case APP_STATE_INIT:
{
DRV_TMR0_Start(); // Start the Timers
break;
}
}
}