Written by Holguer A. Becerra
 
 
 
 
 
Requerimientos:
  • DE0-NANO
  • USB-UART(solo para parte 3)
  • Python 2.7 ó superior.
 
Objetivos:
  • Dar una introducción a los conceptos de Multitasking, Scheduling y Context Switching.
  • Introducir al estudiante al mundo de los sistemas operativos en tiempo real.
  • Hacer descripción de hardware basica compatible con RTOS(Real-Time Operating Systems).
  • Correr un sistema operativo de tiempo real sobre el soft-core Nios II.
  • Transferir datos de acceleración por medio de un conversor UART-USB a el PC.
  • Usar Python para adquirir y graficar datos de acceleración.
 
  1. Introducción.
  2. Construir Hardware y Software para FreeRTOS.
  3. Accelerometro and UART en FREERTOS.
    1. VPython para adquirir graficar datos de accelerometro por UART.
 
 
Parte 1(Introducción a FREERTOS):
 
Hoy en día vivimos en un mundo rodeado de computadores que ayudan a tener una vida mucho mas sencilla, incluso gracias a un computador usted tiene hoy día acceso a esta información que años atrás no hubiera sido posible sin la ayuda de las ciencias de la computación. Hoy en día usted sabe que existen PC, laptops y smartphones y que estos sistemas se basan en procesadores de arquitecturas hardware CISC y ARM, pero también usted sabe que esos sistemas no podrían ser lo que son hoy en día sin un Sistema Operativo(OS) que distribuya de manera eficiente los tiempos que requiere cada aplicación para ejecutarse de manera correcta sobre la maquina en la que esta corriendo.
 
A lo largo del curso usted ha implementado el soft-core Nios II y usted se ha dado cuenta que al igual que cualquier microprocesador el ejecuta cada proceso o tarea de manera secuencial, es decir para poder pasar a otro proceso el antes debe haber terminado el anterior, esto no es solo es cuestión de este soft-core, todos los procesadores diseñados son maquinas de estados generalizadas que ejecutan código linea a linea y que antes de pasar de una linea a otra debe haber terminado la anterior, pero ahora la pregunta que usted probablemente debe hacerse es ¿Como es posible que un computador convencional ejecute varias tareas al mismo tiempo?, bueno muchos responderían que es gracias a la frecuencia del procesador... cosa que no es cierto del todo ya que usted se ha dado cuenta que el procesador por si solo no podría hacer todas las tareas que hace de manera totalmente secuencial y que hay algo mas que debe controlara los tiempos de ejecución de cada programa que esta corriendo en el computador para que todo se ejecute de manera adecuada y sin el mínimo retraso. Bueno pero ¿Qué es eso que controla esos tiempos de ejecución? la respuesta es el OS, gracias a este software las aplicaciones que corren sobre la maquina(HW) pueden aparentemente ejecutarse en "paralelo"(al mismo tiempo), pero recuerde que un procesador solo puede ejecutar una cosa a la vez... lo que sucede es que el sistema operativo se encarga de distribuir tiempos específicos para dar permiso de ejecución a la aplicación y por esto pareciera que estas tareas se ejecutaran de forma simultanea.
 
Usted conoce los sistemas operativos de propósitos general como Windows, Linux, iOS y Solaris, estos como su nombre lo dice, son "de propósito general" y son sistemas no deterministicos lo que quiere decir que no hay certeza un una formula que pueda decir con exactitud el tiempo de ejecución de cada una de las tareas, o que esta se ejecute realmente cada vez de manera estricta y en tiempos especificos, ademas que entre mas servicios se pidan al OS esto puede ocasionar retrasos en los tiempos de ejecución de las tareas que están corriendo sobre la maquina, y como su nombre lo dicen son OS de Proposito General y no para aplicarlos a solucionar problemas específicos.
 
Existen otros sistemas operativos que usted tal vez no conozca llamados sistemas operativos de tiempo real o RTOS, como FreeRTOS, uC/OS-II, uC/OS-III, RTLinux, QNX, eCOS entre otros... estos OS a diferencias del los de propósito general se aplican para cosas especificas y mantienen tiempos específicos para cada aplicación lo que asegura que no existan retrasos entre la ejecución de una tarea y otra tarea(algo muy útil para una aplicación que requiera de confiabilidad y que tenga una aplicación especifica en la industria).
 
Recordando la capa de abstracción recuerde que el OS aparte de distribuir los tiempos de ejecución de las aplicaciones también esta encargado de permitir el paso de información desde la aplicación hasta la capa HAL.
 
 
En esta practica vamos a implementar un RTOS(FreeRTOS) que se ejecutara sobre el soft-core Nios II, pero para esto usted deberá leer antes los siguientes conceptos:
Una vez leído deberá responder estas preguntas(Saldrán en el parcial):
  • ¿Qué es un kernel?.
  • ¿Qué es Multitasking?.
  • ¿Qué es single tasking?
  • Escriba dos diferencias entre Multitasking y Concurrency.
  • ¿Que es un scheduler?
  • ¿Para que se utiliza el Context Switching?
  • ¿Qué es tiempo real?
