PIT - Periodic Interrupt Timer para FRDM-KL25Z

Periodic Interrupt Timer

Olá caro leitor. Continuando com a série de artigos "Bibliotecas de Software para a Freedom Board KL25Z", neste artigo será abortado o PIT - Periodic Interrupt Timer, apresentada a biblioteca de software para a sua utilização e exemplo de aplicação.

 

As bibliotecas aqui apresentadas nesta série de artigos foram desenvolvidas utilizando o Kinetis Design Studio IDE. As bibliotecas são facilmente portáveis para as demais Freedom Board.

 

O microcontrolador presente na Freedom Board KL25Z é o MKL25Z128VLK4. O PIT (Periodic Interrupt Timer) é um dos recursos de Timer que esse microcontrolador possui. Além do PIT, ele conta também com TPM (Timer/PWM Module) abordado no último artigo sobre PWM, LPTMR (Low-Power Timer) e RTC (Real Time Clock).

 

O periférico PIT possui dois canais (0 e 1), conta com contador de 32 bits. As características que mais de destacam neste módulo são: capacidade de temporizar e gerar disparo para o DMA, capacidade de temporizar e gerar interrupções e temporizador independente para cada canal.

 

Demonstrarei a seguir a biblioteca de software com as configurações mínimas para trabalhar com PIT, apresentando funções de inicialização e funções de manipulação de um Timer com o PIT.

 

 

Inicializando o PIT

 

Configurando o Clock do Periférico

 

O primeiro item a ser configurado para inicializar o PIT é habilitar o Clock para o periférico. Essa operação é feita utilizando o registrador System Clock Gating Control Register 6 (SIM_SCGC6). Para habilitar o Clock deve-se utilizar a macro SIM_SCGC6_PIT_MASK.

 

Nas figuras abaixo temos a representação dos bits do registrador System Clock Gating Control Register 6 (SIM_SCGC6).

 

Figura 1 - Detalhes do Registrador System Clock Gating Control Register 6 (SIM_SCGC6)

 

Configurando os parâmetros do PIT

 

O primeiro parâmetro a ser configurado é o registrador PIT Module Control Register (PIT_MCR). Esse registrador é responsável em ativar o temporizador e modo de depuração.

 

É através do Bit MDIS (Module Disable - (PIT section)) que é ativado o temporizador. Para manipular este Bit deve-se utilizar a macro PIT_MCR_MDIS(x), onde “x” é valor do bit (0 ou 1).

 

O bit FRZ (Freeze) é responsável por ativar o módulo de depuração. Para atuar sobre esse bit, deve-se utilizar a macro PIT_MCR_FRZ(x), onde “x” é valor do bit (0 ou 1).

 

As imagens abaixo detalham o registrador PIT Module Control Register (PIT_MCR).

 

Figura 2 - Detalhes Registrador PIT Module Control Register (PIT_MCR).

 

O segundo parâmetro a ser configurado é o contador. Como já dito anteriormente, o PIT possui temporizador de 32 bits. O registrador Timer Load Value Register (PIT_LDVALn) é responsável por receber o valor do temporizador. Para configurar deve-se usar a macro PIT_LDVAL_REG(base,index), onde a “base” é o ponteiro do periférico (PIT) e “index” é o numero do canal (0 ou 1).

 

A seguir temos uma figura que ilustra o registrador Timer Load Value Register (PIT_LDVALn).

 

Figura 3 - Detalhes do Registrador Timer Load Value Register (PIT_LDVALn).

 

O registrador Timer Control Register (PIT_TCTRLn) possui três Bits a serem configurados, são eles: o Bit CHN (Chain Mode), Bit TIE (Timer Interrupt Enable) e Bit TEN (Timer Enable).

 

Para manipular o registrador, deve-se utilizar a macro PIT_TCTRL_REG(base,index), onde a “base” é o ponteiro do periférico (PIT) e “index” é número do canal (0 ou 1).

 

