Control Inalámbrico de Iluminación (RF)

From Qi-Hardware
Jump to: navigation, search

Contents

[edit] INTEGRANTES.

Daniel Cárdenas Toro. 261377 1.0

Juan Sebastián Pachón Arango. 261418 .5

William Eduardo Calderón Castillo 261178 .6


[edit] Calificación

Porcentaje Presentación 20% Informe 30% Funcionamiento 50%
1 Entrega 10% 0.5 0.5 0.5 NO ASISTIERON A LA ENTREGA
2 Entrega 30% 1.8 1.8 1.8
3 Entrega 30% 2 2 5


4 Entrega 40% 5 5 5

[edit] DESCRIPCIÓN GENERAL.

El proyecto consiste en hacer un sistema inalámbrico que permita controlar a distancia la iluminación de un interior. El diseño contará con una interfaz gráfica en la que se visualizará un plano sencillo del lugar con el estado de cada bombillo del sistema.

[edit] VIDEO FUNCIONAMIENTO

MOV00294.ogv

[edit] TAREAS SW Y HW.

HardWare.


La FPGA estará encargada de controlar el modulo RF que trabajara como transmisor en el control remoto. Por lo tanto debe manejar la máquina de estados de este dispositivo, configurarlo en el modo TX para transmitir datos o en STANDBY cuando no se esté transmitiendo para disminuir el consumo de energía. Los pulsadores que se utilizaran para manejar las luces estarán conectados directamente a la FPGA y esta se encargara de enviar las secuencias adecuadas al modulo RF que finalmente enviara la información a los receptores (uno en cada bombillo). A su vez la FPGA debe mandar la información al procesador para que pueda actualizarse la información en la interfaz grafica. El módulo RF sera un RFM22B. Cada modulo receptor se conecta a un microcontrolador, que se encarga de configurar el modulo en estado receptor, a su vez se implementara un botón de reset en cada uno de estos módulos para reconfigurar por si hay algún problema o se descarga completamente la batería y se desconfigura. Los microcontroladores (PIC16F877A) serán programados en C++ en CCS.


SoftWare.


Para dar mayor comodidad del usuario, se realizará una parte gráfica que se realizará con el programa QT y sus librerías para el manejo de gráficos. Se implementará la ejecución de los archivos en QT en el procesador, para que sea posible cargar nuestro programa. Este programa tendrá como finalidad mostrar en el lcd del SIE, un sencillo plano del lugar, en el que se muestran los diferentes bombillos y su estado (prendido o apagado) y la opción de modificar dicho estado, por medio de los módulos RF.

[edit] BLOQUES.

Diagramadebloques1.png

1. Interfaz Gráfica. Desarrollada en QT, se muestra en el LCD los lugares de la casa en la cual se desea prender o apagar la luz. Al mover el slider horizontal se prendería o se apagaría la luz y la indicación de esto se mostraría en la caja de giro.

2. Driver. El módulo RFM22B utiliza comunicación SPI, por lo tanto se implementará en la FPGA (HardWare)un módulo SPI con su respectivo Driver en linux (SoftWare).

3. Comunicación RF. Es necesario controlar la comunicación inalambrica, determinar si los datos que llegan son correctos.

4. Configuración de RX. Un microcontrolador esta encargado de configurar el modulo receptor en su modo de operación adecuado.

5. Potencia. Debido a que el microcontrolador no puede suministrar potencia necesaria al bombillo, se adapta una etapa de potencia

[edit] DIAGRAMAS.

[edit] ESQUEMATICOS.

[edit] PCB. V1

[edit] PCB. V2. Layout


[edit] PCB V3.

[edit] COMUNICACIÓN XBURST--RFM22B

Cuando se crea un puntero que apunta a la dirección virtual de la fpga y se le asigna un valor "X" el procesador se comporta de la siguiente forma:

Diagrama de flujo bloque XBURST->FPGA WRITE SIGNALS

Por lo tanto, para un proceso de escritura, se parte de la condición en que CSn y WEn son iguales a cero, en este punto se verifica si el periferico está ocupado por medio de la señal "busy", si el periferico está ocupado se ignora el dato, de lo contrario se envia el dato. En este caso se ha tomado como base el archivo ADC.v y se ha reemplazado la memoria por un periferico SPI.

EL diagrama de tiempo de trabajo del rfm22b se muestra en la siguiente figura:

rfm22b timing

