Introducción

Esta es la primera parte del curso, en ella veremos una pequeña introducción a los conceptos básicos y aplicaremos estos conceptos para hacer encender el LED ACT (OK en algunos modelos) en nuestra Raspberry Pi.

Ensamblador

Lo primero de todo es saber en que lenguaje vamos a desarrollar nuestro programa. En este curso vamos a programar prácticamente todo en ensamblador.

Existen dos tipos de lenguaje, los de alto nivel y los de bajo nivel. Los de alto nivel no interactúan con el hardware directamente, sino que son interpretados y es el sistema operativo quien le dice a cada parte del ordenador (pantalla, altavoces…) lo que ha de hacer, un ejemplo de lenguaje de alto nivel sería HTML.

Por el contrario, los lenguajes de bajo nivel, le dan órdenes directamente al hardware, le dicen al procesador que es lo que tiene que hacer, a la pantalla que píxeles son los que ha de activar…

 

Todos los programas pasan por ser convertidos a ensamblador antes de ejecutarse. De forma que al escribir un programa directamente en ensamblador es mucho más rápido.

 

 

Al igual que ocurre con los lenguajes de alto nivel, existen muchos tipos de ensamblador, tantos como diferentes microprocesadores, cada uno de ellos diseñado para entender una clase de ensamblador. Es algo lioso, pero en nuestro caso como solo vamos a desarrollar nuestro sistema operativo para la Raspberry Pi no tendremos que preocuparnos de eso.

En nuestro caso, el procesador de la Raspberry Pi (menos la 3) utiliza la arquitectura ARMv6 por lo que estaremos programando para esa arquitectura.

 

Esto no debe asustaros, al igual que pasa con la mayoría de lenguajes de programación de alto nivel, visto uno, vistos todos.

Preparando el escenario

Antes de empezar a programar necesitamos algunas cosas, lo primero un editor de texto, yo os recomiendo Brackets, a mí personalmente me gusta bastante.

 

Lo segundo que vais a necesitar va a ser un compilador, sirve para transformar todo nuestro código en un archivo (llamado imagen) que nuestra Raspberry Pi es capaz de ejecutar, esta instalación es algo más complicada y suele dar algunos problemas.

 

Windows

 

Para Windows podéis instalar YAGARTO y los paquetes de MinGW.

Para instalarlo hay que acceder a la web de YAGARTO, descargar e instalar YAGARTO Tools y YAGARTO GNU ARM toolchain para Windows.

Puedes descargar MinGW aquí. Al terminar la instalación deberás reiniciar el ordenador.

Nota: YAGARTO tiene que ser instalado en  ‘C:\YAGARTO\’ no en ‘C:\Program Files\YAGARTO\’.

 

Mac

 

En Mac lo primero que tendréis que hacer es instalar Homebrew, para ello abrís “Terminal” y copiáis la siguiente linea:

 

/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”

 

Después presionáis la tecla “Enter” y esperáis a que termine.

Seguramente os pida que instaléis alguna utilidad de Xcode, en ese caso simplemente hacéis click en “Instalar”.

Una vez haya terminado copiáis esta linea en Terminal:

 

brew cask install gcc-arm-embedded

 

Presionáis la tecla “Enter” y esperáis a que termine.

Y ya estaría!

 

Linux

 

En linux debéis copiar la siguiente linea en la Terminal:

 

sudo apt-get install gcc-arm-none-eabi

 

Después presionáis la tecla “Enter” y esperáis a que termine.

Todo listo!

 

Lo siguiente que debéis hacer es preparar una carpeta con todo lo necesario, para ello lo único que tenéis que hacer es descargar este archivo y descomprimirlo en el escritorio.

 

Ahora tendremos una carpeta llamada Baking Pi, con todo lo necesario, ahora mismo lo único que hay son un par de carpetas y los archivos necesarios para que el compilador cree la imagen con nuestro programa, que es la que copiaremos a la Raspberry.

 

El comienzo

Dentro de la carpeta “source” encontraremos un archivo llamado “main.s“. En ese archivo es en el que debemos escribir nuestro programa, para ello lo abriremos con el editor de texto Brackets (o alguno de vuestra preferencia).

 

La extensión “.s” se usa generalmente para todos los tipos de ensamblador, en nuestro caso ARMv6.

Los primeros comandos que debemos copiar son estos:

 

