jueves, 3 de octubre de 2013

Creación de una toolchain para crosscompilar para la raspberry

¿Por qué?

"Just for the fun of it". Bueno, puede haber razones mejores, como no poder encontrar un compilador adaptado a la distribución en la que queremos trabajar, por necesitar alguna herramienta de debug que no facilita la toolchain oficial... o simplemente como excusa para familiarizarnos con algunas de las características de la raspberry.

En todo caso el proceso que se describe aquí sirve para crear con relativa facilidad un crosscompilador, especialmente para la arquitectura ARM.


Generar la toolchain

La toolchain puede construirse con ayuda de la herramienta crosstool-ng, disponible en: http://crosstool-ng.org/

Instalación de croostol-ng

Nos descargamos la última versión y la descomprimimos:

tar -xvf crosstool-ng-1.18.0.tar.bz2

El paquete sigue la estructura de las autotools, así que pasito a pasito:

Si no las tenemos instaladas: sudo apt-get install automake autoconf libtool

Finalizada la instalación ejecutar todos los pasitos (en la  versión que me he descargado algunos pasos, como autoheader no son necesarios. Pero pueden ser necesarios en otras versiones, así que mejor ejecutarlos todos :) )

aclocal
autoheader
libtoolize -c
automake -a -c
autoconf
./configure
Este script es posible que nos avise de que nos faltan librerías, herramientas, paquetes... instalar lo que os vaya pidiendo y paciencia. Su función es precisamente controlar que teneis todo lo necesario para generar el contenido del paquete. (La petición de "curses header" es para la instalación de la librería de desarrollo ncurses actualmente sudo apt-get instal libncurses5-dev, pero como "todo pasa y todo queda", comprobar que la versión más actualizada para vuestro sistema es la 5)

make
sudo make install

Nota: Una de las utilidades que crosstool-ng necesita y no menciona es svn... con lo que aseguremonos de que está antes de intentar generar nada (sudo apt-get install subversion)

Generación de la toolchain que nos permitirá compilar para la raspberry

Nos posicionamos en el directorio donde queramos crear la toolchain. Por defecto crosstool-ng lo fija a ${HOME}/x-tools/${CT_TARGET}, pero este valor puede cambiarse si se desea durante la configuración. 

Ejecutamo ct-ng menuconfig



Paths and misc options:
  • Seleccionaremos "Try features marked as EXPERIMENTAL"
  • Si no deseamos que la toolchain se genere en el directorio por defecto, esto puede cambiarse en el apartado "prefix directory"
  • "Number of parallel jobs" nos permite aprovechar la potencia de una máquina de desarrollo con más de un núcleo, el número a seleccionar puede ajustarse al número de núcleos (algunos manuales hablan de número de núclesos X 1.5 redondeando hacia abajo. He optado por la cifra más conservadora)
Target options:
Nota: El significado de los parámetros que vamos a utilizar puede consultarse en http://es.wikipedia.org/wiki/Raspberry_Pi#Hardware y en  http://es.wikipedia.org/wiki/Arquitectura_ARM buscando la raspberrypi entre los chips listados.
  • Target architecture: arm (Al seleccionar esta opción ya asume de forma inmediata valores por defecto para endiannes, bitness, juego de instrucciones...)
  • Architecture level: armv6zk
  • Emit assembly for CPU: arm1176jzf-s
  • Tune for CPU: arm1176jzf-s
Y llegamos a la parte de configurar la forma de manejo de la coma flotante, que puede dar problemas. Depende mucho de la distribución para la que queramos compilar, y debe concordar con ella.
Así que mirando en la configuración guardada en https://github.com/raspberrypi/tools/blob/master/configs/bcm2708hardfp-ct-ng.config para el compilador de la raspbian, comprobamos que no han definido una FPU específica, pero sí han definido que el manejo de la coma flotante se haga a través de hardware.
  • Floating point: hardware (FPU)
Toolchain options
Puede quedarse tal y como está. Si nos hace ilusión, en Tuple's vendor string podemos poner una cadena que nos ayude a distinguir los ejecutables generados de cualquier otra toolchain que utilicemos

Operating system
  • Target OS: Linux
  • Linux Kernell: El que utilce nuestra distribución de la raspberry. Si la hemos bajado de http://www.raspberrypi.org/downloads  lo más usual es que incluyan la versión del kerrnell en los datos de la distribución. No todas las versiones están disponibles, en caso de que la nuestra no estuviera disponible elegiríamos primero aquella que coincidiera la versión, dentro de aquellas las que coincidiera la revisión. La revisión menor no es muy importante, en caso de duda, elegir un número por debajo (siempre que eso no signifique cambiar a otra con distinta versión o revisión)  Es decir, que si la version que aparece listada en mi distribución es la 3.6 y tengo disponibles 3.5, 3.6.11 y 3.7, escogeré la 3.6.11