Debido a que el bus de datos es de 8 bits, se deben enviar dos secuencias, la primera con un bit de r/w y la dirección y la segunda con el dato a escribir en el registro. la simulación del módulo se muestra a continuación:

SPI_write simulation

El diagrama de flujo del control de escritura se muestra en el siguiente diagrama

Diagrama de flujo bloque SPI_WRITE_COTROL

[edit] Periféricos

Para este proyecto, se tienen dos periféricos en la FPGA, en el caso del transmisor, se tiene el módulo SPI y el pad de botones, y para el caso del receptor se tiene el módulo SPI y el pad de leds. Por lo tanto es necesario agregar un control de periféricos.

Periféricos







  1. // Peripherals control
  2.     wire     [1:0]   csN;
  3.     wire     [7:0]   rdBus0, rdBus1:
  4.  
  5.     assign csN = buffer_addr[11]?  4'b0010:4'b0001;
  6.     assign rdBus = buffer_addr[11]? rdBus1:rdBus0;







[edit] Button Pad

Debido a que el reloj de la FPGA es bastante rápido, al pulsar un botón, la fpga asume que este fue presionado varias veces, por lo tanto se crea un bloque para solucionar el problema. Consiste en tres registros (uno para cada pulsador) PB1d, PB2d, PB3d. Estos regustros se activan una ves se presiona el boton.

  1. always @(posedge clk)
  2. begin
  3. 	if(reset)
  4. 	begin
  5. 	PB1d<=1;
  6. 	count1<=0;	
  7. 	end
  8. 	else if(~PB1)
  9. 	count1<=count1+1;
  10. 	if(count1==50000)
  11. 	PB1d<=0;
  12. 	if(addr==2000)
  13. 	begin
  14. 	PB1d<=1;		
  15. 	count1<=0;	
  16. 	end
  17. end


Una vez que el el procesador ha leído el pulsador a través de la FPGA y ha realizado su labor, envía una señal de vuelta a la FPGA y con esto los registros PB1d, PB2d, PB3d se desactivan, con esto se logra que cada que se presiona un pulsador, solo se ejecuta una ves la accion deseada a menos que el boton se mantenga pulsado.


[edit] Led Pad

Para probar el funcionamiento del proyecto se utilizan 3 leds incorporados en la tarjeta del receptor, adicionalmente en esta tarjeta se dejan las salidas disponibles para conectar una etapa de potencia e implementar el proyecto en bombillos reales.

  1. always @(posedge clk)
  2. if(reset)
  3. begin
  4. led1<=0;
  5. led2<=0;
  6. led3<=0;
  7. end
  8. else if(we & cs1) 
  9. begin
  10. 	if(addr==120)
  11. 	led2<=~led2;
  12. 	else if(addr==80)
  13. 	led1<=~led1;	
  14. 	else if(addr==40)
  15. 	led3<=~led3;
  16. end

El funcionamiento de este bloque es bastante sencillo, ya que simplemente cuando se activa el we y el cs1, se prende o apaga algún led, dependiendo de la dirección enviada por el usuario y del estado actual de dicho led.

[edit] SPI

El módulo de SPI es el módulo más importante del proyecto, ya que se encarga de comunicar el procesador con el módulo RFM22B, este modulo cuenta con 128 registros a los cuales se puede acceder utilizando este protocolo.

Inicialmente se tiene un bloque de control que genera un pulso en la señal "SPI_wr"

  1. // CONTROL
  2.     always @(posedge clk)
  3. 	begin
  4. 		if(reset)
  5. 			begin
  6. 		    	{w_st0, SPI_wr} <= 0;
  7. 		        end
  8. 		else 
  9. 			begin
  10. 				    	case (w_st0)
  11. 						 0: begin 
  12. 						    if(we & cs & ~busy)
  13. 							SPI_wr <= 1;
  14. 							if(SPI_wr) 
  15. 								begin
  16. 						 		w_st0 <=1;    
  17. 					       			end
  18. 						    end                       
  19. 						 1: begin 
  20. 						    SPI_wr <= 0; 
  21. 						    w_st0 <=0; 
  22. 						    end
  23.  
  24. 					endcase   
  25. 		end 
  26.  
  27. 	end

En la línea 178 se observa que el pulso se genera cuando se activa "we", "cs" y "~busy", la señal "busy" es necesaria debido a que si el procesador envía un dato mientras el bloque SPI está enviando otro dato, entonces se creará un conflicto y se enviarían valores errados al módulo RF.

