Ejemplo Timer RTC y TPM de forma simultánea
Antes de entrar de lleno con el ejemplo veremos con detalle cuáles son los registros que manipulamos para configurar y utilizar tanto el RTC como el TPM.
En este ejemplo lo primero que se configura es el GPIO, que es configurar como salida los LEDS que queremos utilizar para realizar la demostración del funcionamiento del RTC y el TPM. Se activan los LEDS como puertos de salida colocando un "1" en su registro respectivo de Dirección de Datos 'PTCDD' y 'PTEDD'(Recordamos que los primero 6 LEDS corresponden al bit 0,1,2,3,4 y 5 del puerto C 'PTC' y los últimos dos corresponden al bit 6 y 7 del puerto E 'PTE') aquí también se coloca un "1" en la data de los puertos para apagar los LEDS ya que estos tienen lógica negada ("1" encendido y "0" apagado). De esta manera se inicializan los LEDS como puertos de salida y están listos para ser usados.
RTC
Ahora llegamos a la configuración del RTC el primer registro que queremos modificar es el SCGC2
Aquí colocamos un 1 en el bit número 2 que es el correspondiente al RTC para activarlo. Luego de activarlo se configurará como tal el RTC según lo que se desea.
Ahora vamos a manipular el registro RTCSC
A este registro se le carga %00010110 donde activamos el bit 4 'RTIE' con el que se activan las interrupciones del RTC y se coloca 0110 en el RTCPS que es el prescalador que dicta cada cuanto tiempo aumentará el RTCCNT (que cuenta hasta llegar al valor dado a RTCMOD y ahí entra en la rutina de interrupción del RTC).
El prescalador viene definido de esta manera dependiendo del valor que se le ponga.
Se define el RTCMOD o el Modulo del RTC cargando (por ejemplo con la instrucción STA) algún número en él. Éste es el valor máximo hasta donde contará el RTC Counter 'RTCCNT' y que indica cuando ocurre la interrupción del RTC.
Recordemos que cada vez que se carga algo en el RTCMOD se reinician los registros RTCCNT y RTCSC lo que quiere decir que se desconfigura el RTC. Entonces, si queremos seguir usando el RTC debemos volver a configurarlos, es decir, cargar el registro RTCSC.
El valor del RTCMOD tendrá las unidades correspondiente al preescalador seleccionado el cual se escoge en el registro RTCSC. La tabla anterior de preescaladores definirá el valor máximo al que el RTCCNT llegará que es el del RTCMOD y las unidades de éste (para las distintas fuentes de reloj)
Con esto terminamos de configurar el RTC.
TPM
Ahora para configurar el TPM realizaremos un procedimiento muy parecido, primero configuramos el registro TPM1SC que es la configuración del sistema del sistema del TPM1. Cabe acotar que hay 3 contadores TPM independientes entre si, lo cual es de gran utilidad para tener distintas fuentes de reloj y distintos tiempos.
Aquí cargamos %01001111 donde activamos las interrupciones activando el bit TOIE o Timer Overflow Interrupt Enable, elegimos la fuente del reloj
y también configuramos el prescalador con la siguiente tabla
Por último se carga $FFFF en el TMP1MOD a través de H:X.
La limitación principal de los TPM es que a diferencia del RTC que tiene 15 preescaladores, este tiene solo 8. La ventaja es que existe TPM1, TPM2 y TPM3 así que se tienen varias posibilidades para realizar varios "timers" con TPM a pesar de sus preescaladores.
Ahora nótese que en este ejemplo las interrupciones hacen exactamente lo mismo, apagan y prenden un LED cada una. La diferencia está en que la manera de bajar la bandera de cada interrupción es distinta ya que son registros distintos y también los tiempos en que ocurren cada interrupción son diferentes debido que así se configuraron los módulos y los prescaladores de cada reloj (TPM y RTC).
;*******************************************************************
;*Ejemplo de utilización de Timers por interrupciones *
;* *
;* Se utiliza el RTC para prender y apagar el led de PTC0 cada 2s. *
;* Se utiliza el TPM para prender y apgar el led de PTC1 cada 1s. *
;*******************************************************************
; Include derivative-specific definitions
INCLUDE 'derivative.inc'
;
; export symbols
;
XDEF _Startup
ABSENTRY _Startup
;
; variable/data section
;
ORG RAMStart ; Insert your data definition here
ExampleVar: DS.B 1
;
; code section
;
ORG ROMStart
_Startup:
LDHX #RAMEnd+1 ; initialize the stack pointer
TXS
;Configuración de los pines del Demoqe128
BSR Configurar_GPIO
;------------------------------------------
;Configuración del RTC
BSR Configurar_RTC
;------------------------------------------
;Configuración del TPM
BSR Configurar_TPM1
CLI ; enable interrupts
mainLoop:
NOP
feed_watchdog
BRA mainLoop
;**************************************************************
;* . Subrutinas de Configuración *
*
;**************************************************************
Configurar_GPIO:
; Configuración de los leds del DEMOQE como salida
; Los Leds tienen lógica negada
;Parte inferior de Puerto C (0:5)
LDA #$3F
STA PTCDD
STA PTCD
;------------------------------------------
;Parte superior de Puerto D (6:7)
LDA #$C0
STA PTEDD
STA PTED
RTS
Configurar_RTC:
;------------------------------------------
;Habilitamos el Clock Gate para el RTC
LDA SCGC2
ORA #%00000100
STA SCGC2
;------------------------------------------
;Definimos el valor del registro modulo del RTC
LDA #$00
STA RTCMOD
;------------------------------------------
;Configuramos el RTCSC
;Reloj configurado a 16ms. Fuente reloj interna 1khz.
;Interrupciones habilitadas
LDA #%00010110
; RTIF=0, RTCLKS6=0 RTCLKS5=0, RTIE=1, RTCPS3=0, RTCPS2=1, RTCPS1=1, RTCPS0=0
STA RTCSC
RTS
Configurar_TPM1:
;Configuracion del timer TPM1
;(Interrupcion en overflow del contador)
LDA #%01001111
; TPM1SC: TOF=0,TOIE=1,CPWMS=0,CLKSB=0,CLKSA=1,PS2=1,PS1=1,PS0=1
;Probar diferentes valores de PS2,PS1,PS0
STA TPM1SC
;Valor maximo de conteo (Probar diferentes valores)
LDHX #$FFFF
STHX TPM1MOD ; Compare 0 value setting
RTS
;**************************************************************
;* . Rutinas de atencion a las interrupciones *
*
;**************************************************************
Interrupcion_TPM1:
;Limpiamos las banderas de interrupcion
;Primero se lee el regristro TPMxSC
LDA TPM1SC
;Luego se baja el bit 7 (TOF) escribiendo 0
AND #%01111111
STA TPM1SC
;Negamos el pin0 de PTC (Led0)
;Revisamos si el PTC0 se encuentra encendido
LDA PTCD
BIT #%00000001
BNE ApagarPTC0
;Si el PTC0 está apagado lo encendemos
PrenderPTC0:BSET 0,PTCD
;Regresamos de la interrupcion
RTI
ApagarPTC0: BCLR 0,PTCD
;Regresamos de la interrupcion
RTI
Interrupcion_RTC:
;Limpiamos las banderas de interrupcion
;Se escribe un 1 en la bandera RTIF
;Diferente a TPM!!!
LDA RTCSC
ORA #%10000000
STA RTCSC
;Negamos el pin1 de PTC (Led1)
;Revisamos si el PTC1 se encuentra encendido
LDA PTCD
BIT #%00000010
BNE ApagarPTC1
;Si el PTC0 está apagado lo encendemos
PrenderPTC1:BSET 1,PTCD
;Regresamos de la interrupcion
RTI
ApagarPTC1: BCLR 1,PTCD
;Regresamos de la interrupcion
RTI
;**************************************************************
;* spurious - Spurious Interrupt Service Routine. *
;* (unwanted interrupt) *
;**************************************************************
spurious: ; placed here so that security value
NOP ; does not change all the time.
RTI
;**************************************************************
;* Interrupt Vectors *
;**************************************************************
ORG Vtpm1ovf
DC.W Interrupcion_TPM1
ORG $FFCE
DC.W Interrupcion_RTC
ORG $FFFA
DC.W spurious ;
DC.W spurious ; SWI
DC.W _Startup ; Reset