Analizador Lógico

From Qi-Hardware
Jump to: navigation, search

Universidad Nacional de Colombia


PROYECTO FINAL SISTEMAS EMBEBIDOS

Contents

Logo.png









[edit] Calificación

Porcentaje Presentación 20% Informe 30% Funcionamiento 50%
1 Entrega 10% 0.5 0.5 0.5
2 Entrega 30% 1 1 1
3 Entrega 30% 1 1 1


4 Entrega 30% 3 3 3


[edit] Introducción

Este proyecto de sistemas embebidos consiste en desarrollar un analizador lógico, el cual es un instrumento que se utiliza para la medición de un gran número de señales digitales, utilizando la tarjeta SIE la cual es una adaptación del Ben Nanonote utilizada para desarrollar diferentes aplicaciones, ya sea de pequeña, mediana o alta complejidad debido a que posee integrada una FPGA Spartan3E y un procesador JZ4725, con el cual se pueden desarrollar diferentes aplicaciones multimedia, ya que cuenta con un nucleo incorporado XBurst CPU que permite alta integración, alto desempeño y bajo consumo energético, lo cual es ideal para sistemas embebidos. Ademas esta tarjeta también cuenta con una memoria SDRAM de 32MB y una NAND de 2GB las cuales permiten la inicialización del sistema.

[edit] Descripción del proyecto

Un analizador lógico es un instrumento que se usa para mediciones de señales digitales ya que su función principal es la detección de niveles altos o bajos de voltaje de un conjunto grande de señales, lo cual lo diferencia del osciloscopio porque este se utiliza para la visualización de señales de propósito general, además en su gran mayoria la disponibilidad de canales es de dos mientras que en el analizador se pueden implementar un número mucho mayor de canales.

El primer paso a seguir es entender la arquitectura y el funcionamiento completo de la tarjeta SIE para poder inicializarla de una manera adecuada, con el objetivo de integrar el analizador lógico mediante una tarjeta hija. Una vez hecha la adhesión del analizador se proseguirá con el envio de información adquirida por medio de las sondas puestas en cualquier circuito digital , luego se representará en una pantalla LCD las señales captadas. Para diferenciar las diferentes señales, se designaran diferentes colores a cada una de ellas de forma aleatoria, es decir, el canal 1 siempre será representado con el color amarillo, el 2 con el color rojo y asi sucesivamente hasta completar todos los canales de adquisición.

Como las señales son captadas en tiempo real, es de esperarse que cualquier cambio de tensión del circuito se vea representada inmediatamente cuando esta suceda. Es decir que el analizador lógico podrá medir tiempos entre cambios de nivel, número de estados lógicos, retrasos en la señal, trasitorios y sobre-picos. Con esto se tendrá la capacidad de verificar y depurar señales digitales, al la vez que detectar errores en estado transitorio.

[edit] Especificaciones del proyecto

Este analizador lógico presenta las siguientes características:

  1. Tendrá adquisición de 16 canales, los cuales serán presentados de a grupos de a 4 en el LCD, donde se tendrá la posibilidad de intercambiar grupos para la visualización del resto de las señales, esto controlado por un interruptor.
  2. La señal de máxima frecuencia que se puede medir es de 25MHz, para lo cual será necesario utilizar el reloj (CLK) de la FPGA, adquiriendo datos tanto en el flanco de subida como en el de bajada.
  3. Circuito de protección implementado por medio de 16-bit buffer de 3.3V de alimentación, con velocidad de respuesta del orden de nanosegundos, permitiendo que estos reacciones a una frecuencia alrededor de 100MHz.
  4. El modo de disparo se implementará con un edge trigger o disparo por pendiente.
  5. La resolución de la pantalla LCD será de 320 x 240 pixels.
  6. El analizador lógico está limitado a medir las señales de un solo circuito digital independiente, dado que las tierras deben ser comunes, para los 16 canales.
  7. La FPGA se encargará de las tareas hardware, ya que esta cumplirá la función de adquicisión/almacenamiento de los datos. La memoria RAM distribuida de este dispositivo es de 73K, mientras que la RAM de bloque es de 360K.
  8. Como entrada adicional contará con un botón para cambiar los canales en gupos de a 4, un botón de desplazamiento a la izquierda y otro a la derecha.

[edit] Descripción Hardware

Principalmente se utilizará la placa SIE, la cual nos permite realizar todo tipo de proyectos digitales, ya que cuenta con un microprocesador jz4725 de ingenic, 32MB de memoria SDRAM, 2GB de memoria NAND, una FPGA XC3S500E, pantalla LCD y varios GPIO's. Adicionalmente se desarrollará una tarjeta complementaria que optimizará la aplicación del analizador lógico.

Componente HW del proyecto

  1. Tarjeta SIE: SoCs, Memorias, Periféricos
  2. LCD
  3. Tarjeta Hija
  4. FPGA

[edit] Tareas Hardware

Para el manejo de la compoente software serán encesarias las siguientes tareas:

  1. Adquisición de datos
  2. Visualización en el LCD, refrescamiento y muestra de datos
  3. Almacenamiento en memoria

[edit] Descripción Software

Como herramientas software se utilizarán las cadenas de herramientas GNU, librerías, sistema operativo Linux, formato de archivos ELF, Makefile, creación de aplicaciones mediante Qt y Depuración (GDB). A continuación se describirá algunos de los paquetes de diseño a utilizar:

  1. GNU KiCAD: Con esta herramienta lo que se pretende es diseñar todos los circuitos electronicos que serán utilizados en el desarrollo del analizador lógico, entre los que se encuentra el PCB de la tarjeta hija desde la cual se enviarán las señales que se captarán y procesarán con la tarjeta SIE.
  1. Xilinx ISE: Ésta es la principal herramenta de programación de hardware utilziada hasta ahora y con ella lo que se pretende es poder programar la SIE para que capte las señales que provienen desde la tarjeta hija y las presente en la pantalla LCD.
  1. Qt Creator: Es un entorno de desarrollo integrado (IDE) que le proporciona herramientas para diseñar y desarrollar aplicaciones complejas para escritorios y plataformas móviles.

