Generación de retardos en la familia HC908 - Edudevices
Generación de retardos en la familia HC908 - Edudevices
Generación de retardos en la familia HC908 - Edudevices
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
COMENTARIO TECNICO<br />
<strong>G<strong>en</strong>eración</strong> <strong>de</strong> <strong>retardos</strong> <strong>en</strong> <strong>la</strong> <strong>familia</strong> <strong>HC908</strong><br />
Por el Ing. Gabriel Dubatti – www.ingdubatti.com.ar<br />
Introducción<br />
Una tarea muy frecu<strong>en</strong>te al programar microcontro<strong>la</strong>dores es <strong>la</strong> g<strong>en</strong>eración <strong>de</strong> <strong>retardos</strong>, <strong>en</strong> g<strong>en</strong>eral,<br />
para contro<strong>la</strong>r hardware periférico o para seña<strong>la</strong>r distintos tipos <strong>de</strong> ev<strong>en</strong>tos mediante luces o sonidos.<br />
En algunos casos pue<strong>de</strong> utilizarse para g<strong>en</strong>erar estos tiempos el módulo <strong>de</strong> timer incorporado<br />
<strong>en</strong> el microcontro<strong>la</strong>dor, pero para muchos otros hay que buscar otras soluciones <strong>de</strong>bido a los<br />
inconv<strong>en</strong>i<strong>en</strong>tes que se verán a continuación.<br />
Se muestra, a modo <strong>de</strong> ejemplo, como realizar una puerta serie por software <strong>en</strong> el procesador 68<strong>HC908</strong>JL3.<br />
<strong>G<strong>en</strong>eración</strong> <strong>de</strong> tiempos con el módulo <strong>de</strong> TIMER<br />
El módulo <strong>de</strong> TIMER suele ser utilizado mediante interrupciones <strong>de</strong> <strong>la</strong> sigui<strong>en</strong>te forma:<br />
• Se elige un valor <strong>de</strong> prescaler (que <strong>de</strong>termina el tiempo <strong>de</strong> avance <strong>de</strong>l registro <strong>de</strong> 16 bits <strong>en</strong><br />
función <strong>de</strong> <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus). Cada cu<strong>en</strong>ta <strong>en</strong> el TIMER es un "tick".<br />
• Modo autorecargable: Se le da un valor <strong>de</strong> módulo al TIMER para que interrumpa por "Overflow"<br />
indicando <strong>la</strong> cantidad <strong>de</strong> "ticks" <strong>de</strong>seados (esto g<strong>en</strong>era un aviso periódico).<br />
• Modo libre: Se indica <strong>en</strong> uno <strong>de</strong> los canales <strong>de</strong>l TIMER <strong>de</strong>ntro <strong>de</strong> cuantos "ticks" queremos que<br />
Interrumpa sumando al valor actual <strong>de</strong>l TIMER <strong>la</strong> cantidad <strong>de</strong> "ticks" <strong>de</strong>seados y recalculándolo<br />
manualm<strong>en</strong>te <strong>en</strong> cada interrupción.<br />
El inconv<strong>en</strong>i<strong>en</strong>te <strong>de</strong> este método radica <strong>en</strong> lo que se <strong>de</strong>nomina <strong>la</strong>t<strong>en</strong>cia <strong>de</strong> <strong>la</strong>s interrupciones.<br />
O sea <strong>la</strong> <strong>de</strong>mora que se produce <strong>de</strong>s<strong>de</strong> el ev<strong>en</strong>to <strong>de</strong> tiempo <strong>de</strong>seado y el mom<strong>en</strong>to <strong>en</strong> que realm<strong>en</strong>te<br />
se ejecuta el código.<br />
Esta <strong>la</strong>t<strong>en</strong>cia ti<strong>en</strong>e <strong>la</strong> <strong>de</strong>sv<strong>en</strong>taja <strong>de</strong> no ser pre<strong>de</strong>cible ya que <strong>en</strong> <strong>la</strong> ejecución <strong>de</strong> una interrupción<br />
intervi<strong>en</strong><strong>en</strong> los sigui<strong>en</strong>tes factores: (si fuera pre<strong>de</strong>cible bastaría con restar al tiempo <strong>de</strong>seado al <strong>de</strong> <strong>la</strong> <strong>la</strong>t<strong>en</strong>cia)<br />
• Esperar a que se <strong>de</strong>stap<strong>en</strong> <strong>la</strong>s interrupciones (bit I <strong>de</strong>l registro CC):<br />
Si estamos ejecutando una sección <strong>de</strong> código que ti<strong>en</strong>e <strong>la</strong>s interrupciones <strong>de</strong>shabilitadas, esta<br />
esperará hasta que se habilit<strong>en</strong> para po<strong>de</strong>r ejecutar. Este tiempo pue<strong>de</strong> ser muy difícil <strong>de</strong><br />
estimar si estamos trabajando con varias interrupciones y no habilitamos <strong>la</strong> <strong>en</strong>trada <strong>de</strong> una<br />
interrupción "sobre" otra.<br />
• Esperar a que termine <strong>de</strong> ejecutar <strong>la</strong> instrucción <strong>en</strong> curso:<br />
Las instrucciones se procesan <strong>en</strong> forma "atómica" (o sea <strong>en</strong> forma indivisible) y por lo tanto<br />
para procesar una interrupción <strong>de</strong>be esperarse a que esta se complete. La cantidad <strong>de</strong> ciclos que<br />
<strong>de</strong>mora una instrucción <strong>en</strong> <strong>la</strong> <strong>familia</strong> <strong>HC908</strong> está compr<strong>en</strong>dida <strong>en</strong>tre 1 y 9 ciclos <strong>de</strong> <strong>la</strong> frecu<strong>en</strong>cia<br />
<strong>de</strong> bus.<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
• Tiempo <strong>de</strong> salvado <strong>de</strong> registros<br />
Cuando se logran <strong>la</strong>s condiciones anteriores, el microcontro<strong>la</strong>dor <strong>de</strong>be salvar el "contexto" actual<br />
<strong>de</strong> trabajo. Para ello, inserta <strong>en</strong> el stack los registros: PC,X,A,CC con una <strong>de</strong>mora adicional <strong>de</strong><br />
9 ciclos (suponi<strong>en</strong>do que <strong>de</strong>mora lo mismo que <strong>la</strong> instrucción SWI). Este tiempo al ser fijo,<br />
pue<strong>de</strong> ser restado <strong>de</strong>l tiempo <strong>de</strong>seado para corregirlo.<br />
La <strong>la</strong>t<strong>en</strong>cia hace que el método <strong>de</strong> trabajo por interrupciones se utilice para g<strong>en</strong>erar tiempos re<strong>la</strong>tivam<strong>en</strong>te<br />
gran<strong>de</strong>s <strong>en</strong> ciclos <strong>de</strong> bus, <strong>de</strong> modo que el error obt<strong>en</strong>ido sea <strong>de</strong>spreciable o promediado<br />
(por ejemplo: si programamos el TIMER para g<strong>en</strong>erar 10 interrupciones por segundo con el modo<br />
autorecargable, a pesar <strong>de</strong> <strong>la</strong> <strong>la</strong>t<strong>en</strong>cia, obt<strong>en</strong>dremos 10 interrupciones por segundo cada una con una pequeña<br />
<strong>de</strong>mora distinta, pero "no acumu<strong>la</strong>tiva" ).<br />
Para corregir estos efectos pue<strong>de</strong> usarse el TIMER sin interrupciones. Esto es, leyéndolo y esperando a que<br />
llegue al valor <strong>de</strong>seado. En este caso hay que t<strong>en</strong>er cuidado con <strong>la</strong> comparación, ya que si se hace<br />
"por igual" hay que estar seguro <strong>de</strong> que el tiempo que se <strong>de</strong>mora <strong>en</strong>tre lectura y lectura no haga que se pase<br />
el valor <strong>de</strong>seado "<strong>de</strong> <strong>la</strong>rgo" sin verlo y si se compara por "mayor o igual" hay que t<strong>en</strong>er cuidado con <strong>la</strong><br />
"circu<strong>la</strong>ridad" <strong>de</strong>l registro (o sea, luego <strong>de</strong> $FFFF se vuelve a $0000 y lo que era mayor ahora es m<strong>en</strong>or!).<br />
Cuando los tiempos a g<strong>en</strong>erar son muy chicos (pocos ciclos) hay que t<strong>en</strong>er <strong>en</strong> cu<strong>en</strong>ta <strong>la</strong> incertidumbre <strong>de</strong>l<br />
prescaler <strong>de</strong>l TIMER, ya que no sabemos <strong>en</strong> que valor se <strong>en</strong>cu<strong>en</strong>tra este divisor al iniciar el retardo.<br />
Si <strong>de</strong>seamos g<strong>en</strong>erar <strong>retardos</strong> <strong>de</strong> distintas duraciones, <strong>de</strong>beremos buscar una unidad <strong>de</strong> interrupción que sea<br />
común a todos los <strong>retardos</strong> y contar interrupciones para g<strong>en</strong>erar los ev<strong>en</strong>tos más <strong>la</strong>rgos.<br />
Por ejemplo: si necesitamos <strong>retardos</strong> <strong>de</strong> 15 mseg, 50 mseg y 100 mseg, po<strong>de</strong>mos usar 5 msegs <strong>de</strong> unidad y<br />
contar 3, 10 y 20 interrupciones respectivam<strong>en</strong>te o bi<strong>en</strong> trabajar el timer <strong>en</strong> modo libre y programar<br />
<strong>la</strong> <strong>de</strong>mora <strong>en</strong> cada caso.<br />
<strong>G<strong>en</strong>eración</strong> <strong>de</strong> <strong>retardos</strong> por <strong>de</strong>mora <strong>de</strong> <strong>la</strong>s instrucciones<br />
Dado que cada instrucción <strong>de</strong>l procesador requiere una <strong>de</strong>terminada cantidad <strong>de</strong> ciclos <strong>de</strong> bus para ser<br />
completada, surge <strong>la</strong> posibilidad <strong>de</strong> utilizar este "efecto secundario" para g<strong>en</strong>erar <strong>retardos</strong> <strong>de</strong> duración<br />
contro<strong>la</strong>da. Y dado que <strong>la</strong>s instrucciones <strong>de</strong>moran <strong>de</strong> 1 a 9 ciclos, pue<strong>de</strong>n obt<strong>en</strong>erse <strong>retardos</strong> muy cortos<br />
o <strong>la</strong>rgos y muy precisos.<br />
Es <strong>de</strong> notar que para que el retardo sea <strong>de</strong> <strong>la</strong> duración <strong>de</strong>seada: el código <strong>de</strong>be ejecutarse con <strong>la</strong>s<br />
interrupciones <strong>de</strong>shabilitadas ya que si se pres<strong>en</strong>ta una interrupción, al tiempo transcurrido se le <strong>de</strong>berá<br />
sumar todo el tiempo que tardo <strong>la</strong> interrupción <strong>en</strong> ejecutar. Si lo que se <strong>de</strong>sea es un retardo <strong>de</strong><br />
"por lo m<strong>en</strong>os" <strong>la</strong> <strong>de</strong>mora dada, por ejemplo para g<strong>en</strong>erar un pulso <strong>de</strong> "strobe", no hay problema<br />
<strong>en</strong> t<strong>en</strong>er <strong>la</strong>s interrupciones habilitadas.<br />
Este método ti<strong>en</strong>e el atractivo <strong>de</strong> po<strong>de</strong>r realizar alguna función útil mi<strong>en</strong>tras se está esperando<br />
(como borrar memoria, precargar registros, etc.).<br />
La instrucción <strong>de</strong> <strong>de</strong>mora por excel<strong>en</strong>cia es "NOP" (no operación) que no hace nada salvo<br />
<strong>de</strong>morar 1 ciclo <strong>la</strong> ejecución <strong>de</strong>l programa. Para g<strong>en</strong>erar <strong>de</strong><strong>la</strong>y más <strong>la</strong>rgos po<strong>de</strong>mos colocar varias<br />
instrucciones NOP seguidas, pero consultando <strong>la</strong>s hojas <strong>de</strong> datos <strong>de</strong>l procesador surg<strong>en</strong> variantes<br />
más interesantes:<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
Ciclos Bytes Código Com<strong>en</strong>tarios<br />
1 1 NOP -<br />
2 1 SEI Fuerza I=1<br />
2 1 CLI Fuerza I=0<br />
2 1 DAA Invalida registro A<br />
2 1 TSX Invalida registros H y X<br />
2 2<br />
NOP<br />
NOP<br />
-<br />
3 1 NSA Intercambia nibbles <strong>de</strong>l registro A<br />
3 2 BRN $ -<br />
4 2<br />
PSHA<br />
PULA<br />
Utiliza y libera un byte <strong>de</strong>l stack<br />
5 1 MUL<br />
PSHA<br />
Invalida registros A, X y CC (bits H y C)<br />
5 3<br />
PULA<br />
NOP<br />
Utiliza y libera un byte <strong>de</strong>l stack<br />
5 3 MOV $80,$80<br />
Invalida registro CC (bits V, N y Z)<br />
Usar cualquier dirección <strong>en</strong> página 0.<br />
6 2<br />
NSA<br />
NSA<br />
-<br />
7 1 DIV<br />
PSHA<br />
Invalida registros A, X y H<br />
7 3<br />
NSA<br />
PULA<br />
Utiliza y libera un byte <strong>de</strong>l stack<br />
8 3 (o 2)<br />
9 3<br />
9 4 (o 3)<br />
16 2 (o 1)<br />
BSR rutina<br />
..<br />
rutina: RTS<br />
NSA<br />
NSA<br />
NSA<br />
JSR rutina<br />
..<br />
rutina: RTS<br />
SWI<br />
...<br />
vector_swi: RTI<br />
Utiliza y libera dos bytes <strong>de</strong>l stack<br />
Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />
byte.<br />
Intercambia nibbles <strong>de</strong>l registro A<br />
Utiliza y libera dos bytes <strong>de</strong>l stack<br />
Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />
byte.<br />
Utiliza y libera 5 bytes <strong>de</strong>l stack<br />
Se pue<strong>de</strong> utilizar un RTS exist<strong>en</strong>te y ahorrar un<br />
byte.<br />
En <strong>la</strong> tab<strong>la</strong> se ac<strong>la</strong>ra que efecto co<strong>la</strong>teral ti<strong>en</strong>e realizar <strong>la</strong> <strong>de</strong>mora con <strong>la</strong>s instrucciones indicadas.<br />
Por ejemplo: <strong>la</strong> instrucción "NSA" <strong>de</strong>mora 3 ciclos pero intercambia los nibbles <strong>de</strong>l registro A,<br />
por lo que también se indica <strong>en</strong> <strong>la</strong> tab<strong>la</strong> que usando <strong>la</strong> instrucción "BRN xx" (branch never) se obti<strong>en</strong>e<br />
una <strong>de</strong>mora igual pero sin modificar ningún registro. También pue<strong>de</strong>n ponerse 3 "NOP"s pero a exp<strong>en</strong>sas<br />
<strong>de</strong> 1 byte extra y ningún b<strong>en</strong>eficio.<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
Si <strong>la</strong>s condiciones no nos permit<strong>en</strong> usar un ítem <strong>de</strong> <strong>la</strong> tab<strong>la</strong>, siempre po<strong>de</strong>mos g<strong>en</strong>erar una <strong>de</strong>mora<br />
concat<strong>en</strong>ando 2 o más ítems <strong>de</strong> <strong>la</strong> tab<strong>la</strong> que sí cump<strong>la</strong>n con <strong>la</strong>s condiciones <strong>de</strong>seadas.<br />
Cuando <strong>la</strong>s <strong>de</strong>moras a g<strong>en</strong>erar son <strong>de</strong> muchos ciclos es mucho más compacto obt<strong>en</strong>er dicha <strong>de</strong>mora<br />
por iteración. Así surg<strong>en</strong> los sigui<strong>en</strong>tes ejemplos:<br />
Ciclos Bytes Código Com<strong>en</strong>tarios<br />
769 3<br />
CLRA<br />
DBNZA $<br />
Fuerza registro A= 0<br />
Invalida registro CC (bits V=0, N=0 y Z=1)<br />
Fuerza registro A= 0. Invalida registro CC (V, N y<br />
5,8,11..770 4<br />
LDA #CTE<br />
DBNZA $<br />
Z)<br />
<strong>de</strong><strong>la</strong>y= CTE * 3 + 2 (CTE=1..256)<br />
256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 769 ciclos)<br />
773,776..1538 6<br />
LDA #CTE<br />
DBNZA $<br />
DBNZA $<br />
Fuerza registro A= 0. Invalida registro CC (V, N y<br />
Z)<br />
<strong>de</strong><strong>la</strong>y= CTE * 3 + 770 (CTE=1..256)<br />
256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 1537 ciclos)<br />
6,10,14..1026 5<br />
LDA #CTE<br />
loop: NOP<br />
DBNZA loop<br />
Fuerza registro A= 0. Invalida registro CC (V, N y<br />
Z)<br />
<strong>de</strong><strong>la</strong>y= CTE * 4 + 2 (CTE=1..256)<br />
256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 1025 ciclos)<br />
Fuerza registro X= 0. Invalida registro CC (V, N y<br />
8,14,20..1538 5<br />
LDX #CTE<br />
loop: NSA<br />
DBNZX loop<br />
Z)<br />
<strong>de</strong><strong>la</strong>y= CTE * 6 + 2 (CTE=1..256)<br />
256 => 0 (usar CLRX: un byte m<strong>en</strong>os, 1537 ciclos)<br />
Si CTE es impar : intercambia nibbles <strong>de</strong>l<br />
registro A; si es par : manti<strong>en</strong>e A.<br />
LDA #CTE<br />
Fuerza registro A= 0. Invalida registro CC (V, N y<br />
11,20,29..2306 6<br />
loop: NSA<br />
NSA<br />
Z)<br />
<strong>de</strong><strong>la</strong>y= CTE * 9 + 2 (CTE=1..256)<br />
DBNZA loop<br />
256 => 0 (usar CLRA: un byte m<strong>en</strong>os, 2305 ciclos)<br />
La v<strong>en</strong>taja <strong>de</strong> los métodos <strong>de</strong> <strong>de</strong>mora por iteración es que cambiando <strong>la</strong>s instrucciones que están<br />
<strong>de</strong>ntro <strong>de</strong>l <strong>la</strong>zo, po<strong>de</strong>mos cambiar <strong>la</strong> <strong>de</strong>mora <strong>de</strong> cada iteración y por lo tanto el multiplicador<br />
<strong>en</strong> <strong>la</strong> fórmu<strong>la</strong> <strong>de</strong> "<strong>de</strong><strong>la</strong>y" (<strong>de</strong>mora total).<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
Para <strong>de</strong>moras aún mayores se pue<strong>de</strong>n utilizar los sigui<strong>en</strong>tes ejemplos <strong>de</strong> código:<br />
Ciclos Bytes Código Com<strong>en</strong>tarios<br />
7,10..197377 8<br />
12..589827 9<br />
7,16..590593 10<br />
14..150995714 13<br />
LDA #CTE1<br />
LDX #CTE2<br />
loop: DBNZX $<br />
DBNZA loop<br />
LDHX #CTE<br />
loop: AIX #-1<br />
STHX dirmem<br />
BNE loop<br />
LDA #CTE1<br />
LDX #CTE2<br />
loop: NSA<br />
NSA<br />
DBNZX loop<br />
DBNZA loop<br />
LDA #CTE1<br />
LDHX #CTE2<br />
loop: AIX #-1<br />
STHX dirmem<br />
BNE loop<br />
DBNZA loop<br />
Fuerza registros A= 0, X= 0. Invalida registro CC<br />
<strong>de</strong><strong>la</strong>y= 4 + CTE2 * 3 + (CTE1-1) * (3*256+3)<br />
(CTE1/2=1..256)<br />
256 => 0 (usar CLRA/X: uno o dos bytes m<strong>en</strong>os)<br />
Fuerza registros H= 0, X= 0. Invalida registro CC<br />
<strong>de</strong><strong>la</strong>y= 3 + CTE * 9 (CTE=1..65536)<br />
"dirmem" <strong>de</strong>be estar <strong>en</strong> página 0 (pue<strong>de</strong> ser el<br />
registro <strong>de</strong> canal <strong>de</strong> un timer que no se use)<br />
Fuerza registros A= 0, X= 0. Invalida registro CC<br />
<strong>de</strong><strong>la</strong>y= 4 + CTE2 * 9 + (CTE1-1) * (9*256+3)<br />
(CTE1/2=1..256)<br />
256 => 0 (usar CLRA/X: uno o dos bytes m<strong>en</strong>os)<br />
Fuerza registros A= 0, H= 0, X= 0. Invalida CC.<br />
<strong>de</strong><strong>la</strong>y= 5 + CTE2 * 9 + (CTE1-1) * (9*65536+3)<br />
(CTE1=1..256, CTE2=1..65536)<br />
"dirmem" <strong>de</strong>be estar <strong>en</strong> página 0 (pue<strong>de</strong> ser el<br />
registro <strong>de</strong> canal <strong>de</strong> un timer que no se use)<br />
Dado que no existe una instrucción "TSTHX" para ver si el registro HX, llegó a 0, <strong>en</strong> el código mostrado<br />
se graba el valor <strong>de</strong> los registros H y X <strong>en</strong> una dirección <strong>de</strong> memoria cualquiera para que actualice el<br />
registro <strong>de</strong> condición (<strong>en</strong> particu<strong>la</strong>r el bit Z) y <strong>de</strong>terminar si llegó a 0.<br />
Por supuesto estas no son <strong>la</strong>s únicas formas <strong>de</strong> g<strong>en</strong>erar <strong>de</strong>moras, sino que son algunas que utilizan<br />
muy pocos bytes <strong>de</strong> código (bi<strong>en</strong> siempre escaso!). Des<strong>de</strong> ya, si se le ocurre alguna forma más compacta<br />
<strong>de</strong> g<strong>en</strong>erar un retardo, no du<strong>de</strong> <strong>en</strong> mandarme un e-mail para agregar<strong>la</strong> a <strong>la</strong> lista.<br />
Ejemplos<br />
• Supongamos que t<strong>en</strong>emos que g<strong>en</strong>erar un retardo <strong>de</strong> 1 milisegundo con una frecu<strong>en</strong>cia <strong>de</strong><br />
bus <strong>de</strong> 8 Mhz:<br />
1. Cada ciclo <strong>de</strong> bus correspon<strong>de</strong> a: 1 / 8 Mhz = 0.125 microsegundos.<br />
2. Por lo tanto <strong>la</strong> <strong>de</strong>mora es <strong>de</strong>: 1 milisegundo / 0.125 microsegundos = 8000 ciclos <strong>de</strong> bus.<br />
3. Elegimos <strong>de</strong> <strong>la</strong> tab<strong>la</strong> el m<strong>en</strong>or código para este <strong>de</strong><strong>la</strong>y:<br />
LDA #CTE1<br />
LDX #CTE2<br />
loop: DBNZX $<br />
DBNZA loop<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
;o <strong>en</strong> formato MacAsm:<br />
lda #CTE1<br />
ldx #CTE2<br />
do{<br />
do{<br />
}while( --x != 0 )<br />
}while( --a != 0 )<br />
4. De <strong>la</strong> formu<strong>la</strong>: <strong>de</strong><strong>la</strong>y= 4 + CTE2 * 3 + (CTE1-1) * (3*256+3) (CTE1/2=1..256)<br />
<strong>de</strong>spejamos el valor <strong>de</strong> <strong>la</strong>s constantes:<br />
5. CTE1= ((8000-4)/771)+1= 11.37 => CTE1= 11<br />
CTE2= (8000-4-10*771)/3=95.33 => CTE2= 95<br />
De<strong>la</strong>y= 4+3*95+10*771= 7999<br />
6. En g<strong>en</strong>eral un error <strong>de</strong> 1 <strong>en</strong> 8000 pue<strong>de</strong> ser más que tolerable, pero para lograr el <strong>de</strong><strong>la</strong>y<br />
exacto hay que agregar un "NOP" al final o aum<strong>en</strong>tar CTE2 a 96 y obt<strong>en</strong>er un <strong>de</strong><strong>la</strong>y<br />
<strong>de</strong> 8002 ciclos si el tiempo pedido es el mínimo <strong>de</strong>seado.<br />
• Otros ejemplos los pue<strong>de</strong> <strong>en</strong>contrar <strong>en</strong> <strong>la</strong>s rutinas <strong>de</strong> grabación y borrado <strong>de</strong> <strong>la</strong> FLASH<br />
para el GP32 <strong>en</strong> particu<strong>la</strong>r <strong>la</strong> rutina "DoDe<strong>la</strong>yYStaFLCR" que realiza un <strong>de</strong><strong>la</strong>y <strong>de</strong><br />
3*X ciclos, setea el registro FLCR y produce un <strong>de</strong><strong>la</strong>y extra: cargando los registros A y X<br />
y con un RTS, g<strong>en</strong>erando el "<strong>de</strong><strong>la</strong>y TRCV" (<strong>de</strong> 1 useg.= 8 ciclos) al salir <strong>de</strong> <strong>la</strong> rutina<br />
y precargando registros para usar <strong>en</strong> otras partes <strong>de</strong>l código.<br />
Puerta serie por software<br />
A modo <strong>de</strong> ejemplo se <strong>de</strong>tal<strong>la</strong> a continuación <strong>la</strong>s rutinas para realizar una puerta serie por software a<br />
9600 bauds para frecu<strong>en</strong>cias <strong>de</strong> bus <strong>de</strong> 8MHz y 4MHz <strong>en</strong> un procesador 68<strong>HC908</strong>JL3<br />
(9600 N 8 1 = 8 bits, sin paridad y con 1 bit <strong>de</strong> stop).<br />
Para probar el sigui<strong>en</strong>te código <strong>de</strong>berá conectarse un driver <strong>de</strong> RS232 (tipo MAX232 o simi<strong>la</strong>r)<br />
<strong>de</strong> <strong>la</strong> sigui<strong>en</strong>te forma:<br />
• PORTD.7 a driver TX (salida <strong>de</strong>l micro)<br />
• PORTD.6 a driver RX (<strong>en</strong>trada al micro)<br />
Para seleccionar <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus se utiliza el switch BUS8MEGA (com<strong>en</strong>tar <strong>la</strong> línea que no<br />
corresponda) <strong>de</strong> modo que el código funcione para ambas frecu<strong>en</strong>cias <strong>de</strong> bus (si utiliza otra<br />
frecu<strong>en</strong>cia, <strong>de</strong>berá ajustar <strong>la</strong>s constantes <strong>de</strong> los <strong>retardos</strong>).<br />
El formato serie RS232 utilizado incluye los sigui<strong>en</strong>tes bits a g<strong>en</strong>erar (TX) o leer (RX):<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
Don<strong>de</strong> cada uno <strong>de</strong> los bits dura: 1 / 9600 bauds = 104.16 microsegundos que a 8MHz son 833.33 ciclos<br />
y a 4MHz son 416.66 ciclos.<br />
Transmisión: <strong>la</strong> rutina itera 10 veces para <strong>en</strong>viar los 8 bits, el "start" y el "stop". El bit <strong>de</strong> "start"<br />
es g<strong>en</strong>erado forzando TX a 0 antes <strong>de</strong> <strong>en</strong>trar al loop. El bit <strong>de</strong> "stop" es g<strong>en</strong>erado con <strong>la</strong> instrucción "sec"<br />
para que luego <strong>de</strong>l 8vo bit salga el stop <strong>en</strong> "1".<br />
Las instrucciones que se ejecutan antes <strong>de</strong> <strong>en</strong>trar al <strong>la</strong>zo (psha, pshx, ldx) <strong>de</strong>moran 6 ciclos al igual<br />
que <strong>la</strong>s que hay <strong>en</strong>tre que se setea el bit a transmitir y se vuelve a iterar (bra o brn y dbnzx),<br />
lo cual asegura que los anchos <strong>de</strong> todos los bits sean iguales. Estos 6 ciclos más los <strong>de</strong> <strong>la</strong>s operaciones<br />
<strong>de</strong>l <strong>la</strong>zo (sin contar el <strong>de</strong><strong>la</strong>y) suman 21 ciclos. Por lo tanto los <strong>de</strong><strong>la</strong>ys <strong>de</strong> ajustan para que <strong>de</strong>mor<strong>en</strong> 812<br />
o 316 ciclos y obt<strong>en</strong>er así los 833 o 417 ciclos totales por bit.<br />
Recepción: <strong>la</strong> rutina espera "eternam<strong>en</strong>te" a que baje RX (comi<strong>en</strong>zo <strong>de</strong>l bit <strong>de</strong> "start") y realiza un<br />
<strong>de</strong><strong>la</strong>y inicial <strong>de</strong> 1 bit y medio, esto es todo el bit <strong>de</strong> "start" y medio "D0", <strong>de</strong> forma <strong>de</strong> leer los bits <strong>en</strong><br />
su c<strong>en</strong>tro para obt<strong>en</strong>er una mayor inmunidad a <strong>la</strong>s variaciones <strong>de</strong> cristal <strong>de</strong>l transmisor y <strong>de</strong>l procesador.<br />
La rutina luego lee los 8 bits e "ignora el stop" (esto es para utilizar ese tiempo para procesar el caracter<br />
recibido, ya que inmediatam<strong>en</strong>te luego <strong>de</strong>l "stop" pue<strong>de</strong> v<strong>en</strong>ir otro "start"). La rutina pres<strong>en</strong>tada no es<br />
óptima <strong>de</strong>s<strong>de</strong> el punto <strong>de</strong> vista <strong>de</strong>l filtrado <strong>de</strong> <strong>la</strong>s lecturas (sólo realiza una lectura por bit). No le<br />
incorporé filtrado mediante varias lecturas para mant<strong>en</strong>er el código lo más c<strong>la</strong>ro posible pero pue<strong>de</strong><br />
agregarlo dividi<strong>en</strong>do el tiempo <strong>de</strong> iteración, por ejemplo, a <strong>la</strong> décima parte, realizando 10 lecturas<br />
y <strong>de</strong>terminando si es "1" o "0" según <strong>la</strong> mayor cantidad <strong>de</strong> lecturas obt<strong>en</strong>idas.<br />
;$SET BUS8MEGA ;BUS <strong>de</strong> 8 MHZ requiere cristal <strong>de</strong> 32MHZ<br />
$SETNOT BUS8MEGA ;BUS <strong>de</strong> 4 MHZ requiere cristal <strong>de</strong> 16MHZ<br />
;==============================================================================<br />
; TXByte:<br />
; Transmite un byte por <strong>la</strong> puerta serie simu<strong>la</strong>da a 9600 (como caracter)<br />
; REQUIERE BUS <strong>de</strong> 8 MHZ. (<strong>de</strong><strong>la</strong>y= 833 ciclos x bit)<br />
; o BUS <strong>de</strong> 4 MHZ. (<strong>de</strong><strong>la</strong>y= 416-417 ciclos x bit)<br />
;<br />
; Requiere:<br />
; A= byte a <strong>en</strong>viar. (MANTIENE A,X,H)<br />
;==============================================================================<br />
TxByte:<br />
sei ;TAPA INTS (para no arruinar tiempos)<br />
sta COPCTL ;reset COP<br />
bclr 7,PORTD ;TX=0 (START)<br />
psha ;manti<strong>en</strong>e A y X<br />
pshx<br />
ldx #!10 ;X=numero <strong>de</strong> bits a <strong>en</strong>viar<br />
do{<br />
pshx<br />
$IF BUS8MEGA<br />
ldx #!203 ;<strong>de</strong><strong>la</strong>y= 812 + 21= 833<br />
do{<br />
nop<br />
}while( --x != 0 ) ;DELAY= X * 4 ciclos<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
$ELSEIF<br />
ldx #!132 ;<strong>de</strong><strong>la</strong>y= 396 + 21= 417<br />
do{<br />
}while( --x != 0 ) ;DELAY= X * 3 ciclos<br />
$ENDIF<br />
pulx<br />
sec ;CY=1 (STOP)<br />
rora ;<strong>en</strong>via bits 0,1,2... al carry<br />
if( cy == 1 ){ ;hace TX= CY<br />
bset 7,PORTD ;TX=1<br />
}else{<br />
bclr 7,PORTD ;TX=0<br />
brn $ ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 3 ciclos (igual al branch <strong>de</strong>l else)<br />
}<br />
}while( --x != 0 )<br />
pulx<br />
pu<strong>la</strong><br />
cli ;DESTAPA INTS<br />
sta COPCTL ;reset COP<br />
rts<br />
;==============================================================================<br />
; RXByte:<br />
; Espera y RECIBE un byte por <strong>la</strong> puerta serie.<br />
; Espera INFINITA.<br />
;<br />
; Requiere:<br />
; OUT: A= byte recibido. (MANTIENE H,X)<br />
;==============================================================================<br />
RXByte:<br />
pshx ;salva X<br />
sei ;TAPA INTS (para medir los bits)<br />
do{<br />
sta COPCTL ;reset COP<br />
}while( PORTD.6 == 1 ) ;espera el START<br />
$IF BUS8MEGA<br />
ldx #!249 ;espera tiempo <strong>de</strong> 1+1/2 bit= 1251 ciclos<br />
do{<br />
sei ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 2 ciclos<br />
}while( --x != 0 )<br />
$ELSEIF<br />
ldx #!206 ;espera tiempo <strong>de</strong> 1+1/2 bit= 625 ciclos<br />
do{<br />
}while( --x != 0 )<br />
$ENDIF<br />
lda #$80 ;<strong>de</strong>tecta RX completa (8bits)<br />
while(1){<br />
if( PORTD.6 == 0 ){ ;CY=DATA BIT<br />
}<br />
rora<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar
Dto. Técnico EduDevices www.edu<strong>de</strong>vices.com.ar<br />
if( cy == 1 ){ ;ya leyo los 8 (ignora el STOP)<br />
cli ;DESTAPA INTS<br />
pulx ;manti<strong>en</strong>e X<br />
sta COPCTL ;reset COP<br />
rts<br />
}<br />
$IF BUS8MEGA<br />
ldx #!205 ;espera tiempo <strong>de</strong> 1 bit= 834 ciclos<br />
do{<br />
nop<br />
}while( --x != 0 ) ;205x4= 820<br />
$ELSEIF<br />
ldx #!134 ;espera tiempo <strong>de</strong> 1 bit= 416 ciclos<br />
do{<br />
}while( --x != 0 ) ;134x3= 402<br />
$ENDIF<br />
} ;leer otro bit<br />
Pue<strong>de</strong> <strong>de</strong>scargar el ejemplo <strong>de</strong> <strong>la</strong> puerta serie para <strong>HC908</strong>JL3 que incluye el uso <strong>de</strong> <strong>la</strong><br />
memoria FLASH para grabar<strong>la</strong> <strong>de</strong> a 1 byte por vez. El archivo ZIP ti<strong>en</strong>e el código <strong>en</strong> formato MacAsm<br />
(archivo MAS) y ya preprocesado (archivo ASM) al igual que todos los programas necesarios para usar<br />
el utilitario.<br />
El código <strong>de</strong> ejemplo <strong>en</strong>vía por <strong>la</strong> puerta serie: "Ho<strong>la</strong> mundo!", borra una página <strong>de</strong> FLASH (64 bytes),<br />
graba el string "HOLA" <strong>en</strong> <strong>la</strong> FLASH y transmite lo grabado (<strong>de</strong>bería ser: "HOLA"),<br />
luego se pone <strong>en</strong> modo "eco" (repite todo lo que recibe).<br />
Conclusión<br />
En el pres<strong>en</strong>te artículo se han visto distintas formas <strong>de</strong> g<strong>en</strong>erar <strong>retardos</strong> mediante instrucciones.<br />
La lista pres<strong>en</strong>tada está lejos <strong>de</strong> ser exhaustiva ya que cualquier código realiza una <strong>de</strong>mora<br />
al ejecutarse y <strong>de</strong>p<strong>en</strong>di<strong>en</strong>do <strong>de</strong> <strong>la</strong> aplicación particu<strong>la</strong>r pue<strong>de</strong> que un método sea mejor que otro.<br />
Por ejemplo <strong>en</strong> <strong>la</strong> nota <strong>de</strong> aplicación AN1831 <strong>de</strong> Freescale se pue<strong>de</strong> observar el código <strong>de</strong> <strong>la</strong><br />
ROM <strong>de</strong> los procesadores <strong>HC908</strong> mo<strong>de</strong>los GR8, KX8, JL3, JK3 y JB8 que para obt<strong>en</strong>er los <strong>de</strong><strong>la</strong>ys<br />
<strong>de</strong> grabación y borrado <strong>de</strong> <strong>la</strong> FLASH ajustados con una única constante a <strong>la</strong> frecu<strong>en</strong>cia <strong>de</strong> bus,<br />
todos los <strong>de</strong><strong>la</strong>y se g<strong>en</strong>eran <strong>en</strong> base a <strong>la</strong> rutina "DELNUS" (que produce un <strong>de</strong><strong>la</strong>y <strong>de</strong> X * 12 microseg),<br />
lo cual requiere más código que ajustar <strong>la</strong>s rutinas para una frecu<strong>en</strong>cia <strong>de</strong> bus <strong>en</strong> particu<strong>la</strong>r,<br />
pero es más flexible (opción correcta para una ROM).<br />
Para verificar que los ciclos <strong>de</strong> <strong>la</strong>s instrucciones correspon<strong>de</strong>n con lo calcu<strong>la</strong>do, convi<strong>en</strong>e activar<br />
<strong>la</strong> opción "ver cu<strong>en</strong>ta <strong>de</strong> ciclos" <strong>en</strong> el <strong>en</strong>samb<strong>la</strong>dor para que g<strong>en</strong>ere un archivo <strong>de</strong> listado como<br />
el que se ve a continuación (con <strong>la</strong> opción "C" <strong>en</strong> <strong>la</strong> línea <strong>de</strong> comandos <strong>de</strong> "CASM08Z.EXE" o marcando <strong>en</strong> WIN<br />
IDE: "Show Cycles in Listing" <strong>de</strong>ntro <strong>de</strong> "Setup Environm<strong>en</strong>t..") :<br />
....<br />
EC58 [04] 1F03 201 bclr 7,PORTD ;TX=0<br />
EC5A [03] 21FE 202 brn $ ;<strong>de</strong><strong>la</strong>y <strong>de</strong> 3<br />
Ing. Daniel Di Lel<strong>la</strong>: - Dedicated Field Application Engineer e-mail: dilel<strong>la</strong>@arnet.com.ar