Una vez usted tenga claro los conceptos anteriores podrá seguir a la parte aplicada de esta practica.
 
 
Parte 2(Aplicación):
 
Materiales:
  1. DE0-NANO.
  2. USB-UART.
 
En esta parte implementaremos el sistema operativo de tiempo real FreeRTOS sobre el soft-core Nios II utilizando la DE0-NANO.
 
Como guía descargue la siguiente Download this file (doc.zip)documentación.
 
  1. Cree una plantilla con el System Builder de la DE0-NANO, como el que se muestra a continuación(recuerde guardarla en una ruta sin espacios y corta):
  2. Descargue el archivo IP y descomprima en la carpeta o plantilla manteniendo el nombre de la carpeta ip.
  3. Diseñe utilizando Qsys un sistema que funcione a 100MHz con las siguientes características(Puede guiarse de otro que ya haya descrito), pero asegúrese de que los nombres de los diferentes periféricos son los que se indican a continuación.
    1. Reset Vector conectado a la epcs.
    2. Exception vector conectado a la sdram.
    1. Nios II/e, llamado cpu.
    2. System ID Pheripheral, llamado sysid
    3. SDRAM Controller 32 MB, llamado sdram.
    4. JTAG UART conecte tambien al IRQ y de prioridad 5, llamado jtag_uart.
    5. Interval Timer a 1ms con interrupcion conectada al bus IRQ y de prioridad 0, llamado sys_clk.==> gracias a la interrupción con este  timer, el scheduler puede distribuir tiempos, hasta este punto usted ha creado un HW compatible con FreeRTOS, lo siguiente se agrega para hacer demostraciones usando el FreeRTOS.
      El sys_clk es el timer con el que funcionara el FreeRTOS, sin el no funcionaria el OS.
    6. UART(RS-232 serial port), llamado uart, con IRQ conectada y prioridad de 2
    7. PIO Parallel I/O de salida, llamado LED y de 8 bits.
    8. PIO Parallel I/O de entrada, llamado SW y de 4 bits.
    9. PIO Parallel I/O de entrada, llamado KEY y de 2 bits.
    10. EPCS, llamado epcs.
    11. TERASIC_SPI_3WIRE, llamado gsensor_spi. ==> vamos a utilizar el accelerometro en la parte 3 mas adelante en esta practica

      Para comprobar que su sistema esta bien diseñado en qsys descargue el archivo Download this file (doc.zip)system.qsys siguiente.


  4. Una vez tenga su sistema Qsys, agréguelo al quartus y instancielo de la siguiente manera(recuerde crear el pll_sys y recuerde el desfase de sdram_clk).
  5. Ahora genere el hardware con el Quartus.
  6. Abra Nios II Software Build Tools y cree una Nios II application and BSP  from template de tipo "Blank Project", seleccione el SOPC information y llame el proyecto como "FreeRTOS_test".
  7. Descargue el Download this file (doc.zip)archivo .zip  y copie los archivos que se encuentran en este zip, en la carpeta de aplicación del proyecto "FreeRTOS_test".
  8. Ahora haga click derecho sobre la carpeta FreeRTOS_test del proyecto y vaya a propierties y modifique el "Application includes directories" para que se vea como el siguiente(Debe ubicar cada carpeta donde esta ubicado su proyecto y cuando agregue cada directorio le saldrá un letrero que le preguntara si quiere convertir el path en un path relativo, usted debe decirle que si).
  9. Ahora cree la carpeta de aplicación un SourceFile llamado "main.c" y agregue en el encabezado del proyecto las siguientes librerías.
  10. Ahora escriba debajo de los includes, los siguientes macros que nos ayudaran a leer y escribir en los puertos LED, SW y KEY de nuestro sistema.


  11. Ahora escriba la función principal del sistema int main(), y escriba un programa que haga TOGGLE de LED 0 cada segundo si el puerto SW esta en 0, que haga toggle cada 0.5 segundos si el puerto SW esta en 1, de lo contrario que haga toggle cada 5 segundos.
  12. El anterior solo fue un ejemplo sin OS, antes de implementar el OS haremos unos ejercicios extras para luego apreciar al FreeRTOS. Ahora modifique el programa para que tambien haga TOGGLE del LED 1, de manera constante cada 200ms, y que el LED 0 haga toggle cada segundo.
  13. En el anterior programa usted se ha dado cuenta que para lograr que el LED1 y el LED0 se enciendan en diferentes tiempos usted debe distribuir los tiempos en que ellos hagan TOGGLE, usted por medio de código hizo lo que hace un scheduler, el código debió quedarle algo similar a esto.

    Si no logro hacer el punto 12, analice el código que aparece en la imagen y tendrá claro lo que es administrar tiempos.
  14. Ahora modifique el código para que haga lo siguiente:
    ->Haga Toggle del LED 0 cada 1Hz.
    ->Haga Toggle del LED 1 cada 5Hz.
    ->Haga que utilice los LED del 2 al 6 para hacer la siguiente secuencia con cambios de 10Hz entre cambio:
    100000
    010000
    001000
    000100
    000010
    000001

  15. Si hizo bien el código debió quedarle algo así:
  16. Ahora a este mismo código añada que cada 11Hz haga toggle de LED 7 y seguido de esto llame la función usleep(1000000) 
  17. ¿Que sucedió con las demás tareas?, ¿Estas siguen ejecutándose en los tiempos predispuestos anteriormente?, ¿Por qué ocurre este retraso en las otras tareas?, ¿Por qué el LED 7 hace TOGGLE cada 11 Hz? y ¿Como haría para que este proceso no afecte a las demás secuencias?.

    Como usted vio usleep(1000000) afecta la continuidad del encendió y apagado de los otros leds, el usleep() seria la representación de una función que requiera una carga computacional un poco mas alta que solo asignar valores a los LEDs o leer un puerto, si esto fuera un sistema que necesita muestrear datos a tiempos específicos, claramente al agregar una función que requiera de un costo computacional alto, esta afectaría el muestreo en tiempo real.
    Esto también demuestra que para hacer código que respete tiempos utilizando single tasking, requiere que el programador sea quien modifique los tiempos, y como se ve en el momento que se llame una función que requiera bastante tiempo se verán afectados los otros procesos.

    Para ve un ejemplo vamos a ver un vídeo que muestra como un sistemas puede ser afectado(este vídeo lo grabe hace dos años, así que el ingles no es muy bueno).


  18. Todos los ejercicios que se han hecho hasta ahora han sido sin OS, ahora veamos como seria usando el FreeRTOS, replicando el ejercicio anterior.
    Para esto usted ha debido leer el archivo "Sistemas Embebidos_RTOS.pdf" que esta dentro de la documentación de FreeRTOS.
  19. Como usted leyó en el archivo, específicamente en la pagina 12, se habla de que una tarea es un subproceso que debe gestionar el sistema operativo y que cada proceso es un pequeño main que tiene un bucle principal y ademas un delay que libera la CPU por un tiempo especifico, ademas que cada tarea tiene una prioridad para el OS.


    Ahora vamos ha replicar el experimento que se hizo sin OS, pero esta vez con FreeRTOS.

  20. Copie entre los includes y los macros de acceso a puertos lo siguiente, con el fin de definir las prioridades que va a tener cada tarea:
  21. Ahora modifique el código para que luzca como el siguiente:
  22. Compile y corra el programa sobre el Nios, ¿Que pasa con el LED0, cada cuanto hace toggle?.
  23. Ahora agregue otra tarea para que haga toggle el LED 1 cada 5Hz.
  24. ¿Cuantas tareas están siendo ejecutadas en el FreeRTOS?.
    Ahora agregue una tarea que tenga prioridad LED_2_6_TASK_PRIORITY
    Haga que utilice los LED del 2 al 6 para hacer la siguiente secuencia con cambios de 10Hz entre cambio:
    100000
    010000
    001000
    000100
    000010
    000001
  25. Ahora por ultimo agregue la tarea que causo problemas cuando no se tenia OS.
    La tarea que cada 11Hz haga toggle de LED 7 y seguido de esto llame la función vTaskDelay(1000 /portTICK_RATE_MS);
  26. Ahora responda: 
    1) ¿Cada cuanto se prende y apaga el LED 7?.
    2)¿Por qué ahora no se afectan las otras tareas?.
    3)¿Que ventajas tiene utilizar un RTOS con respecto al single tasking visto anteriormente?
    4) ¿Para que sirve el archivo FreeRTOSConfig.h? http://www.freertos.org/a00110.html
    5) ¿Cual es la tarea de mayor prioridad y cual la de menor?.
    6) ¿Qué pasaría si una tarea tuviera la misma prioridad que otra usando FreeRTOS?
    7)¿Qué ventajas tiene utilizar RTOS con Nios II y en una FPGA?, ¿Que pasaría si usted combinara los conceptos que ha aprendido a lo largo del curso HW y SW con el FreeRTOS?, ¿Qué podría hacer con un RTOS en un FPGA comparado con un procesador convencional, teniendo en cuenta custom hardware?.

  27. Con estos conocimiento ahora es su turno de investigar, las otras funcionalidades que ofrece un RTOS, en este caso FreeRTOS, como Mutex, Semaphores entre otras cosas que usted puede ver en la documentación de FreeRTOS.
 

 

