martes, 5 de septiembre de 2017

Solucionado: The selected compiler 'Arduino AVR' is not installed

Si estamos desarrollando un proyecto de Arduino en Proteus y a la hora de construir el código del proyecto nos da el error “The selected compiler 'Arduino AVR' is not installed” es porque no tenemos correctamente configurado el compilador Arduino AVR:


Para configurar correctamente el compilador vamos a System-> Compilers Configurations:


Tras esto, se nos abre el apartado de configuración de los compiladores. Lo más probable es que no tengamos instalado el compilador de Arduino, en cuyo caso solo tendremos que pinchar en Download y éste comenzará a descargarse y se instalará automáticamente. Si conocemos que ya lo tenemos instalado en nuestro ordenador, solo tendremos que indicarle la ruta donde lo tenemos instalado:


Una vez instalado/configurado, si recompilamos el proyecto veremos que ahora nos compila correctamente:


lunes, 21 de agosto de 2017

Recalbox: Configurar wifi con IP estática

Recalbox es un sistema operativo para Raspberry Pi basado en Debian que, tras instalarlo, nos ofrece un entorno completamente configurado para jugar a juegos retro (nes, mega drive,...etc) y para disponer de un media center como Kodi, entre otros.
A continuación, voy a indicar los pasos que tenemos que realizar para configurar la wifi en un Recalbox con IP fija para una red encriptada con WPA2.
En primer lugar, tenemos que acceder a la consola del sistema operativo. Para ello solo tenemos que pulsar alt+F4 y a continuación pulsar alt+F2.
Tras lo anterior, realizamos login con el usuario root cuya contraseña por defecto es recalboxroot .
Una vez que estamos logados en el sistema, tenemos que poner el sistema de ficheros en modo lectura y escritura porque por defecto Recalbox lo arranca con permisos solo de lectura. Para realizar este cambio lanzamos el siguiente comando:

mount -o rw,remount /

Después de esto configuramos las interfaces y para ello en Recalbox hay 2 ficheros que contienen la configuración de estas, el fichero /etc/network/interfaces y el /etc/network/interfaces.base. El fichero interfaces contiene la configuración que actualmente se está aplicando en nuestro sistema y el fichero interfaces.base contiene la configuración base de las interfaces. Ésta configuración base es la que utiliza el sistema por defecto porque cuando se levanta, vuelca el contenido del fichero interfaces.base en el fichero interfaces. Por esto, si nosotros cambiamos solo el fichero interfaces, cuando el sistema se reinicie nuestros cambios se perderán y serán sustituidos por el contenido del fichero interfaces.base.
Como en mi caso solo uso Recalbox mediante wifi, el apartado auto eth0 correspondiente a la interface ethernet en ambos ficheros estará como viene por defecto. La configuración de la interfaz wifi wlan0 que yo he configurado tiene la IP 10.0.100.40, la máscara de red 255.255.255.0, la puerta de enlace por defecto 10.0.100.1 y coge la información característica de la red, tales como el ssid, la clave psk,...etc del fichero /etc/wpa_supplicant/wpa_supplicant.conf. A continuación muestro como quedan tanto el fichero interfaces como el fichero interfaces.base (tendrán el mismo contenido):

> nano /etc/network/interfaces

# Configure Loopback
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto wlan0
iface wlan0 inet static
address 10.0.100.40
netmask 255.255.255.0
gateway 10.0.100.1
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf


> nano /etc/network/interfaces.base

# Configure Loopback
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
auto wlan0
iface wlan0 inet static
address 10.0.10.40
netmask 255.255.255.0
gateway 10.0.10.1
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf


Una vez que tenemos las interfaces correctamente configuradas pasamos a configurar el contenido del fichero /etc/wpa_supplicant/wpa_supplicant.conf que contiene la configuración especifica de la wifi a la que nos vamos a conectar. A continuación pongo el contenido que tiene que tener este fichero tanto para redes WPA como para WPA2, teniendo solo que modificar los apartados ssid con el nombre de nuestra red (en mi caso CASA ) y psk con nuestra contraseña (en mi caso Hola$).

> nano /etc/wpa_supplicant/wpa_supplicant.conf

ctrl_interface=DIR=/var/run/
update_config=1
network={
ssid="CASA"
scan_ssid=1
psk="Hola$"
proto=RSN
key_mgmt=WPA-PSK
pairwise=CCMP
group=CCMP
auth_alg=OPEN
}


Para finalizar, Recalbox tiene también un fichero de configuración propio donde se encuentran todos los parámetros de configuración relativos a él. Tendremos que modificar, en el apartado Network, la etiqueta wifi.ssid con nuestro ssid y wifi.key con nuestra contraseña (cuidado que si tenemos caracteres especiales deberemos escaparlos con ‘\’):

> nano /recalbox/share/system/recalbox.conf