Para configurar o Bit CHN deve-se usar a macro PIT_TCTRL_CHN(x), onde “x” é o valor do Bit (0 ou 1).
A macro PIT_TCTRL_TIE(x), onde “x” é o valor do Bit (0 ou 1), é utilizada para configurar o Bit TIE. Para manipular o Bit TEN devesse utilizar a macro PIT_TCTRL_TEN(x), onde “x” é o valor do Bit (0 ou 1).

 

Nas figuras abaixo são apresentados detalhes do registrador Timer Control Register (PIT_TCTRLn).

 

Figura 4 - Detalhes do Registrador Timer Control Register (PIT_TCTRLn)

 

O último a ser configurado na inicialização do PIT é habilitar a interrupção, para essa tarefa deve utilizar a função:

// Enable External Interrupt
void NVIC_EnableIRQ(IRQn_Type IRQn)

 

Com o parâmetro “PIT_IRQn”, que é numero da interrupção do PIT no vetor de interrupção.

 

Inicializando Contagem e Encerando Contagem no PIT

 

Para iniciar e encerar a contagem com o periférico Periodic Interrupt Timer, é feita através do registrador Timer Control Register (PIT_TCTRLn), manipulando o Bit TEN (Timer Enable), onde o Bit com o valor em 1 inicia a contagem e com valor em 0 para a contagem.

 

Rotina de Interrupção 

 

É através do registrador Timer Flag Register (PIT_TFLGn) que ocorre a notificação de interrupção do PIT. A macro utilizada para realizar a consulta a Flag da interrupção PIT_TFLG_REG(base,index), onde “base” é ponteiro do periférico (PIT) e “index” é o numero do canal (0 ou 1). Para limpar a Flag devesse utilizar a macro PIT_TFLG_TIF_MASK.

 

A seguir temos imagem que ilustra com maior detalhes o registrador Timer Flag Register (PIT_TFLGn).

 

Figura 5 - Detalhes do Registrador Timer Flag Register (PIT_TFLGn)

 

Funções para Timer 

 

Na biblioteca de software que estou apresentando é para a utilização do Periodic Interrupt Timer. Optei em apresentar duas maneiras de trabalhar com o Timer, a primeira é utilizando uma Flag para sinalizar o término da contagem do PIT. A segunda é um contador, que retorna o número de interrupção do PIT.

 

Para a rotina com a Flag são apresentadas duas funções:

bool pit_GetFlag_Isr(void)

 

que é através dessa função que é feita a consulta a Flag. A segunda função é limpar a Flag:

void pit_ClearFlag_Isr(void)

 

A rotina de contador de interrupções também são apresentadas nas duas funções:

uint64_t pit_GetCounter_Isr(void)

 

que retorna o número de interrupções. A segunda função é responsável por zerar a variável que armazena o número de interrupções ocorridas:

void pit_ClearCounter_Isr(void)

 

A seguir é apresentado o código fonte da biblioteca desenvolvida para o periférico.

 

/*
 * pit.h
 *
 *  Created on: 18/04/2017
 *      Author: Evandro
 */

#ifndef SOURCES_PIT_H_
#define SOURCES_PIT_H_

#include "externs.h"
//#include "stdbool.h"

#define PIT_CH_0    0
#define PIT_CH_1	1

#define FLAG_TPM 	1
//#define COUNTER_TPM	2
#define NOFLAG_TPM	0
#define MODEISRTPM (NOFLAG_TPM)

#define OTHER_TPM   (DUAL_TPM)
#define COUNTER_TPM 1
#define DUAL_TPM    0

//void init_pit(uint32_t value);
bool pit_Init(uint32_t value,bool ch);
void pit_Start(bool ch);
void pit_Stop(bool ch);

#if (MODEISRTPM == FLAG_TPM)
	bool pit_GetFlag_Isr(bool ch);
	void pit_ClearFlag_Isr(bool ch);
#else //if (MODEISRTPM == COUNTER_TPM)

	#if (OTHER_TPM == COUNTER_TPM)
		void pit_ClearCounter_Isr(bool ch);
		uint64_t pit_GetCounter_Isr(bool ch);
	#else
		// Flag - channel 0
		bool pit_GetFlag_Isr(void);
		void pit_ClearFlag_Isr(void);

		// counter - channel 1
		void pit_ClearCounter_Isr(void);
		uint64_t pit_GetCounter_Isr(void);
	#endif
