ARM KL25Z Periodic Interrupt Timer

Hannah Lormenyo
Nov 18, 2020 · 4 min read
FRDM-KL25Z

Periodic Interrupt Timer(PIT) is one of the timer peripherals for the KL25Z series. PIT can be used as a trigger for modules like the Timer/PWM Module (TPM), Analog-to-Digital convertor(ADC), and Digital-to-Analog converter(DAC). This means that the PIT can be used to trigger the TPM module to generate pulse width modulated waves, and it can activate the ADC and DAC to do their respective conversions.

PIT can also be used to trigger very simple events like toggling the states of a pin. An example can be seen in the short video below. In this example, PIT is used to blink the on-board LED every 400ms 5 times, and afterward, it blinks at a 100ms rate 5 times and repeats the process.

PIT has 2 channels: Channel 0 and channel 1. Each channel has 32 bits for counting and can count up to 4294967295. However, if you want to count down from a larger number, you can chain the two channels to get a 64-bit counter. Cool right!

The PIT uses the Bus clock which has a frequency that is half of the System Clock’s frequency. The system clock has a frequency of 20971520 Hz, hence the frequency of the PIT bus clock is 20971520 * 0.5 = 10485760 Hz

Configuring the PIT module

  • Enable the clock to the PIT module

    SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;
  • Write 0 to the Module Disable(MDIS) register to enable the clock to PIT. The Module Control Register(MCR) enables or disables the PIT when it enters the debug mode.

    PIT->MCR &= ~PIT_MCR_MDIS_MASK;
  • Initialize the PIT channel to count down from the starting value(Load Value). When the timer counts down to 0, it generates an interrupt and restarts the countdown.

    PIT->CHANNEL[0].LDVAL |= starting_value;

The code above loads the starting value into the LDVAL register for channel 0.

  • Enable interrupts from the PIT. The example below enables interrupts for channel 0.

    PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK;
  • Enable the channel Timer. The example below enables the timer for channel 0.

    PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;
  • Configure NVIC
    1. Set PIT IRQ priority

    NVIC_SetPriority(PIT_IRQn, 3);

    2. Clear any pending IRQ from PIT

    NVIC_ClearPendingIRQ(PIT_IRQn);

    3. Enable the PIT interrupt in the NVIC

    NVIC_EnableIRQ(PIT_IRQn);

Calculating the Load Value

The Load Value is the value that the PIT counts down from.
Assuming you want an interrupt every T seconds, the LoadValue V can be calculated using this formula:

V = T * 10485760–1

Generating PIT interrupts

PIT_IRQHandler is the interrupt handler for PIT. To do something for every interrupt:
1. Check if the channel interrupt flag has been raised

if (PIT->CHANNEL[n].TFLG & PIT_TFLG_TIF_MASK) {
}
n is the channel number [n=0,1]

2. If yes, do something like toggling the state of an LED in this case.

if (PIT->CHANNEL[n].TFLG & PIT_TFLG_TIF_MASK) {
PTB -> PTOR |= 1UL << LED;
}

n is the channel number [n=0,1]

3. After that clear the flag.

if (PIT->CHANNEL[n].TFLG & PIT_TFLG_TIF_MASK) {
PTB -> PTOR |= 1UL << LED;
PIT->CHANNEL[n].TFLG &= PIT_TFLG_TIF_MASK;
}
n is the channel number [n=0,1]

Example

Task: Use PIT interrupts to blink an LED every 400ms. After blinking 5 times, make it blink every 100ms for 5x and repeat the process.

NB: Blinking 5x is 10 toggles.[on, off, on, off, ….]

  • PIT has 2 channels. I used one channel for the 400ms interrupts and the other channel for the 100ms interrupts.
void init_pit(){
//Enable clock to PIT module
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; //Enable module
PIT->MCR &= ~PIT_MCR_MDIS_MASK; //enable mdis
PIT->MCR |= PIT_MCR_FRZ_MASK;
//Initialize PIT0 to count down from starting_value
PIT->CHANNEL[0].LDVAL =0x3FFFFF; //every 400ms //No chaining of timers
PIT->CHANNEL[0].TCTRL &= PIT_TCTRL_CHN_MASK;
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; //Let the PIT channel generate interrupt requests
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK;
//Initialize PIT0 to count down from starting_value
PIT->CHANNEL[1].LDVAL =0xFFFFF; //every 100ms
//No chaining of timers
PIT->CHANNEL[1].TCTRL &= PIT_TCTRL_CHN_MASK;
//Let the PIT channel generate interrupt requests
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TIE_MASK;
NVIC_SetPriority(PIT_IRQn, 3); //Clear any pending IRQ from PIT NVIC_ClearPendingIRQ(PIT_IRQn); //Enable the PIT interrupt in the NVIC NVIC_EnableIRQ(PIT_IRQn); }
  • I kept track of the num of toggles and after every 10 toggles, I disable the channel being used and switch to a different channel.
void PIT_IRQHandler(){ //Determine which channel triggered interrupt 
if (PIT->CHANNEL[0].TFLG & PIT_TFLG_TIF_MASK) {
PTB->PTOR |=MASK(RED_LED); //toggle RED
//Clear interrupt request flag for channel
PIT->CHANNEL[0].TFLG &= PIT_TFLG_TIF_MASK;
num_of_toggles++;
if (num_of_toggles == 10){
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;
PIT->CHANNEL[0].TCTRL &= ~PIT_TCTRL_TEN_MASK;
num_of_toggles = 0;
}
}
if (PIT->CHANNEL[1].TFLG & PIT_TFLG_TIF_MASK) {
PTB->PTOR |=MASK(RED_LED); //toggle RED
//Clear interrupt request flag for channel
PIT->CHANNEL[1].TFLG &= PIT_TFLG_TIF_MASK;
num_of_toggles++;
if (num_of_toggles == 10){
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;
PIT->CHANNEL[1].TCTRL &= ~PIT_TCTRL_TEN_MASK;
num_of_toggles = 0;
}
}
}

Other methods can be explored. You can load a different value to the LDVAL register every time you want a different rate.

The entire code can be found here.

The Startup

Get smarter at building your thing. Join The Startup’s +793K followers.

Sign up for Top 10 Stories

By The Startup

Get smarter at building your thing. Subscribe to receive The Startup's top 10 most read stories — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +793K followers.

Hannah Lormenyo

Written by

Electrical and Electronics Engineering at Ashesi University, Passionate about sanitation, data science, web development and Engineering.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +793K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store