Ubuntu ARM toolchain compiles Stellaris USB examples correctly

22/12/2012

I managed to get the StellarisWare libraries and examples working without Sourcery Codebench. Based on these two articles:

The complete StellarisWare suite compiles without errors, and the examples I tried (including usb_dev_serial and usb_dev_mouse) work correctly. This is an improvement over summon-arm-toolchain, which compiled non-functional USB examples.

Instructions for Ubuntu 12.10:

  1. # Install toolchain
    sudo aptitude install gcc-arm-linux-gnueabi
    # Download and compile newlib (had trouble with the toolchain's libc and libm)
    wget ftp://sources.redhat.com/pub/newlib/newlib-1.18.0.tar.gz
    tar xzf newlib-1.18.0.tar.gz
    cd newlib-1.18.0/
    ./configure --target arm-linux-gnueabi --disable-newlib-supplied-syscalls
    make

    This makes the files libc.a and libm.a in the subdirectory arm-linux-gnueabi/newlib

  2. Unzip the StellarisWare files, and in the root directory edit makedefs. Search for the following settings and change them, replacing something with the directory where you unzipped newlib
    PREFIX=arm-linux-gnueabi
    LIBC=/something/newlib-1.18.0/arm-linux-gnueabi/newlib/libc.a
    LIBM=/something/newlib-1.18.0/arm-linux-gnueabi/newlib/libm.a

    Also change CFLAGS, adding the line with -fno-stack-protector, so it looks like this:

    CFLAGS=-mthumb             \
           ${CPU}              \
           ${FPU}              \
           -Os                 \
           -ffunction-sections \
           -fdata-sections     \
           -MD                 \
           -std=c99            \
           -Wall               \
           -pedantic           \
           -DPART_${PART}      \
           -fno-stack-protector \
           -c
  3. To compile everything, run make clean and make

USB Mouse example for Stellaris Launchpad

10/12/2012

With some help I got the USB Mouse example from the LM3S9D90 board working on the Stellaris Launchpad. It needed a few changes:

  • Replaced the linker script usb_dev_mouse.ld with one from the Launchpad examples. The only difference was the size and location of the FLASH and SRAM memory regions.
  • Added code to configure the USB pins at startup, as suggested by dellwoodbu.
  • Changed several lines in the Makefile:
    • PART=LM4F120H5QR
    • VARIANT=cm4f
    • Set ROOT to my StellarisWare directory as usual
    • Added a target for programming the board:
      .PHONY: download

      download: ${COMPILER}/usb_dev_mouse.bin
          lm4flash -v $<

    • Replaced all instances of “cm3″ with “cm4f”
    • CFLAGSgcc=-DTARGET_IS_BLIZZARD_RA2

You can download the example project files. Remember to set ROOT in the Makefile to your StellarisWare directory.

Warning: it does not work when compiled with the Summon Arm Toolchain. It compiles without errors but the device fails to enumerate. It responds to descriptor requests with malformed USB packets (seen with Wireshark). Works fine if compiled with Sourcery Codebench, haven’t tried other toolchains.

15/11/2012

My Stellaris Launchpad finally arrived. I’ve been following this tutorial for programming it on Linux successfully.

However, I was annoyed at having to run the flashing utility as root. So I created a udev rule that gives the board’s device file the proper permissions. First, create a group called stellaris and add yourself to that group:
sudo addgroup stellaris
sudo adduser $USER stellaris

Then create the udev rule. Create the file /etc/udev/rules.d/45-stellaris.rules with the following contents:
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0664", GROUP="stellaris"
What does this mean? This line consists of key-value pairs separated by commas.

  1. The first two are match keys: when something is plugged in, udev checks if its vendor and product IDs match the ones here.
  2. The last two are assignment keys: if there’s a match, the device file is created with the specified permissions and group. These permissions mean that the owner (root) and members of the the group stellaris can read from and write to the file, while others can only read.

You might have to restart your terminal in order for it to recognize you’re now in the stellaris group. You can also run
exec su -l $USER

Collaborative latex editing with Dropbox and inotifywait

10/11/2012

I’ve settled on this workflow for writing lab reports in a group:

  • We share a folder with Dropbox that holds the measurements and report files (graphs, latex source files).
  • To prevent collisions we use separate .tex files for different sections, and split the sections between group members.
  • To make sure the output is consistent, only one person compiles the PDF. Inspired by this blog post I wrote a short script to build the PDF whenever a file changes:
#!/bin/bash

while true
do
    echo Compiling
    pdflatex -interaction nonstopmode -file-line-error informe.tex &>salida.log
    inotifywait -e modify -r .
done

Previously I’d tried running

make

in a loop (it only compiles if one of the input files changed). However, this script automatically checks all files for changes, without having to add them to a Makefile.

Configurar un servidor virtual en Apache2

06/08/2012

Me gusta mantener mis proyectos web organizados. Una forma de lograr esto con Apache2 es usando Virtual Hosts. Así Apache espera pedidos en una sola IP, pero según el dominio que se pida, sirve un sitio distinto.

