Scope/es

From Qi-Hardware
Jump to: navigation, search

NOTE, SAKC has been renamed SIE. So, some places SIE is referred to as SAKC.


Contents

[edit] Osciloscopio Básico

En esta sección realizaremos un ejemplo básico haciendo uso del conversor Análogo-Digital y el LCD del que dispone la plataforma para mostrar señales. Comenzaremos por describir el funcionamiento del ADC.

[edit] Usando el ADC

SIE utiliza el conversor Análogo-Digital TLV1548; La siguiente Figura muestra el diagrama de tiempos de este dispositivo, en el que basaremos el diseño de nuestro periférico.

Formas de onda del ADC TLV1548.

La interface en modo "microprocesador" con el ADC funciona de la siguiente manera: en cada flanco de bajada de CS se resetean todos los contadores e inicializa la máquina de estados. Luego durante los primeros 4 flancos de I/O CLK el ADC recibe los datos en DI comenzando por el bit más significativo, esto quiere decir que durante los seis flancos restantes no recibe información. En el décimo flanco de subida de I/O CLK la señal EOC se pone en bajo durante el tiempo de conversión (10us o 40us) y se pone en alto cuando esta halla terminado. El MSB del valor de la última conversión es puesto en DO en el flanco de bajada de CS, así recibiremos los diez bits de cada conversión durante los primeros diez flancos de subida del reloj. En resumen, mientras estamos enviando un comando al ADC también estamos recibiendo los valores de muestreo.

Para poder comenzar a utilizar el conversor debemos inicializarlo, para ello le enviamos el comando 0x09, que lo configura en modo de conversión rápida. A continuación mostramos la lista completa de comandos que recibe el ADC:


Función Valor Hexadecimal Comentario
Canal A0 seleccionado 0h
Canal A1 seleccionado 1h
Canal A2 seleccionado 2h
Canal A3 seleccionado 3h
Canal A4 seleccionado 4h
Canal A5 seleccionado 5h
Canal A6 seleccionado 6h
Canal A7 seleccionado 7h
Modo de bajo consumo 8h No hay resultados de conversión
Modo de conversión rápida 9h (~10us) No hay resultados de conversión
Modo de conversión lenta Ah (~40us) No hay resultados de conversión
Modo de auto-prueba 1 Bh (Vref) – Vref–)/2 >> Retorna 200h
Modo de auto-prueba 2 Ch Vref– >> Retorna 000h
Modo de auto-prueba 2 Dh Vref >> Retorna 3FFh


[edit] ADC como periférico en la FPGA

Basados en lo desarrollado en Xburst-FPGA Interface y en Xburst-FPGA communication example hemos descrito el hardware necesario para usar el ADC, los archivos fuente se pueden encontran en el siguiente enlace.

El archivo ADC.v es el que se encarga de realizar la sincronización de las señales y de decodificar el bus de direcciónes para generar las señales de Chip Select correspondientes y controlar el bus de datos.