# ------------ B - Network ------------ #
## Set system hostname
system.hostname=RECALBOX
## Activate wifi (0,1)
wifi.enabled=1
## Wifi SSID (string)
wifi.ssid=CASA
## Wifi KEY (string)
## Escape your special chars (# ; $) with a backslash : $ => \$
wifi.key=HolaXXXX\$
## Samba share
system.samba.enabled=1
### Virtual Gamepads
system.virtual-gamepads.
### SSH
system.ssh.enabled=1


Una vez que tenemos configurada nuestra interfaz de red solo nos faltará indicarle al sistema cual es la dirección de nuestro DNS. En Debian el DNS del sistema se almacena en el fichero /etc/resolv.conf pero en Recalbox este fichero se sobrecarga en el arranque con el contenido del fichero /tmp/resolv.conf, por ello modificaremos el contenido del fichero /etc/resolv.conf para que tenga el contenido adecuado en nuestro arranque actual y el archivo /etc/init.d/S40network para que en cada arranque sobrecargue el fichero /tmp/resolv.conf con el contenido que queremos que tenga el archivo /etc/resolv.conf. Para ello, el contenido de ambos ficheros quedará de la siguiente manera:

> nano /etc/resolv.conf

nameserver 8.8.8.8

> nano /etc/init.d/S40network

#!/bin/sh
#
# Start the wifi network if it has been configured
#
echo "nameserver 8.8.8.8" >> /tmp/resolv.conf
case "$1" in
  start)
        sleep 2
        /sbin/ifup lo
        /recalbox/scripts/recalbox-config.sh ethernet start
        /recalbox/scripts/recalbox-config.sh wifi start
        ;;
  stop)
        echo -n "Stopping network..."
        /sbin/ifdown -a
        killall wpa_supplicant
        ;;
  restart|reload)
        "$0" stop
        "$0" start
        ;;
  *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
esac

exit $?


Siguiendo estos pasos tendremos correctamente configurada nuestra interfaz wifi en Recalbox con una IP fija para redes tanto WPA como WPA2.

lunes, 3 de julio de 2017

Proteus: Emulación con chip de memoria RAM 62256 (lectura y escritura)

Asociación de las Entradas al Bus

 

Para el chip de memoria RAM 62256, los pines del bus de datos referentes a las entradas y salidas van del D0 al D7.
Lo que hace que estos pines funcionen como entradas de datos para una posición de memoria dada es que tenga un 0 en el pin notWE.
Si no definiéramos un bus, tendríamos que cablear cada una de las entradas individualmente a cada uno de los pines de entrada del chip, lo que hace que sea tedioso y que el circuito quede con un aspecto menos claro. Para evitar esto podemos utilizar un bus, donde etiqueto la entrada de la línea al bus y en el pin que quiero vincular esa entrada le indico esa misma etiqueta. El bus está representado como una línea ancha de color azul oscuro.
Además de lo anterior, tenemos que tener en cuenta que los pines de salida son bidireccionales porque cada uno puede funcionar como entrada o salida y como estamos trabajando con buses, esto se hace extensible también a ellos. Por esto, tendremos que utilizar puertas tribuffer o de tres estados en las entradas que impidan que cuando viaje una información de entrada también pueda estar viajando una información de salida provocando un corto circuito. Asignaremos la pata de control de la puerta al estado de lectura o escritura de la memoria. De esta manera, cuando la memoria esté en modo escritura y por lo tanto el buffer se utilice para enviar datos de entrada, esa pata tendrá un 1 permitiendo el flujo de información a través de ella. Por el contrario, si la memoria esta en modo lectura la entrada de control tendrá un 0 y el tribuffer tendrá un estado de alta impedancia impidiendo el paso de información.


Asociación de las Salidas al Bus

 

Al haber asociado las entradas al bus de datos ya tendríamos asociadas las salidas porque como he comentado anteriormente, éstas son bidireccionales en función del estado de la memoria. Para hacer más grafico la información que está viajando por este buffer, tenemos conectados dos displays de 7 segmentos asociando sus patas a cada uno de los pines D0 a D7 para que me indique el número en BCD que está viajando en hexadecimal. A continuación, muestro como hay que interconectar estos displays para que nos muestre correctamente el número:


¿Para qué sirve el Bus de Control? 

 

El bus de control nos va a permitir enviar la información a los pines que determinan si la memoria está encendida o no y si está activada en modo lectura o escritura. Como todos los pines están negados, cuando tengan un 0 estará activo y cuando tengan un 1 estarán desactivados. Además de lo anterior, indicarán si las puertas tribuffer están en un estado de alta impedancia o no. El significado es el siguiente:
•    notCE: Pin que enciende la memoria.
•    notWE:Pin que indica que la memoria está en molo escritura.
•    notOE:Pin que indica que la memoria está en modo lectura.
A continuación, muestro como están interconectados estos pines:




Simulación de proceso de Escritura/Lectura en memoria

 

