Project 4: Using chipKIT™ Pro with Stepper Motors

PIC™32 Timers

Using MPLAB® X Integrated Development Environment and chipKIT™ Pro

Project 4: PIC®32 Timers


The purpose of this project is to understand the operation of PIC™32 timers so that they can be used to implement a synchronized multi-rate periodic control system by polling the timer interrupt flag. Project 4 concepts are based on those explored in Project 3, where you designed systems that controlled the stepper motor direction of the shaft rotation and the step mode at a constant speed.

Before you begin, you should:


Qty Description
1 chipKIT™ Pro MX7 processor board with USB cable
1 PmodSTEP™
1 Stepper Motor (5V-12V, 25Ω, unipolar or bi-polar)
1 Logic analyzer or oscilloscope (Digilent Analog Discovery™ recommended)

Introduction to Timers

Types of Timers

Section 14 of the PIC32 family reference manual identifies two types of timers. The Type A timer is a 16-bit counter that can be clock from either the peripheral bus clock or from a secondary oscillator that typically uses a 32 KHz crystal and is used for the real time clock. This timer will be used to generate an interrupt that can wake up the processor after it has been put into a sleep mode. The clock source for the timer has the option of four software-programmable prescale dividers: 1, 8, 64, or 256. The PIC32 Timer 1 is a Type A timer or counter.

Type B timers are similar to Type A timers in that they use 16-bit counters. However, two Type B timers can be programmed to operate together to form a 32-bit counter. The Type B timers have eight possible prescale values of 1, 2, 4, 8, 16, 32, 64, and 256.

All timers have a period register that is used to set the timer's maximum count. The period registers are declared as PR1 for Timer 1, PR2 for Timer 2, and so on. Whenever the time count reaches the value stored in the period register (PR), a timer interrupt flag is set and the timer register is reset to zero. Figure 1 shows the relationship of the timing in the interrupt flag to the CPU crystal frequency. Timers 2 through 5 are similar to Timer 1, with the differences being the timer prescale options and the period register.

Figure. 1. Divider chain from the CPU crystal (oscillator) to the Timer 1 interrupt flag.

Once the timer interrupt flag is set, it will remain set until a software instruction clears the flag. (Since the timer interrupt has not been enabled, although the timer interrupt flag is set, no interrupt will be generated. Thus, all peripherals that can potentially be used to generate an interrupt can also be used in a polled mode.) Since the timer counts from zero to the period register value, the value set into the period register must be one less than the desired period.

Peripheral Library Support for Timers

Section 11 of the 32-bit peripheral library guide contains the functions pertaining to the core timer and Timers 1 through 5. Timers are initialized using the OpenTimer function that requires two arguments: the configuration argument and the initial PR value. For example, initializing Timer 1 to use the peripheral bus clock, a prescale value of 8, and an initial period of 1000 requires the following assignment:

                  OpenTimer1((T1_ON | T1_SOURCE_INT | T1_ON | T1_IDLE_CON | T1_PS_1_8), 999);

The arguments to this procedure are defined in the timers.h file of the peripheral library. The timer interrupt flag is polled using the macro statement, “mTxGetIntFlag();,” and can be cleared using the macro, mTxClearFlag(). Both macros are defined by the peripheral library.

The timer interrupt flag is cleared using the C program instruction “mTxClearFlag();.”

The PR register for the timers can be changed within the software at any time by simply using the assignments PRx = ###; or WritePeriodx( ###);, where x is the timer number and ### is the value to be set into the PR register. The following code listing illustrates using Timer 1 to implement a delay by polling the interrupt flag.

Example Program:

 * The purpose of this example code is to demonstrate the use of 
 * peripheral library macros and functions supporting the PIC32MX general 
 * purpose Type A Timer 1.
 * Platform:     ChipKITPro MX7  
 * Features demonstrated:
 *      - Timer configuration
 *      - Timer Interrupt flag polling
 *      - Timer Interrupt flag resetting
 * Description:
 *         - This example polls the Timer 1 interrupt flag and toggles LEDA
 * Oscillator Configuration Bit Settings: config_bit.h
 * chipKITPro MX7 hardware setup: chipKIT_Pro_MX7.h and chipKIT_Pro_MX7.c
 * Notes:
 *        - Timer1 clock = FOSC/PB_DIV/PRESCALE = 80E6/8/1 = 10KHz
 *        - To generate a 1 ms delay, PR1 is loaded with (10000-1) = 9999
#include <plib.h>
#include "config_bits.h"   // PIC32 Configuration settings
#include "chipKIT_Pro_MX7.h" // Processor hardware 

#define T1_PRESCALE         1
#define TOGGLES_PER_SEC     1000
#define T1_TICK             (FPB/T1_PRESCALE/TOGGLES_PER_SEC)