Binary utilities
No es necesario modificar nada

C Compiler
  • Seleccionar C++ entre los "lenguajes adiccionales" (y por supuesto cualquier otro que queramos utilizar)
  • Seleccionar "show linaro versions" (aunque esto no es estrictamente necesario, es conveniente. Parte porque Linaro está especializado en desarrollo para ARM, y parte porque muchas de las distribuciones de raspberry lo utilizan. En la duda, de nuevo, consultar la configuración del crosscompilador utilizado en nuestra distribución.)
  • Elegir la versión de compilador más avanzada, salvo que tengamos fuertes razones para sospechar que no es estable.
C Library
  • Seleccionar la versión de eglibc que coincida con nuestra distribución. Para ello basta ejecutar ldd --version dentro de la rapberry
  • Seleccionar "optimize eglibc for size"
Debug Facilities
Aquí depende de lo que cada cual suela usar, yo opto por seleccionar gdbstrace y ltrace

Ahora ejecutamos ct-ng build (y podemos dedicarnos a otra cosa que esto va a tardar lo suyo)

Nota: Al realizar este paso me encontré con un fallo en la creación del debugger gdb, "python is missing or unusable". Afortunadamente tras una breve búsqueda resultó ser un fallo ( ya detectado ) que se soluciona instalando los paquetes develop de phyton. Cometí el error sin embargo de instalar la última versión, que no era la que busca la configuración. Una búsqueda en el log (grep python build.log) mostró que la que andaba buscando era la 2.7.

sudo apt-get install python2.7-dev

y, de nuevo  ct-ng build

Y ahora si, la creación se realiza por completo.

Con esto nos habrá generado un directorio  arm-<vendor string>-linux-gnueabi, y dentro de el un bin con los compiladores, linkadores, utilidades de debug, etc:

Nota: Vendor string es esa cadena que pusimos en la configuración, dentro de "toolchain options"


En mi caso he elegido un vendor string que me ayude a diferenciar tanto que es una toolchain casera como su función (chus4raspbian)

Hola de nuevo, raspberry

Ahora solo queda probar que funciona. Como en el post Crosscompilando. Facil y rápido definimos para ello un programa "holamundo2.c"

#include <stdio.h>
int main() 

   printf("Chus se curró una toolchain enterita y solo sacó otra frase tonta. Menuda ñoñería.\n"); 
   return 0; 
}

Compilamos:

~/raspberrypi/toolchain/arm-chus4raspbian-linux-gnueabi/bin/arm-chus4raspbian-linux-gnueabi-gcc -o holamundo2 holamundo2.c 

Lo copiamos con scp a la raspberry:

scp holamundo2 pi@<dir IP de la rasp>:/home/pi/

Y ejecutamos dentro de la rasp para ver si todo funciona como es debido:


Pues sí. Funciona perfectamente. Para mi sorpresa, porque esperaba que no mostrara bien las eñes y los acentos :) :) :)

miércoles, 2 de octubre de 2013

Crosscompilando. Facil y rápido

Obtener la toolchain


Las distribuciones de la raspberry tienen a menudo una toolchain pregenerada, de forma que es sencillo compilar para ella.  La toolchain de raspbian se puede obtener:

git clone git://github.com/raspberrypi/tools

Con esto nos descarga el toolchain completo en el directorio donde queramos tenerlo (tecnicamente nos carga dos, tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/ que es el recomendado para la raspbian y otro más, que a dia de hoy ignoro su función.)

Si realizamos un ls del directorio <directorio inicial>/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/  podemos ver con qué contamos:


Vemos que hay con compiladores, linkers y herramientas de depuración, todos con un prefijo que ayuda a diferenciarlos de otros compiladores nativos o crosscompiladores configurados para distintas plataformas

Hola, raspberry

Vamos a compilar nuestro primer programa. Un holamundo de toda la vida que salvamos como holamundo.c

#include <stdio.h>
int main() 
   printf("Chus hizo un programa para la rasp y solo saco esta frase tonta\n"); 
   return 0; 
}

Para compilarlo:

<directorio inicial>/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc -o holamundo holamundo.c


lo copiamos a la raspberry con scp:

scp holamundo pi@<dir IP de la rasp>:/home/pi/

Y... ejecutamos:



Pues como dije, fácil y rápido. En la próxima entrada explicaré los pasos para crearnos nosotros mismos la toolchain :)