Partimos de la siguiente situación del circuito:
 Para poder realizar la escritura de un valor en la posición de memoria 0 tendremos que realizar los siguientes pasos:
  • Activamos el chip de memoria pulsando el botón que permite el paso de un 0 que negado generará un 1 en la entrada notCE.
    •  
  • Seleccionamos la posición con los selectores numéricos en hexadecimal. En los laterales tienen un botón para subir y otro para bajar y lo traducen a binario en las salidas de la A0 a la A3.
    •  
  • Cerramos la llave para permitir que llegue un 0 al pin notWE transformándose en un 1. De este modo estará en modo escritura.
    •  
  • Seleccionamos el valor que queremos almacenar en memoria, por ejemplo el 0011.
    •  
  • Ahora para que este valor quede almacenado en memoria solo tenemos que cambiar el modo de escritura a lectura, abriendo la llave. De esta manera el valor estará almacenado.

Para comprobar que el valor 3 se ha almacenado en memoria voy a dejar el circuito en modo lectura y voy a ver el valor que tiene la memoria en la posición 1:
Tras esto voy a volver a la posición de memoria 0 para ver que seguimos teniendo el valor 3, anteriormente almacenado:
Como podemos comprobar, poniendo la memoria en modo lectura podemos ver los valores almacenados en cada una de ellas y hemos comprobado que el valor se ha almacenado correctamente.


domingo, 11 de junio de 2017

Ensamblador 8086 II

Programa para el uP i8086, en el que se represente en pantalla del PC todo lo que se escriba en el teclado hasta que se presione la tecla ESC (se hace uso del buffer de teclado):

org 100h
INICIO:
MOV AH,01H ;SE CAPTURA EL CARACTER
INT 21H
CMP AL,1BH ;SE COMPARA CON ENTER
JE FIN ;SI ES IGUAL SALTA A 'FINPALABRA'    
JMP INICIO
FIN:
ret









lunes, 22 de mayo de 2017

Ensamblador 8086 I

Tras analizar varias arquitecturas para un proyecto de electrónica relacionado con el medio ambiente (proyecto que colgaré de manera íntegra en lapsusmentis.com) he decidido decantarme por una arquitectura basada en el Intel 8086. En esta serie de post pondré varios ejemplos de código que he realizado y que me han facilitado el aprendizaje y el manejo de las instrucciones en esta arquitectura. El entorno de desarrollo que he elegido es emu8086.

Escribir un código que verifique si una cadena es igual o es subcadena de otra:

org 100h

comienzo:
mov si, x; contador de posición de cadena
mov al, msg2[si]; copio el carácter a al
cmp msg[si], al ;comparar letra por letra las cadenas, si uno no
                ;coincide manda directamente a fin
                ;y termina el programa
jne no_iguales: ; si no son iguales compruebo subcadena
cmp msg[si], "$" ;si es el final quiere decir que son iguales
jz iguales:
inc x; incremento el contador 

jmp comienzo  

;******************************
;todavía pude ser subcadena
;******************************
no_iguales:
mov si, 0 ;ponemos el contador si en 0

comienzo_sub:                           
mov al, msg2[0] ;copiar la primera letra de la
                ;palabra a al
cmp msg[si],"$" ;si es el fin de la cadena mandar a final_no_iguales
jz final_no_iguales
cmp msg[si], al ;comparar si encuentra la primera letra de la cadena
jne seguir_sub  ;si he encontrado la primera continuo

mov di, 1 ;poner en 1 den di
comprobar_sub:
mov al, msg2[di]
mov bx, di
cmp msg[si+bx], al ;compruebo la posición de la letra coincidente +si
jne seguir_sub ;si no coincide mandar a seguir                  
inc di ;incrementar di para seguir recorriendo cadena
cmp msg2[di],"$" ;si es el fin de la cadena y el programa
                 ;y he llegado aqui es que es subcadena
jz si_es_subcadena
loop comprobar_sub ;bucle para recorrer  

seguir_sub:
inc si ;para seguir recorriendo la palabra
loop comienzo_sub ;bucle principal para recorrer


si_es_subcadena:
mov dx, offset msg5 ;copiar msg3 a dx
mov ah, 9 ;preparar ah con 9 para la interrupción 21h
int 21h ;mostrar contenido en dx
final:
ret            

final_no_iguales:
mov dx, offset msg4;paso el mensaje a dx 
mov ah, 9;salida del string almacenado en dx y debe acabar en $
int 21h; interrupción 21h 
ret

iguales:
mov dx, offset msg3;paso el mensaje a dx
mov ah, 9;salida del string almacenado en dx y debe acabar en $
int 21h; interrupción 21h
ret 


msg db "hello world $";cadena base,db para poder hacer cmp
msg2 db "helloo $";db para poder copiarse a al
msg3 dw "Son iguales $"
msg4 dw "Son diferentes $"   
msg5 dw "Si es subcadena $"
x dw 0

ret


 

Ejemplo de salida para las cadenas:

msg db "hello world $"
msg2 db "helloo $"





Ejemplo de salida para las cadenas:

msg db "hello world $"
msg2 db "hello $"




Ejemplo de salida para las cadenas:

msg db "hello world $"
msg2 db "hello world $"