Adicionalmente se tiene el bloque SPI CONTROL que se encarga de manejar todas las señales necesarias para el protocolo SPI.


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

Se utilizan además los bloques SPI CLOCK GENERATOR, SPI RECEPTOR Y SPI TRANSMITTER utilizados en el ADC.

El bloque Write Control se encarga de tomar los datos provenientes del procesador y enviarlos de forma serial.

  1.  // REGISTER BANK:   Write control
  2.     always @(posedge clk)
  3.     	begin
  4. 	   if(reset) 
  5.           	{RFM_REG} <= 0;
  6.            else 
  7. 		if(we & cs & ~busy) 
  8. 			begin
  9. 		 	RFM_REG[15:0]   <= {addr[9:2],wrBus[7:0]};
  10. 			end 
  11. 	end

Como se puede ver en la línea 148, el dato que se enviará de forma seríal "RFM_REG" se compone de la dirección desplazada dos bits a la izquierda y el dato. El desplazamiento de la dirección es necesario debido a que el bus de direcciones que sale del procesador, llega a la fpga multiplicado por 4.

Finalmente el bloque de lectura.

  1. // REGISTER BANK:   Read control    
  2.     always @(posedge clk)
  3.        if(reset) 
  4. 		{rdBus0, rdBus1} <= 0;
  5.       else 
  6. 		if(~we & cs) 
  7. 			begin
  8. 			if(addr==40)
  9. 		        rdBus0  <= nSEL;
  10. 			else 
  11. 			rdBus0<=out_buffert;
  12. 		       end
  13. 		else 
  14. 		if(~we & cs1)
  15. 			begin     			
  16. 			if(addr==120)
  17. 			begin
  18.  
  19. 		        rdBus1  <= PB3d;
  20. 			end
  21. 			else if(addr==40)
  22. 		        rdBus1  <= PB1d;
  23. 			else if(addr==80)
  24. 		        rdBus1  <= PB2d;
  25. 			end

Dependiendo de cual CS esté activado, el procesador estará leyendo datos del módulo SPI o del pad de botones, en el caso del SPI, dependiendo de la dirección que envíe el procesador, se lee la señal "nSEL" que es utilizada por el procesador para determinar el momento en que el módulo SPI termino de enviar un dato para poder enviar el siguiente, por otro lado se tiene el registro "out_buffert" en el cual se ha almacenado el valor de algún registro del RFM22B obtenido a través de la señal "SDOUT".

Por otro lado si está activo el "cs1" se lee el pad de botones.

La señal "nSEL" del SPI tiene un tiempo de establecimiento mas alto que el resto de las señales, por eso fue necesario crear una maquina de estados que se encargara de manejar este tiempo.

  1. always @(posedge clk)
  2. case (w_st2)
  3. 	 0: begin 
  4. 		if(SPI_wr)
  5. 		nSEL<=0;							
  6. 		if(pulsecount==32)
  7. 		w_st2<=1;
  8. 	    end                       
  9. 	 1:begin 
  10. 	    if(pulsecount==0)
  11. 		w_st2<=2;	
  12. 	   end
  13. 	 2:begin
  14.              count<=count+1;
  15. 	     if(count==5)
  16.              nSEL<=1;
  17. 	     if(count==6)
  18. 	     begin
  19. 	     w_st2<=0;
  20. 	     count<=0;
  21. 	    end
  22. 	   end							 
  23.  
  24. endcase

[edit] Antena WLP434

El módulo RFM22B no cuenta con una antena para la transmisión de datos, por lo tanto es necesario adaptar úna externa, para este fin se escogio la antena WLP434 ya que trabaja a 434MHz y tene una impedancia de 50 ohm. Para verificar estos valores, se caracterizó la antena en el laboratorio de comunicaciones de la Universidad Nacional de Colombia (CMUN), verificando los valores mencionados anteriormente como se muestra en las siguientes figuras.

[edit] REGISTROS DE CONFIGURACIÓN DEL RFM22B

El RFM22B cuenta con 128 registros de configuración utilizados para seleccionar la frecuencia, el tamaño de los paquetes, tipo de modulación, Header, Potencia de salida de la antenna, configuración de GPIO's, modo de operación (TX, RX, Sleep, Shut Down). En la siguiente tabla se encuentran algunos de los registros modificados para configurar tanto en modo receptor como en modo transmisor.