Parte 3(Accelerometro, plus de la practica):

En esta sección vamos agregar(Conservando las de la parte 2) crear una tarea en el FreeRTOS donde se lea del accelerometro el Pitch, Roll and Yaw,  y enviarlas por medio de UART a un script de python, donde se visualizara el movimiento de manera tridimensional.
  1. Ya en el laboratorio 3 usted vio como usar con python el puerto serial para enviar y recibir datos, ahora implementara un script que no solo recibe datos si no que gráfica de forma tridimensional la posición de un bloque en la pantalla del computador. Para esto usted debe tener instalado.
    1. Python 2.7.
    2. Pyserial 2.7.
    3. Vpython 2.7.
  2. Descargue el Download this file (doc.zip)archivo .zip que contiene los drivers para usar el accelerometro y copie la carpeta Drivers en la carpeta del proyecto "FreeRTOS_test".
  3. Ahora en el encabezado del main.c agregue la librería para usar el driver.
  4. Modifique el procedimiento SetupHardware para que se vea como se muestra a continuación:
  5. Ahora defina la prioridad de la tarea que se va a crear:
  6. Agregue la tarea y ejecútela al iniciar el sistema.
  7. Compile, conecte al USB-Serial a la DE0-NANO y al PC, descargue el script de python, cambien el puerto por el cual desea adquirir la información en el script y ejecútelo., y tendrá que obtener como resultado lo siguiente:
 