[edit] Tareas Software

Las tareas software que se manejarán en el proyecto son:

  1. Control de los datos adquiridos
  2. Manejo de la memoria
  3. Control de la visualización de los datos (Canales mostrados, tiempo de representación)
  4. Procesamiento de datos
  5. Medición de los parámetros importantes (estados lógicos, tiempo de subida, tiempo de bajada)

[edit] Tarjeta Hija

[edit] Esquemático y PCB

A continuación se presenta el esquematico de la tarjeta hija, la cual debe realizar el trabajo de acomple de impedancias y seguridad de la tarjeta SIE.

Para la adquisición de los datos se utilizará unas puntas de prueba que estarán conectadas al adaptador de la tarjeta hija. Como se mencionó anteriormente, para aislar la plataforma SIE del bloque de adquisición, se utilizará un buffer no-inversor 3-estados de 16 bits 74ALVCH162244, el cual permite controlar el flujo de señales ya que cuenta con cuatro señales ~OE (Ouput Enable), que cuando se encuentra en un nivle lógico ALTO, la salida asume un estado de alta impedancia. El voltaje de alimentación de este chip es de 3.3V y el tiempo de propagación de nAn a nYn es de 3,5 ns en condiciones normales.

La distribución de los pines es de la siguiente manera:

Número de Pin Símbolo Nombre y función
1 1 ~OE Output Enable input (Active LOW)
2, 3, 5, 6 1Y0 to 1Y3 Data Outputs
4, 10, 15, 21, 28, 34, 39, 45 GND Ground (0V)
7, 18, 31, 42 Vcc Positive supply voltage
8, 9, 11, 12 2Y0 to 2Y3 Data outputs
13, 14, 16, 17 3Y0 to 3Y3 Data Outputs
19, 20, 22, 23 4Y0 to 4Y3 Data Outputs
24 4 ~OE Output Enable input (Active LOW)
25 3 ~OE Output Enable input (Active LOW)
30, 29, 27, 26 4A0 to 4A3 Data inputs
36, 35, 33, 32 3A0 to 3A3 Data Inputs
41, 40, 38, 37 2A0 to 2A3 Data Inputs
47, 46, 44, 43 1A0 to 1A3 Data Inputs
48 2 ~OE Output Enable input(Active LOW)

[edit] Arquitectura del Analizador Lógico

En esta sección será presentada la arquitectura básica del proyecto en el que se demarcan las comunicaciones que se presentaran entre la FPGA y el procesador. Tal como se indica en la gráfica, se reciben todas las señales digitales mediante un arreglo de 4 bits que son representadas por medio de 1A, 2A,3A y 4A y dichas señales entrarán a el chip 74ALVCH162244, que es un buffer con el cual serán controlados los niveles lógicos de entrada al dispositivo. Cuando dichas señales salgan del chip, lo harán de la misma forma en la que ingresaron a él, es decir mediante arreglos de 4 bits, para de esa manera llegar a la RAM de la FPGA en la cual se almacenan los datos, cumpliendose de esta manera la función de escritura, para posteriormente llegar a las señales de control de los datos como lo son WritePulse Generator con la cual se accede a los datos almancenados, el Address decoder con la cual se le asigna un espacio de memoria especifico a los datos de entrada y estas dos ultimas señales han sido sincronizadas de tal forma que puedan llegar al procesador como instrucciones sincronicas. Adicionalmente, se establecen señales de enable para especificar cual es el momento en el que se empeiza la toma de datos y se asignan las funciones a los pulsadores.


[edit] Manejo de Memoria

En este moduló se controla el almacenamiento de los datos (El encargado directo de la memoria es el procesador), siendo simultáneos los procesos de lectura y de escritura. La memoria con la cual se va a trabajar en este proyecto sera la memoria RAM en bloque de la FPGA XC3S500E, la cual consta de 20 bloques de dicha memoria RAM doble puerto cuya capacidad de cada bloque es de 18 Kbits. Dado que se necesita realizar las tareas de lectura y escritura simultáneamente, la memoria debe tener la siguiente configuración.

Memoria RAM doble puerto


Como se puede apreciar en la figura de arriba, se cuenta con las señales WE, EN, CLK, y SSR que cumplen las funciones de control de memoria. A continuación se presenta una tabla que describe la función de cada una de las señales:

Descripción de la señal Nombre de la señal Puerto A Nombre de la señal Puerto B Tipo de señal Función
Bus de direcciones ADDRA ADDRB Entrada El bus de direcciones selecciona una espacio de memoria para realizar las funciones de lectura y/o escritura. El ancho del puerto asociado al camino de datos determina el número de lineas de direcciones. Dichas funciones dependen de los habilitadores ENA y ENB ya que al realizar la transmisión de datos se deben tener en cuenta los tiempos setup y hold con respecto a CLKA y CLKB y deben tenerse en cuenta sin importar si se esta leyendo o escribiendo.
Bus de entrada de datos DIA DIB Entrada Esta señal se encarga de escribir los datos provenientes del sistema analizado en la RAM cuando el Bus de direcciones establece su dirección en la memoria en cada flanco de subido del CLK y cuando el EN y WE esten activados.
Entrada de dato de paridad DIPA DIPB Entrada La entrada de paridad repesenta un conjunto de bits adicionales incluidos en el camino de entrada de datos. No son de gran utilidad a la hora de revisar y generar la paridad de los bits de entrada y se colocan como datos adicionales del bus de direcciones. EL numero de bits de paridad 'p' estan incluidas en el dato de entrada.
Salida de dato de paridad DOPA DOPB Salida El dato es escrito en el dus de direcciones de salida desde el espacio de memoria RAM especificado desde el bus de direcciones, ADDR. Configura el ancho del puerto de datos de salida con la description de la señal de datos de entrada.
Write Enable WEA WEB Entrada Cuando se activa al mismo tiempo que el EN, esta entrada permite escribir los datos en la memoria RAM. Cuando esta deshabilitada, se habilita la función de lectura. Cuando este es el caso, un latch pasa datos desde el espacio de memoria hacia las salidas DO.
Clock Enable ENA ENB Entrada Cuando se activa, esta entrada habilita la señal CLK para hacer operaciones de lectura y escritura en el bloque de memoria RAM. Cuando esta inactiva, el bloque de RAM ni escribe ni lee
Set/Reset SSRA SSRB Entrada Cuando se activa, este pin hace que la salida DO tome el valor del atributo SRVAL. Se sincroniza con la señal CLK.
Clock CLKA CLKB Entrada Esta entrada recibe la señal de reloj para sincronizar las operaciones de lectura y escritura.

[edit] Definiciones de atributos de Memoria RAM

Un bloque de memoria tiene una serie de atributos que controlan su comportamiento.

Función Atributo Posibles Valores
Inicializar contenido de la memoria de datos, cargados durante la configuración INITxx (INIT_00 hasta INIT3F) Cada cadena de inicialización define 32 valores hexadecimales de 16384 bits de la memoria de datos del bloque de RAM.
Inicializar contenido para el bit de paridad, cargados durante la configuración INITPxx (INITP_00 hasta INITP0F) Cada cadena de inicializacion define 32 valores hexadecimales de los 2048 bits de paridad de la memoria de datos de los bloque RAM.
Latch de inicializacion de la salida de datos INITA, INITB (dual-port) Valor hexadecimal con el ancho del puerto seleccionado.
Latch de sincronismo para la salida de datos SRVAL_A, SRVAL_B (dual-port) Valor hexadecimal con el ancho del puerto seleccionado.
Latch de comportamiento de escritura de la salida de datos WRITE_MODE WRITE_FIRST, READ_FIRST, NO_CHANGE

[edit] Operaciones de datos

Escribir datos y acceder a ellos desde el bloque de RAM es una operación síncrona que se realiza sin importar el puerto de cada bloque. La operación de lectura se realiza de la siguiente manera:

Operación escritura.

Tal y como se observa en esta gráfica, la operación de escritura para un solo puerto cumple con la descripción que se hizo anteriormente en la cual se escribe siempre y cuando la señal EN y la señal WE se encuentran en un nivel lógico 1. Por otro lado, para la lectura, se debe tener la señal EN activa y WE con un 0 lógico. Debido a que se necesita para el analizador lógico una memoria de doble puerto, se seleccionará el puerto A como de escritura y el puerto B como de lectura ya que cada una cuenta con un bus de direcciones que funcionan de forma independiente.