.section .init
.globl _start
_start:

 

Esto no hará nada en nuestra Raspberry, son simplemente instrucciones para el compilador. Éste se encargará de traducir nuestro código escrito en ensamblador a binario, para que la Raspberry lo entienda.

La primera linea le dice al compilador dónde debe poner nuestro código, cuando vayamos a compilarlo para generar la imagen que debemos copiar a la Raspberry, el compilador leerá el archivo kernel.ld y pondrá la sección init al comienzo. Especificar que debe ejecutarse primero es importante, si tuviésemos otros archivos aparte de “main.s” (algo que veremos más adelante) estos se ejecutarían alfabéticamente.

Las dos lineas siguientes son únicamente para evitar un error de compilación, con la linea anterior le hemos especificado que debe empezar en ese archivo, pero ahora debemos decirle por qué parte, y eso es lo que hacemos definiendo _start como un identificador global (accesible por cualquier otro archivo).

 

La primera línea

Ahora vamos a programar nuestra primera linea. En ensamblador, el ordenador simplemente va leyendo las lineas una por una, en orden, a no ser que especifiquemos lo contrario. Cada instrucción comienza en una nueva linea.

 

Vamos a copiar la siguiente linea:

 

ldr r0,=0x20200000

 

ldr reg,=val pone el número val en el registro reg

Lo que hace este comando es almacenar el número 0x20200000 en el registro r0, más adelante veremos que función tiene cada registro, ahora mismo lo único que debemos saber es que existen 13 registros de “Propósito general”, numerados del 0 al 12, y sirven para almacenar datos, pueden almacenar cualquier número entero entre 0 y 4.294.967.295. En este caso hemos usado el registro 0 (r0).

Aunque no lo parezca 0x20200000 es un número, lo que pasa es que está escrito en hexadecimal.

Existen varios sistemas de notación, algunos de ellos son: el binario, decimal, octal y hexadecimal.

 

Puedes aprender más sobre la notación hexadecimal aquí.

 

Pues bien, lo que hemos hecho ha sido almacenar el número 0x20200000 en el registro r0, esto puede parecer que no es mucho, pero lo es. En los ordenadores hay muchos trozos de memoria y dispositivos conectados (como por ejemplo el LED que queremos encender), cada uno de ellos tiene asignada una dirección. Al igual que cuando accedemos a una página web o mandamos una carta, tenemos que especificar una dirección que identifique el dispositivo que queremos.

 

En los ordenadores estas direcciones son números, y el número 0x20200000 es la dirección del controlador GPIO. Las direcciones las establecen los fabricantes, podrían haber usado cualquier otra (siempre que no se use para otra cosa).

Esta dirección la obtenemos mirando el manual del fabricante.

 

El controlador GPIO es el que se encarga de controlar los pines GPIO (General Purpose Input/Output, Entrada/Salida de Propósito General). El LED que queremos encender se encuentra conectado a un pin GPIO

Habilitando el pin

Para encender el LED debemos enviarle dos mensajes al controlador GPIO.

Nuestro LED se encuentra en el pin 16 (esto varía dependiendo del modelo), de modo que lo primero que debemos hacer es activar ese pin. Aquí se complica un poco la cosa, hay 54 pines en total, que se dividen en 6 sets (0-9, 10-19,  20-29, 30-39, 40-49, 50-54). Cada uno de estos sets controla 10 pines, menos el último, que controla 5.

Cada set ocupa 4 bytes, es decir, que si la dirección del controlador GPIO es 0x20200000, controlaremos los 10 primeros pines, al aumentar 4 bytes (0x20200000 + 4) estaremos controlando los 10 siguientes, y así sucesivamente. En nuestro caso el pin que debemos activar es el 16, por lo que deberemos ir al segundo set (0x20200000 + 4).

Una vez hayamos especificado a que grupo de pines nos estamos refiriendo, tenemos que especificar el pin concreto que queremos activar. Cada 3 bits hacemos referencia a un pin, es decir, el primer pin podríamos decir que se encuentra en el bit 0, el segundo en el bit 3, el tercero en el bit 6… Y así.

Dado que nuestro pin es el 16, y ya estamos en el set adecuado, debemos decirle que nuestro pin es el sexto de ese set, y como hay un pin cada 3 bits, es tan sencillo como multiplicar 3 x 6.

 