Codigo PythonDownload this file (Box_3d.py)Box_3d.py
 
import serial, math,time
from visual import *

ser = serial.Serial('COM5', 115200)

data1=0;
data2=0;
data3=0;
data4=0;
data5=0;
data6=0;
data7=0;

X=0;
Y=0;
Z=0;
signo=0;

scene.title='ECE 31289 UPB'

mybox = box(pos=(50,10,57/2), length=100, height=20, width=57)
pointer = arrow(pos=(0,0,0),axis=(0,100,0),shaftwidth=1)
pointer1 = arrow(pos=(0,0,0),axis=(0,0,100),shaftwidth=1)
pointer2 = arrow(pos=(0,0,0),axis=(100,0,0),shaftwidth=1)

mybox.opacity=0.5
mybox.color= color.blue
pointer.color= color.cyan
pointer1.color= color.red
pointer2.color= color.yellow
picth=0
roll=0
yaw=0

scene.autoscale =0

theta = 0 # initial polar angle of shaft (from vertical)
thetadot = 0 # initial rate of change of polar angle
alpha = 0 # initial spin angle
alphadot = 0.0 # initial rate of change of spin angle (spin ang. velocity)
phi = -pi/2. # initial azimuthal angle
phidot = 0 # initial rate of change of azimuthal angle
dt = 0.0001

while 1:
    
    keys1=ord(ser.read(1))
    
    if(keys1==7):
        data1=ord(ser.read(1))
        data2=ord(ser.read(1))
        data3=ord(ser.read(1))
        data4=ord(ser.read(1))
        data5=ord(ser.read(1))
        data6=ord(ser.read(1))
        data7=ord(ser.read(1))
        X=(data1 & 1)*128 | (((data1>>1)&1)<<16) | (data2 & 127)| ((data3 & 127)<<8)
        if(X & 4096):# paso a signed short 16 bits
            
            X=-0x1000 + (X & 4095)
        
            
        
        Y=(data1>>2 & 1)*128 | (((data1>>3)&1)<<16) |(data4 & 127) | ((data5 & 127)<<8)
        if(Y & 4096):# paso a signed short 16 bits
               
            Y=-0x1000 + (Y & 4095)
        
        
        Z=(data1>>4 & 1)*128 | (((data1>>5)&1)<<16) |(data6 & 127) | ((data7 & 127)<<8)
        if(Z & 4096):# paso a signed short 16 bits
               
            Z=-0x1000 + (Z & 4095)
            
        print 'X='+ str(X) + ' Y=' + str(Y) + ' Z=' + str(Z)
        #pitch=math.atan((X/(math.sqrt(Y**2 +Z**2)+0.01)))
        #roll=math.atan((Y/(math.sqrt(X**2 +Z**2)+0.01)))
        #yaw=math.atan((math.sqrt(X**2 +Y**2)/(Z+0.01)))

        mybox.axis= X,Y,Z
        #mybox.axis= pitch,roll,yaw
        mybox.length=30 
        mybox.width=100
        mybox.height=57

        
        
        
        
        

        
        
        
        
    
    


 
 
Ahora puede usar FreeRTOS para los proyectos que desee usando Nios II en la DE0-NANO.
 
Tambien puede usar otros sistemas operativos de tiempo real usando Nios II u otros procesadores sobre la DE0-NANO, trate de implementar uC/OS-IIeCOSRTLinuxuClinux, entre otros...