Dirección Descripción valor RX valor TX
0x06 Interrupt Enable 2 0x00 0x00
0x07 Operating & Function Coontrol 1 0x09 0x9
0x09 Crystal Oscilator Load Capacitance 0x7f 0x7f
0x0a Microcontroller Output Clock 0x05 0x05
0x0b GPIO0 Configuration 0xf4 0xf4
0x0c GPIO1 Configuration 0xfd 0xef
0x0d GPIO2 Configuration 0xfd 0xfd
0x0e I/O Port Configuration 0x00 0x00
0x70 Modulation Mode Control 1 0x20 0x20
0x6e TX Data Rate 1 xxxx 0x13
0x6f TX Data Rate 0 xxxx 0xa9
0x1d AFC 0x00 xxxx
0x1c IF Filter Bandwidth 0x1d xxxx
0x20 Clock Recovery Oversampling Ratio 0x41 0x7f
0x21 Clock Recovery offset 2 0x60 0x7f
0x22 Clock Recovery offset 1 0x27 0x7f
0x23 Clock Recovery offset 0 0x52 0x7f
0x24 Clock Recovery Timing Loop Gain 1 0x00 0x7f
0x25 Clock Recovery Timing Loop Gain 0 0x06 0x7f
0x2a AFC Limiter 0x1e 0x7f
0x30 Data Access Control 0x8c 0x8c
0x32 Header Control 1 0xff 0xff
0x33 Header Control 2 0x42 0x42
0x34 Preamble Length 64 64
0x35 Preamble Detection Control 0x20 0x7f
0x36 Sync Word 3 0x2d 0x2d
0x37 Sync Word 2 0xd4 0xd4
0x38 Sync Word 1 0x00 0x00
0x39 Sync Word 0 0x00 0x7f
0x3a Transmit Header 3 0x00 's'
0x3b Transmit Header 2 xxxx 'o'
0x3c Transmit Header 1 0x00 'n'
0x3d Transmit Header 0 xxxx 'g'
0x3e Transmith Packet Length 1 1
0x3f Check Header 3 's' 0x7f
0x40 Check Header 2 'o' 0x7f
0x41 Check Header 1 'n' 0x7f
0x42 Check Header 0 'g' 0x7f
0x43 Header Enable 3 0xff 0x7f
0x44 Header Enable 2 0xff 0x7f
0x45 Header Enable 1 0xff 0x7f
0x46 Header Enable 0 0xff 0x7f
0x6d TX Power xxxx 0x0f
0x79 Frequency Hopping Channel Select 0x00 0x00
0x7a Frequency Hopping Step Size 0x00 0x00
0x71 Modulation Mode Control 1 0x22 0x22
0x72 Frequency Deviation xxxx 0x38
0x73 Frequency offset 1 0x00 0x00
0x74 Frequency offset 2 0x00 0x00
0x75 Frequency Band Select 0x53 0x53
0x76 Nominal Carrier Frequency 1 0x64 0x64
0x77 Nominal Carrier Frequency 0 0x00 0x00

Despues de configurar los registros como se muestra en la tabla anterior, el proceso de transmisión se reduce a escribir y leer las FIFO's de transmisión del módulo.

Una operación de escritura sobre el registro 0x7f es una operación de escritura sobre la FIFO de transmisión, por otro lado si se lee este registro (0x7f) se esta leyendo la FIFO de Recepción del módulo. Cada fifo cuenta con 64 bytes de espacio, el momento en q se transmiten los datos depende de un registro de configuración que determina si se envia cada 1, 2, 3 ... o 64 bytes escritos en la FIFO de transmisión.

Es importante aclarar que el módulo rfm22b tiene un protocolo de comunicación incorporado, por lo que no es necesario agregar uno, el rfm22b cuenta con un Header (Encabezado) que se envia previo al dato que se desea transmitir, este Header es configurable y cada uno de los receptores puede configurarse para responder ante un Header diferente.

[edit] DRIVER

Con el fin de modificar los valores que vienen por defecto en los registros del RFM22B se crea un driver para el transmisor y uno para el receptor. Estos drivers se encargan de enviar los datos necesarios al SPI para que este los envíe de forma serial al RFM22B. Para enviar estos datos desde espacio de kernel no es necesario remapear la memoria física en memoria virtual, ya que las funciones "outb(data, address)" pone directamente el dato que se pase como argumento en la direción física "address". Sin embargo el mapeo se puede hacer de la siguiente forma:

  1. ioaddress = __ioremap(FPGA_BASE, 0x4000,_CACHE_UNCACHED);

