The MPLAB® Harmony Timer Driver library provides a high-level interface to the PIC32 Timer peripherals. The library provides interfaces to support:
- System Interaction
- Sync Mode Setup
- Period Modification
- Counter Modification
- Client Core Functionality
- Client Alarm Functionality
There are two kinds of Timer Drivers:
Static Timer Drivers
Capabilities of a Static Timer Driver
- The Timer Static Driver provides a basic set of timer access functions such as read, write, start, stop … etc.
- When a Static Driver is used, the project is configured with unique APIs to access each timer instance. To access a timer, you will call a function whose name is determined by the timer driver instance number.
- Harmony generates a "stub" interrupt service routine (ISR) for each timer with a static driver. You will code the application's ISR functionality into the stub ISRs. These ISR are set during development and cannot be changed at run time.
- Static Timer Drivers offer a straight forward, easy to understand interface.
- It minimizes interrupt latency.
- The Static API forces you to use different functions to control each Timer Driver (minimal hardware abstraction).
- If circumstances force the developer to re-allocate the timers between tasks using Static Drivers will require changes in the application code.
- Interrupt Service Routines cannot be changed at run time. This limits the timer's ability to alter its performance in response to run time conditions.
Static Driver API Assignment
Static Driver APIs reference the hardware timers by driver instance (e.g. DRV_TMR0) rather than by the timer peripheral number (e.g. Timer2). You will use the MPLAB® Harmony Configurator (MHC) to determine which specific hardware peripheral timer is associated with each timer driver instance.
Interrupt Processing with Static Timer Drivers
For each timer configured with a Static Driver, Harmony inserts code to create an interrupt service routine (ISR) and instructs the linker to place the ISR at the appropriate vector address. Inserted into these ISRs is code to clear the relevant interrupt request flag. You are responsible for writing the body of the ISR.
API's for Static Timer Drivers
Each timer is controlled by its own set of functions. The function names for the API contain the specific timer instance of the timer being accessed. The list of functions below all use the letter X to designate the driver instance of the timer. You can use MHC to control which timer (Timer1, Timer2, etc…) is associated with each instance.
This page states the generic function DRV_TMRx_Start as the function which starts a timer. The specific functions for starting the timers are DRV_TMR0_Start, DRV_TMR1_Start ..etc
|DRV_TMRx_Start()||Enables the timer to run|
|DRV_TMRx_Stop()||Stops the Timer|
|DRV_TMRx_CounterClear()||Loads the timer with the value of ZERO|
|DRV_TMRx_CounterValueSet()||Sets the Timer value|
|DRV_TMRx_CounterValueGet()||Reads the Timer's current value.|
|DRV_TMRx_Initialize()||Calls individual PLIB commands to configure timer SFRs|
Dynamic Timer Drivers
Capabilities of the Dynamic Timer Driver
- The Dynamic Timer Driver is a set of API's allowing you to control any PIC32 timer similar to those offered by the Static timer Driver. The Dynamic Driver offers you more options for application management than a Static Driver.
- Applications written using Dynamic Drivers do not need to know the timer number they are accessing. Access to the timers use run-time retrieved 'handles'. The hardware abstraction facilitated by the handles allows code to be generated that can be transparently run using any available PIC32 timer.
- The functions called by the Interrupt Service Routines can be assigned or changed at run-time by the application, allowing a timer to be used by several different tasks.
- You are not required to have foreknowledge of the system clock speed when designating the period of a timer interrupt. Dynamic Drivers have the capability of allowing the application to designate only the desired frequency of the interrupt. This allows applications with fixed-period interrupts to maintain their performance characteristics, even if they are migrated to another PIC32 with a different clock speed.
- Timer interrupts can be set as continuous or 'one-time' by the application.
- When working with the Timer System Service, Dynamic Drivers permit a single timer to initiate multiple interrupt service routines, with each of these ISRs having their own period.
Timer Setup and Hardware Abstraction
Harmony Projects contain a data structure called sysObj which consists of one pointer for each peripheral defined with a Dynamic Driver. The sysObj entries for timers are: sysObj.drvTmr0, sysObj.drvTmr1, … sysObj.drvTmr(N-1) (where N is the number of timers configured with a dynamic driver).
The initialization function DRV_TMR_Initialize(… ) initializes the timer's register and loads the address of the timer into sysObj.
Before an application can use a timer, it must receive a handle from the function DRV_TMR_OPEN(..). DRV_TMR_Open() returns a numeric handle if the timer is available. Once an application opens a timer all subsequent calls to the timer are made referencing the handle.
Interrupt Processing with a Dynamic Timer Driver
- MHC will create and populate the individual interrupt vectors for Dynamic timers. Each of these interrupt vectors consists of a call to the shared timer interrupt service routine DRV_TMR_Tasks_ISR.
- The system object sysObj.tmrX of the timer generating the interrupt, is passed as a parameter to DRV_TMR_Tasks_ISR by the code in the interrupt vector.
- After some error checking, the shared timer ISR calls the user functions designated as the "Registered" callback function for the timer.
- You are responsible for writing and registering the function to execute on a timer interrupt.
Setting up Your ISR
In order for a function to be called by the shared timer ISR, your function must be set at the Registered Alarm Callback function for the timer. The function DRV_TMR_AlarmRegister causes your function to be called by the shared ISR.
|handle||Handle returned from DRV_TMR_Open|
|divider||The value to divide the timer clock source to obtain
the required alarm frequency.
|isPeriodic||Flag indicating whether the alarm should be one-shot or periodic.|
|context||An optional value to be passed to the callback function.
Can be 0 if not needed.
void myISR (uintptr_t context, uint32_t alarmCount)