martes, 1 de octubre de 2013

Montar un fichero con una imagen de la raspberry en nuestro disco

¿Para qué?

Normalmente para ver o modificar su contenido de forma directa, sin necesidad de tostar la imagen en una SD y arrancar la raspberry

¿Cómo funciona?

Un fichero img es una imagen de disco (sea su soporte físico una SD, un CD, un disco duro...) Incluye también la tabla de particiones y la estructura de ficheros. El comando format permite tomar una de estas particiones y extenderla como un sistema de archivos dentro del punto de montaje que le definamos. Podremos acceder por tanto a los archivos y directorios guardados en el archivo  .img. Y, lo que es más interesante si cabe: cualquier cambio que hagamos sobre ese sistema de archivos se grabará realmente en el archivo .img

Pasos:


Como hemos dicho antes, un fichero .img es una imagen completa de un sistema de archivos, tabla de particiones incluida. Cuando contiene más de una partición, es necesario montar cada una de forma independiente. Para averiguar que particiones existen en el fichero .img y sus características podemos usar la utilidad parted





En el ejemplo vemos que primero cambiamos la unidad de tamaño de parted con el comando interno unit, cuando nos pregunta fijamos la unidad a B (bytes) y por último ejecutamos el comando interno print.

Observamos que hay una partición primaria de arranque y otra extendida que contiene a su vez una lógica en formato ext4. Es habitual en los sistemas de la raspberry: La primera contiene archivos referentes al arranque y en la segunda se encuentra el sistema de archivos.

Dentro de la raspberry lo habitual es que la segunda partición se monte en la raiz de directorios "/" y la primera se montará en /boot


Elegimos un directorio como punto de montaje (en mi caso usaré /mnt/sbdboot para la primera /mnt/sbd para la segunda partición), y el comando utilizado será finalmente: sudo mount ~/Descargas/archlinux-hf-2013-07-22.img /mnt/sbd -o loop,offset=96468992 -t ext4
  • -o indica que debe montar el archivo a partir de la posición de comienzo de la partición que nos interesa. (eliminada la B final, que indica solo la unidad de medida en bytes)
  • -t tipo de formato de sistema de ficheros, que tal y como indica parted es ext4 (Dependiendo de la versión, parted y mount puedes utilizar literales distintos para definir los distintos tipos de formato, así es posible que en lugar de fat16 sea necesario usar vfat. Cualquier problema debería poder resolverse con una consulta al man)

Un ls /mnt/sbd nos confirmará si hemos instalado o no la partición correcta:


jueves, 19 de septiembre de 2013

Instalar una imagen en la tarjeta SD desde un sistema Linux


¿Sirve este procedimiento para todas las distribuciones disponibles para la raspberry?

Claro. Siempre que la distribución facilite un archivo imagen, el procedimiento es esencialmente el mismo.

Enlaces recomendados

http://elinux.org/RPi_Easy_SD_Card_Setup (en inglés) Explica el proceso de forma mucho más detallada y exahustiva que este post, que pretende solo ser un rápido how-to.

¿Que necesito?

  • Un ordenador de trabajo con sistema linux instalado, con ranura o dispositivo para acceder a una SD y conexión a internet.
  • Una SD de dos o mas gigas
  • Idealmente una Raspberry para probar el resultado