Con respecto al ejemplo de comunicación con la FPGA, este archivo no tiene la RAM y en lugar de ello tenemos:


  1. // Peripherals control     
  2. wire     [3:0]   csN;     
  3. wire     [7:0]   rdBus0, rdBus1, rdBus2, rdBus3;            
  4.  
  5. assign csN = buffer_addr[12]? (buffer_addr[11]? 4'b1000:
  6.                                                 4'b0100)                                 
  7.                             : (buffer_addr[11]? 4'b0010:                                                      
  8.                                                 4'b0001);      
  9.  
  10. assign rdBus = buffer_addr[12]? (buffer_addr[11]? rdBus3:
  11.                                                   rdBus2)
  12.                               : (buffer_addr[11]? rdBus1:                                                        
  13.                                                   rdBus0);


Diagrama de interfaz básica


Este ejemplo está diseñado para que eventualmente podamos incluir más periféricos adicionales al ADC, por ello se muestran en gris los componentes que podrían existir.

Como vemos, de las trece líneas de dirección que llegan a la FPGA utilizamos las primeras dos como selector de periférico, por lo tanto para este ejemplo podremos conectar hasta cuatro periféricos, cada uno capaz de direccionar hasta 2048 bytes.

El siguiente diagrama muestra el diseño del periférico

Diagrama de periférico ADC

Basados en este diagrama describimos el hardware necesario en el archivo ADC_peripheral.v. Ahora explicaremos el funcionamiento de este periférico:

En el diagrama, las señales o buses de color gris son las entradas o salidas del módulo, en ADC.v lo encontraremos instanciado de la siguiente forma


  1. // Peripheral instantiation     
  2. ADC_peripheral  P1(                          
  3. .clk(clk),                          
  4. .reset(reset),                          
  5. .cs(csN[0]),                        
  6. .ADC_EOC(ADC_EOC),                          
  7. .ADC_CS(ADC_CS),                          
  8. .ADC_CSTART(ADC_CSTART), 				        
  9. .ADC_SCLK(ADC_SCLK),  				        
  10. .ADC_SDIN(ADC_SDIN),  				        
  11. .ADC_SDOUT(ADC_SDOUT),  				        
  12. .addr(buffer_addr[10:0]), 				        
  13. .rdBus(rdBus0),  				        
  14. .wrBus(wrBus),  				        
  15. .we(we));


Mientras que las señales o buses de color negro son señales internas del módulo ADC_peripheral.

[edit] Registros de configuración (Memory Map)

Para configurar el periférico tenemos disponibles seis registros:


CLKDIV: Utilizado para generar el reloj para la comunicación con el ADC.

SIZEB: Determina el tamaño del buffer, o más bien, la cantidad de muestras que se tomaran.

CMD_SW: Se utiliza para realizar el cambio de canal análogo de maneta automática en cada lectura del ADC.

CMD_START: Cuando este en alto le indica al control cuando debe iniciar un proceso de lectura o muestreo, cuando el periférico termine de leer la cantidad de datos especificados por SIZEB esta señal se pondrá en bajo automáticamente.

CMD_TYP: Este define el tipo de comando que se realizará, tiene un valor de '1' para tipo SET y '0' para tipo READ, este registro existe debido a que algunos comando no necesariamente implican una lectura de datos.

CMD_ADC: este es el comando que se le envía al ADC, corresponde a los descritos en la tabla mostrada anteriormente.


Esto es de acuerdo con el memory map dispuesto. Además de los registros de configuración tenemos el RX_BUFFER que es donde se almacenarán los datos recibidos desde el ADC, esté consta de una RAM dual-port para que pueda ser escrita y leída desde el microprocesador e internamente.


[edit] Bloque REGISTER BANK

El bloque REGISTER BANK se encarga específicamente de controlar la escritura y lectura de los registros de configuración y del buffer de datos en base al mapeo de memoria que se muestra en el diagrama. Éste bloque toma las señales fullB y rstStart que resetean el valor del registro CMD_START cuando el buffer este lleno o cuando el bloque CONTROL termine de enviar un comando al ADC. En el archivo fuente se encuentra definido en dos partes, el control de escritura y el control de lectura, en el primero se realiza la escritura de los registros de configuración y se controla la escritura sobre la RAM dual-port (RX_BUFFER), además de incluir un reset del registro CMD_START, en el segundo se leen los registros de configuración y además se controla la lectura de la RAM, esto para cuando vamos a leer los datos recibidos desde el ADC. El código que describe este bloque es el siguiente:


  1.     // REGISTER BANK:   Write control
  2.     always @(negedge clk)
  3.     begin
  4.         if(reset) 
  5.             {CMD_START, CMD_TYP,CMD_ADC,SIZEB,we1} <= 0;
  6.         else if(we & cs) begin
  7.             case (addr)   
  8.                     0: begin CLKDIV[7:0]    <= wrBus;      end
  9.                     1: begin SIZEB[7:0]     <= wrBus;      end
  10.                     2: begin SIZEB[9:8]     <= wrBus[1:0]; end            
  11.                     3: begin CMD_SW[1:0]    <= wrBus[7:6];
  12.                              CMD_START      <= wrBus[5];
  13.                              CMD_TYP        <= wrBus[4];
  14.                              CMD_ADC[3:0]   <= wrBus[3:0]; end
  15.               default: begin we1 <= 1; end     
  16.             endcase 
  17.         end 
  18.         else begin 
  19.             we1 <= 0; end
  20.  
  21.         if(fullB | rstStart) CMD_START <= 0; 
  22.     end   
  23.  
  24.     // REGISTER BANK:   Read control    
  25.     always @(posedge clk)
  26.         if(reset) 
  27.             {rdBus} <= 0;
  28.         else begin
  29.             case (addr)   
  30.                   0: begin rdBus  <= CLKDIV;       end
  31.                   1: begin rdBus  <= SIZEB[7:0];   end
  32.                   2: begin rdBus  <= SIZEB[9:8];   end            
  33.                   3: begin rdBus  <= {CMD_SW,CMD_START,CMD_TYP,CMD_ADC};end
  34.             default: begin rdBus  <= rdBus1;       end
  35.             endcase 
  36.         end


[edit] Bloque CONTROL

Para establecer el estado de la señal ADC_CS, realizar el control de la comunicación SPI y la recepción de datos tenemos el bloque CONTROL. Éste iniciará su proceso cuando se ponga en alto CMD_START, luego pone en alto a SPI_wr para comenzar una nueva transmisión de datos, cuando la transmición finaliza (determinado por los valores que tomen busy y ADC_EOC) la máquina de estados indicará que se debe guardar un dato del buffer de recepción colocando en alto las señales initB y loadB en la secuencia adecuada para cuando el comando transmitido es de tipo READ, en caso contrario, si se trataba de un comando de tipo SET simplemente no indica el almacenamiento de datos y en lugar de ello pone en alto la señal rstStart durante un ciclo de reloj para que CMD_START se ponga en bajo. El comportamiento puede quedar más claro si analizamos el siguiente diagrama de flujo.

Diagrama de flujo bloque CONTROL


Luego la descripción de hardware del bloque CONTROL es:


  1.     // CONTROL
  2.     always @(posedge clk)
  3.         if(reset) begin
  4.             {w_st0, SPI_wr, loadB, initB} <= 0;
  5.             ADC_CS <=1;
  6.         end
  7.         else begin
  8.             case (w_st0)
  9.                  0: begin 
  10.                         rstStart <= 0; 
  11.                         if(CMD_START) begin
  12.                             ADC_CS <=0; 
  13.                             SPI_wr <= 1;                            
  14.                             w_st0 <=1;    
  15.                         end
  16.                     end                       
  17.                  1: begin SPI_wr <= 0; w_st0 <=2; end
  18.                  2: begin
  19.                         if(!busy & ADC_EOC) begin 
  20.                             ADC_CS <=1;
  21.                             if(CMD_TYP) begin
  22.                                 rstStart <= 1; 
  23.                                 w_st0<= 0; 
  24.                             end
  25.                             else begin 
  26.                                 initB<=1;
  27.                                 w_st0<= 3; 
  28.                             end                     
  29.                         end
  30.                     end              
  31.                  3: begin loadB <= 1; w_st0<= 4; end              
  32.                  4: begin loadB <= 0; initB<=0; w_st0<= 0; end
  33.             endcase            
  34.         end


[edit] Bloques de comunicación SPI

Cuando la señal SPI_wr se pone en alto el bloque SPI CTRL comienza a funcionar activando la señal load_in para cargar el registro CMD_ADCt como dato de transmisión en TRANSMITTER, luego pone en alto la señal clkdiv_en para poner en funcionamiento el bloque CLOCK GENERATOR que genera el reloj para el ADC y los pulsos para los registros de corrimiento RECEPTOR y TRANSMITER, estos registros se activan dependiendo del valor de la señal fallingSCLK, los datos de transmisión se ponen en ADC_SDOUT en los flancos de subida (fallinSCLK='0') y los datos de recepción puestos por el ADC en ADC_SDIN se almacenan en los flancos de bajada (fallingSCLK='1'). La señal fallingSCLK es generada con un contador de pulsos en el SPI CTRL, quien detiene la transmisión cuando el contador alcanza un valor determinado. El diagrama de flujo es el sigueinte.


Diagrama de flujo bloque SPI CTRL


Además la descripción de hardware de este bloque es:


  1.     // SPI Control
  2.     always @(posedge clk)
  3.     if(reset) begin
  4.         {w_st1, pulsecount, clkdiv_en, busy} <= 0;
  5.     end else begin
  6.         case (w_st1)
  7.              0: begin  
  8.                     if(SPI_wr) begin
  9.                         clkdiv_en  <= 1;
  10.                         load_in <= 1;
  11.                         w_st1 <= 1; busy <= 1;
  12.                     end
  13.                 end
  14.              1: begin
  15.                      load_in <= 0;
  16.                      if(pulse)  
  17.                          pulsecount <= pulsecount + 1;   
  18.                      else if (pulsecount > 55) begin 
  19.                           clkdiv_en  <= 0; busy <= 0; 
  20.                           w_st1 <= 0; pulsecount <= 0; 
  21.                      end
  22.                 end
  23.           endcase
  24.      end


Como deciamos anteriormente el bloque CLOCK GENERATOR se activa con la señal clkdiv_en y es quien genera el reloj para el ADC (ADC_SCLK), es decir, el reloj de transmisión y su velocidad depende del valor del registro CLKDIV. La descripción de hardware es sencilla:


  1.     // SPI Clock Generator
  2.     always@(posedge clk)
  3.         if (clkdiv_en) begin
  4.            if(clkcount < CLKDIV) begin
  5.                    clkcount <= clkcount + 1; pulse <=0;
  6.            end else begin
  7.                 clkcount <= 0; pulse <=1;
  8.                 if((pulsecount>0) && (pulsecount < 21)) 
  9.                     ADC_SCLK_buffer <= ~ADC_SCLK_buffer;
  10.            end
  11.         end else  begin
  12.             ADC_SCLK_buffer <= 0; pulse <=0;
  13.         end


Los otros dos componentes relacionados a la comunicación con el ADC son el RECEPTOR y el TRANSMITTER, que son dos registros de corrimiento hacia la izquierda activados por la señal fallingSCLK y la señal pulse. La descripción también es sencilla:


  1.     // SPI Receptor
  2.     always@(posedge clk)
  3.     begin
  4.         if((fallingSCLK & pulse) && (pulsecount < 21)) begin
  5.             out_buffer <= out_buffer << 1;
  6.             out_buffer[0] <= ADC_SDOUT;
  7.         end
  8.     end
  9.  
  10.     // SPI Transmitter
  11.     always@(posedge clk)
  12.     begin
  13.         if(load_in) in_buffer <= CMD_ADCt[3:0]; 
  14.         if(!fallingSCLK & pulse) begin
  15.             ADC_SDIN_buffer <= in_buffer[3];
  16.             in_buffer <= in_buffer << 1;
  17.         end
  18.     end


[edit] Bloque RECEPTION BUFFER

El bloque RECEPTION BUFFER es el encargado de almacenar los datos recibidos del ADC (salida out_buffer de registro de corrimiento RECEPTOR) en la memoria RAM para que puedan ser leidos desde el procesador accediendo al periférico en la FPGA. Cuando el buffer de datos esta lleno se pone en lato la señal fullB que puede ser utilizada como IRQ y que en este caso también resetea el valor de CMD_START. El buffer tiene un tamaño máximo de 1024 datos, usando dos bytes contiguos para almacenar un valor de muestra recibido desde el ADC en una RAM dual-port de 2K 8bit, aunque los primeros dos datos (cuatro primeras posiciones de la RAM) son inaccesibles, aunque esto no implica problema debido a que al usar el ADC a altas frecuencias debemos desprecias una cierta cantidad de datos iniciales inválidos. El diagrama de flujo para el RECEPTION BUFFER se muestra a continuación.


Diagrama de flujo bloque RECEPTION BUFFER


Y la descripción de hardware es la siguiente:


  1.     // Reception Buffer        
  2.     always @(posedge clk)
  3.     if(reset) 
  4.         {we2, w_st2, fullB, SIZEB1, SIZEB2} <= 0;
  5.     else begin
  6.         case (w_st2)
  7.              0: begin 
  8.                     fullB <= 0; 
  9.                     if(initB) begin 
  10.                         w_st2 <= 1; 
  11.                         SIZEB1<=SIZEB; 
  12.                         SIZEB2<=SIZEB; 
  13.                     end
  14.                 end 
  15.              1: begin 
  16.                     if(loadB) begin 
  17.                         // If buffer full set fullB flag by a clock cicle
  18.                         if(SIZEB2>0) begin
  19.                             w_st2 <= 2; end
  20.                         else begin
  21.                             fullB <= 1;
  22.                             w_st2 <= 0;                            
  23.                         end
  24.                     end
  25.                 end
  26.              2: begin 
  27.                     //Write data on BRAM  (LOW)
  28.                     wrBus2[7:0] <= out_buffer[7:0]; 
  29.                     addr2 <= {subSIZEB,1'b0};
  30.                     we2 <= 1; w_st2 <= 3; 
  31.                 end
  32.              3: begin we2 <= 0; w_st2 <= 4;  end    
  33.              4: begin 
  34.                     //Write data on BRAM  (HI)
  35.                     wrBus2[7:0] <= out_buffer[9:8]; 
  36.                     addr2 <= {subSIZEB,1'b1}; 
  37.                     we2 <= 1; w_st2 <= 5;
  38.                 end
  39.              5: begin 
  40.                     we2 <= 0; w_st2 <= 1; SIZEB2 <= SIZEB2-1;
  41.                 end         
  42.         endcase
  43.       end     
  44.  
  45.     assign subSIZEB = SIZEB1-SIZEB2;


[edit] Modo muestreo alternado de canales

En la mayoría de los casos necesitamos realizar muestreos de varios canales de forma simultánea, aunque esto no sea posible, si podremos realizar un cambio de canal de forma rápida después de cada conversión del ADC. Para implementar esta función hemos dispuesto un contador MOD8 aumenta cada vez que almacenamos un dato en el buffer y se resetea cada vez que el buffer se llena, el valor de este contador es sumado al comando que se envia al ADC (CMD_ADC), de esta forma después de cada conversión del ADC estamos leyendo una muestra de un canal diferente, comenzando por el canal A0 hasta el A7. Pero no siempre querremos tomar muestras de los ocho canales de forma alterna además de que con esto reducimos drásticamente la velocidad de muestreo por canal. Para ello disponemos de la señal CMD_SW que utilizamos para multiplexar el valor que se le suma al comando ADc. Cuando CMD_SW='00' sólo se toman muestras del canal determinado por CMD_ADC, cuando CMD_SW='01' se alternan dos canales tomando como base el canal determinado por CMD_ADC, es decir, si CMD_ADC determina la selección del canal A6 (CMD_ADC=6h) los datos que se guarden el buffer corresponderan a los canales A6 y A7 alternados. Cuando CMD_SW='10' se alternan cuatro canales y cuando CMD_SW='11' se alternan ocho canales. Esta función debe ser usada con cuidado, debido a que al alternar no se discrimina entre un comando para establecer un canal o un comando para configurar el ADC, es decir, se debe asegurar que CMD_ADCt es menor a 7h cuando el modo de canales alternados esta activo para evitar un comportamiento indeseable. La descripción de hardware para implementear esta función es la siguiente.


  1.     // ADC channel offset, MOD8 counter
  2.     always @(posedge clk)
  3.         if(fullB | reset) 
  4.             CMD_OFFSET <= 0;
  5.         else if(loadB) begin  
  6.             CMD_OFFSET <= CMD_OFFSET + 1; 
  7.         end
  8.  
  9.     // MUX to select the channel offset     
  10.     assign CMD_OFFSETt = CMD_SW[1]? (CMD_SW[0]? CMD_OFFSET[2:0]    : 
  11.                                                 CMD_OFFSET[1:0]    )
  12.                                   : (CMD_SW[0]? CMD_OFFSET[0]      : 
  13.                                                 3'b0               );
  14.  
  15.     // Add ADC command and offset                                                
  16.     assign CMD_ADCt = CMD_ADC + CMD_OFFSETt;

[edit] Usando el periférico ADC y QT

Para utilizar el periférico desarrollado decidimos realizar un pequeño ejemplo usando QT para mostrar las señales desde dos de los ocho canales analógicos del ADC. El código fuente completo de éste ejemplo se encuentra en el siguiente enlace.

La GUI de la aplicación es muy básica, se compone de un Main Window y dentro de él un widget llamado Signal Display que simplemente dibuja un vector de datos en el área especificada haciendo uso de la clase QPainter.

La funciones básicas del widget Signal Display:

  • Agregar valores a los vetores, addPoint1() y addPoint2(), para cambia la señal que se esta mostrando. En este caso los vectores se comportan como registros de corrimiento.
  • Establecer los segundos por división horizontal, setSecsPerDiv().
  • Establecer los voltios por división vertical, setVoltsPerDiv().
  • Establecer la longitud de los vectores, setPointsPerPlot().
  • Establecer el color de los trazos, setColorTrace1() y setColorTrace2().


Primero realizamos una pequeña prueba de la aplicación en el PC colocando en los vectores señales fijas, en este caso dos señales sinusiodales de frecuencia diferente.

Prueba en PC, dibujando señales de prueba


Luego escribimos una clase sencilla llamada ADCw que se encarga de controlar el periférico en la FPGA haciendo uso de los códigos escritos para Xbusrst-FPGA comunication example. El constructor de esta clase se encarga de realizar la configuración adecuada del GPIO correspondiente al CS2 y de realizar el mapeo de la memoria física para poder direccionar la región de memoria correspondiente a CS2, además inicializa el ADC en modo de conversión rápida. Las funciones públicas que hemos dispuesto para esta clase son las siguientes:

  • Realizar prueba del ADC, testADC(), que configura al periférico para enviar los comandos correspondientes al ADC para colocarlo en modo auto-selft (ver tabla de comados) y luego leer los datos para corroborar que son correctos y que el ADC está realizando su trabajo.
  • Colocar el ADC en modo de bajo consumo, powerDownADC(), que configura al periférico para enviar el comando correspondiente para colocarlo en modo Power Down.
  • Tomar muestras de determinado canal del ADC, takeSamples(int CHANNEL), que configura el periférico para que tome muestras del canal especificado o canal base si se esta utilizando el modo de canales alternados.
  • Establecer el valor del divisor de reloj, setClockDiv(uchar value), que es la variable que se le envía al periférico para el registro de configuración CLKDIV.
  • Establecer la longitud del buffer, setBufferLen(int value), que es la variable que se le envía al periférico para el registro de configuración SIZEB.
  • Establecer el modo de canales alternados, setMuxChannels(uchar value), que es la variable que se le envía al periférico para el registro de configuración CMD_SW.


Ahora hacemos uso de estas clases para generar nuestra aplicación, el diagrama de flujo general del inicio es muy sencillo y se muestra a continuación.

Diagrama de flujo inicio general

Luego el hilo principal queda a la espera de que la clase del timer indique un time out. El diagrama de flujo también es sencillo como se muestra a continuación.

Diagrama de flujo ciclo de captura de datos


Para dejar más claro el funcionamiento del proyecto en QT mostramos el siguiente diagrama de secuencia que relaciona las clases creadas.

Diagrama de secuencia para las clases

en el diagrama trazamos 120 puntos por cada señal, pero configuramos el periférico ADC de tal manera que se tomen 240 muestras alternando dos canales siendo el canal base A0, es decir, el periférico llenará el buffer con 240 muestras alternadas del canal A0 y el canal A1, esto se realizará cada 50ms.


[edit] Compilando aplicaciones en QT para Openwrt-xburst

Primero debemos asegurarnos de que tenemos compilado QT, para ello podemos seguir las instrucciones Building Software Image, específicamente debemos obtener los "feeds", luego ir al menú de configuración de openwrt-xburst y en las opciones Xorg seleccionar el framework de QT, y entonces compilar de nuevo con make.

En el directorio /DIRECTORIO/HASTA/OPENWRT/openwrt-xburst/build_dir/target-mipsel_uClibc-0.9.30.1/qt-everywhere-opensource-src-4.6.2/ podremos encontrar todas las librerías y archivos necesarios para compilar nuestras aplicaciones en QT.

Para compilar aplicaciones lo primero que debemos hacer es editar el archivo /DIRECTORIO/HASTA/OPENWRT/openwrt-xburst/build_dir/target-mipsel_uClibc-0.9.30.1/qt-everywhere-opensource-src-4.6.2/mkspecs/qws/linux-openwrt-g++/qmake.conf, agregando las siguientes líneas:


QMAKE_INCDIR_QT       = /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/include
QMAKE_LIBDIR_QT       = /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/lib
QMAKE_MOC            = /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/bin/moc
QMAKE_UIC            = /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/bin/uic


Luego podremos ir a nuestro directorio de trabajo y generamos el archivo "Makefile" necesario de la siguiente forma:

$ make clean
$ /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/bin/qmake -spec \
  /DIRECTORIO/HASTA/QT/qt-everywhere-opensource-src-4.6.2/mkspecs/qws/linux-openwrt-g++ -unix -o Makefile

Finalmente obtendremos nuestra aplicación compilada para nuestra plataforma ejecutando en consola:

$ make


SAKC as scope.ogv
Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export