/*#else //if (MODEISRTPM == DUAL_TPM)
// Dual mode
	bool pit_GetFlag_Isr(bool ch);
	void pit_ClearFlag_Isr(bool ch);

	void pit_ClearCounter_Isr(bool ch);
	uint64_t pit_GetCounter_Isr(bool ch);*/
#endif

#endif /* SOURCES_PIT_H_ */

 

/*
 * pit.c
 *
 *  Created on: 18/04/2017
 *      Author: Evandro
 */

#include "pit.h"

/*****************************************************************************************
* Global Variable
*****************************************************************************************/
#if (MODEISRTPM == FLAG_TPM)
	static bool pitIsrFlag[2] = {false};
#else // if (MODEISRTPM == COUNTER_TPM)
	#if (OTHER_TPM == COUNTER_TPM)
		static uint64_t tpm_i[2] = {0};
	#else
		static bool pitIsrFlag = false;
		static uint64_t tpm_i = 0;
	#endif
#endif

/*****************************************************************************************
*
*****************************************************************************************/
bool pit_Init(uint32_t value,bool ch)
{
	// Verifica parametros
	if((ch < 2) && (value < 0x100000000))
	{
		// Habilita clock para o PIT
		SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;

		// Habilita PIT Module Control Register (PIT_MCR)
		PIT_MCR = 0;

		// Configura contador
		PIT_LDVAL_REG(PIT,ch) = value;

		// Enable interrupt and enable timer
		//PIT_TCTRL0 |= PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK;
		PIT_TCTRL_REG(PIT,ch) |= PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK;

		// Enable External Interrupt
		NVIC_EnableIRQ(PIT_IRQn);

		return true;
	}
	else
	{
		return false;
	}
}
/*****************************************************************************************
*
*****************************************************************************************/
void pit_Start(bool ch)
{
	PIT_TCTRL_REG(PIT,ch) |= PIT_TCTRL_TEN_MASK;
}
/*****************************************************************************************
*
*****************************************************************************************/
void pit_Stop(bool ch)
{
	PIT_TCTRL_REG(PIT,ch) &= ~PIT_TCTRL_TEN_MASK;
}
/*****************************************************************************************
*
*****************************************************************************************/
#if (MODEISRTPM == FLAG_TPM)
	bool pit_GetFlag_Isr(bool ch)
	{
		return pitIsrFlag[ch];
	}
	/********************************************************************************
	*
	*********************************************************************************/
	void pit_ClearFlag_Isr(bool ch)
	{
		 pitIsrFlag[ch] = false;
	}
#else //if (MODEISRTPM == COUNTER_TPM)
	#if (OTHER_TPM == COUNTER_TPM)
		void pit_ClearCounter_Isr(bool ch)
		{
			tpm_i[ch] = 0;
		}
		/******************************************************************************
		*
		*******************************************************************************/
		uint64_t pit_GetCounter_Isr(bool ch)
		{
			return tpm_i[ch];
		}
	#else
		// Flag - channel 0
		bool pit_GetFlag_Isr(void)
		{
			return pitIsrFlag;
		}
		/******************************************************************************
		*
		*******************************************************************************/
		void pit_ClearFlag_Isr(void)
		{
			pitIsrFlag = false;
		}
		/******************************************************************************
		*
		*******************************************************************************/
		// counter - channel 1
		void pit_ClearCounter_Isr(void)
		{
			tpm_i = 0;
		}
		/******************************************************************************
		*
		*******************************************************************************/
		uint64_t pit_GetCounter_Isr(void)
		{
			return tpm_i;
		}
	#endif
#endif
/*****************************************************************************************
* Handles PIT interrupt if enabled
*****************************************************************************************/
void PIT_IRQHandler(void)
{
	uint8_t index = 0;

	for(index=0;index<2;index++)
	{
		if( PIT_TFLG_REG(PIT,index) )
		{
			// Clear interrupt
			//PIT_TFLG0 = PIT_TFLG_TIF_MASK;
			PIT_TFLG_REG(PIT,index) = PIT_TFLG_TIF_MASK;
#if (MODEISRTPM == FLAG_TPM)
			pitIsrFlag[index] = true;
#else //if (MODEISRTPM == COUNTER_TPM)
	#if (OTHER_TPM == COUNTER_TPM)
			tpm_i[index] += 1;
	#else
			if(index)
				tpm_i++;
			else
				pitIsrFlag = true;
	#endif
#endif
		}
	}
}
/****************************************************************************************/

 

 

