Mostrando entradas con la etiqueta Instrucciones. Mostrar todas las entradas
Mostrando entradas con la etiqueta Instrucciones. Mostrar todas las entradas

martes, 21 de enero de 2020

Uso de la instrucción "LD" y "ST"

LD(Load Indirect from SRAM(data Space) To Register using Index Y,X

  • Se carga Rd con el contenido que apunta el registro apuntador Y.
  • Carga indirecta del espacio de datos hacia Rd.

Instrucción LD
Como pueden ver  esta instrucción es muy similar a la instrucción LDS, pero ahora vemos que usa el registro Y(16 bits), éste registro Y, la cual  se usa como apuntador de dirección.

Descripción y puntos importantes.

  •  Para usar esta instrucción se debe cargar previamente el apuntador Y, ya que según  la dirección que este apuntado "Y" va a mover el dato que esta en esta dirección y la colocará en Rd .
  • En algunos casos en vez de "Y" encontraremos "Y+" o "-Y" , eso quiere decir que cuando se ejecute la instrucción va a aumentar o disminuir este registro apuntador"Y" de 16 bits.
  • Esta instrucción no la cuenta todos los microcontroladores ATMEL
  • Para algunos microcontroladores ATMEL que solo tienen 256Bytes de memoria solo es suficiente usar 8 bits(los menos significativos).
  • Para microcontroladores ATMEL con mayor memoria de datos ya se usan los 16 bits.
  • Recordemos que  la pila se ubica en la SRAM interno y su inicio es la última dirección de memoria, para el caso del Atmega32 la última dirección(RAMEND) es 0x85F.
  • Se pueden usar los punteros X,Y, los dos  de 16 bits.
  • Debemos tener en cuenta que el puntero X esta formado por los registros R26,R27, el puntero Y está formado por los registros R28,R29 y finalmente el puntero Z esta formado por los registros R30,R31, como se muestra en la siguiente imagen:
Punteros

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
Agregar el contenido de la ubicación de la dirección de 0X1F(Correspondiente a R31) hacia el registro R16.
Código
Este es un método indirecto de cargar valores dentro la memoria de datos según la dirección que deseemos  de SRAM hacia la misma SRAM. 
Debug
------------------------------------------------------------------------------------------------------------------------------------------------------
ST(Store Indirect From Register to Data Space using index X,Y

  • Se carga el valor de la dirección apuntada por  Y con el contenido de Rr, 0<=r<=31
  • Carga indirecta de Rr  hacia la dirección de SRAM apuntada por Y.
Instrucción ST
  • Como pueden ver  esta instrucción es muy similar a la instrucción STS, pero ahora vemos que usa el registro Y(16 bits), éste registro Y, la cual  se usa como apuntador de dirección.
  • Como se observa este es el proceso inverso de la instrucción LD.
  • En algunos casos en vez de "Y" o "X" encontraremos "Y+" ,"-Y","X+","-X" , eso quiere decir que cuando se ejecute la instrucción va a aumentar o disminuir este registro apuntador"Y" o "X" de 16 bits.

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
Agregar el contenido de la ubicación del registro R16 hacia la dirección de X.
------------------------------------------------------------------------------------------------------------------------------------------------------

Código

Este es un método indirecto de cargar valores dentro la memoria de datos según la dirección que deseemos  de SRAM hacia la misma SRAM. 
Debug
------------------------------------------------------------------------------------------------------------------------------------------------------

lunes, 4 de febrero de 2019

Instrucción SBRC y SBRS

SBRS(Skip if Bit in Register is Set)
Esta instrucción testea un bit de un registro y salta la siguiente instrucción si el bit es 1
Instrucción SBRS
SBRS Rr,b 0 ≤ r ≤ 31, 0 ≤ b ≤ 7
 
SBRC(Skip if Bit in Register is Clear)
Esta instrucción testea un bit de un registro y salta la siguiente instrucción si el bit es 0
Instrucción SBRC
SBRS Rr,b 0 ≤ r ≤ 31, 0 ≤ b ≤ 7
Ejemplo-Instrucción sbrc

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
;Corrimiento de leds de 0-8, si se presiona el pulsador del pin pd7 se encienden todos los leds, si se deja de presionar el corrimiento sigue en el valor último que se dejó antes de presionar el pulsador.
------------------------------------------------------------------------------------------------------------------------------------------------------
Procedimiento de corrimiento de leds

Procedimiento de encendido de leds-pulsador presionado
código completo

domingo, 3 de febrero de 2019

Instrucción LPM(Load Program Memory)


La instrucción LPM son las iniciales de "Load Program Memory" que quiere decir que va a cargar en un registro Rd el valor de un byte de dato del Flash Program Memory.

3 maneras de leer dato de program memory a un registro:
  • LPM;                Carga un Byte apuntado por Z a R0.
  • LPM Rn,Z;       Carga un Byte apuntado por Z hacia Rn(R0-R31).
  • LPM Rn,Z+;     Igual que los anteriores pero se incrementa Z despues de cargar el Byte.
Cuando se usa LPM, el registro Z debe contener la dirección de byte de los datos.

>>LPM R16,Z;--->va a cargar a en R16 un dato de flash program memory apuntado por Z.
LPM Instruction
Lo que hace posible que podamos acceder a los 16kword  de direcciones es el PC(Program Counter), por ejemplo nuestro atmega32 tiene un PC de 14 bits, eso significa que podemos acceder a 2^14 direcciones que es equivalente a 16384 direcciones(0--16383)=16k 

En la siguiente imagen se puede observar mejor como funciona la Instrucción LPM.
LPM Instruction
Ejemplo de uso
Ejemplo de uso 2

¿Por qué *2 ó <<1?


Como pueden ver en la primera imagen, la memoria de programa está organizada en words de 16 bit y el bit menos significativo del puntero Z selecciona si se elegirá el byte bajo (0) o el byte alto (1). Según lo anterior tenemos 15 bits para apuntar a cualquier dirección de flash  y 1 bits(LSB) para ELEGIR LA MANERA QUE SE VA A ACCEDER(SEA LA PARTE BAJA O LA PARTE ALTA).
Esta instrucción puede dirigirse a los primeros 2^15 direcciones word = 32768 word= 32KBytes de memoria de programa. 

Para que sepas como se guardan los datos en flash te recomiendo que leas el tutorial que realicé tiempo atrás, su nombre es "Ubicando código en la memoria FLASH-ROM". 
Una vez que ya has leído te darás cuenta como se guarda cada instrucción de código en flash, en la cual se resumen a la manera de guardar opcodes y operandos, cada línea de código son 16 bits y es porque el ancho de la menoría flash es de 16 bits.


En esta primera tabla se muestran los posibles valores que tomará Z(en binario) cuando apunta a N dirección.

Valores de Z(en binario)

Para leer el byte bajo de cada  ubicación de memoria de flash nosotros debemos desplazar la dirección 1 bit a la izquierda y colocar un 0 lógico.
Para leer el byte alto de cada  ubicación de memoria de flash nosotros debemos desplazar la dirección 1 bit a la izquierda y colocar un 1 lógico.
Por ejemplo :
Para acceder al byte bajo de la ubicación 0b0000_0101, debemos de cargar a Z con  0b000_1010.
Para acceder al byte alto de la ubicación  0b0000_0101, debemos de cargar a Z con  0b000_1011.
Para acceder al byte bajo de la ubicación 0b0000_0011, debemos de cargar a Z con  0b000_0110.
Para acceder al byte alto de la ubicación  0b0000_0011, debemos de cargar a Z con  0b000_0111.
En código acceder a la parte baja sería:
                   LDI ZH, HIGH(ADDRESS FLASH<<1)
                                                            LDI ZL,  LOW(ADDRESS FLASH<<1) 
En código acceder a la parte alta sería:
                      LDI ZH, HIGH(ADDRESS FLASH<<1|1)
                                                            LDI ZL,  LOW(ADDRESS FLASH<<1|1) 

La tabla de los posibles valores de Z en valores hexadecimales serían como se muestra en la siguiente imágen:


  • EJEMPLOS:
  • Si queremos apuntar a la parte baja de la dirección flash(16 bits)=0x0002 --> Z =  0x0004. 
  • Si queremos apuntar a la parte alta de la dirección flash(16 bits)=0x0002 -->  Z =  0x0005.
  • Si queremos apuntar a la parte baja de la dirección flash(16 bits)=0x0005 --> Z =  0x000A. 
  • Si queremos apuntar a la parte alta de la dirección flash(16 bits)=0x0005 -->  Z =  0x000B. 

Volvamos a nuestro ejemplo, al momento de cargar la dirección de TABLE se le desplaza 1 bit a la izquierda, con el fin de que LSB sea cero, de esa forma cargo el Byte bajo.
                    LDI ZH, HIGH(TABLE<<1)
                    LDI ZL,  LOW(TABLE<<1)
Por ejemplo si dirección de TABLE es 1111111100000111(16 bits) al desplazar un bit a la izquierda sería 1111111000001110 de esa manera indico que estoy apuntando al Byte bajo para ser leído.
Algunos en vez de desplazar un bit a la izquierda prefieren multiplicarlo *2 que el resultado es el mismo, por ello también es válido haber usado:
                    LDI ZH, HIGH(TABLE*2)
                    LDI ZL,  LOW(TABLE*2)

  • Existe un "puente" entre el bus de datos de la memoria de programa y el bus de datos de la memoria de datos y esto se hace a traves de la instrucción LPM.
  • Para acceder a un byte de la memoria del programa se usa el registro Z, que contendrá su dirección. 
  • El bit 0 del registro Z selecciona el byte alto o bajo de la palabra de 16 bits elegida que se vuelca en R0 u otro registro.
  • La instrucción LPM se usa cuando se usan tablas.
  • La memoria de programa(ROM CODE) es parte de memoria Flash.
  • Cuando se apunta a una dirección de flash para leer el valor de dicha dirección se realiza pensando apuntando a su parte baja o alta de tal dirección.

fuente,fuente2

jueves, 22 de noviembre de 2018

Uso de la instrucción "LDS" y "STS"

LDS(Load Direct from SRAM(data Space)
Se carga Rd con el contenido de lo que está en la dirección K.
Carga Directa del espacio de datos hacia Rd.

Instrucción

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
;Agregar el contenido de la ubicación de memoria 0x300 hacia la ubicación de memoria 0x302.
------------------------------------------------------------------------------------------------------------------------------------------------------
Código





Importante

Los datos que puedo copiar a través de sus direcciones puede ser cualquier datos de la  SRAM( registros SFRs(I/O registers), SRAM interna o incluso datos de GPRs). es decir hay tres opciones de uso de LDS:
  • Opción1: de SRAM interna a GPRs
      • LDS R20, 0x300,se sabe que direcciones[0x0060,.....,0x045F] le corresponde a datos de SRAM interna.
  • Opción2: de I/O registers a GPRs
      • LDS R20, 0x20 ,se sabe que direcciones[0x0020,.....,0x005F] le corresponden a registros SFRs[TWBR,......,SREG]
  • Opción3: de GPRs a GPRs
      • LDS R20,0x1; R20=R1, se sabe que direcciones [0,.....,1F]  le corresponden a registros de datos [R0,......,R31]
Las direcciones variaran según el microcontrolador AVR que se use, pero la manera de utilizar LDS es la misma.
Haremos mención a la última opción de uso de la LDS:

LDS R20,0x1 ; instrucción copiará el contenido de la ubicación1 (en hexadecimal) dentro de R20, Como sabemos la ubicación o dirección 1 es la memoria de datos es parte de GPRs y la dirección le corresponde a R1, así la instrucción copia R1 a R20.

STS(Store Direct to SRAM)

Almacenamiento Directo hacia el SRAM(espacio de datos)
Guarda un valor en una ubicación de memoria.
Store Rr a ubicación de memoria k.
Instrucción===> STS dirección donde se va a almacenar, el valor a almacenar.
Instrucción
Ejemplo
---------------------------------------------------------------------------------------------------------------------
; cuando el pinb,0 =0 se guarda en la dirección 0x0200 el valor de 0x55
;cuando el pinb,0=1 se guarda el la dirección 0x0200 el valor de 0x10
---------------------------------------------------------------------------------------------------------------------
Guarda el dato 0x55

Guarda el dato 0x10


Diagrama de flujo

Memory

USO DE STS PARA CARGAR REGISTROS DENTRO DE  GPRS

Como podemos ver en la gráfica los registros GPRS forman parte de las primeras direcciones de la memoria de datos.  
Memoria de datos
sus direcciones son:
R0<-0x0000  -  R1<-0x0001  -  R2<-0x0002  -  R3<-0x0003  -  R4<-0x0004
R5<-0x0005  -  R6<-0x0006  -  R7<-0x0007  -  R8<-0x0008  -  R9<-0x0009
R10<-0x000A  -  R11<-0x000B  -  R12<-0x000C  -  R13<-0x000D  -  R14<-0x000E
R15<-0x000F  -  R16<-0x0010  -  R17<-0x0011  -  R18<-0x0012  -  R19<-0x0013  R20<-0x0014  -  R21<-0x0015  -  R22<-0x0016  -  R23<-0x0017  -  R24<-0x0018  R25<-0x0019  -  R26<-0x001A  -  R27<-0x001B  -  R28<-0x001C  -  R29<-0x001D
R30<-0x001E  -  R31<-0x001F

EJEMPLO:
Deseamos guardar en R17 el valor del registro R16. Como sabemos R17 esta en la dirección 0x0011 y R16 se encuentra en la dirección 0x0010.

                                                                                                   Código

                                                                                  Debug

Detalles a tomar en cuenta al usar estos comandos(LDS y STS):
  1. Para ejecutar el comando LDS o STS el CPU utiliza 2 ciclos de maquina.
  2. LDS y STS son instrucciones que ocupan mas código en memoria de programa ya que por ejemplo para pasar datos a una dirección determinada, primero debemos cargar el dato a un registro GPRs y luego recién cargamos a alguna dirección de memoria SRAM.
  3. Trabajar con direcciones y no con nombres es poco tedioso al trabajar.
  4. Las instrucciones LDS y STS no están disponibles en algunos AVRs y eso debemos tener en cuenta si se desea utilizar.



miércoles, 21 de noviembre de 2018

Uso de las instrucciones "BRNE" y "BREQ"

BRNE(Branch if not equal)
Branch if Flag Z=0

BREQ(Branch if equal)
Branch if Flag Z=1

Flag Z
Se pone a 1 cuando una operación lógica o aritmética da cero como resultado.
Se pone a 0 cuando una operación lógica o aritmética da distinto de cero como resultado.

Branch if la variable(de la instrucción anterior) no es igual a cero.

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
El objetivo de este ejemplo es agregar 3 unidades a r20 10 veces y enviar la suma total al puerto B.
-----------------------------------------------------------------------------------------------------------------------------------------------------

Código
al final de haber pasado los 10 veces el valor de R20 es 30 (0x1E) reflejada en el puertob
Diagrama de Flujo

domingo, 18 de noviembre de 2018

Uso de la instrucción "IN","OUT"

IN( IN from I/O location)

Carga el dato de las ubicaciones de la dirección SFRs-A[I/O(puertos, Timers,Configuration, etc)] hacia registro Rd[GPRs]. A es un byte(8 bits).
Instrucción IN

Trabajar con los registros de entrada salida(I/O) es mas facil, nosostros podemos usar sus nombres en lugar de sus direcciones (I/O). 

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
;Cargar en R19 el contenido de PIND.
------------------------------------------------------------------------------------------------------------------------------------------------------
IN R19,$030; Se carga R19 con PIND, usando la direccion del registro.
IN R19,PIND; Se carga R19 con PIND,usando el nombre del registro.

Acceso a SFRs usando sus nombres.
OUT( OUT TO I/O location)
Carga un registro GPRs(R0-R31) hacia un Registro SFRs A[I/O(puertos, Timers,Configuration, etc)].

Instrucción OUT
Los registros I/O son referidos por sus direcciones I/O. 

La instrucción "OUT" realiza la operación contraria de la instrucción "IN".

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
; Copiar PIND hacia PORTA.
------------------------------------------------------------------------------------------------------------------------------------------------------

IN R0,PIND; Se carga R0 con PIND, usando la direccion del registro.
OUT PORTA ,R0; Se carga PORTB con el valor de R0.



Uso de "SBI" y "CBI"

SBI(Set Bit in I/O Register)
Coloca el nivel alto(setea) a un bit de un registro de entrada/salida.

CBI(Clear Bit in I/O Register)
Coloca el nivel bajo(limpia) a un bit de un registro de entrada/salida.

Ejemplo

------------------------------------------------------------------------------------------------------------------------------------------------------
El objetivo de este ejemplo es leer el estado de un bit mediante un switch conectado por el pin PB0 y un led en el pin PB7 que reflejará el estado del PB0.
-----------------------------------------------------------------------------------------------------------------------------------------------------

Código
SBIS=1,SBI portb,7

SBIS=0,CBI portb,7
Diagrama de Flujo
Implementación

sábado, 17 de noviembre de 2018

Uso de la instrucción "SBIC"

SBIC(Skip if Bit in I/O register Cleared)
Esta instrucción permite monitorear el estado de un bit, salta a la siguiente instrucción del código si en el bit del registro es detectado el estado bajo("0").
Esta instrucción trabaja con registros I/O.

Instrucción SBIC
I/O R ≤ 31, 0 ≤ b ≤ 7
Ejemplo:
un switch es conectado a pinb2. Escribir un programa que chequee el estado del switch y ejecute lo siguiente:
  • Si pinb,2=1 enviar la letra "00000000" al puerto D.
  • Si pinb,2=0 enviar la letra "11111111" al puerto D.
Código
Pinb,2=0
Pinb,2=1

En este programa el bucle led_encendido esta en lazo cerrado siempre cuando(pinb2=0) es decir después que se ejecute la instrucción sbic pinb,2 va a ver un salto de linea a la siguiente instrucción de código y de esta manera se omite(rjmp) la bifurcación para salir del bucle y además se carga el valor de 255 y luego se escribe en el puerto D. 
Cuando hay bifurcación(rjmp) se carga el valor de 0 y se escribe en el puerto D



Diagrama de flujo

Implementación

miércoles, 14 de noviembre de 2018

Uso de la instrucción "SBIS"

                                                SBIS(Skip if Bit in I/O register Set)
Esta instrucción permite monitorear el estado de un bit, salta a la siguiente instrucción del código si en el bit del registro es detectado el estado alto("1").
Esta instrucción trabaja con registros I/O.
Instrucción SBIS
I/O R ≤ 31, 0 ≤ b ≤ 7
Código.
En este programa el bucle inicio esta en lazo cerrado siempre cuando(pinb2=1) es decir después que se ejecute  la instrucción sbis pinb,2 va a ver un salto de linea a  la siguiente instrucción de código y de esta manera se omite(rjmp) la bifurcación para salir del bucle y además se carga el valor de 255 y luego se escribe en el puerto D. 
Cuando hay bifurcación(rjmp)  se carga el valor de 0 y se escribe en el puerto D.

pinb2=0. 
pinb2=1


Diagrama de flujo.
Implementación.