Adicionalmente es necesario configurar el CS, para esto se utiliza la siguiente función:

  1. #define CS2_PIN               JZ_GPIO_PORTB(26)


  1. jz_gpio_set_function(CS2_PIN, JZ_GPIO_FUNC1);

Despues de esto se puede escribir y leer de la siguiente forma:

  1. //write process
  2. outb(0x00, ioaddress+(4*(0x06 + 0x80)));
  1. //read process
  2. test=inb(ioaddress+40);

En el proceso de escritura, la dirección a la que se envía el dato se compone de la siguiente forma (según el ejemplo), el valor "0x06" es el registro que se desea modificar, a este valor se le suma "0x80" (decimal 128), con el fin de habilitar el bit "RDWR" (primer bit de la trama del SPI) para realizar una operación de escritura. finalmente este valor se multiplica por 4 para tener el mismo funcionamiento que en espacio de usuario.

A continuación se muestra una parte del driver:

  1. static int __init qem_init(void)
  2. {
  3.   int res;
  4.   printk(KERN_INFO "FPGA module is Up.\n");
  5.   jz_gpio_set_function(CS2_PIN, JZ_GPIO_FUNC1);       
  6.   Major = register_chrdev(0, DEVICE_NAME, &fops);         
  7.    if (Major < 0) {
  8.       printk(KERN_ALERT "Registering char device failed with %d\n", Major);
  9.     return Major;
  10.   } 
  11.  
  12.   printk(KERN_ALERT  "I was assigned major number %d. To talk to\n", Major);
  13.   printk(KERN_ALERT  "the driver, create a dev file with\n");
  14.   printk(KERN_ALERT  "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
  15.  
  16.   ioaddress = __ioremap(FPGA_BASE, 0x4000,_CACHE_UNCACHED);
  17.  
  18.  
  19. outb(0x00, ioaddress+(4*(0x06 + 0x80))); 
  20. while(test==0) 	
  21. 	test=inb(ioaddress+40);
  22. outb(0x01, ioaddress+(4*(0x07 + 0x80)));
  23. test=0;
  24. while(test==0) 	
  25. 	test=inb(0xb5000000+40);
  26. outb(0x05, ioaddress+(4*(0x0A + 0x80))); 
  27. test=0;
  28. while(test==0) 	
  29. 	test=inb(0xb5000000+40);
  30. outb(0xf4, ioaddress+(4*(0x0B + 0x80))); 
  31. test=0;
  32. while(test==0) 	
  33. 	test=inb(0xb5000000+40);
  34. outb(0xfd, ioaddress+(4*(0x0c + 0x80)));

Despues de enviar cada dato, el driver se queda leyendo la señal "nSEL" al leer la dirección 40 de la FPGA, esta señal se mantiene normalmente en -1-, cuado seva a enviar un dato la señal baja a -0-, y cuando el dato se ha enviado la señal vuelve a -1-, por lo tanto el driver no debe mandar un dato hasta que la señal sea de nuevo -1- (!=0).

Debido a que el sistema tiene reset, es necesario que el driver pueda reescribir los registros una ves esta arriba, por lo tanto se crea la misma rutina realizada en __init, en la funcion device_write".

  1. static ssize_t
  2. device_write(struct file *filp, const char *buff, size_t count, loff_t * off)
  3. {
  4.   const char cmd = buff[0];
  5.  
  6.   if(cmd=='W')
  7.   {
  8. outb(0x00, ioaddress+(4*(0x06 + 0x80))); 
  9. while(test==0) 
  10. 	test=inb(0xb5000000+40);
  11. outb(0x01, ioaddress+(4*(0x07 + 0x80)));
  12. test=0;
  13. while(test==0) 
  14. 	test=inb(0xb5000000+40);
  15. outb(0x05, ioaddress+(4*(0x0A + 0x80))); 
  16. test=0;
  17. while(test==0) 
  18. 	test=inb(0xb5000000+40);
  19. outb(0xf4, ioaddress+(4*(0x0B + 0x80))); 
  20. test=0;
  21. while(test==0) 
  22. 	test=inb(0xb5000000+40);
  23. outb(0xfd, ioaddress+(4*(0x0c + 0x80)));

Para por utilizar esta función, es necesario crear el nodo para comunicarse con el driver.

$ mknod /dev/setRX c 252 0

$ mknod /dev/setTX c 252 0

Una ves se ha creado el nodo, se pueden reescribir los registros con el siguiente comand:

$ echo "W">/dev/setRX

[edit] RECEPTOR

Inicialmente se propuso implementar el receptor en un microcontrolador, sinembargo finalmente se decide implementarlo en otra plataforma SIE con el fin de facilitar la programación y dejando la posibilidad de tener ambas plataformas como emisor/receptor tan solo con variar algunos registros de configuración.


[edit] COMUNICACIÓN INALÁMBRICA

Se realiza la comunicación inalámbrica obteniendo una distancia de alcance de aproximadamente 100 mts, inicialmente se envia un byte de información el cual es recibido correctmente gracias al protocolo de comunicación interno del RFM22B, posteriormente se configura tanto el transmisor como el receptor para transferir 8 bytes. Con esto se envía un contador de 1 a 8 obteniendo siempre los datos correctamente.

El RFM22B tiene una señal de interrupción que se activa cada que se recibe un dato, por lo tanto se conecta esta señal al procesador a través de la FPGA con el fin de imprimir cada dato que llega al receptor. Aunque desde espacio de usuario no se pueden manejar interrupciones, el pin C15 del procesador puede ser definido como una entrada y ser leido constantemente.

[edit] DIAGRAMAS DE FLUJO DE LOS MODOS TX Y RX

[edit] INTERFAZ GRÁFICA

Con el fin de que el usuario pueda decidir cual led (bombillo) desea prender, se crea una interfaz gráfica utilizando el programa QTcreator. Para esto se parte por el diseño gráfico de la interfaz modificando el archivo "mainwindow.ui" (esto se puede hacer gráficamente).

Luego se modifica el archivo mainwindow.h en el cual se declaran las variables que se van a utilizar.

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include "jz47xx_mmap.h"
  5. #include "jz47xx_gpio.h"
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include <stdlib.h>
  9.  
  10. #define CS2_PORT JZ_GPIO_PORT_B
  11. #define CS2_PIN 26
  12. #define TEST_PORT JZ_GPIO_PORT_C
  13. #define TEST_PIN  15
  14.  
  15.  
  16. namespace Ui {
  17.     class MainWindow;
  18. }
  19.  
  20. class MainWindow : public QMainWindow {
  21.     Q_OBJECT
  22. public:
  23.     MainWindow(QWidget *parent = 0);
  24.     ~MainWindow();
  25.     JZ_PIO *initGPIO_LED();
  26.     JZ_REG *initFPGA_RAM();
  27. private:
  28.     Ui::MainWindow *ui;
  29.     JZ_PIO *LED;
  30.     JZ_REG *RAM;
  31.     int iter, count, led1, led2, led3;
  32.   unsigned char i, test;
  33.     unsigned char a, b, c;
  34. protected:
  35.     void timerEvent(QTimerEvent*);
  36. };
  37.  
  38. #endif // MAINWINDOW_H

Teniendo definidas las variables necesarias, se crea el archivo mainwindow.cpp, inicialmente se debe configurar el CS y se debe mapear la memoria física de la FPGA en memoria virtual, para esto se utiliza la siguiente función:

  1. JZ_REG *
  2. MainWindow::initFPGA_RAM()
  3. {
  4. JZ_PIO *pio;
  5. JZ_PIO *pio1;
  6. JZ_REG *virt_addr;
  7. pio = jz_gpio_map (CS2_PORT);
  8. jz_gpio_as_func (pio, CS2_PIN, 0);
  9.  
  10. pio1 = jz_gpio_map (TEST_PORT);
  11. jz_gpio_as_input(pio1, TEST_PIN);
  12. virt_addr = (JZ_REG *) (jz_mmap(0x13010000) + 0x18);
  13. if (*virt_addr != 0x0FFF7700)
  14. {
  15. *virt_addr = 0x0FFF7700;
  16. printf ("ADC: Configuring CS2 8 bits and 0 WS: %08X\n", *virt_addr);
  17. }
  18. else
  19. printf ("ADC: CS2, already configured: %08X\n", *virt_addr);
  20. virt_addr = (JZ_REG *) jz_mmap (0x14000000);
  21. return virt_addr;
  22. }

Finalmente como se tiene mapeada la dirección dela FPGA y se tienen las variables necesarias, se genera la función MainWindow::timerEvent(QTimerEvent*), en la cual está el motor de la interfaz gráfica.

Para la visualización se crearon 6 label: boton led1, led 2 y led3, y un label para mostrar el estado d cada led. para hacer la interfaz un poco mas agradable a la vista, se decidio utilizar la función

  1. setPixmap(QPixmap("imagen.jpg"));

para esto se deben copiar todas las imagenes que se quieran utilizar a la tarjeta SIE utilizando el comando:

$ scp imagen.jpg oot@192.168.254.101:

se crea entonces un contador que define el led que está selecciónando el usuario, dicho contador aumenta con un pulsador de la tarjeta hija y disminuye con otro. cada que se actualiza el valor del contador se cambian las imágenes de cada uno de os label dependiendo el led que este seleccionado:

  1.                 c=RAM[512 + 20];
  2.  
  3.                 b=RAM[512 + 10];
  4.  
  5. else if (b==0x00)
  6.                 {
  7.                 if(count<1)
  8.                 count=2;
  9.                 else
  10.                 count--;
  11.                 RAM[500]=0;
  12.                 usleep (15000);
  13.                 }
  14.  
  15.  
  16.                 else if (c==0x00)
  17.                 {
  18.                     if(count>1)
  19.                         count=0;
  20.                     else
  21.                         count++;
  22.                 RAM[500]=0;
  23.                 usleep (15000);
  24.                 }
  25.  
  26.                 switch(count){
  27.                         case 0:{
  28.                                  ui->label->setPixmap(QPixmap("led1set.jpg"));
  29.                                  ui->label_2->setPixmap(QPixmap("led2.jpg"));
  30.                                  ui->label_3->setPixmap(QPixmap("led3.jpg"));
  31.  
  32.                                 }
  33.                         break;
  34.                         case 1:{
  35.                                 ui->label->setPixmap(QPixmap("led1.jpg"));
  36.                                 ui->label_2->setPixmap(QPixmap("led2set.jpg"));
  37.                                 ui->label_3->setPixmap(QPixmap("led3.jpg"));
  38.                                }
  39.                         break;
  40.                         case 2:{
  41.                                 ui->label->setPixmap(QPixmap("led1.jpg"));
  42.                                 ui->label_2->setPixmap(QPixmap("led2.jpg"));
  43.                                 ui->label_3->setPixmap(QPixmap("led3set.jpg"));
  44.                                 }
  45.                         break;
  46.  
  47.                                 }

Las imagenes led1set.jpg, led2set.jpg y led3set.jpg, son los mismos botones led1.jpg, led2.jpg y led3.jpg pero desplazados hacia la derecha para que se evidencie el led seleccinado.

las variables b y c, están siendo constantemente actualizadas leyendo el valor de los pulsadores a través de la FPGA.

finalmente la sección encargada de enviar los datos se muestra a continuación:

  1.   if(a==0x00)
  2.                 {
  3.                     printf ("Writing Register..\n");
  4.                     RAM[500]=0;
  5.                     while(test==0)
  6.                     test=RAM[10];
  7.                     RAM[0x7f + 0x80]=count;
  8.                     test=0;
  9.                     while(test==0)
  10.                         test=RAM[10];
  11.                     RAM[0x05 + 0x80]=0x04;
  12.                     test=0;
  13.                     while(test==0)
  14.                         test=RAM[10];
  15.                     RAM[0x03 + 0x00]=0x04;
  16.                     test=0;
  17.                     while(test==0)
  18.                         test=RAM[10];
  19.                     RAM[0x04 + 0x00]=0x04;
  20.                     test=0;
  21.                     while(test==0)
  22.                         test=RAM[10];
  23.                     RAM[0x07 + 0x80]=0x09;
  24.                     test=0;
  25.                    usleep (150000);
  26.                    switch(count){
  27.                             case 0:{
  28.                                     led1=~led1;
  29.                                     if(led1)
  30.                                     ui->label_5->setPixmap(QPixmap("on.png"));
  31.                                     else
  32.                                     ui->label_5->setPixmap(QPixmap("off.jpg"));
  33.                             }
  34.                             break;
  35.                             case 1:{
  36.                                     led2=~led2;
  37.                                     if(led2)
  38.                                     ui->label_6->setPixmap(QPixmap("on.png"));
  39.                                     else
  40.                                     ui->label_6->setPixmap(QPixmap("off.jpg"));
  41.                                     }
  42.                             break;
  43.                             case 2:{
  44.                                     led3=~led3;
  45.                                     if(led3)
  46.                                     ui->label_7->setPixmap(QPixmap("on.png"));
  47.                                     else
  48.                                     ui->label_7->setPixmap(QPixmap("off.jpg"));
  49.                                     }
  50.                             break;
  51.                             default:plain_text="OUT";
  52.                                 break;}
  53.                 }

Esta sección se encarga de escribir en el registro "0x7f" (dirección de la FIFO de salida) el valor de "cont", con esto se enviará un valor diferente para cada led seleccionado. A su vez en esta sección se actualiza el estado en pantalla de cada uno de los leds. Teniendo esto, en el receptor sólo es necesario una condición para prender o apagar un led dependiendo del valor enviado inalambricamente (cont).

Receptor:

  1.             RAM[0x7f] =0;
  2.             usleep (500);
  3.             i=RAM[0x7f];
  4.  
  5.                             if(i==0x01)
  6.                             {
  7.                             RAM[512 + 20]=0;
  8.                             }
  9.                             else if(i==0x02)
  10.                             {
  11.                             RAM[512 + 30]=0;
  12.                             }
  13.                             else if(i==0x00)
  14.                             {
  15.                             RAM[512 + 10]=0;
  16.                             }
  17.  
  18.                             RAM[0x03 + 0x00]=0x00;
  19.                             test=0;
  20.                             while(test==0)
  21.                                 test=RAM[10];
  22.                             RAM[0x04 + 0x00]=0x00;
  23.                             test=0;
  24.                             while(test==0)
  25.                                 test=RAM[10];
  26.                             test=0;
  27.                             RAM[0x07 + 0x80]=0x05;
  28.                             while(test==0)
  29.                                 test=RAM[10];

Para leer el dato recibido, se debe leer la FIFO de entrada (registro 0x7f) como se ve en las lineas 122-124. La linea 122 se encarga de enviar al RFM22B un "rdwr=0" y la dirección que se quiere leer (0x7f), luego es necesario esperar un tiempo mientras el módulo devuelve el valor de este registro para ejecutar la linea 124.

El dato recibido inalámbricamente siempre está entre 0 y 2, por lo tanto cada uno de estos valores corresponde a un led o bombillo del receptor, al escribir en la posición 10, 20 y 30 del cs2, se está escribiendo sobre el pad de leds, invirtiendo el estado actual de cada led respectivamente.

Después de recibir cada dato se envía una secuencia de datos al RFM22B para limpiar la FIFO de entrada como se ve en la linea 139 en adelante.

[edit] ESTUDIO ECONÓMICO

Inicialmente se tuvo en cuenta el trabajo de los estudiantes de la siguiente forma:

2 horas de trabajo diarias por cada uno durante 14 semanas -> 140 horas en total cada estudiante. Con lo cual el trabajo suma 420 horas. Tomando un valor de $40.000 pesos la hora da un total de $16'800.000 pesos en mano de obra.

Se tiene en cuenta que este tiempo incluye el proceso de diseño del prototipo, por lo tanto para fabricación en masa, este tiempo se reduce al tiempo de producción.

Gastos Adicionales

  • Servicios públicos $20.000 pesos mes -> $80.000 pesos

Componentes del Prototipo

  • 2 tarjetas SIE a $200.000 pesos c/u ---------------> $400.000 pesos.
  • 2 tarjetas hijas a $32.000 pesos c/u ----------------> $64.000 pesos.
  • 2 Antenas a $24.000 pesos c/u ----------------------> $48.000 pesos.
  • 2 Módulos RFM22B a $10.000 pesos c/u --------> $20.000 pesos.
  • Componentes pasivos -----------------------------------> $10.000 pesos.
  • Total prototipo -------------------------------------------> $542.000 pesos.

Es importante tener en cuenta que si se va a producir en masa, se puede modificar la tarjeta SIE, dejando solo los componentes necesarios para el proyecto. Adicionalmente se considera que la tarjeta SIE no tiene muchos GPIOS disponibles, lo cual limita la cantidad de bombillos que se pueden controlar, por esta razón dependiendo de la cantidad de bombillos del sistema se deben agregar más receptores aumentando los costos de producción.

Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export