Está en la página 1de 12

Módulo Timer/PWM

El módulo temporizador/PWM (TPM) consiste en


un núcleo con un contador de 16 bits y múltiples
canales que utilizan el valor del contador del
núcleo para medir el tiempo de las señales de
entrada o generar señales de salida. La figura 1
muestra un diagrama de bloques de los circuitos
TPM. La familia de MCU KL28Z tiene tres TPM:
TPM0 tiene seis canales, mientras que TPM1 y
TPM2 tienen dos canales.
Módulo Timer/PWM

Fig. 1. El periférico Timer/PWM tiene un contador de 16 bits y múltiples canales con soporte de procesamiento de entrada y salida.
Módulo Timer/PWM


El corazón del TPM es un contador de subida/bajada
precargable de 16 bits llamado TPMx_CNT. El campo
CPWMS en TPMx_SC establece la dirección de conteo
solo hacia arriba (cero) o alternando hacia arriba y hacia
abajo (uno). El estado de TPM y el registro de control
(TPMx_SC) controla el funcionamiento básico del núcleo
del TPM y se muestra en la Figura 2. El campo CMOD de
TPMx_SC determina la fuente de reloj para el TPM.
Puede ser una señal de reloj externa (LPTPM_EXTCLK),
el reloj LPTPM del módulo o puede desconectarse para
deshabilitar el TPM.
Fig. 2 Registro de estado y control de TPMx_SC.
Módulo Timer/PWM


El preescalador es un circuito de hardware que divide la
frecuencia de la señal de entrada por un factor de 1, 2, 4,
8, 16, 32, 64 o 128, según lo controlado por el campo PS
del registro TPMx_SC. El registro TPMx_STATUS, que se
muestra en la Figura 3, indica el estado del núcleo TPM y
sus canales.

Fig. 3. El registro TPMx_STATUS indica si el contador se ha desbordado y si se han producido eventos


de canal.
Módulo Timer/PWM

El registro MOD define qué tan alto cuenta el registro CNT. Un comparador detecta la
condición de desbordamiento que ocurre cuando CNT intenta contar el MOD pasado. La
lógica del controlador responde al desbordamiento realizando las siguientes acciones:

El indicador de desbordamiento TOF se establece en uno.

Si el campo TOIE de TPMx_SC se establece en uno, el TPM generará una interrupción
TPMx.

Si el campo DMA de TPMx_SC se establece en uno, el TPM generará la solicitud TPMx
DMA.

El contador se modifica de acuerdo con el valor del bit CPWMS:
 si el contador está configurado para contar hacia arriba (CPWMS es cero), CNT se
borra a cero.
 Si el contador está configurado para contar hacia arriba/hacia abajo (CPWMS es uno),
entonces la dirección se establece en cuenta regresiva y se reduce la CNT (a MOD-1).
Módulo Timer/PWM


