En el anterior artículo explicaba cómo instalar linux en el marco digital Parrot DF3120. En este explicaré cómo generar el toolchain para poder crear programas que funcionen en el marco digital. De paso crearemos una versión de la imagen más moderna para nuestro marco. El artículo original que lo explicaba es este, pero está desfasado y hay que hacer retoques para que funcione bien.
Lo voy a hacer todo desde mi linux Ubuntu 11.10, por lo que es posible que algunas cosas haya que modificarlas si usáis otra distribución.
Lo primero es instalarse usa serie de paquetes que son necesarios para que todo el proceso sea correcto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
sudo apt-get install git-core sudo apt-get install tig sudo apt-get install lzop sudo apt-get install uboot-mkimage sudo apt-get install libelf-dev sudo apt-get install libncurses-dev sudo apt-get install gtk-doc-tools sudo apt-get install checkinstall sudo apt-get install e2fsprogs sudo apt-get install libglib2.0-dev sudo apt-get install libxml2-dev sudo apt-get install genext2fs sudo apt-get install lzma sudo apt-get install subversion sudo apt-get install cvs sudo apt-get install gawk sudo apt-get install bison sudo apt-get install flex sudo apt-get install automake sudo apt-get install gcc sudo apt-get install build-essential sudo apt-get install texinfo sudo apt-get install curl |
Después hay que bajarse minifs con el git:
1 |
git clone http://oomz.net/git/minifs.git minifs |
A continuación hay que hacer un par de modificaciones:
- Edita el fichero minifs/conf/board/df3120/config_busybox.conf y reemplaza la línea # CONFIG_CHMOD is not set por CONFIG_CHMOD=y
- Edita el fichero minifs/conf/packages/05crosstools.sh y reemplaza la línea hset libtool url «http://ftp.gnu.org/gnu/libtool/libtool-2.4.2.tar.gz» por hset libtool url «http://ftp.gnu.org/gnu/libtool/libtool-2.4.tar.gz»
- Edita el fichero minifs/conf/packages/11graphical.sh y reemplaza la línea hset libpng url «ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.4.8.tar.bz2» por hset libpng url «ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.4.9.tar.bz2»
Después ya podemos ejecutar el script de la siguiente forma (Puede tardar varios minutos):
1 2 3 |
cd minifs export MINIFS_BOARD=df3120 ./minifs_build.sh |
Ahora vemos que entre otras cosas se han creado dos ficheros en el directorio build-df3120, un .img y un .plt. Pues bien con ellos hay que volver a hacer lo mismo que comentaba en el anterior artículo. Si todo ha ido bien veremos la nueva versión del firmware donde lo más destacado es que aparecen los mensajes de arranque:
Ahora vamos a compilar nuestro primer programa, y cómo no, tenía que ser un Hola Mundo:
1 2 3 4 5 6 |
#include <stdio.h> void main(void) { printf("Hola Mundo.\n"); } |
Copiamos el código que aparece arriba y lo guardamos en un fichero llamado holamundo.c. Después ejecutamos el siguiente comando:
1 |
toolchain/arm-v4t-linux-uclibcgnueabi/bin/arm-v4t-linux-uclibcgnueabi-gcc holamundo.c -o holamundo |
Esto habrá generado un fichero ejecutable llamado holamundo, pero ¿cómo lo subimos al marco para ejecutarlo?. Pues bien entre otros comandos el marco tiene dos, el tftp y wget para descargar ficheros mediante el protocolo tftp y http respectivamente, por tanto hay que instalar un servidor web o tftpd en nuestra máquina linux.
Servidor web apache:
1 |
sudo apt-get install apache2 |
Servidor tftp: Instrucciones
Si hemos optado por el servidor web sólo hay que copiar el fichero holamundo al directorio /var/www. Si la elección ha sido tftpd entonces hay que copiar el fichero holamundo al directorio que se haya configurado.
Ahora tenemos que descargarlo desde el marco digital. Hacemos un telnet como explicaba en el anterior artículo. En el firmware actual todo el disco está montado como sólo lectura, por lo que tendremos que remontarlo como escritura también de la siguiente forma:
1 |
mount / / -o remount,rw |
Ahora nos vamos al directorio /tmp y descargamos el programa.
Para tftp el comando sería:
1 |
tftp -g -r holamundo <IP DEL SERVIDOR TFTP> |
Para wget el comando sería:
1 |
wget http://<IP DEL SERVIDOR WEB>/holamundo |
Ahora que tenemos el fichero, hay que darle permisos de ejecución y finalmente ejecutarlo:
1 2 |
chmod a+x holamundo ./holamundo |
Obtendremos esto:
Ya hemos compilado nuestro primer programa y lo hemos hecho funcionar, pero claro, nos interesa que se pueda dibujar en la pantalla algo para ver cómo se ve en el marco. Lo primero que hay que saber es que la pantalla tiene asignado el dispositivo /dev/fb0 y que lo que tenemos que conseguir es acceder a su memoria para escribir directamente los colores. Esto se consigue de la siguiente forma:
Con la función open abrimos el dispositivo como lectura/escritura:
1 |
int g_fb = open("/dev/fb0", O_RDWR); |
Con la función ioctl recibimos en una estructura información sobre la pantalla:
1 2 |
struct fb_var_screeninfo var_info; ioctl(g_fb, FBIOGET_VSCREENINFO, &var_info); |
Con la función mmap obtenemos el buffer de la memoria de vídeo para leerlo y escribir en el:
1 |
char *buffer = (char *)mmap(0, 153600, PROT_READ|PROT_WRITE, MAP_SHARED, g_fb, 0); |
Ahora sólo queda dibujar los bytes en la memoria para que se vean reflejados como pixeles en la pantalla. Al poder representar la pantalla 64k colores estos se codifican a RGB mediante 16 bit con el formato 5-6-5 (rrrrrggggggbbbbb). Así el rojo es 1111100000000000 (0xF800), el verde es 0000011111100000 (0x07E0) y el azul es 0000000000011111 (0x001F). Por tanto cada pixel en la pantalla ocupa 16 bits.
Para probar todo esto he creado un programa que muestra un cuadro verde rebotando por el marco usando la técnica de doble buffer para evitar parpadeos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> char *inicializa(int *cuantos) { char* buffer; int g_fb; struct fb_var_screeninfo var_info; g_fb = open("/dev/fb0", O_RDWR); if (g_fb == -1) { printf("No se puede abrir /dev/fb0\n"); _exit(1); } printf("/dev/fb0 abierto con el handle 0x%x\n", (unsigned)g_fb); if (ioctl(g_fb, FBIOGET_VSCREENINFO, &var_info)) { printf("No se puede obtener la información variable de la pantalla\n"); _exit(1); } printf("xres: %d\n", var_info.xres); printf("yres: %d\n", var_info.yres); printf("bpp: %d\n", var_info.bits_per_pixel); *cuantos = var_info.xres * var_info.yres * var_info.bits_per_pixel /8; printf("El tamaño del buffer de pantalla es de %d bytes\n", *cuantos); buffer = (char *)mmap(0, *cuantos, PROT_READ|PROT_WRITE, MAP_SHARED, g_fb, 0); if ((int)buffer == -1) { printf("falló mmap().\n"); exit(1); } printf("Pantalla devuelta\n"); return buffer; } void cuadro(int x, int y, short int *buffer, int color) { int anchura; int altura; short int *puntero; for(altura = 0; altura < 50; altura++) { puntero = buffer + ((y + altura) * 320); for(anchura = 0; anchura < 50; anchura++) { *(puntero + x + anchura) = color; } } } void main(void) { int indice; int cuantos; int x = 0; int y = 0; int suma_x = 1; int suma_y = 1; short int *buffer = (short int *)inicializa(&cuantos); short int *ventana = (short int *)malloc(cuantos); if (ventana == NULL) { printf("No se puede crear el doble buffer\n"); _exit(1); } // fondo negro for(indice = 0; indice < (cuantos / 2); indice++) { buffer[indice] = 0; } for(;;) { usleep(10000); cuadro(x, y, ventana, 0); x += suma_x; y += suma_y; if(x > 269 || x < 0) { suma_x *= -1; x += suma_x; } if(y > 189 || y < 0) { suma_y *= -1; y += suma_y; } cuadro(x, y, ventana, 0x7E0); memcpy(buffer, ventana, cuantos); } } |
Que ejecutándolo quedaría así:
En un próximo artículo explicaré como acceder a la interfaz con SDL, comunicarse con bluetooth mediante RFCOMM y obtener los valores de los botones traseros y del inclinómetro.
Edición 12/02/2012:
¡Que máquina! Como se nota que lo mio es el hardware, llevo todo el fin de semana sin poder compilar correctamente la toolchain bajo SuSe 12.1 de 64 bits.
A ver si con tu tutorial lo consigo.
Por lo visto los tutoriales estan un poco desfasados (Hay más funcionalidades de las que comentan) y han añadido nuevas cosas y usado otras que no vienen en las guías (programas a instalar y versiones de paquetes). Por eso lo he ido recopilando aquí. Ya me dirás si al final lo conseguiste.
Para configurar uboot para 32 MB hay que modificar unos comentarios en:
minifs/build-df3120/uboot/include/configs/df3120h
#define PHYS_SDRAM_1_SIZE 0x00800000 /* 8Mb */
// #define PHYS_SDRAM_1_SIZE 0x02000000 /* 32Mb */
Tambien hay una linea al final:
#define CONFIG_EXTRA_ENV_SETTINGS
que podria usarse para redirigir stdout a otro stream que no sea usb0
(framebuffer?)
Fantástico. Ahora si que se puede usar todo el potencial del marco. Lástima que en mi caso no tenga herramientars para desoldar el chip de memoria para sustituirlo por otro.
Impresionante tutorial, ¡has matado de 1 tiro la creación del toolchain, el paso de archivos y la escritura de gráficos como está mandado (con doble buffer) en la pantalla!
Y el siguiente tuto del Bluetooth se me antoja también un indispensable.
Yo he recibido ayer mis 2 marcos, pero no he tenido mucho tiempo para trastear. En un rato que tuve he sustituido el chip de SDRAM que trae por un MT48LC16M16A2P-75, y el marco sigue arrancando, con lo que intuyo que la modificación ha ido bien. Eso sí, aún no me he puesto con el software, a ver si cuando pueda me pongo y os cuento a ver si van esos 32 MB.
Cuentanos que tal van. Yo he tenido problemas de memoria con el comando hcitool al escanear dispositivos bluetooth.
He seguido el tutorial para compilar la distro, y tras ejecutar el minifs_build.sh, después de un buen rato, el script acaba sin errores, pero dentro del directorio build-df3120 no está ni el .plf ni el .img (ni en ningún otro subdirectorio, he buscado con find).
El toolchain se compila bien (puedo ejecutar el compilador cruzado), y dentro del directorio build-df3120 hay muchos subdirectorios con cosas compiladas, pero nada del plf ni de la imagen.
¿Alguna sugerencia?
Salida de ./minifs_build.sh quitando la parte de descargas (que va antes): http://pastebin.com/rrbZ45qk
Se me olvidó comentar que utilizo Ubuntu 10.04 64 bits.
Ya he dado con el error, pero ni idea de cómo solucionarlo. Al hacer el configure de libglib, me da este error:
checking for glib-compile-schemas… no
configure: error: Could not find a glib-compile-schemas in your PATH
PD: Perdón por inundar los comentarios con mis dudas.
No te preocupes por exponer tus dudas, esto sirve para otra gente que viene detrás y tenga el mismo problema. Hiciste el sudo apt-get install libglib2.0-dev?
En efecto ya tenía instalado de antes el paquete libglib2.0-dev, pero probé a reinstalarlo por si acaso y no solucionó nada.
He probado a repetir todo el proceso en una distro Ubuntu 11.10, y ha compilado perfecto. Creo que es un problema con Ubuntu 10.10, que no incluye el binario glib-compile-schemas. También probé a copiar este binario «a pelo» en mi PC y pasa con éxito la fase de configuración, pero falla al compilar con este error:
http://pastebin.com/FT1mxFYL
Creo que va siendo hora de actualizar mi Ubuntu 10.10…
Es bueno saber que hay que tener una versión reciente para hacerlo funcionar. ¿El Ubuntu que usaste y que te funcionó era de 64 o de 32 bit?
El que falló fue Ubuntu 10.10 64 bits.
El que funcionó fue Ubuntu 11.10 64 bits.
Mientras buscaba por Google para intentar averiguar algo, vi gente que tenía también ese problema con Ubuntu 10.10 para compilar otros paquetes que nada tienen que ver con esto, debe ser un problema de esa versión en concreto.
Sigo con los problemas 🙁
He logrado que el sistema arranque con el u-boot preparado para 8MB, pero cuando modifico la linea correspondiente a la RAM de 32MB, recompilo u-boot y lo actualizo, no logro que arranque, se queda la pantalla negra. Si vuelvo a recompilar para 8MB, arranca sin problemas. Lo único que cambio son estas 2 líneas, dejándolas así:
//#define PHYS_SDRAM_1_SIZE 0x00800000 /* 8 MB */
#define PHYS_SDRAM_1_SIZE 0x02000000 /* 32 MB */
¿Alguien podría pasarme un .plf preparado para 32MB que sepa que funciona?
Hola, yo tembien he sufrido mucho con la toolchain. La he compilado con ubuntu 11.10 32 bits sin problemas (despues de ir instalando los paquetes que faltaban). Con SuSe 12.1 x64 también, pero no me gusta esta versión. Con SuSe 11.4 x64 tuve que instalar las libtools de la versión 12.1 (modificando los repositorios de soft.)
Pese a todo no he podido arrancar correctamente el linux en el marco, kernel panic y otros errores, probaré el tema del formato de la SD con ext3 y crear la partición.
En cuanto a la modificación y ampliación de memoria, en el directorio del uboot hay un fichero .S con una línea comentada que podría ser necesaria también para usar los 32M. Se trata de la inicialización del hardware de la unidad de gestión de memoria.
EL mecanizado de la tapa trasera con taladritos queda muy bien:
https://picasaweb.google.com/helitp/MarcoParrot?authuser=0&feat=directlink
Seguiré probando el firmware…
He estado investigando el tema de la SDRAM, y parece que el tema de conseguir los 32MB RAM funcionando no es tan sencillo como parecía.
Después de 2 tardes enteras haciendo pruebas con u-boot, modificando la rutina que configura la SDRAM (lowlevel_init.S en board/df3120), me daba la impresión de que la rutina no se ejecutaba. Probé a borrarla entera y para mi sorpresa Linux seguía arrancando bien en el modo 8MB. La conclusión es que esta rutina no estaba haciendo nada. Me conecté al IRC al canal #df3120 y allí me confirmaron que si usas el bootloader de Parrot, este inicializa la SDRAM a 8MB y cuando carga u-boot ya está en la SDRAM, por lo que no puede reconfigurarla. ¿Soluciones al problema? Hay 2 opciones:
1.- Usando un programador JTAG, eliminar el bootloader de Parrot y reemplazarlo por u-boot. Tiene el problema de que se pierde la funcionalidad de marco, y la facilidad de actualizar u-boot con el cable USB.
2.- Mantener el bootloader de Parrot, pero modificar u-boot, para que cuando se cargue, se copie a la SRAM interna de 4KB de la CPU, y se ejecute desde ahí, pudiendo entonces reconfigurar la SDRAM.
La opción 2 se escapa a mis posibilidades (supongo que requiere bastantes conocimientos de ensamblador de ARM). Para la opción 1, tengo uno de estos (http://code.google.com/p/opendous/wiki/JTAG) que supongo que valdrá, pero nunca lo he usado y no me vendría mal un tutorial. Si alguno sabéis de uno, avisad.
Vaya, Pues si que parece más complicado hacerlo funcionar con 32 MB de RAM.
Muchas gracias, usando tus instrucciones de base he conseguido que funcione todo, e incluso juguetear un poco con SDL…
Quedo con ganas de la tercera parte, sobre todo el tema de los botones, que no se de donde coger el evento (si me adelantas alguna pista…)
Gracias!
Hola
Me temo que es algo complicado de explicar en un comentario. A grandes rasgos consiste en abrir con open el fichero /dev/mem, configurar unos bits para que los GPIO sean entradas y leer esos bits a continuación, todo dentro de ese segmento de memoria. Estoy todavía probando cosas ya que no conozco el dispositivo ni sus posibilidades y carencias, por el momento tengo problemas con el bluetooth para crear un puerto serie con spp.
De todas formas si quieres un códgido que funciona mira esto: http://rflk.googlecode.com/svn-history/r9/trunk/sw/lib/gpio-s3c2410/gpio.c
Después de compilarlo y de subirlo al marco ejecuta esto:
gpio F2=Z
gpio F3=Z
gpio F4=Z
Ahora pulsa cualquiera de los 3 botones de la parte de atrás y sin soltarlo ejecuta gpio sin parámetros, verás en la lista del puerto F que hay dos «1» y un «0», el «0» es el botón que has pulsado y los «1» son los botones que no has pulsado.
Muchas gracias,
Si bien lo que comentas para acceder a los botones funciona, no me gusta mucho ir accediendo a direcciones de memoria…
He estando investigando un poco y se puede activarf el acceso a GPIO directamente en el kernel:
http://brew-j2me.blogspot.com/2010/03/linux-accessing-gpio-from-user-space.html
He conseguido exportar sin problema los pins, pero aun no he conseguido leerlo, será tema de encontrar el pin correcto…
Muchas gracias!
Esta bien, pero ten en cuenta que el acceso a los GPIOs a través de la memoria es la práctica más extendida:
http://www.simtec.co.uk/appnotes/AN0014/
http://www.google.es/search?ie=UTF-8&q=gpio+dev+mem
muy buen tuto!! asi falta algo asi, yo tengo una pandboard y he realizo algo muy parecido has probado algo asi ? conoces la pandaboard ?te la recomiendo. me gustario activarles los GPOIs pero no he podido
Si la conocía de oidas. ¿No te sirve esto? http://www.nerdenmeister.org/2011/11/13/using-the-gpio-pins-on-a-pandaboard/
Would it be possible to get Python running on this frame?
Yes, but it is not an easy task: http://www.crosscompile.org/static/pages/Python.html