EA871 – LAB. DE PROGRAMAÇÃO BÁSICA DE SISTEMAS DIGITAIS
EXPERIMENTO 12 – TIMERS (II): PERIFÉRICOS
Prof. Antonio Quevedo e Profa. Wu Shin-Ting
INTRODUÇÃO
Além dos timers integrados ao núcleo, o nosso MCU tem ainda diversos periféricos de temporização,
como os módulos TPM (Timer/PWM) (Cap. 31 de [1]), PIT (Periodic Interrupt Timer) (Cap. 32 de [1])
e LPTMR (Low-Power Timer) (Cap. 33 de [1]). O primeiro é um temporizador de baixo consumo de
potência e o segundo, é constituído de um contador LPTPM de 16 bits, também de baixo consumo,
programável para operar numa das 3 funções: Input Capture, Output Compare e PWM (pulse-width
modulation) (Cap. 12 de [3]). Na primeira função, Input Capture, as transições nos sinais do seu pino
de entrada podem ser capturadas e os instantes destas ocorrências armazenados. Na função Output
Compare ele gera um nível de sinal no seu pino de saída quando o valor do contador fique igual a um
valor pré-definido. E, na função PWM, ele gera no seu pino de saída um sinal modulado por largura de
pulso (PWM, pulse width modulation) [6]. O módulo PIT consiste de contadores de 32 e 64 bits com a
função específica de disparar interrupções condicionadas a intervalos de tempo programados. E
LPTMS são contadores de 16 bits de baixo consumo de energia.
Figura 1: Pontos de conexão dos componentes externos
Neste experimento, vamos estudar os dois módulos de temporização TPM e PIT através de quatro
programas. No primeiro programa vamos controlar as piscadas do led azul do kit FRDM-KL25 com
uso do PIT. No segundo programa vamos gerar sinais na frequência audível com o módulo TPM
operando no modo Output Compare e alimentar um transdutor piezoelétrico através dos pinos “F” (1 de
H7 no esquemático [3]), “G” (2 de H7 no esquemático [3]) e “H” (3 de H7 no esquemático [3]) da
placa auxiliar (Figura 1), e no terceiro programa vamos estimar a frequência de um sinal de entrada, via
pino “H” (3 de H7 no esquemático [3]), com o módulo TPM operando no modo Input Capture. Para
verificar a precisão do nosso procedimento, o módulo PIT é utilizado para gerar um sinal de frequência
programável no pino “E” (1 de H6 no esquemático [3]) da placa auxiliar. Finalmente, veremos uma
aplicação do modo PWM no controle de velocidade de um cooler através do header H6 do
esquemático [3]. Neste caso, a fonte de alimentação é conectada aos pinos “A” (5 de H6 no
esquemático [3]) e “B” (4 de H6 no esquemático [3]), e o cooler aos pinos “C” (3 de H6 no
esquemático [3]) e “D” (2 de H6 no esquemático [3]).
EXPERIMENTO
1. PIT: O módulo PIT (Periodic Interrupt Timer) contém dois contadores de 32 bits que podem
operar separadamente ou ser encadeados para formar um contador de 64 bits. Quando operado
separadamente, cada contador n conta de forma decrescente a partir do valor setado no
registrador PIT_LDVALn
até 0, quando o valor é recarregado automaticamente (Seção 32.4.1.1 de [1]). Como todos os
módulos que vimos até agora, é necessário ativar a fonte de relógio do módulo (clock gate), o
módulo e o(s) contador(es) do módulo a ser(em) utilizado(s). Segundo a Tabela 5-2 em [1], o
clock destes contadores é o bus clock, cuja frequência, segundo a Seção 5.4 em [1], é a
frequência do relógio do sistema dividido pelo valor setado em SIM_CLKDIV1[OUTDIV4].
Vimos ainda nos experimentos anteriores que a frequência do relógio do sistema é
20.971520MHz. Quando o mecanismo de interrupção de um contador n é habilitado, a sua
bandeira de interrupção PIT_TFLGn[TIF] é levantada e, se o módulo é apropriadamente
habilitado no controlador NVIC (Seção B3.4 em [2]), a interrupção é atendida pelo núcleo com
a chamada da sua rotina de serviço. Neste caso, é fundamental identificar o vetor de interrupção
do módulo PIT na Tabela 3-7 de [1]. E, para evitar que se gere novos eventos após o
atendimento, deve-se abaixar a bandeira escrevendo 1 no bit (w1c). O código no Anexo 1
ilustra a configuração do contador 0 do módulo PIT para gerar interrupções periódicas. Para
verificar visualmente estas interrupções foi usado o led azul do kit FRDM-KL25, alternando os
seus estados. Execute e complete o código no lugar onde há ???? e com os comentários
para cada uma das suas instruções de configuração do MCU indicando explicitamente os bits
setados.
2. TPM: O módulo TPM (Timer/PWM) contém 2 a 8 canais compartilhando um mesmo contador
de 16 bits que pode contar de forma crescente (up) ou crecente-decrescente (up-down) (Seção
31.4.3 de [1]). Diferente do PIT, o TPM dispõe de um relógio independente para este contador,
que é selecionável pelos campos SIM_SOPT2[TPMSRC] e SIM_SOPT2[PLLFLLSEL]. De
acordo com as Seções 31.4.2 e 31.4.3 de [1], o período de contagem máxima do TPM depende,
além da frequência do relógio selecionado, dos valores setados em TPMx_MOD[MOD] e em
TPMx_SC[PS]. Quando ocorre estouro na contagem, a bandeira TPMx_SC[TOF] é levantada.
Se o seu bit TPMx_ SC[TOIE]=1 e o controlador NVIC é adequadamente configurado (Seção
B3.4 em [2]), o fluxo de controle é desviado para a sua rotina de serviço. A principal
característica do módulo TPM é que cada um dos seus canais pode ser configurado para operar
em uma das três seguintes funções: Output Compare, Input Capture e PWM (Seção 31.3.4em
[1]). O evento levantador da bandeira de interrupção TPMx_CnSC[CHF] de cada canal n
depende, portanto, da sua função.
a. Output Compare: Quando o valor do contador TPMx_CNT[COUNT] chegar ao valor
setado no registrador TPMx_CnV[VAL] do canal n, é colocado o valor pré-definido no
pino de saída do canal. Este é o evento levantador da bandeira de interrupção desta
função (Seção 31.4.5 em [1]). O código no Anexo 2 ilustra a configuração do canal 1 do
módulo TPM1 para operar com a função Output Compare, de forma que, quando os
valores dos registradores se igualam, o valor no pino de saída do canal (pino 44/F da
Figura 1) é alternado. Para visualizar esta alternância foi usado o led verde do kit
FRDM-KL25.
b. Input Capture: Quando o tipo de borda pré-configurado for detectado no sinal do pino
de entrada do canal n, o valor do contador TPMx_CNT[COUNT] é capturado no
registrador TPMx_CnV[VAL]. Este é o evento levantador da bandeira de interrupção
desta função (Seção 31.4.4 em [1]). O código no Anexo 3 ilustra a configuração do
canal 0 do módulo TPM1 para operar com a função Input Capture. O módulo PIT foi
configurado para gerar no PTB1 (pino 44/F da Figura 1) um trem de pulsos que alimenta
o pino de entrada do canal (pino 43/E da Figura 1). A cada borda de subida é levantada a
bandeira de interrupção e, como a interrupção do canal é habilitada e setada no
controlador NVIC, é chamada a sua rotina de serviço. Com os valores de contadores
capturados, é possível estimar o período do sinal gerado pelo contador 0 do PIT. Para
visualizar os instantes de captura foi usado o led azul do kit FRDM-KL25. Para
execução correta do código, é necessário conectar os pinos E e F da Figura 1.
c. PWM (Pulse Width Modulation): Quando o valor do contador TPMx_CNT[COUNT]
chega ao valor setado no registrador TPMx_CnV[VAL] do canal n, o sinal no pino de
saída do canal é alternado. Este é o evento levantador da bandeira de interrupção desta
função (Seção 31.4.6 em [1]). O nível inicial do sinal é pré-configurado. A relação da
largura do nível alto em relação ao período do sinal é conhecido como ciclo de trabalho.
O código no Anexo 3 ilustra a configuração do canal 0 do módulo TPM1 para operar
com a função PWM, de forma que, quando se variam os valores do registrador
TPMx_CnV[VAL], as larguras dos pulsos no pino de saída do canal (pino 43/E da
Figura 1) são alteradas. Para visualizar estas variações foi usado o led vermelho do kit
FRDM-KL25.
Execute e complete os códigos dos Anexos 2, 3 e 4 no lugar onde há ???? e com os
comentários para cada uma das suas instruções de configuração do MCU indicando
explicitamente os bits setados e a programação dos pinos utilizados.
3. Acionamento de Periféricos: Podemos aplicar os sinais gerados pelos contadores PIT e TPM
para acionar dispositivos físicos.
a. Um transdutor piezoelétrico transforma sinais elétricos em sinais de áudio [5]. Sabendo
que as características elétricas do buzzer disponível no nosso almoxarifado são
compatíveis com as do nosso MCU [7] (a tensão 3.3V, correspondente ao nível lógico 1é
suficiente para gerar pressão necessária sobre o material piezoelétrico do buzzer), ligue o
seu conector no header H7 e execute o programa do Anexo 2. O que aconteceu?
Sabendo que a faixa de frequências audíveis é [20,20000]Hz, re-configure o PIT com
uma das frequências das notas musicais listadas numa das propostas de problema do
item 4.
b. O cooler é um ventilador CC que opera na faixa de 6V-13V DC com uma corrente
mínima de 0.07A, muito acima dos valores que o nosso MCU conseguiria suprir [6].
Portanto, foi implementado na placa auxiliar uma interface elétrica entre ele e o MCU
(esquemático em [3]). O circuito é constituído de um transistor de Darlington
TIP31/TIP122, que proporciona um elevado ganho de corrente, e um diodo
1N4004/1N4007 para proteger o transistor das correntes reversas. Ligue a fonte de
tensão nos pinos 4 e 5 do header H6 e o cooler nos pinos 2 e 3 de mesmo header.
Observe que os pinos 3 e 4 são curto-circuitados. Execute o programa do Anexo 4. O
que aconteceu? Explique sucintamente os efeitos observados no cooler.
4. Desafio: Inclua no relatório a solução de UM dos seguintes problemas. Não se esquecem de
documentar detalhadamente os códigos e acrescentar alguns principais resultados dos testes:
a. Tomando como base o programa do Anexo 1 ou Anexo 2, implemente um programa que
reproduz o som das notas musicais digitadas por um usuário através do “Terminal”. As 7
notas musicais são: A (lá, 440Hz), B (si, 493,883Hz), C (dó, 261,625Hz), D (ré,
293,665Hz), E (mi, 329,628Hz), F (fá, 349,228Hz) e G (sol, 391,995,736Hz) [7]. Ecoe
as letras digitadas no “Terminal”.
b. Tomando como base o programa do Anexo 4, implemente um programa que controla a
rotação do cooler através do “Terminal”. O valor digitado deve ser ecoado no próprio
“Terminal”. A rotação varia de 0 a 100% da rotação máxima. Quando a rotação estiver
entre 0 a 20% o led azul acende. Entre 21 a 80% acende o led verde. Acima disso
acende o led vermelho do kit FDRM-KL25.
c. Tomando como base os programas do Anexo 3, implemente um programa que
contabilize os intervalos de tempo que um usuário pressiona qualquer uma das 3
botoeiras, NMI, PTA5 e PTA12, da placa auxiliar. Logo que soltar a botoeira, o intervalo
de tempo contabilizado deve ser exibido de forma centrada na primeira linha do LCD.
REFERÊNCIAS
Todas as referências podem ser encontradas nos links abaixo ou ainda na página do curso.
[1] KL25 Sub-Family Reference Manual – Freescale Semiconductors (doc. Number
KL25P80M48SF0RM), Setembro 2012.
ftp://ftp.dca.fee.unicamp.br/pub/docs/ea871/ARM/KL25P80M48SF0RM.pdf
[2] ARMv6-M Architecture Reference Manual – ARM Limited.
ftp://ftp.dca.fee.unicamp.br/pub/docs/ea871/ARM/ARMv6-M.pdf
[3] A. Quevedo. Descrição da placa auxiliar, com esquemático
ftp://ftp.dca.fee.unicamp.br/pub/docs/ea871/ARM/DescricaoDoHardware/.pdf
[4] Entenda o PWM , PNCA Robótica e Eletrônica.
http://www.pnca.com.br/index.php?
option=com_content&view=article&id=67:pwm&catid=42:saiba-mais&Itemid=150
[5] Specification for Piezo Electric Sounder
ftp://ftp.dca.fee.unicamp.br/pub/docs/ea871/datasheet/ piezo-buzzer-datasheet.pdf
[6] DC Fan Motor – San Ace
ftp://ftp.dca.fee.unicamp.br/pub/docs/ea076/datasheet/ SANCooler92.pdf
[7] Tabela de Frequências, Períodos e Comprimentos de Onda
http://www2.eca.usp.br/prof/iazzetta/tutor/acustica/introducao/tabela1.html
Revisado em Fevereiro de 2014
Revisado em Julho de 2014 com base nas sugestões dos monitores da disciplina, Rose Landeira, João Henrique
Stange Hoffmam e Eduardo Carlassara.
ANEXO 1: LISTAGEM DO PRIMEIRO PROGRAMA
#include "derivative.h"
#define GPIO_PIN(x) ((1)<<(x)) ///< obtem o bit do pino x
/**
* \fn InitGPIO (void)
* \brief Inicializa o pino conectado ao ledR do FRDM para verificação visual.
*/
void InitGPIO(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;///< PORTD=SIM_SCGC5[12]=1 (Clock gate de PORTD habilitado)
PORTD_PCR1 |= (PORT_PCR_ISF_MASK | ///< ISF=PORTB_PCR1[14]: w1c (limpa a pendência)
PORT_PCR_MUX(0x1) );
///< MUX=PORTB_PCR1[10:8]=0b011 (TPM1_CH1)
GPIOD_PDDR |= GPIO_PDDR_PDD(GPIO_PIN(1)); ///< GPIOD_PDDR[1]=1 (pino de saída)
GPIOD_PSOR |= GPIO_PSOR_PTSO(GPIO_PIN(1)); ///< GPIOD_PSOR[1]=1 (seta 1 no pino)
}
/**
* \fn InitPIT (void)
* \brief Configura o timer 0 do PIT para que gere um sinal periódido de ????s.
*/
void InitPIT(void) {
SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;
///< TPM1=SIM_SCGC6[23]=1 (Clock gate de PIT habilitado)
/*
* Clock do PIT é bus clock (Tabela 5-2 de KL-25 Sub-Family Reference Manual)
* frequência de bus clock =(clock do núcleo)/(SIM_CLKDIV1[OUTDIV1]*SIM_CLKDIV1[OUTDIV4])
*
(Figura 5-1 de KL-25 Sub-Family Reference Manual)
*
= ????
* frequência do núcleo = 20.971520 MHz
* Periodo_{PIT} = PIT_LDVAL0[TSV]/(frequência de bus clock)
*
= ???
*/
//OUTDIV1=SIM_CLKDIV1[31:28] é carregado no reset com 0000 (dividido por 1)
SIM_CLKDIV1 &= SIM_CLKDIV1_OUTDIV4(0x0);
PIT_TCTRL0 &= ~(PIT_TCTRL_TEN_MASK |
PIT_TCTRL_TIE_MASK );
PIT_LDVAL0 = PIT_LDVAL_TSV(0xA00000);
PIT_TFLG0 |= PIT_TFLG_TIF_MASK;
PIT_TCTRL0 |= (PIT_TCTRL_TEN_MASK |
PIT_TCTRL_TIE_MASK );
PIT_TCTRL0 &= ~PIT_TCTRL_CHN_MASK;
PIT_MCR &= ~(PIT_MCR_FRZ_MASK |
PIT_MCR_MDIS_MASK );
}
/**
* \fn enableNVIC (void)
* \brief ????
*/
void enableNVIC(void) {
NVIC_ISER |= 1 << (38-16);
NVIC_ICPR |= 1 << (38-16);
NVIC_IPR5 |= NVIC_IP_PRI_22(0x40);
}
/**
* \fn PIT_IRQHandler (void)
* \brief ????
*/
void PIT_IRQHandler(void) {
GPIOD_PTOR |= GPIO_PTOR_PTTO(GPIO_PIN(1)); ///< GPIOD_PTOR[1]=1 (alterna o valor)
PIT_TFLG0 |= PIT_TFLG_TIF_MASK;
}
int main(void)
{
InitPIT();
InitGPIO();
enableNVIC();
for(;;) {
}
}
ANEXO 2: LISTAGEM DO SEGUNDO PROGRAMA
#include "derivative.h"
#define GPIO_PIN(x) ((1)<<(x)) ///< obtem o bit do pino x
/**
* \fn InitGPIO (void)
* \brief Inicializa o pino conectado ao ledR do FRDM para verificação visual.
*/
void InitGPIO(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
///< PORTB=SIM_SCGC5[10]=1 (Clock gate de PORTB habilitado)
PORTB_PCR19 |= (PORT_PCR_ISF_MASK |
///< ISF=PORTB_PCR1[14]: w1c (limpa a pendência)
PORT_PCR_MUX(0x1) );
///< MUX=PORTB_PCR1[10:8]=0b011 (TPM1_CH1)
GPIOB_PDDR |= GPIO_PDDR_PDD(GPIO_PIN(19)); ///< GPIOB_PDDR[19]=1 (pino de saída)
GPIOB_PSOR |= GPIO_PSOR_PTSO(GPIO_PIN(19)); ///< GPIOB_PSOR[19]=1 (seta 1 no pino)
}
/**
* \fn InitTPM (void)
* \brief Configura o canal 1 do módulo TPM1 com a função "Output Compare",
*
de forma que a igualdade seja satisfeita a cada ???? segundos.
*/
void InitTPM(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
PORTB_PCR1 |= (PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x3) );
SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;
SIM_SOPT2 |= SIM_SOPT2_TPMSRC(0b01);
SIM_SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
/*
* Veja a relação dos campos dos registradores na Figura 31-1 de KL-25 Sub-Family Reference Manual
* (1) Configuração do módulo TPM1
* Periodo_{UP} = (MOD+1) * (PS/(frequência de source clock))
(CPWMS=0)
* Periodo_{UP-DOWN} = (MOD) * (PS/(frequência de source clock)) * (1/(1+CPWMS)) (CPWMS=1)
* Fórmula geral:
* Periodo_{TPMx} ~ (MOD) * (PS/(frequência de source clock)) * (1/(1+CPWMS))
* frequência de MCGFLLCLK = ????
*
* Período_{TPM1} = ????
*/
TPM1_SC |= (TPM_SC_TOF_MASK |
TPM_SC_CMOD(0x1) |
TPM_SC_PS(0x7) );
TPM1_SC &= ~(TPM_SC_DMA_MASK |
TPM_SC_TOIE_MASK |
TPM_SC_CPWMS_MASK);
TPM1_MOD &= TPM_MOD_MOD(16384);
TPM1_CNT |= TPM_CNT_COUNT(0x0) ;
TPM1_CONF &= ~(TPM_CONF_CROT_MASK |
TPM_CONF_CSOO_MASK |
TPM_CONF_CSOT_MASK |
TPM_CONF_GTBEEN_MASK |
TPM_CONF_DOZEEN_MASK);
TPM1_CONF |= TPM_CONF_DBGMODE(0b11);
/*
* (2) Configurção do canal 1: ????
*
*/
TPM1_C1SC |= (TPM_CnSC_CHF_MASK |
TPM_CnSC_MSA_MASK |
TPM_CnSC_ELSA_MASK);
TPM1_C1SC &= ~(TPM_CnSC_CHIE_MASK |
TPM_CnSC_MSB_MASK |
TPM_CnSC_ELSB_MASK |
TPM_CnSC_DMA_MASK);
TPM1_C1V |= TPM_CnV_VAL(0x0);
}
int main(void)
{
short tempo = 0;
InitTPM();
InitGPIO();
for(;;) {
if (TPM1_STATUS & (TPM_STATUS_CH1F_MASK)) {
///< C1V == MOD?
tempo++;
if (!(tempo % 5)) {
GPIOB_PTOR |= GPIO_PTOR_PTTO(GPIO_PIN(19)); ///< GPIOB_PTOR[19]=1 (alterna o valor)
tempo = 0;
}
TPM1_C1SC |= TPM_CnSC_CHF_MASK;
}
}
}
ANEXO 3: LISTAGEM DO TERCEIRO PROGRAMA
#include "derivative.h"
#define GPIO_PIN(x) ((1)<<(x)) ///< obtem o bit do pino x
unsigned short valor;
/**
* \fn InitGPIO (void)
* \brief Inicializa o pino conectado ao ledB (para verificação visual do sinal)
*
e a PTB1 (a alimentar o pino PTB0 do canal 0 de TPM1).
*/
void InitGPIO(void) {
SIM_SCGC5 |= (SIM_SCGC5_PORTB_MASK | ///< PORTB=SIM_SCGC5[10]=1 (Clock gate de PORTB habilitado)
SIM_SCGC5_PORTD_MASK);
///< PORTD=SIM_SCGC5[12]=1 (Clock gate de PORTD habilitado)
PORTB_PCR1 |= (PORT_PCR_ISF_MASK | ///< ISF=PORTB_PCR1[14]: w1c (limpa a pendência)
PORT_PCR_MUX(0x1));
///< MUX=PORTA_PCR1[10:8]=0b001 (PTB1)
PORTD_PCR1 |= (PORT_PCR_ISF_MASK | ///< ISF=PORTB_PCR1[14]: w1c (limpa a pendência)
PORT_PCR_MUX(0x1));
///< MUX=PORTA_PCR19[10:8]=0b001 (PTD1)
GPIOB_PDDR |= GPIO_PDDR_PDD(GPIO_PIN(1)); ///< GPIOB_PDDR[1]=1 (saída)
GPIOD_PDDR |= GPIO_PDDR_PDD(GPIO_PIN(1)); ///< GPIOD_PDDR[1]=1 (saída)
}
/**
* \fn InitPIT (void)
* \brief Configura o timer 0 do PIT para que gere um sinal periódido de ???? segundos.
*/
void InitPIT(void) {
SIM_SCGC6 |= SIM_SCGC6_PIT_MASK;
///< TPM1=SIM_SCGC6[23]=1 (Clock gate de PIT habilitado)
/*
* Periodo_{PIT} =PIT_LDVAL0[TSV]/(frequência de bus clock)
*
= ????
*/
//OUTDIV1=SIM_CLKDIV1[31:28] é carregado no reset com 0000 (dividido por 1)
SIM_CLKDIV1 &= SIM_CLKDIV1_OUTDIV4(0x0); ///< OUTDIV1=SIM_CLKDIV1[18:16]=0b000 (dividido por 1)
PIT_TCTRL0 &= ~(PIT_TCTRL_TEN_MASK |
PIT_TCTRL_TIE_MASK );
PIT_LDVAL0 = PIT_LDVAL_TSV(0x80000);
PIT_TFLG0 |= PIT_TFLG_TIF_MASK;
PIT_TCTRL0 |= (PIT_TCTRL_TEN_MASK |
PIT_TCTRL_TIE_MASK );
PIT_TCTRL0 &= ~PIT_TCTRL_CHN_MASK;
PIT_MCR &= ~(PIT_MCR_FRZ_MASK |
PIT_MCR_MDIS_MASK );
}
/**
* \fn InitTPM (void)
* \brief Configura o canal 0 do módulo TPM1 com a função "Input Capture",
*
de forma que a borda de ???? do sinal de entrada gere um evento.
*/
void InitTPM(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
PORTB_PCR0 |= (PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x3) );
SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;
SIM_SOPT2 |= SIM_SOPT2_TPMSRC(0b01);
SIM_SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
/*
* Periodo_{TPM} = MOD * (PS/(frequência de source clock)) * (1/(1+CPWMS))
*
= ????
*/
TPM1_SC |= (TPM_SC_TOF_MASK |
TPM_SC_CMOD(0x1) |
TPM_SC_PS(0x6) );
TPM1_SC &= ~(TPM_SC_DMA_MASK |
TPM_SC_TOIE_MASK |
TPM_SC_CPWMS_MASK);
TPM1_MOD &= TPM_MOD_MOD(32758);
TPM1_CNT |= TPM_CNT_COUNT(0x0) ;
TPM1_CONF &= ~(TPM_CONF_CROT_MASK |
TPM_CONF_CSOO_MASK |
TPM_CONF_CSOT_MASK |
TPM_CONF_GTBEEN_MASK |
TPM_CONF_DOZEEN_MASK);
TPM1_CONF |= TPM_CONF_DBGMODE(0b11);
/*
* (2) Configurção do canal 0: ????
*/
TPM1_C0SC |= (TPM_CnSC_CHF_MASK |
TPM_CnSC_CHIE_MASK |
TPM_CnSC_ELSA_MASK );
TPM1_C0SC &= ~(TPM_CnSC_MSB_MASK |
TPM_CnSC_MSA_MASK |
TPM_CnSC_ELSB_MASK |
TPM_CnSC_DMA_MASK);
TPM1_C0V |= TPM_CnV_VAL(0x0);
}
/**
* \fn enableNVIC (void)
* \brief ????
*/
void enableNVIC(void) {
NVIC_ISER |= (1 << (38-16) |
1 << (34-16));
NVIC_ICPR |= (1 << (38-16) |
1 << (34-16));;
NVIC_IPR5 |= NVIC_IP_PRI_22(0x40);
NVIC_IPR4 |= NVIC_IP_PRI_18(0x80);
}
/**
* \fn PIT_IRQHandler (void)
* \brief Rotina de Serviço para ????. Gera trem de pulsos no PTB1 e alterna o ledB para verificação visual
*/
void PIT_IRQHandler(void) {
GPIOB_PTOR |= GPIO_PTOR_PTTO(GPIO_PIN(1)); ///< GPIOB_PTOR[1]=1 (alterna o valor)
GPIOD_PTOR |= GPIO_PTOR_PTTO(GPIO_PIN(1)); ///< GPIOD_PTOR[1]=1 (alterna o valor)
PIT_TFLG0 |= PIT_TFLG_TIF_MASK;
}
/**
* \fn FTM1_IRQHandler (void)
* \brief Rotina de serviço para ????
*/
void FTM1_IRQHandler(void) {
valor = TPM1_C0V;
TPM1_C0SC |= TPM_CnSC_CHF_MASK;
}
int main(void)
{
unsigned short inicio, fim, amostras;
unsigned int soma, media;
double periodo;
InitTPM();
InitGPIO();
InitPIT();
enableNVIC();
/*
* Estimativa do período com base na média de 1000 amostras de intervalos
* entre 2 bordas de subida
*/
valor = 0;
soma = 0;
amostras = 0;
while (valor == 0);
///< ???? Para quê?
inicio = valor;
for(;;) {
fim = valor;
if (fim > inicio) {
amostras++;
soma += (fim-inicio);
inicio = fim;
} else if (fim < inicio) {
amostras++;
soma += ((0xFFFF-inicio) + fim);
inicio = fim;
}
if (amostras == 1000) {
media = (unsigned int)(0.001*soma);
/*
* periodo estimado = ???? segundos (adicione a instrução no código)
*/
amostras = 0;
///< seta brkp nesta instrução
}
}
}
ANEXO 4: LISTAGEM DO QUARTO PROGRAMA
#include "derivative.h"
#define GPIO_PIN(x) ((1)<<(x)) ///< obtem o bit do pino x
#define COUNTER_OVF 16384
/**
* \fn InitGPIO (void)
* \brief Inicializa o pino conectado ao ledR do FRDM para verificação visual.
*/
void InitGPIO(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
///< PORTB=SIM_SCGC5[10]=1 (Clock gate de PORTB habilitado)
PORTB_PCR18 |= (PORT_PCR_ISF_MASK |
///< ISF=PORTB_PCR1[14]: w1c (limpa a pendência)
PORT_PCR_MUX(0x1) );
///< MUX=PORTB_PCR1[10:8]=0b011 (TPM1_CH1)
GPIOB_PDDR |= GPIO_PDDR_PDD(GPIO_PIN(18)); ///< GPIOB_PDDR[18]=1 (pino de saída)
GPIOB_PSOR |= GPIO_PSOR_PTSO(GPIO_PIN(18)); ///< GPIOB_PSOR[18]=1 (seta 1 no pino)
}
/**
* \fn InitTPM (void)
* \brief Configura o canal 0 do módulo TPM1 com a função "PWM",
*
de forma que a igualdade seja satisfeita a ???? duty cycle.
*/
void InitTPM(void) {
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK;
PORTB_PCR0 |= (PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x3) );
SIM_SCGC6 |= SIM_SCGC6_TPM1_MASK;
SIM_SOPT2 |= SIM_SOPT2_TPMSRC(0b01);
SIM_SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
/*
* Periodo_{TPMx} ~ (MOD) * (PS/(frequência de source clock)) * (1/(1+CPWMS))
*
= ????
*/
TPM1_SC |= (TPM_SC_TOF_MASK |
TPM_SC_CMOD(0x1) |
TPM_SC_PS(0x7) );
TPM1_SC &= ~(TPM_SC_DMA_MASK |
TPM_SC_TOIE_MASK |
TPM_SC_CPWMS_MASK);
TPM1_MOD &= TPM_MOD_MOD(COUNTER_OVF);
TPM1_CNT |= TPM_CNT_COUNT(0x0) ;
TPM1_CONF &= ~(TPM_CONF_CROT_MASK |
TPM_CONF_CSOO_MASK |
TPM_CONF_CSOT_MASK |
TPM_CONF_GTBEEN_MASK |
TPM_CONF_DOZEEN_MASK);
TPM1_CONF |= TPM_CONF_DBGMODE(0b11);
/*
* (2) Configurção do canal 0:
*/
TPM1_C0SC |= (TPM_CnSC_CHF_MASK |
///< CHF=TPM1_C1SC[7]: w1c (limpa a pendência do canal)
TPM_CnSC_MSB_MASK |
///< MSB=TPM1_C1SC[5]=1
TPM_CnSC_ELSB_MASK );
///< ELSB=TPM1_C1SC[3]=1
TPM1_C0SC &= ~(TPM_CnSC_CHIE_MASK | ///< CHIE=TPM1_C1SC[6]=0 (desabilita interrupção)
TPM_CnSC_MSA_MASK |
///< MSA=TPM1_C1SC[4]=0
TPM_CnSC_ELSA_MASK |
///< ELSA=TPM1_C1SC[2]=0
TPM_CnSC_DMA_MASK);
///< DMA=TPM1_C1SC[0]=0 (desabilita DMA)
TPM1_C0V = TPM_CnV_VAL((short)(1.1*COUNTER_OVF)); ///< (> COUNTER_OVF????) (Seção 31.4.6}
}
int main(void)
{
int count = 0;
short CnV;
InitTPM();
InitGPIO();
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK)); ///< ???? Para quê? (Seção 31.4.8.2)
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
///< GPIOB_PCOR[18]=1 (seta 0 no pino)
for(;;) {
count++;
if (TPM1_STATUS & TPM_STATUS_TOF_MASK) {
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18)); ///< GPIOB_PCOR[18]=1 (seta 0 no pino)
TPM1_C0SC |= TPM_CnSC_CHF_MASK;
///< baixa a bandeira de igualdade
TPM1_SC |= TPM_SC_TOF_MASK;
///< baixa a bandeira de overflow
} else if (TPM1_STATUS & TPM_STATUS_CH0F_MASK) {
GPIOB_PSOR |= GPIO_PSOR_PTSO(GPIO_PIN(18)); ///< GPIOB_PSOR[18]=1 (seta 1 no pino)
TPM1_C0SC |= TPM_CnSC_CHF_MASK;
///< baixa a bandeira de igualdade
TPM1_SC |= TPM_SC_TOF_MASK;
///< baixa a bandeira de overflow
}
if (count == 0x100000) {
TPM1_C0V = TPM_CnV_VAL((short)(0.8*COUNTER_OVF)); ///< 80%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
} else if (count == 0x200000) {
TPM1_C0V = TPM_CnV_VAL((short)(0.6*COUNTER_OVF)); ///< 60%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
} else if (count == 0x300000) {
TPM1_C0V = TPM_CnV_VAL((short)(0.4*COUNTER_OVF)); ///< 40%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
} else if (count == 0x400000) {
TPM1_C0V = TPM_CnV_VAL((short)(0.2*COUNTER_OVF)); ///< 20%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
} else if (count == 0x500000) {
TPM1_C0V = TPM_CnV_VAL((short)(0.02*COUNTER_OVF)); ///< 2%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
} else if (count == 0x600000) {
TPM1_C0V = TPM_CnV_VAL((short)(1.1*COUNTER_OVF)); ///< 100%
while (!(TPM1_STATUS & TPM_STATUS_TOF_MASK));
GPIOB_PCOR |= GPIO_PCOR_PTCO(GPIO_PIN(18));
count = 0;
}
}
}
Download

rot12-ting