Instanciación de la memoria:

  1. //***********************************************************************************************
  2. // Memory
  3. //***********************************************************************************************
  4.      always @ (wd or CS)
  5. WdRam = wd && (CS == TRIG_TRIG);
  6. RAMB16_S9_S9 RAM1 (
  7.       .DOA(dout[7:0]),      // Port A 8-bit Data Output
  8.       .DOB(),      // Port B 8-bit Data Output
  9.       .DOPA(),    // Port A 1-bit Parity Output
  10.       .DOPB(),    // Port B 1-bit Parity Output
  11.       .ADDRA(WdCntr),  // Port A 11-bit Address Input
  12.       .ADDRB(RdCntr[10:0]),  // Port B 11-bit Address Input
  13.       .CLKA(~clk),    // Port A Clock
  14.       .CLKB(~clk),    // Port B Clock
  15.       .DIA(Ireg[7:0]),// Port A 8-bit Data Input
  16.       .DIB(8'b0),      // Port B 8-bit Data Input
  17.       .DIPA(1'b0),    // Port A 1-bit parity Input
  18.       .DIPB(1'b0),    // Port-B 1-bit parity Input
  19.       .ENA(1'b1),      // Port A RAM Enable Input
  20.       .ENB(1'b1),      // Port B RAM Enable Input
  21.       .SSRA(1'b0),    // Port A Synchronous Set/Reset Input
  22.       .SSRB(1'b0),    // Port B Synchronous Set/Reset Input
  23.       .WEA(WdRam),      // Port A Write Enable Input
  24.       .WEB(1'b0)       // Port B Write Enable Input
  25.    );
  26. RAMB16_S9_S9 RAM2 (
  27.       .DOA(dout[15:8]),      // Port A 8-bit Data Output
  28.       .DOB(),      // Port B 8-bit Data Output
  29.       .DOPA(),    // Port A 1-bit Parity Output
  30.       .DOPB(),    // Port B 1-bit Parity Output
  31.       .ADDRA(WdCntr),  // Port A 11-bit Address Input
  32.       .ADDRB(RdCntr[10:0]),  // Port B 11-bit Address Input
  33.       .CLKA(~clk),    // Port A Clock
  34.       .CLKB(~clk),    // Port B Clock
  35.       .DIA(Ireg[15:8]),// Port A 8-bit Data Input
  36.       .DIB(8'b0),      // Port B 8-bit Data Input
  37.       .DIPA(1'b0),    // Port A 1-bit parity Input
  38.       .DIPB(1'b0),    // Port-B 1-bit parity Input
  39.       .ENA(1'b1),      // Port A RAM Enable Input
  40.       .ENB(1'b1),      // Port B RAM Enable Input
  41.       .SSRA(1'b0),    // Port A Synchronous Set/Reset Input
  42.       .SSRB(1'b0),    // Port B Synchronous Set/Reset Input
  43.       .WEA(WdRam),      // Port A Write Enable Input
  44.       .WEB(1'b0)       // Port B Write Enable Input
  45.    );

[edit] Diagrama De Bloques

Diagrama de Bloques
RTL




[edit] Modulo Trigger

El trabajo principal de este modulo es el de controlar la adquisición de los datos a la memoria. Como se puede observar en el código a continuación, se utilizó un modulo de comparación realmente sencillo, el cual simplemente compara el dato de entrada con el trigger dado por el usuario con el fin de obtener la señal de control que será utilizada en la maquina de control mostrado anteriormente.

Debido a que la plataforma con la que se cuenta no posee los suficientes números de entradas digitales para facilitarle al usuario el poder escoger el trigger de una manera sencilla, se opto por realizar una maquina de estados con dos entradas de control trigger, tal y como se muestra al principio del código.

A continuacion se presenta un diagrama de bloques del trigger en el que se puede observar como es el funcionamiento de la maquina de estados que lo conforman. Es necesario anotar que se ha omitido la senal de reset dado que es un estado adicional controlado por un pulsador y no interfiere en el nivel logico del trigger.

Maquina de algorítmica del Trigger


  1. parameter [1:0] //synopsys enum STATE_TYPE
  2. TRIG_IDLE = 2'b00, //do nothing
  3. TRIG_ARMED = 2'b01, //arm trigger mechanism
  4. TRIG_TRIG = 2'b10; //record data
  5. //----------------------------------------------------------
  6. // Trigger compare logic
  7. //----------------------------------------------------------
  8.  
  9. TrigCompare T0 (.A(Ireg[ 0]),.B(treg[ 0]),.T(TCout[ 0]));
  10. TrigCompare T1 (.A(Ireg[ 1]),.B(treg[ 1]),.T(TCout[ 1]));
  11. TrigCompare T2 (.A(Ireg[ 2]),.B(treg[ 2]),.T(TCout[ 2]));
  12. TrigCompare T3 (.A(Ireg[ 3]),.B(treg[ 3]),.T(TCout[ 3]));
  13. TrigCompare T4 (.A(Ireg[ 4]),.B(treg[ 4]),.T(TCout[ 4]));
  14. TrigCompare T5 (.A(Ireg[ 5]),.B(treg[ 5]),.T(TCout[ 5]));
  15. TrigCompare T6 (.A(Ireg[ 6]),.B(treg[ 6]),.T(TCout[ 6]));
  16. TrigCompare T7 (.A(Ireg[ 7]),.B(treg[ 7]),.T(TCout[ 7]));
  17. TrigCompare T8 (.A(Ireg[ 8]),.B(treg[ 8]),.T(TCout[ 8]));
  18. TrigCompare T9 (.A(Ireg[ 9]),.B(treg[ 9]),.T(TCout[ 9]));
  19. TrigCompare T10(.A(Ireg[10]),.B(treg[10]),.T(TCout[10]));
  20. TrigCompare T11(.A(Ireg[11]),.B(treg[11]),.T(TCout[11]));
  21. TrigCompare T12(.A(Ireg[12]),.B(treg[12]),.T(TCout[12]));
  22. TrigCompare T13(.A(Ireg[13]),.B(treg[13]),.T(TCout[13]));
  23. TrigCompare T14(.A(Ireg[14]),.B(treg[14]),.T(TCout[14]));
  24. TrigCompare T15(.A(Ireg[15]),.B(treg[15]),.T(TCout[15]));
  25.  
  26. always @ (TCout)
  27. TC = TCout[15] & TCout[14] & TCout[13] & TCout[12] &
  28. TCout[11] & TCout[10] & TCout[9] & TCout[8] & TCout[7] &
  29. TCout[6] & TCout[5] & TCout[4] & TCout[3] & TCout[2] & TCout[1] & TCout[0];
  30.  
  31.  
  32. //----------------------------------------------------------------
  33. // Trigger State machine
  34. //----------------------------------------------------------------
  35. always @ (posedge clk or posedge reset)
  36. begin
  37. 	if(reset)
  38. 		CS <= 0; //reset triggered status
  39. 	else
  40. 		CS <= NS; //goto next state
  41. 	end
  42.  
  43. always @(CS or Done or TC or arm)
  44. begin
  45. case (CS)
  46. 	TRIG_IDLE: begin
  47. 	if(arm)
  48. 		begin
  49. 			NS = TRIG_ARMED; //arm system?
  50. 			ClearCntr = 1; //clear address counters
  51. 			clearready = 1; //put into not ready state
  52. 			setready = 0;
  53. 		end
  54. 	else
  55. 		begin
  56. 			NS = TRIG_IDLE;
  57. 			ClearCntr = 0;
  58. 			clearready = 0;
  59. 			setready = 0;
  60. 		end
  61. end
  62. TRIG_ARMED: begin
  63. 	if(TC)
  64. 		begin
  65. 			NS = TRIG_TRIG; //triggered...record
  66. 			ClearCntr = 0;
  67. 			clearready = 0;
  68. 			setready = 0;
  69. 		end
  70. 	else
  71. 		begin
  72. 			ClearCntr = 0;
  73. 			NS = TRIG_ARMED;
  74. 			clearready = 0;
  75. 			setready = 0;
  76. 		end
  77. end
  78. TRIG_TRIG: begin
  79. 	if(Done)
  80. 		begin
  81. 			NS = TRIG_IDLE; //done, stop
  82. 			ClearCntr = 0;
  83. 			clearready = 0;
  84. 			setready = 1; //put into ready state
  85. 		end
  86. 	else
  87. 		begin
  88. 			NS = TRIG_TRIG;
  89. 			ClearCntr = 0;
  90. 			clearready = 0;
  91. 			setready = 0;
  92. 		end
  93. end
  94. 	default: 
  95. 		begin
  96. 			NS = TRIG_IDLE;
  97. 			ClearCntr = 0;
  98. 			clearready = 1;
  99. 			setready = 0;
  100. 		end
  101. endcase
  102. end
  103. //-------------------------------------------------
  104. //Trigger compare
  105. //-------------------------------------------------
  106. module TrigCompare(A,B,T);
  107. 	input A; //data input
  108. 	input B; //tirgger input
  109. 	output T; //output
  110.  
  111. 	reg T;
  112.  
  113. always @ (A or B)
  114. 	begin
  115. 		if(A == B)
  116. 				T = 1; //triggered
  117. 			else
  118. 				T = 0; //not triggered
  119. 	end
  120. endmodule

[edit] Banco de Registros de Configuración

Para la configuración de las funciones de escritura y lectura del periférico de adquisición se establecieron los siguientes registros y funciones:

  1. // parameter:
  2. // clk.............system clock
  3. // reset...........system reset
  4. // data_in.............this is the data to record
  5. // enable..........causes the data to be recorded
  6. // data............output data port
  7. // arm.............arm trigger unit
  8. // rd..............read data from recording
  9. // ready...........indicates that memory is full
  10. // trigger.........trigger word
  11. //-----------------------------------------------------------
  12. input clk;
  13. input reset;
  14. input [15:0] data_in;
  15. input [12:0] addr;
  16. reg enable=0;
  17. output reg [7:0] rdBus;
  18. reg [7:0] data=0;
  19. reg arm=0;
  20. reg rd=0;
  21. input [7:0] wrBus;
  22. output ready;
  23. reg [15:0] trigger;
  24. //writes data to trigger registers
  25. reg wdtrig=0;
  26. reg [15:0] treg=0; //contains bit 0 of trigger for each bit (polarity)
  27. reg [15:0] Ireg=0; //data input reg
  28. reg [8:0] WdCntr=0; //address counter for writing data
  29. reg [10:0] RdCntr=0; //address counter for reading data
  30. wire [15:0] dout; //data output register
  31. reg [1:0] CS=0; //state indicates that the system was triggered
  32. reg [1:0] NS=0;
  33. reg Done=0; //indicates memory is full
  34. reg TC=0;
  35. reg ClearCntr=0; //clear the address counters
  36. wire [15:0] TCout;
  37. reg wd,WdRam=0;
  38. reg ready,setready,clearready=0;
  39. input we,cs;
  40.  
  41. //Write control
  42. 	    always @(negedge clk)
  43. 	    begin
  44. 	        if(reset)
  45. 	            {enable, arm,rd,wdtrig,trigger} <= 0;
  46. 	        else if(we & cs) begin
  47. 	            case (addr)
  48. 	                    0: begin trigger[7:0] <= wrBus; end
  49. 	                    1: begin trigger[15:8] <= wrBus; end
  50. 	                    2: begin enable <= wrBus[0]; 
  51. 				 arm <= wrBus[1];
  52. 				 rd <= wrBus[2];
  53. 				 wdtrig <= wrBus[3];
  54. 				  end
  55. 	                    default: begin enable <= 1; end
  56. 	            endcase
  57. 	        end
  58. 	        else 
  59. 				begin
  60. 				{enable, arm,rd,wdtrig,trigger} <= 0; 
  61. 				end
  62. end 
  63.  
  64. //Read control
  65. 	    always @(posedge clk)
  66. 	        if(reset)
  67. 	            {rdBus} <= 0;
  68. 	        else begin
  69. 	            case (addr)
  70. 	                  0: begin rdBus <= trigger[7:0]; end
  71. 	                  1: begin rdBus <= trigger[15:8]; end
  72. 	                  2: begin rdBus <= {enable, arm,rd,wdtrig};end
  73. 	            default: begin rdBus <= data; end
  74. 	            endcase
  75. 	        end

[edit] Interfaz con el Usuario utilizando QT

La interfaz pensada para el analizador consta de la pantalla lcd en la que seran mostrados los canales a partir de las decisiones que tome el usuario por medio de los 8 botones laterales, los cuales controlaran una lista de opciones que estara presente en la parte derecha de la pantalla, permitiendole al usuario controlar el tipo de visualizacion, la referencia del triger, la frecuencia de captura y la posición.

Interfaz con el usuario

Lo primero que hay que hay que hacer es agregar en el encabezado csv.h los encabezados necesarios para que QT pueda leer y escribir de la memoria RAM

#ifndef MYQTAPP_H
#define MYQTAPP_H
 
#include "ui_csv.h"
#include "jz47xx_mmap.h"
#include "jz47xx_gpio.h"
 
#define CS2_PORT JZ_GPIO_PORT_B
#define CS2_PIN 26
 
 
class csv : public QWidget, private Ui::find_inout
{
    Q_OBJECT
 
public:
    csv();
 
 
public slots://funciones
    void principal();
    void graf();
    void change();
 
    JZ_REG *initFPGA_RAM();
 
 
private:
 
    JZ_REG *RAM;
 
};
 
 
#endif

Posteriormente se modifican la clase csv y la función cpp de tal manera que se grafiquen los 16 canales, se introduzcan los bits de control necesarios para el periférico y se puedan hacer las transiciones entre los diferentes QspinBox necesarios para realizar las elecciones de las opciones y la parte de visualización de la siguietne manera:

#include <QtGui>
#include <QFile>
#include <QString>
#include <QStringList>
#include <QList>
#include <QTextStream>
#include "csv.h"
#include <iostream>
#include <stdio.h>
#include <QImage>
#include <QPainter>
#include <QtGui>
 
// if we include <QtGui> there is no need to include every class used: <QString>, <QFileDialog>,...
QImage imagen;
int N;
 
csv::csv()
{
    setupUi(this); // this sets up GUI
    printf ("Acaba de iniciar el proceso");
    RAM=initFPGA_RAM();
    N=2000;
    spinBox1->setRange(1,16);
    spinBox2->setRange(1,16);
    spinBox3->setRange(0,25000000);
    spinBox3->setSingleStep(5000);
    connect(spinBox1, SIGNAL(valueChanged(int)),this,SLOT(graf()));//Esto es lo importante para graficar
    connect(spinBox3, SIGNAL(valueChanged(int)),this,SLOT(change()));//Esto es lo importante para cambiar las propiedades del QsinBox3
}
 
void csv::principal()
{
    spinBox3->setValue(1000);
    printf ("Comienza el proceso: Grafica sin nada");
    graf();
}
 
void csv::graf(){
    int c,t,f;
        c=spinBox1->value();c=c-1;//lee canal guado los primeros 4 bits para eso
        t=spinBox2->value();//lee trigger guardo los demas 4 bits
        f=spinBox3->value();//lee frecuencia dejamos 20 posiciones para la frecuencia
    printf ("Se tomaron los valores de canal, trigger y frecuencia");
    //Comienzo a escribir en la memoria
    //Reservados para trigger
    switch(t)
    {
 
    case 0:{RAM[10]=0 ;RAM[11]=0 ;RAM[12]=0 ;RAM[13]=0;}
        break;
    case 1:{RAM[10]=0;RAM[11]=0;RAM[12]=0;RAM[13]=1;}
        break;
    case 2:{RAM[10]=0;RAM[11]=0;RAM[12]=1;RAM[13]=0;}
        break;
    case 3:{RAM[10]=0;RAM[11]=0;RAM[12]=1;RAM[13]=1;}
        break;
    case 4:{RAM[10]=0;RAM[11]=1;RAM[12]=0;RAM[13]=0;}
        break;
    case 5:{RAM[10]=0;RAM[11]=1;RAM[12]=0;RAM[13]=1;}
        break;
    case 6:{RAM[10]=0;RAM[11]=1;RAM[12]=1;RAM[13]=0;}
        break;
    case 7:{RAM[10]=0;RAM[11]=1;RAM[12]=1;RAM[13]=1;}
        break;
    case 8:{RAM[10]=1;RAM[11]=0;RAM[12]=0;RAM[13]=0;}
        break;
    case 9:{RAM[10]=1;RAM[11]=0;RAM[12]=0;RAM[13]=1;}
        break;
    case 10:{RAM[10]=1;RAM[11]=0;RAM[12]=1;RAM[13]=0;}
        break;
    case 11:{RAM[10]=1;RAM[11]=0;RAM[12]=1;RAM[13]=1;}
        break;
    case 12:{RAM[10]=1;RAM[11]=1;RAM[12]=0;RAM[13]=0;}
        break;
    case 13:{RAM[10]=1;RAM[11]=1;RAM[12]=0;RAM[13]=1;}
        break;
    case 14:{RAM[10]=1;RAM[11]=1;RAM[12]=1;RAM[13]=0;}
        break;
    case 15:{RAM[10]=1;RAM[11]=1;RAM[12]=1;RAM[13]=1;}
        break;
    default:break;
    }
    printf ("Se guardaron los bits de control del trigger");
    //Reservados para frecuencia
    switch(f)
    {
 
    case 1000:{RAM[14]=0 ;RAM[15]=0 ;RAM[16]=0 ;RAM[17]=0;}
        break;
    case 5000:{RAM[14]=0;RAM[15]=0;RAM[16]=0;RAM[17]=1;}
        break;
    case 10000:{RAM[14]=0;RAM[15]=0;RAM[16]=1;RAM[17]=0;}
        break;
    case 50000:{RAM[14]=0;RAM[15]=0;RAM[16]=1;RAM[17]=1;}
        break;
    case 100000:{RAM[14]=0;RAM[15]=1;RAM[16]=0;RAM[17]=0;}
        break;
    case 500000:{RAM[14]=0;RAM[15]=1;RAM[16]=0;RAM[17]=1;}
        break;
    case 1000000:{RAM[14]=0;RAM[15]=1;RAM[16]=1;RAM[17]=0;}
        break;
    case 5000000:{RAM[14]=0;RAM[15]=1;RAM[16]=1;RAM[17]=1;}
        break;
    case 10000000:{RAM[14]=1;RAM[15]=0;RAM[16]=0;RAM[17]=0;}
        break;
    case 15000000:{RAM[14]=1;RAM[15]=0;RAM[16]=0;RAM[17]=1;}
        break;
    case 20000000:{RAM[14]=1;RAM[15]=0;RAM[16]=1;RAM[17]=0;}
        break;
    case 25000000:{RAM[14]=1;RAM[15]=0;RAM[16]=1;RAM[17]=1;}
        break;
   default:break;
    }
    printf ("Se guardaron los bits de control de las frecuencias");
    RAM[18]=1;//Este es el bit de start
    int ramaux = RAM[18];
    int value[N*16];
    printf ("Se va a comenzar a leer la memoria");
    //lee de la memoria
    if(ramaux==1 && RAM[18]==0)
    {//Es necesario cambiar el star de 1 a 0 cuando se termine de escribir en la memoria para comenzar a leer
        for (int i4=0;i4<N*16;i4++){
            value[i4]=RAM[i4];
        }
    }
 
    imagen=QImage("fondo.png");
    QPainter painter(&imagen);
    painter.setFont(QFont("Arial", 14));
    int dx=20,dy=20,n=0,aux1=0,aux2=0;
    textEdit->clear();
    painter.eraseRect(0,0,640,400);
    painter.setPen(Qt::blue);
    textEdit->textCursor().insertImage(imagen);   //label->setPixmap(QPixmap("fondo.png"));
    painter.drawText(100,10,"Analizador Logico");
    painter.setFont(QFont("Arial", 12));
    painter.drawText(10,30,"Canal 1");
    painter.drawText(10,50,"Canal 2");
    painter.drawText(10,70,"Canal 3");
    painter.drawText(10,90,"Canal 4");
    painter.drawText(10,110,"Canal 5");
    painter.drawText(10,130,"Canal 6");
    painter.drawText(10,150,"Canal 7");
    painter.drawText(10,170,"Canal 8");
    painter.drawText(10,190,"Canal 9");
    painter.drawText(10,210,"Canal 10");
    painter.drawText(10,230,"Canal 11");
    painter.drawText(10,250,"Canal 12");
    painter.drawText(10,270,"Canal 13");
    painter.drawText(10,290,"Canal 14");
    painter.drawText(10,310,"Canal 15");
    painter.drawText(10,330,"Canal 16");
    painter.setPen(Qt::green);
    for(int i2=0;i2<N;i2++)//Dibujo la cuadricula
    {
        painter.drawLine(70+(dx*(i2)),15,70+(dx*(i2)),335);//Dibuja las lineas verticales
        for(int i3=0;i3<=16;i3++)
        {
            painter.drawLine(70,15+(i3*20),640,15+(i3*20));//Dibuja las lineas horizontales
        }
    }
    painter.setPen(Qt::black);
    //Dibujo ceros y unos para cualquier canal
    for(int i4=0;i4<c+1;i4++)
    {
        int c2=i4;
        n=0;
        for(int i=0;i<N;i++)//Las primeras 9 posiciones del canal 1 me indican los bits de control
        {
            aux1=value[i+N*c2];//Para las otras muestras: value[i+N*c2] con N tamano de cada muestra
            aux2=value[i+1+N*c2];//Para las otras muestras: value[i+1+N*c2] con N tamano de cada muestra
            if (aux1==0){
            painter.drawLine(70+(dx*n),30+(c2*dy),70+(dx*(n+1)),30+(c2*dy));}//Dibuja un 0
            if (aux1==1){
            painter.drawLine(70+(dx*n),20+(c2*dy),70+(dx*(n+1)),20+(c2*dy));}//Dibuja un 1
            if (aux1!=aux2){
            painter.drawLine(70+(dx*(n+1)),30+(c2*dy),70+(dx*(n+1)),20+(c2*dy));}//Dibuja una linea vertical
            n=n+1;
         }
    }
    //textEdit->verticalScrollBar()->setValue(50);
    //textEdit->horizontalScrollBar()->setValue(50);
 
}
 
void csv::change(){
    if (spinBox3->value()==0){
        spinBox3->setValue(1000);
    }
    if (spinBox3->value()==6000){
        spinBox3->setValue(5000);
    }
    if (spinBox3->value()==60000){
        spinBox3->setValue(50000);
    }
    if (spinBox3->value()==600000){
        spinBox3->setValue(500000);
    }
    if (spinBox3->value()==6000000){
        spinBox3->setValue(5000000);
    }
    else if (spinBox3->value()<10000){
        spinBox3->setSingleStep(5000);
    }
    else if (spinBox3->value()<100000){
        spinBox3->setSingleStep(50000);
    }
    else if (spinBox3->value()<1000000){
        spinBox3->setSingleStep(500000);
    }
    else if (spinBox3->value()<25000000){
        spinBox3->setSingleStep(5000000);
    }
}
 
JZ_REG *
csv::initFPGA_RAM()
{
    JZ_PIO *pio;
    JZ_REG *virt_addr;
 //      pio = jz_gpio_map (CS2_PORT);
 //   jz_gpio_as_func (pio, CS2_PIN, 0);
    virt_addr = (JZ_REG *) (jz_mmap(0x13010000) + 0x18);
    if (*virt_addr != 0x0FFF7700)
    {
    *virt_addr = 0x0FFF7700;
    printf ("ADC: Configuring CS2 8 bits and 0 WS: %08X\n", *virt_addr);
    }
    else
    printf ("ADC: CS2, already configured: %08X\n", *virt_addr);
    virt_addr = (JZ_REG *) jz_mmap (0x14000000);
    return virt_addr;
}

[edit] Driver

Un device driver es un programa que le permite al sistema operativo interactuar con un periférico, proporcionando una interfaz para utilizarlo. Para la realización de este driver fue necesario modificar el driver del irq y el de un teclado de una consola de juegos , con el fin de implementar los botones que controlan las funciones principales del analizador.

#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>       /* Needed for KERN_INFO */
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/irq.h>        /* We want an interrupt */
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>  
#include <asm/io.h>
#include <linux/gpio.h>
#include <asm/mach-jz4740/gpio.h>
 
 
#define FPGA_IRQ_PIN          JZ_GPIO_PORTC(15)
#define FPGA_BASE             0x15000000 
#define BASE                  0xB5000000 
MODULE_AUTHOR(" ");
MODULE_DESCRIPTION("Botones Analizador Lógico keyboard driver");
MODULE_LICENSE("GPL");
 
unsigned int irq;
 
static unsigned char atakbd_keycode[0x5] = {	/* American layout */
 
	[0] = KEY_UP,[1] = KEY_TAB,[2] = KEY_LEFT,[3] = KEY_RIGHT,[4] = KEY_DOWN,
};
 
static struct input_dev *atakbd_dev;
 
static irqreturn_t irq_handler(int irq, void *dev_id)//función que toma las interrupciones y define las acciones a seguir
{
  unsigned char opciones=0;
  opciones=inb(BASE);
	printk("Se oprimio la tecla\n"); 
 switch(opciones){
 
   case 0: 
	input_report_key(atakbd_dev,atakbd_keycode[0],1);
	input_report_key(atakbd_dev,atakbd_keycode[0],0);	
   break;
   case 1: 
	input_report_key(atakbd_dev,atakbd_keycode[1],1);
	input_report_key(atakbd_dev,atakbd_keycode[1],0);	
   break;
   case 4: 
	input_report_key(atakbd_dev,atakbd_keycode[2],1);
	input_report_key(atakbd_dev,atakbd_keycode[2],0);	
   break;
   case 8: 
	input_report_key(atakbd_dev,atakbd_keycode[3],1);
	input_report_key(atakbd_dev,atakbd_keycode[3],0);	
   break;
   case 16: 
	input_report_key(atakbd_dev,atakbd_keycode[4],1);
	input_report_key(atakbd_dev,atakbd_keycode[4],0);	
   break;
   default: 
	input_report_key(atakbd_dev,0,1);
	input_report_key(atakbd_dev,0,0);	
   break;
}
	input_sync(atakbd_dev);
	return IRQ_HANDLED;
}
 
static int __init atakbd_init(void)
{
	int i, error,res;
 
 
	atakbd_dev = input_allocate_device();
	if (!atakbd_dev)
		return -ENOMEM;
 
	atakbd_dev->name = "Analizador Keyboard";
	atakbd_dev->phys = "analizador/input0";
	atakbd_dev->id.bustype = BUS_HOST;
	atakbd_dev->id.vendor = 0x0001;
	atakbd_dev->id.product = 0x0001;
	atakbd_dev->id.version = 0x0100;
 
	atakbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
	atakbd_dev->keycode = atakbd_keycode;
	atakbd_dev->keycodesize = sizeof(unsigned char);
	atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
 
	for (i = 0; i < 0x6; i++) {
		set_bit(atakbd_keycode[i], atakbd_dev->keybit);
	}
 
	/* error check-->indica al sistema el nuevo dispositivo de entrada */
	error = input_register_device(atakbd_dev);
	if (error) {
		input_free_device(atakbd_dev);
		return error;
	}
 
 	irq = gpio_to_irq(FPGA_IRQ_PIN);//asigna el numero del irq al pin fisico del procesador
 
  	res = request_irq(irq, irq_handler, IRQF_DISABLED | IRQF_TRIGGER_RISING, "FPGA - IRQ", NULL); // IRQF_TRIGGER_FALLING --> asignar el valor del irq y la funcion que lo utiliza
 
	return 0;
}
 
static void __exit atakbd_exit(void)
{
	input_unregister_device(atakbd_dev);
}
 
module_init(atakbd_init);
module_exit(atakbd_exit);

[edit] Análisis Económico

Los costos asociados al proyecto son los siguientes:

Se trabajaron 2 horas diarias a lo largo de las 14 semanas del semestre, con lo que por cada uno de los integrantes se tiene en total 140, lo que suma finalmente 420 horas de trabajo las cuales son avaluadas en $40.000 pesos cada una, para un costo total de mano de obra de $16'800.000.

En cuanto a los materiales utilizados y demás derivados se tienen:

  • SIE ---------------> $200.000 pesos.
  • Tarjeta hija----------------> $182.000 pesos.
  • Sondas, resistencias y conectores -----------------------------------> $100.000 pesos.
  • Servicios públicos $20.000 pesos mes -> $80.000 pesos
  • Total prototipo -------------------------------------------> $562.000 pesos.



[edit] Cronograma de Actividades

A continuación se presenta el cronograma de actividades a desarrollar a lo largo del semestre:

Semana Actividad a realizar
4 Presentación especificaciones proyecto, diagrama de bloques y PCB.
5 Pruebas PCB de la tarjeta hija (circuito de protección)
6 Diseño comunicación entre tarjeta hija y SIE
7 Desarrollo de drivers en Linux
8 Segunda entrega proyecto
9 Diseño interfaz hardware/software
10 Diseño interfaz hardware/software
11 Prueba de funcionalidad básica de la tarjeta
12 Tercera entrega proyecto
13 Pruebas finales modulo memorias y adquisición
14 Pruebas finales modulo control
15 Pruebas finales modulo vizualización
16 Entrega final

[edit] Bibliografía

[1] "The XYZs of Logic Analyzers", Nota de aplicación de Tektronix.2001.

[2] "Feeling Confortable with Logic Analyzers”, Nota de aplicación 1337. Agilent Technologies.

[3] "ANALIZADORES LÓGICOS", lección 9.

Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export