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

Big Endian Vs Little Endian

Es simple aunque no es común escuchar sobre esto.
La diferencia entre uno y otro es el orden en que los datos son guardados en las celdas de memoria. 
Para ayudar a entender la diferencia entre Big Endian y Little Endian, veremos  más de cerca cómo se almacenan los datos en la memoria.

Almacenamiento de datos-Sistema Little Endian


Los procesadores  Intel x86,DEC alpha,VAX,AMD siguen este sistema al alamcenar datos en memoria.
Sistema Little Endian 
El byte menos significativo(OD) se guarda en el byte de orden mas bajo.

Almacenamiento de datos-Sistema Big Endian


Los procesadores  MIPS, Sparc,Motorola 6800/68k,IBM 360/370 siguen este sistema al alamcenar datos en memoria.
Sistema Big Endian

Almacenamiento en AVR-Sistema Little Endian

Tabla de datos con  Word(.DB-Data Byte)

Si deseamos guardar el dato 0x3F06 a la memoria, y como el valor está en una tabla tipo .DB(Data Byte-cada  entrada es de 1 byte) como almaceno el datos en dirección que es de tamaño de una palabra??, pues el proceso es el siguiente:

Almacencamiento en AVR-
Donde 06 es el byte menos significativo del dato,06 es guardado en el byte más alto de la dirección y 3F que es el byte mas significativo del dato se guarda en el byte mas bajo de la dirección . Como se puede ver el almacenamiento de los datos sigue al modelo de sistema Little Endian.

Cada dirección de memoria esta formado puede almacenar 1 palabra(16 bits) se puede mandar a guardar por cada byte(.DB) o se puede mandar a guardar por cada palabra(.DW) 

Tabla de datos con  Word(.DW-Data Word)

  • Si mandamos el dato 0x0400(word) este dato se divide en 2 byte y se guarda en 27D como 00 04.
  • Si mandamos el dato 0x1000(word) este dato se divide en 2 byte y se guarda en 27E como 00 10.
  • Si mandamos el dato 0x0D01(word) este dato se divide en 2 byte y se guarda en 27F como 01 0D.
  • Si mandamos el dato 0x0802(word) este dato se divide en 2 byte y se guarda en 280 como 02 08.
  • Si mandamos el dato 0x0104(word) este dato se divide en 2 byte y se guarda en 281 como 04 01.
.....
Y así se van guardando los datos en la memoria, la forma de almacenamiento es porque el AVR sigue el modelo de Little Endian.


Tabla .DW(Data Word)

Pero para que necesitamos saber esto??????.
Pues es bueno saber que orden sigue nuestros datos en nuestro avr, sabiendo esto sabremos como recuperar nuestros datos guardados y otras ventajas más que iremos descubriendo.

Tienes alguna duda de este tema, o ¿de qué otros temas quieres que hablemos?, puedes escribirnos a nuestro grupo de Telegram

sábado, 2 de febrero de 2019

Registro de trabajo y Punteros X,Y,Z

Todos los microcontroladores AVR de 8 bits, desde los ATtiny, ATmega y ATxmega tienen 32 registros de trabajo que van desde R0 a R31. Los Registros de Trabajo tienen la función de alojar los datos más inmediatos que el CPU procesa.

A continuación se puede notar, los registros de trabajo. Estos estan divididos de 16 en 16. La diferencia se encuentra en que los 16 primeros (R0-R15) no permiten el uso de la instrucción LDI, que sirve para cargar constantes al registro. Los registros (R16-31), si admiten el LDI, y por general son los más utilizados por este motivo.

Los registros (R26-R31) pueden adicionalmente funcionar como punteros de 16 bits cada uno.
Registros de trabajo-punteros.
  • El puntero X esta formado por los registros R26,R27.
  • El puntero Y esta formado por los registros R28,R29.
  • El puntero Z esta formado por los registros R30,R31.

Los punteros pueden apuntar a (contener la dirección de) cualquier locación del espacio de RAM. Esto junto con las instrucciones adecuadas conforman el direccionamiento indirecto más potente, muy útil por ejemplo para mover grandes bloques de datos.
Punteros o Apuntadores

  • El AVR tiene los tres últimos pares de registros internos del procesador son usados como punteros de 16 bits al espacio de memoria externa, bajo los nombres X, Y y Z. Esto es un compromiso que se hace en arquitecturas de 8 bits desde los tiempos de Intel 8008.
  • Una palabra(word) esta formada por 16 bits.
PunteroS a SRAM(modo indirecto)
El puntero Z es el único que puede apuntar a la memoria FLASH utilizando la instrucción LPM Y SPM. En este ejemplo se muestra la memoria flash de un Atmega 32.
Apuntamiento a la memoria FLASH

Uso del firmware original de la grabadora USBasp AVR en MX-USBASP (clon chino)

Te vendieron un USBisp pensado que es un USBasp?? Hace 2 meses compré un "USBasp" fui a probarlo y no funcionó....pensé me estafar...