Ahora que sabemos la teoría, vamos a ver como podemos implementarla, para ello, copiamos estas lineas a continuación en nuestro editor de texto:

 

mov r1,#1
lsl r1,#18
str r1,[r0,#4]

 

La primera linea pone el número 1 (en notación decimal)  en el registro r1

 

mov reg,#val pone el número val en el registro reg

Podríamos haber usado ldr igual que antes, pero el comando mov es más rápido porque no tiene que acceder a la memoria. La pega es que solo sirve para almacenar números cuya representación binaria son ocho unos o ceros seguidos únicamente de ceros.

Esto no debe preocuparnos mucho, pero como solo tenemos que almacenar un uno, usamos mov, que es más rápido.

Con el número 1 almacenado en r1 pasamos a la siguiente linea.

 

lsl reg,val desplaza el número en reg escrito en binario val espacios a la izquierda

Con esta instrucción lo que hacemos es desplazar el número 1 almacenado en r1, en binario, 18 espacios a la izquierda, quedando así: 1000000000000000000. Es decir un 1 seguido de 18 ceros. Ahora veremos para que nos sirve esto.

 

str reg,[dest,#val] almacena el número en reg en la dirección dada por dest + val

Con la última linea lo que hacemos es cargar el número 1000000000000000000 a las dirección 0x20200000 + 4. La dirección es, la dirección del controlador GPIO + los 4 bytes que especifican que nuestro pin se encuentra entre el 10 y el 19.

En binario, cada 0 o 1 ocupa un bit, de modo que el número que hemos creado tendría 19 bits, un 1 seguido de 18 ceros. Pero en la Raspberry Pi, al cargar un número en una dirección, cargará un 1 en la parte baja (low en inglés), los ceros. Hay 18 ceros, que equivalen a 18 bits, por lo tanto cargará un 1 en el bit 18.

Ahora que ya tenemos listo el pin 16 podemos enviarle el mensaje para que encienda el LED.

Un haz de luz

El segundo mensaje que debemos enviar hará que encienda el LED

Para eso copiamos las siguientes lineas:

 

mov r1,#1
lsl r1,#16
str r1,[r0,#40]

 

La primera linea pone el número 1 en el registro r1. La segunda lo desplaza 16 espacios a la izquierda (en binario). Puesto que queremos encender el LED que está en el pin 16, tenemos que mandar un 1 en el bit 16, igual que hemos hecho antes. Aunque esto puede variar, porque al igual que antes, cuando los pines están en modo salida, es decir, activados y listos para encenderlos o apagarlos, se dividen en sets, pero esta vez en dos, de 4 bytes. 4 bytes son 32 bits, y le corresponde 1 bit a cada pin, por lo que el primer set va desde el pin 0 hasta el 31, y el segundo desde el 32 hasta el 54.

 

En este caso como nuestro pin se encuentra dentro del primer set no tendremos que hacer nada. En los nuevos modelos será necesario hacer algunos cambios pero eso lo veremos más adelante.

 

La última linea es la que se encarga de enviar el 1 en el bit 16 a la dirección dada por r0 + 40. El 40 viene dado por el fabricante, para encender el LED tenemos que apagar el pin, sí apagarlo. El número 28 encendería el pin, es decir, que apagaría el LED.

 

Actualización (nuevos modelos)

Este tutorial se quedó obsoleto hace tiempo, porque no funciona con los nuevos modelos. Eso se debe a que el LED se encuentra en un pin diferente y la dirección del controlador GPIO es otra.

 

Raspberry Pi 1 A y B – Dirección –> 0x20000000, número de pin del LED –> 16

 

Estos son los modelos para los que está hecho el tutorial, por lo que no hay que realizar ningún cambio, simplemente seguir el tutorial.

 

Raspberry Pi 1 A+, B+ y Zero – Dirección –> 0x20000000, número de pin del LED –> 47

 

En estos modelos la dirección no cambia, por lo que lo único que nos afecta es el cambio de pin.

La primera linea se queda igual:

ldr r0,=0x20200000

Ahora tenemos que enviarle el primer mensaje al controlador GPIO, para activar la salida del pin que queremos. En este caso las cosas cambian, puesto que se trata del pin 47. Lo primero de todo es especificar el set en el que se encuentra, como cada set controla 10 pines, debemos irnos al set número 4 (que controla los pines 40-49).

Como cada set ocupa 4 bytes, deberemos multiplicar 4 x 4.

Ahora debemos especificar cual es el pin que queremos dentro de nuestro set, como cada 3 bits tenemos un pin, y el nuestro es el séptimo, es algo tan simple como 3 x 7.

De modo que el código de la sección “Habilitando el pin” adaptado para este modelo quedaría así:

mov r1,#1
lsl r1,#21
str r1,[r0,#16]

Por último, para encender el led, debemos hacer algunos cambios, en primer lugar, como ya vimos, cuando están en modo salida se dividen en dos sets de 4 bytes, el primer set controla los primeros 32 pines, y el segundo los 22 restantes. Como nuestro pin se encuentra en el segundo set, tenemos que sumar 4 a la dirección del controlador GPIO

Al haber especificado que nuestro pin está en el segundo set, no tendremos que mandar un 1 al bit 47 puesto que nuestro pin en el segundo set el 15 (47 – 32).

Además, aquí para encender el LED han decidido que hay que encender el pin (al contrario que para el modelo original). Por lo que en vez de 40 usamos 28.

Esos 28 se suman a la dirección del controlador, pero como además tenemos que sumarle los 4 bytes que indican que el pin se encuentra en el segundo set, tendríamos que sumarle 32 a la dirección del controlador GPIO.

Quedando el código de la sección “Un haz de luz” así:

mov r1,#1
lsl r1,#15
str r1,[r0,#32]

 

Raspberry Pi 2 B – Dirección –> 0x3F000000, número de pin del LED –> 47

 

En este modelo la dirección del controlador GPIO es 0x3F000000 por lo que la primera linea debemos cambiarla por:

ldr r0,=0x3F000000

Ahora tenemos que enviarle el primer mensaje al controlador GPIO, para activar la salida del pin que queremos. En este caso las cosas cambian, puesto que se trata del pin 47. Lo primero de todo es especificar el set en el que se encuentra, como cada set controla 10 pines, debemos irnos al set número 4 (que controla los pines 40-49).

Como cada set ocupa 4 bytes, deberemos multiplicar 4 x 4.

Ahora debemos especificar cual es el pin que queremos dentro de nuestro set, como cada 3 bits tenemos un pin, y el nuestro es el séptimo, es algo tan simple como 3 x 7.

De modo que el código de la sección “Habilitando el pin” adaptado para este modelo quedaría así:

mov r1,#1
lsl r1,#21
str r1,[r0,#16]

Por último, para encender el led, debemos hacer algunos cambios, en primer lugar, como ya vimos, cuando están en modo salida se dividen en dos sets de 4 bytes, el primer set controla los primeros 32 pines, y el segundo los 22 restantes. Como nuestro pin se encuentra en el segundo set, tenemos que sumar 4 a la dirección del controlador GPIO

Al haber especificado que nuestro pin está en el segundo set, no tendremos que mandar un 1 al bit 47 puesto que nuestro pin en el segundo set el 15 (47 – 32).

Además, aquí para encender el LED han decidido que hay que encender el pin (al contrario que para el modelo original). Por lo que en vez de 40 usamos 28.

Esos 28 se suman a la dirección del controlador, pero como además tenemos que sumarle los 4 bytes que indican que el pin se encuentra en el segundo set, tendríamos que sumarle 32 a la dirección del controlador GPIO.

Quedando el código de la sección “Un haz de luz” así:

mov r1,#1
lsl r1,#15
str r1,[r0,#32]

Buenas a todos, o a nadie, porque es mi segunda entrada y la primera con contenido. De cualquier modo he decidido empezar con este proyecto de forma personal, y lo estoy compartiendo aquí por si a alguien le sirve de ayuda.

 

Hace un tiempo me compré una Raspberry Pi, algo realmente asombroso, es un ordenador completo (con su micro, su memoria RAM, tarjeta gráfica…) montado en una placa del tamaño de una tarjeta de crédito (el modelo “Zero” es incluso más pequeño) y asequible para todo el mundo, desde 5€. La adquirí precisamente por su bajo precio y la cantidad de posibilidades que tenía, pero fueron dos las que más me atrajeron.

Una de ellas fue la cantidad de emuladores de consolas retro que había, y claro, a mí cualquier objeto tecnológico con historia me fascina. De modo que pensé en montarme una pequeña consola retro. Pero más tarde encontré un emulador del Apple II, y si juntamos mi obsesión con Apple y algo retro… Blanco y en botella (horchata).

La segunda se debía a su tamaño, y es que un ordenador con esas dimensiones tenía infinitas posibilidades como herramienta de hacking. Y claro, por aquel entonces yo andaba buscando el modo de hackear mi instituto (cuando me aburro me da por hackear cosas). Aquí es donde entra mi lado hacker, el sistema que administraba todo en mi instituto lo había desarrollado personalmente el director, nada de una empresa privada o el mismo gobierno que ofrece programas de gestión a los colegios e institutos. Había sido el genio de mi director (la verdad es que es un genio) y para mí era un reto conseguir hackearlo, de modo que pensé que la Raspberry podría ayudarme con eso.

Y entre unas cosas y otras me compré una Raspberry, también conseguí hackear mi instituto, pero eso lo dejaré para otra ocasión.

 

Una vez la compré, empecé a trastear con un montón de sistemas que encontraba por Internet, desde Raspbian, una distro de Linux (que como imaginaréis por el nombre está hecha específicamente para la Raspberry) hasta algún sistema multimedia para ver películas piratas en la tele.

Y me encontré con un curso en la web de la universidad de Cambridge llamado Baking Pi, me pareció de lo más interesante, consistía en crear tu propio sistema operativo, desde cero y en un lenguaje de muy bajo nivel, ensamblador.

Esto fue cuando yo tenía 14 años, un nivel de inglés muy por debajo del actual y poca paciencia. Por lo que al día siguiente de haber empezado a leerlo, desistí.

La semana pasada lo retomé desde el principio, porque la última vez no entendí absolutamente nada. Y la verdad es que me gusta bastante como avanza, me costó bastante al principio, primero porque no era compatible con mi Raspberry, ya que el curso está hecho para la primera que sacaron y no funciona con las actuales. También me costaba bastante entender la mayoría de las cosas que se explicaban, pero más adelante, a medida que iba avanzando comprendía como funcionaba. Hay mucha documentación, pero nada en español.

 

Por todo esto me he decidido a desarrollar el mismo curso, actualizado para las nuevas versiones de la Raspberry, en español, y lo más importante, fácil de seguir por cualquiera sin conocimientos previos.

Bueno, supongo que lo primero que hay que hacer en un blog es presentarse, así que me llamo David Begara, tengo 17 años y un problema muy grande, porque quiero hacer muchas cosas, pero muchas. Y claro no me da la vida porque quiero hacerlas todas “Ya!”. Por ejemplo escribir un blog, que ahora mismo lo estoy usando como excusa, porque tengo que recuperar lengua y dibujo técnico y aún no me he puesto a estudiar.

Y le he dicho a mi madre “Mira madre, como estudiar literatura y ponerme a hacer comentarios de texto así de la nada es un poco duro, hago un blog donde cuento lo que voy estudiando con mis palabras y así asimilo conceptos.”

No ha colado, para que mentir, pero ahora que lo pienso no me parece tan mala idea, así que lo mismo lo hago.

 

Pero yo no he empezado con esto del blog para contar como estudio, es más bien una ventana, por la que puedo mostrar lo que voy haciendo. Por ejemplo ahora mismo me he topado de frente con Baking Pi, que es básicamente un curso que ha escrito un alumno de Cambridge (o eso creo) y que es accesible para todo el mundo. El curso te enseña a desarrollar un sistema operativo muy simple para la Raspberry Pi. No os voy a meter el rollo ahora porque ya vendrá más adelante.

Pongo esto como ejemplo porque lo que quiero es explicarlo de forma que cualquier persona lo entienda y pueda seguirlo sin problemas, yo tengo que leer y releer una y otra vez cada párrafo para poder seguirlo, de modo que quiero hacer un “remake” del curso, en español, y a mi parecer de una forma mucho más simple.

Me gusta bastante la programación, y supongo que gran parte de este blog tratará de eso. Pero no quiero quedarme solo ahí, quiero tratar todos mis proyectos, todo lo que haga, cada vez que tenga una idea venir aquí y desarrollarla. Tanto como si hoy me da por programar algo y mañana por la filosofía o la medicina tradicional china. Voy a desarrollar toda mi vida en este blog.

 

Resumiendo, toda la mierda que se me pase por la cabeza pienso escribirla en este blog tan maravilloso.