Aplicação Dual Blink LED

 

A aplicação proposta é utilizar os dois canais do PIT para sincronizar o acionamento de cada LED. Para o LED vermelho é utilizado o canal 0 e fazendo uso da rotina de Flag. O LED verde utiliza o canal 1, inicializado com valor 100, menor em relação ao canal 0. A rotina de contador de interrupção foi utilizada para sincronizar o acionamento do LED. Quando a contagem atinge o valor de 100 o LED verde é acionado.

 

// Projeto: Dual Blink LED
// Autor: Evandro Teixeira
// Endereço da Lib: /home/evandro/Documentos/lib-frdm-kl25z/Library-FRDM-KL25Z-master
#include "/home/evandro/Documentos/lib-frdm-kl25z/Library-FRDM-KL25Z-master/externs.h"
#include "MKL25Z4.h"

static int i = 0;

int main(void)
{
    // Inicializa PIT canal 0
	pit_Init(10000000,PIT_CH_0);
	// Inicia PIT canal 0
	pit_Start(PIT_CH_0);
	// Incializa PIT canal 1
	pit_Init(100000,PIT_CH_1);
	// Inicia PIT canal 1
	pit_Start(PIT_CH_1);
	// Inicializa PTB18 - LED Vermelho
	gpio_Init(GPIOB,18,OUTPUT,NO_PULL_RESISTOR);
	// Inicializa PTB18 - LED Verde
	gpio_Init(GPIOB,19,OUTPUT,NO_PULL_RESISTOR);
	// Apaga LED Vermelho
	gpio_Set(GPIOB,18,1);
	// Aciona LED Verde
	gpio_Set(GPIOB,19,0);

    for (;;)
    {
        // Checa de Flag
    	if(pit_GetFlag_Isr()==true)
    	{
    		// Limpa Flag
    		pit_ClearFlag_Isr();
    		// Inverte o valor do LED Vermelho
    		gpio_Toggle(GPIOB,18);
    	}
    	// Verifica o valor do contador
    	if(pit_GetCounter_Isr() >= 100)
    	{
    		// Reset contador
    		pit_ClearCounter_Isr();
    		// Inverte o valor do LED Verde
    		gpio_Toggle(GPIOB,19);
    	}
    }
    /* Never leave main */
    return 0;
}

 

 

Conclusão 

 

Neste artigo foi apresentada mais uma biblioteca de software para a Freedom Board KL25Z utilizando o periférico PIT - Periodic Interrupt Timer.

 

Nos próximos artigos vamos apresentar mais bibliotecas de software (Timer, UART e entre outras) para a Freedom Board KL25Z. A biblioteca apresentada está disponível no meu Github.

 

 

Referências

 

Github - Library-FRDM-KL25Z

Reference Manuals KL25Z

community.nxp

Outros artigos da série

<< Biblioteca PWM para FRDM-KL25ZBiblioteca DAC para FRDM-KL25Z >>
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Evandro Teixeira
Desenvolvedor de Sistemas Embarcados. Sou formado Técnico em Instrumentação e Automação Industrial/Mecatrônica pelo Colégio Salesiano Dom Bosco de Americana-SP, cursei o Engenharia Elétrica com Ênfase em Eletrônica pela UNISAL Centro Universitário Salesiano de São Paulo e atualmente estou cursando Superior de Tecnologia em Análise e Desenvolvimento de Sistemas pela UNIP Universidade Paulista.

2
Deixe um comentário

avatar
 
1 Comment threads
1 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Evandro TeixeiraAdriel Vasques dos Santos Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Adriel Vasques dos Santos
Visitante
Adriel Vasques dos Santos

O valor 100 é em que: ns, ms???