int main(void)
   chipKIT_Pro_MX7_Setup(); // Common hardware setup for chipKITPro MX7
   PORTSetPinsDigitalOut(IOPORT_B, SM_LEDS); // Set JA pins as outputs
   LATBCLR = SM_LEDS;           // and set to zero

   // Initialize Timer 1 for 1 ms
   OpenTimer1(T1_ON | T1_SOURCE_INT | T1_PS_1_1, (T1_TICK-1));    

      Timer1_delay(1000);     /* Toggle LEDA once every Second */

   return (EXIT_SUCCESS);

SYNTAX:         void Timer1_delay(int delay);
KEYWORDS:       Millisecond, hardware delay, Timer A, multirate timer
DESCRIPTION:    Delays the number of milliseconds specified by the passed
                argument, delay.
Parameter 1:    int - number of ms to delay
RETURN:         None
void Timer1_delay(int delay)
int int_flag;
      while(!mT1GetIntFlag());    // Wait for interrupt flag to be set
      mT1ClearIntFlag();          // Clear the interrupt flag

Peripheral Library Support for Timers

There are two arguments required for the OpenTimer1 function, the configuration bits, and the value to be programmed into the PR1 register. Among other options, the configuration bits turn on Timer 1, set the prescale value, and set Timer 1 to use the peripheral clock for the input to the prescale divider, and sets the prescale value.

As Fig. 1 illustrates, the Timer 1 clock frequency is determined from the crystal frequency on the chipKIT Pro MX7 board (XTAL), the PLL input divider (FPLLIDIV), the PLL multiplier (FPLLMUL), the PLL output divider (FPLLODIV), the peripheral bus clock divider (FPBDIV), and the Timer prescale (TCKPS). This frequency is computed using Eq. 1. The values of XTAL, FPLLMUL, FPLLDIV, FPLLODIV, and FPBDIV are set in the common config_bits.h header file.

\[T1CLK{\rm{ }} = {\rm{ }}XTAL{\rm{ }}*{\rm{ }}FPLLMUL{\rm{ }}/{\rm{ }}\left( {{\rm{ }}FPLLIDIV{\rm{ }}*{\rm{ }}FPLLODIV{\rm{ }}*{\rm{ }}FPBDIV{\rm{ }}*{\rm{ }}TCKPS} \right)\]

The period that sets the Timer 1 terminal count is determined by the value set into the PR1 register plus 1. The Timer 1 counter register increments each Timer 1 clock period as determined by Eq. 1 for T1CLK. Each Timer 1 count is compared to the value of the PR1 register. When the PR1 register equals the Timer 1 count register, the timer has reached its terminal count and initiates two actions: the Timer 1 register is reset to zero, and secondly, the Timer 1 Interrupt Flag (T1IF) bit is set in the Interrupt Flag Status register (IFS0). (See the PIC32MX5XX/6XX/7XX Family Data Sheet Section 7, Table 7-1 and the p32mx795f512l.h file for additional information.) Since the Timer 1 register is reset to zero, the value set into the PR register is one less than desired number of Timer 1 clock counts. We will use the T1IF in the next project to generate interrupts.

Try It on Your Own!

Now that you've completed this project, you should look at the following questions/problems:

  1. What restrictions must be placed on the tasks of functions that are called after a period counter counts down to zero?


    1. In order to keep all processes executing on time, the time required to execute the code for each process must be less than one millisecond.
    2. Priority can be given to the stepper motor code by testing that delay counter before testing the button-delay counter.

  2. When using counters, what is the advantage of using the “less than or equal to” comparison rather than the “equals to” comparison to determine when the counter has reached zero?

    ANSWER: If the counter is decremented in the Timer1_delay function only if the counter value is greater than zero, then it is guaranteed that the value will never go negative. The function that calls the Timer1_delay should treat all values less than or equal to zero as zero to keep the process from missing the delay equal to zero. Signed integer variables are required to ensure negative values.

  3. Is there any advantage to counting down to zero rather than counting up to a set value?

    ANSWER: Operationally, there is no difference, provided that the comparison uses a “greater than or equal to” comparison and the variables are unsigned integers. Performance wise, this method requires a subtraction operation. Decrementing a variable and testing for a zero result, in some processors, is a faster executing operation.

  4. What is the error introduced to the millisecond delay if the PR1 register is set, forgetting to subtract one from the value?

    ANSWER: The error is one part out of the desired period value. For the one millisecond delay, the error is one part out of 10,000, or 0.01%. The smaller the value that is to be programmed into the timer period register, the more significant the resulting error if one is not subtracted from the value before setting the period register.

  5. What is the advantage of polling the Timer 1 interrupt flag over the method of implementing a software delay by reading the timer value used in Projects 2 and 3?

    ANSWER: Since Timers 1 through Timer 5 used 16-bit counters, there is a possible timer rollover that can cause a period delay to be missed. The interrupt flag is a “sticky bit” that is set by hardware and only cleared by a reset or explicit software instruction.

  6. Why is it important to use a large period values?

    ANSWER: When computing the PR value for a timer tick rate that does not divide evenly into the peripheral bus clock, there will be round off error. The larger the period value, the smaller the relative error introduced by round off.

  • Other product and company names mentioned herein are trademarks or trade names of their respective companies. © 2014 Digilent Inc. All rights reserved.