Pasos de la instalación

  1. Descargar la distribución desde http://www.raspberrypi.org/downloads (en adelante supondremos que el archivo descargado es el  archlinux-hf-2013-07-22.img.zip)
  2. Una vez descargado comprobamos que es el archivo correcto ejecutando sha1sum archlinux-hf-2013-07-22.img.zip. El resultado debe coincidir con el indicado como valor de SHA1-checksum para el archivo.
  3. Una vez descomprimido el archivo .gz, comprobamos que lo que tenemos es un archivo .img, es decir, una imagen completa de una tarjeta SD de dos gigas, incluida la tabla de particiones 
  4. Desde linea de comando, ejecutamos df -k    Esto nos mostrará los sistemas de archivos conectados a nuestro ordenador
  5. Pinchamos la tarjeta SD en nuestro ordenador de trabajo.
  6. Volvemos a ejecutar df -k. Nos aparecerá una o varias lineas nuevas (una por cada partición que contenga la SD pinchada). Valores habituales son “/dev/mmcblk0p1" or "/dev/sdd1” (A partir de ahora suponemos que el valor aparecido es /dev/mmcblk0p1).
  7. Desmontamos el dispositivo para que no pueda leerse o escribirse en él mientras volcamos la imagen. Para ello ejecutaremos el comando umount /dev/mmcblk0p1 (Si se ha generado más de un punto de montaje, deberemos desmontarlos todos).
  8. Escribiremos la imagen en la sd con el comando dd. Hay que tener en cuenta que no vamos a escribir la imagen en una partición de la tarjeta, sino directamente en la tarjeta. Eso quiere decir que como destino utilizaremos /dev/mmcblk0 o /dev/ssd, ya que la última parte corresponde al número de partición dentro del dispositivo: sudo dd if=archlinux-hf-2013-07-22.img of=/dev/mmcblk0 El comando dd no muestra barra de progreso, tener en cuenta que puede llevar algún tiempo, la velocidad de escritura de una SD no es muy alta.
  9. Asegurarnos de que los datos se han escrito en su totalidad antes de extraer la tarjeta con el comando sudo sync 
  10. Pinchar la tarjeta  y conectar la raspberry a una toma de red, y a una toma de corriente. El sistema arrancará de forma automática nada más instalarle la toma de corriente. La forma más sencilla para conectarse a ella es mediante ssh. A tener en cuenta:
    • En las dos distribuciones que he probado (arch y raspbian) la raspberry toma la dirección IP directamente por DHCP. La forma mas sencilla de averiguar qué IP ha tomado, en una instalación doméstica, es mirarlo directamente en la tabla del router.
    • El login-password por defecto en arch es root/root, pero de todas formas teneis todos los usuarios y password en la página de descargas de distribuciones (http://www.raspberrypi.org/downloads)

Anexo: Reparticionar la tarjeta

  1. Si hemos utilizado una tarjeta de más de dos gigas, actualmente estamos desaprovechando ese espacio, ya que al copiar la imagen se le ha asignado una tabla de particiones correspondiente a dos gigas. Algunas distribuciones de Raspberry reparticionan automáticamente la tarjeta en el primer arranque, otras no. Lo mejor es que compruebes después del primer arranque si estás perdiendo espacio (df -k o df -m nos dará el tamaño en kbytes o en megas). En caso de que el tamaño disponible sea menor al disponible en la tarjeta:
    • ejecutar sudo raspi-config
    • seleccionar en el menú la opción expand_rootfs
    • ejecutar sudo reboot
    • comprobar que el tamaño disponible es ahora el correcto
  2. Si la distribución que utilizamos no tiene el script raspi-config, necesitaremos reparticionar la SD a mano. El proceso es algo largo y yo personalmente no lo he realizado, con lo que me limitaré a facilitaros un enlace (en inglés) donde se indican diversos modos de realizarlo: (http://elinux.org/RPi_Resize_Flash_Partitions)


miércoles, 17 de abril de 2013

Realizar en linux un backup de la tarjeta SD



¿Por qué?

Como muchos otros integrados, la raspberry pi tiene como disco duro una tarjeta SD, que tienen un número limitado de escrituras antes de hecharse a perder. Es conveniente que una vez tengamos estabilizado el sistema, hagamos una imagen de backup. Tiene otras utilidades, como poder tener distintas configuraciones de la raspi guardadas y poder instalarlo de forma inmediata en la tarjeta, distribuir rápidamente un desarrollo, etc.

¿A qué tipo de tarjetas puedo restaurar posteriormente esta imagen?

A cualquiera que tenga el mismo tamaño o mayor que la tarjeta que estuvieramos utilizando.

¿Qué se guarda en la imagen?

Todo, es una copia clonada de la tarjeta de origen, incluida la tabla de particiones. Una vez volcada a otra tarjeta, será indistingible de la original.

Pasos

  1. Desde linea de comando, ejecutamos df -k    Esto nos mostrará los sistemas de archivos conectados a nuestro ordenador
  2. Pinchamos la tarjeta SD en nuestro ordenador de trabajo.
  3. Volvemos a ejecutar df -k. Nos aparecerá una o varias lineas nuevas (una por cada partición que contenga la SD pinchada). Valores habituales son “/dev/mmcblk0p1" or "/dev/sdd1” (A partir de ahora suponemos que el valor aparecido es /dev/mmcblk0p1).
  4. Realizamos la copia con el comando dd. La copia se hace de toda la tarjeta, así que tomamos la entrada sin los valores "1" o "p1", que se corresponden con el número de partición y no con el dispositivo completo.  sudo dd if=/dev/mmcblk0 of=4GB_instalacioninicial.img
  5. Recomendación: Es conveniente poner como nombre del fichero de destino los datos de tamaño y función de la copia (aunque existen herramientas para averiguar esos datos sin necesidad de volcarlo a una SD, nos ahorrará tiempo si el número de imágenes empieza a ser excesivo)