Voy a explicar cómo crear un servidor virtual para pruebas locales, con el hostname notas.

Por el momento sólo configuramos el nombre del servidor y la ubicación de los documentos.

Crear como root el archivo /etc/apache2/sites-available/notas con el contenido:

<VirtualHost *:80>
    ServerName notas
    DocumentRoot /home/ignacio/notas
</VirtualHost>

Para activar el sitio, hay que hacer un link simbólico.

# cd /etc/apache2/sites-enabled
# ln -s ../sites-available/notas 123-notas

(el número tiene que ver con el orden en que se cargan los archivos, no tiene mucha importancia).

Hay que instruirle a apache que vamos a usar servidores virtuales por nombre de dominio. Para eso, agregar al final de /etc/apache2/apache2.conf  la línea

NameVirtualHost *:80

Para que recargue la configuración,

# service apache2 reload

Por último, para que el dominio notas resuelva a nuestra PC, cambiamos /etc/hosts. En mi caso, cambié

127.0.0.1 localhost

por

127.0.0.1 localhost notas

Para probar la configuración, creamos la carpeta /home/ignacio/notas y el archivo /home/ignacio/notas/index.html con algún contenido como “Hola, mundo!”.
Apuntamos el navegador a http://notas/ y debería verse correctamente.

Estudiando la curva misteriosa

18/06/2012

Hace unos años estaba aburrido y me puse a dibujar en una hoja cuadriculada. Encontré un dibujo interesante dibujando segmentos de cierta forma. Empezaba haciendo un segmento del borde izquierdo al inferior. Luego otro, pero que empezaba un poco arriba y terminaba un poco a la izquierda.




Siguiendo así se va formando una grilla muy loca y una curva particular. El otro día me propuse encontrar una función que la describa. Lo primero es darle un nombre a cada una de las rectas que dibujé. Para esto digo que la recta t es la que empieza en (x,y)=(0,t) y termina en (x,y)=(1-t,0).

La ecuación de la recta t es y=t-\frac t{1-t} x.

Ahora quiero ver dónde queda la envolvente. Para esto busco la intersección entre la recta t y una muy cercana, t+dt.

Hay que combinar las ecuaciones

y=t-\frac t{1-t} x
y=t+dt-\frac {t+dt}{1-t-dt} x

Tomando límite con dt\to0 llegamos a que

x = (1-t)^2
y = t^2

Expresando todo en función de x encontramos y = (1-\sqrt x)^2

No es un círculo, ni siquiera sé si tiene nombre.

Visualizador del espectro de una señal

13/10/2010

Hice un programita que permite dibujar un período de una señal y ver su espectro de Fourier. Por ahora permite darle un valor inicial a la señal, ya sea una constante o ruido, cambiarle valores con el mouse y modularla con una frecuencia a elección. El código está disponible en github.

Simulación de ondas

02/10/2010

Estoy desarrollando un simulador de ondas con Python, Qt4 y OpenGL.
Por el momento permite visualizar modos normales de una cuerda. A la brevedad voy a agregar controles para poder variar los modos, condiciones de borde, etc. sin tener que meter mano al código.
Se encuentra disponible aquí

Administrador de materias para la facultad

02/10/2010

Estoy escribiendo en Python un programa que toma una lista de materias y correlativas, y permite ver cosas como

  1. Correlativas de una materia
  2. Qué me falta aprobar para poder cursar algo
  3. Materias a las que me puedo anotar

El código está disponible en github

Tetris (parte 1)

05/09/2010

Edit 2/10: El código completo está en github

Hace una semana empecé a escribir un Tetris simple en Python (para
ir aprendiendo el lenguaje). Al poco tiempo me dejé ir con la abstracción y generalización, hasta que vi que terminarlo iba a ser imposible.

Por eso decidí empezar de nuevo con una versión más simple y no pensar demasiado a futuro, para mantener el proyecto manejable. Lo que conseguí, como primera etapa, es la lógica de juego básica de Tetris, por el momento sin interfase gráfica.

Estructuras y funciones

Lo principal es la matriz contenida en grilla, la cual almacena el contenido de cada celda. Un cero representa una celda vacía, y otros números representan los distintos colores, texturas o como sea que la interfase diferencie a los bloques.

filas = 14
columnas = 10
# Guarda el color de cada celda de la grilla (0 = vacío)
grilla = [[0 for i in range(columnas)] for j in range(filas)]
colores_max = 5

Por otra parte está la lista pieza. Cada elemento es una dupla con las coordenadas de una celda que pertenece a la pieza. De este modo, cuando quiero que la pieza en juego caiga o se mueva de costado, sé qué celdas tengo que actualizar. El color de la pieza en juego se guarda en colorPieza. Ambas estructuras se actualizan al llamar piezaNueva(). Para la generación de piezas nuevas, está la lista formas, que contiene matrices que describen las piezas posibles (se carga de un archivo de texto).