Cuando está en modo de conteo
ascendente/descendente, la cuenta regresiva a cero da
como resultado una condición de flujo insuficiente, por lo
que la dirección del conteo cambia a ascendente. La
siguiente entrada de reloj incrementará CNT a uno. El
TPM se desbordará a una frecuencia de fclock/(preescaler
* (MOD + 1) cuando esté en modo de conteo ascendente,
y fclock/(preescaler*2*MOD) cuando esté en modo de
conteo ascendente/descendente.
Ejemplo: LED Dimmer


Vamos a manejar un LED con una salida PWM para que
podamos atenuarlo a un brillo parcial. La Figura muestra
cómo el LED RGB de la placa Freedom KL28Z tiene sus
cátodos conectados a la MCU, con el LED azul conectado
al pin PTE31. Examinamos la hoja de datos de MCU para
encontrar la multiplexación de señales y las asignaciones
de pines para PTE31. El pin PTE31 se puede conectar al
canal 4 de TPM0 (TPM0_CH4) configurando el MUX en 3.
Por lo tanto, necesitaremos usar el canal 4 de TPM0 para
controlar el LED.
Ejemplo: LED Dimmer


El listado muestra el código para inicializar el TPM para
controlar el LED azul con una señal PWM. Utilizaremos el
modo de conteo ascendente alineado con los bordes para
simplificar. Debido a que el LED se encenderá cuando la
salida sea baja, configuraremos el canal para generar una
salida verdadera baja para que al configurar CnV en cero
apague el LED. Para encender completamente el LED,
configuramos CnV en MOD.
Ejemplo: LED Dimmer

La frecuencia de la señal PWM generada debe ser de al menos
50 Hz para evitar el parpadeo visible. Vamos a elegir 500 Hz
como la frecuencia PWM. La frecuencia de reloj de entrada TPM
de 48 MHz deberá dividirse a 500 Hz, por lo que necesitamos un
factor de división de 96000. Usaremos el preescalador para
reducir este valor a no más de 65536, que es el factor de
división máximo para nuestro registro MOD de 16 bits.
Necesitaremos un factor de prescaler de al menos 96000/65536
= 1.46, por lo que cualquier factor de 2 o más es suficiente. El
uso del factor preescalador de 2 significa que el valor MOD debe
ser 96000/2 –1 = 48000 - 1 = 47999. Podremos configurar el
LED en uno de los 48000 niveles de brillo.
Ejemplo: LED Dimmer


Tenga en cuenta que cuanto mayor sea el factor de
preescalador, menos valores diferentes de PWM estarán
disponibles. El uso del factor de preescalador de 128 significa
que el valor MOD debería ser 96000/128 - 1 = 750 - 1 = 749.
Entonces podríamos configurar el LED en uno de los 750
niveles de brillo. Para algunas aplicaciones, esta resolución
reducida puede ser un problema.

Para este ejemplo, no habilitamos las interrupciones. Sin
embargo, si lo hiciéramos, ocurrirían a 500 Hz, lo que podría
servir como una referencia de tiempo útil para otras partes del
programa.
Ejemplo: LED Dimmer

#define PWM_PERIODO (48000)


/* TODO: insert other definitions and declarations here. */
void Init_Blue_LED_PWM(uint16_t periodo){
//Habilitación del Clock del Puerto E y TPM0
PCC_TPM0 = 0xC3000000;
PCC_PORTE |= (1UL<<30);
TPM0->SC=0;
TPM0->CNT=0;
//Configuración de TPM0
TPM0->MOD = periodo - 1;
/*Establezca la dirección de recuento ascendente de TPM
* con división por 2 (PS=001) */
TPM0->SC =TPM_SC_PS(1);
//Continue la operación en modo DEBUG
TPM0->CONF |= TPM_CONF_DBGMODE(3);
//Establezca el canal 4 en PWM de activo bajo alineado con los bordes
TPM0->CONTROLS[4].CnSC =TPM_CnSC_MSB_MASK | TPM_CnSC_ELSA_MASK;
//Inicialización del Cíclo de trabajo
TPM0->CONTROLS[4].CnV=0;
//Inicia conteo
TPM0->SC |= TPM_SC_CMOD(1);
}
Ejemplo: LED Dimmer
int main(void) {
/* Init board hardware. */
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitBootPeripherals();
/* Init FSL debug console. */
BOARD_InitDebugConsole();

PRINTF("Hello World\n");

/* Force the counter to be placed into memory. */


uint16_t i=0;
volatile int32_t delay;
Init_Blue_LED_PWM(PWM_PERIODO);

//Parpadea para siempre


while(1) {
//Brillo de LED
for(i=0;i<PWM_PERIODO;i++){
TPM0->CONTROLS[4].CnV=i;
for(delay=0;delay<100;delay++);
}
//Regulador de Intensidad
for(i=PWM_PERIODO - 1; i>0;i--){
TPM0->CONTROLS[4].CnV=i;
for(delay=0;delay<100;delay++);
}
/* 'Dummy' NOP to allow source level single
stepping of
tight while() loop */
}
return 0 ;
}