formas = cargarPiezas("piezas.txt")
# Duplas con las coordenadas de cada celda que pertenece a la pieza actual
pieza = []
colorPieza = 0

mover(dx,dy)

Esta función se usa tanto para que el jugador mueva la pieza de costado como para hacerla caer. Los dos parámetros son el desplazamiento en x e y. Lo primero es verificar que haya lugar en la nueva posición:

def mover(dx,dy):
    global pieza
    # Me fijo que haya lugar para mover la pieza y que no se salga del tablero
    piezaNueva = []
    for (x,y) in pieza:
        if y+dy == filas or x+dx == columnas or y+dy < 0 or x+dx < 0 or \
            (x+dx,y+dy) not in pieza and grilla[y+dy][x+dx] != 0:
            return True
        piezaNueva.append((x+dx,y+dy))

Si hay lugar creo una nueva lista piezaNueva, con las nuevas coordenadas de la pieza. Me va a convenir poder comparar las coordenadas viejas con las nuevas para saber qué celdas necesito actualizar:

    # La muevo
    for (x,y) in pieza:
        if (x,y) not in piezaNueva:
            grilla[y][x] = 0
    for (x,y) in piezaNueva:
        grilla[y][x] = colorPieza
    pieza = piezaNueva
    return False

cargarPiezas(archivo)

Las piezas que puedo generar están guardadas en un archivo con el siguiente formato:

 1
111

1
1
11

11
11

Para traducir esto a una estructura manejable, leo el archivo línea por línea y voy generando la lista formas:

def cargarPiezas(archivo):
    piezas= [[]]
    # Las piezas están en un archivo de texto, separadas por lineas vacías
    f = open(archivo,'r')
    nueva = None
    for linea in f:
        if linea.isspace():
            piezas.append([])
            continue
        piezas[-1].append([(0,1)[c != " "] for c in linea.rstrip()])

    # Ahora me aseguro que las filas de cada pieza tengan largo uniforme
    for pieza in piezas:
        ancho = max([len(fila) for fila in pieza])
        for fila in pieza:
            fila.extend([0]*(ancho-len(fila)))
    return piezas

piezaNueva()

Cuando una pieza termina de caer, genero otra nueva. Esta función elija una forma al azar, genera la lista pieza, elije un color y verifica que haya lugar para colocarla. Luego la copia al tablero.

def piezaNueva():
    from random import random
    global pieza, grilla, colorPieza
    # Selecciono una forma al azar
    nueva = formas[int(random()*len(formas))]
    ancho = max([len(fila) for fila in nueva ])
    pieza = []
    # Posición inicial
    dx = int(random()*(columnas-ancho))
    # Traduzco de la grilla que describe la pieza al array de coordenadas
    for (y,fila) in enumerate(nueva):
        for (x,celda) in enumerate(fila):
            if celda != 0:
                pieza.append((x+dx,y))
    colorPieza = int(random()*colores_max)+1
    for (x,y) in pieza:
        if grilla[y][x] != 0:
            # No hay lugar para la pieza, perdiste.
            return True
    for (x,y) in pieza:
        grilla[y][x] = colorPieza

Interfase textual

Por el momento el tablero se muestra como una grilla de números en la consola, mediante una función muy simple:

def mostrarGrilla():
    for fila in grilla:
        for celda in fila:
            sys.stdout.write('{0:d}'.format(celda))
        print

La lógica del juego está contenida aquí. Se encarga de aceptar entrada del usuario y las distintas etapas del juego. No permite iniciar un juego nuevo (sin reiniciar el programa), y si bien avisa cuando uno pierde, no hace terminar el juego.

if __name__ == "__main__":
    piezaNueva()
    while 1:
        # Hago caer la pieza, si da true no pudo caer
        if mover(0,1):
            print "Se trabó"
            # La pieza no puede caer más. 
            # Me fijo si completó una fila y agrego una pieza nueva
            pieza = []
            # Me fijo qué filas falta completar
            incompletas = []
            for fila in grilla:
                if min(fila) == 0:
                    incompletas.append(fila)
            ncompletas = filas-len(incompletas)
            if ncompletas > 0:
                print ncompletas,"filas completas"
            # Esas filas son las únicas que van a quedar, todas al fondo
            grilla[ncompletas:] = incompletas
            # Lo demás queda vacío
            grilla[:ncompletas] = [[0 for i in range(columnas)]
                for j in range(ncompletas)] 
            if piezaNueva():
                print "Perdiste"
                break 
        mostrarGrilla()
        print
        entrada = raw_input(">")
        if entrada == "q":
            break
        elif entrada == "a":
            mover(-1,0)
        elif entrada == "d":
            mover(1,0)

En el siguiente artículo voy a contar cómo implemento una interfase gráfica con Qt y OpenGL.
Edit 12/9: también voy a permitirle rotar las piezas, sino no sería exactamente un tetris…


Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.