Aprenda FPGA con este truco de visión persistente

Miguel Vidal
Miguel Vidal

Todo el mundo quiere probar el desarrollo de FPGA y esta es una excelente forma de hacerlo. Puede crear su propia pantalla Persistence of Vision con un tablero de aplicaciones de $ 30. Es un proyecto divertido y aprenderá mucho sobre el diseño de FPGA, así como sobre el uso del software de diseño Quartus.

La inspiración para este artículo está llegando [vpecanins] quién hizo un proyecto de ejemplo en el que desliza el tablero hacia adelante y hacia atrás y aparece un mensaje en el medio. Esto usa el MAX1000, una placa FPGA bastante poderosa pero extraña por alrededor de $ 30. Contiene un Intel MAX10 (¿cuándo comenzó Intel a fabricar FPGA? Recuerde, Intel compró Alterra en 2015). Encuentro la placa extraña porque también tiene un acelerómetro con el que puedes hablar a través de SPI. Eso es un poco extraño para una placa FPGA en general, pero junto con ocho LED incorporados, es perfecto para esta pantalla.

Como no pude encontrar un documento escrito para este ejemplo, pensé que podríamos ayudarlo e ir paso a paso por el proyecto. Además, en una próxima entrega, te mostraré cómo realizar algunos cambios significativos en el tutorial que lo harán aún más práctico como base para otros proyectos.

Solo como motivación, mire el video a continuación para ver qué hace el proyecto. Modifiqué el texto (por supuesto, WD5GNR). El efecto es mejor en la vida real, pero el video te dará la idea. El FPGA monitorea el acelerómetro invierte el orden para encender los LED y apagarlos para formar las señales. Es una demostración bastante impresionante, ya que aprovecha las características únicas de la placa, es trivial y no es demasiado Verilog para tragar si recién está comenzando.

Prerrequisitos

Primero necesitará instalar Quartus. La edición Lite es gratuita y muy capaz. Puede descargar los archivos y abrir el archivo test0.qpf en la carpeta demo02_led_text. Es posible que obtenga un cuadro de diálogo de reemplazo de base de datos desagradable si tiene una versión más nueva de Quartus que los archivos originales utilizados. Puede aceptar eso con seguridad.

Archivo de torneo

En el navegador de proyectos dentro de Quartus, puede seleccionar Archivos y verá que el proyecto tiene solo unos pocos:

  • top.v: el código principal de Verilog.
  • Programming_chain.cdf: este archivo debería decirle a Quartus cómo programar la configuración en el chip, pero falta. Sin embargo, eso no es un problema. No es realmente necesario y es fácil de recrear.
  • font_rom.qip: un componente que utiliza Alter IP (propiedad intelectual) para crear una ROM con los patrones de caracteres en ella.
  • spi_master.v – Código para hablar con el acelerómetro.
  • macro.do: este archivo en realidad no existe y aparentemente permanece de los esfuerzos anteriores del autor.
  • sequencer.v – Código para usar el acelerómetro.
  • Si expande el elemento font_rom.qip en la lista, verá que hay un archivo Verilog oculto. Este archivo fue generado por un asistente de IP, por lo que, aunque puede verlo, no es necesario que lo toque. Utiliza el bloque de IP Altera Sync RAM para crear un bloque de memoria. Una cosa notable es que el archivo Verilog especifica un archivo init, que es font5x7.hex. Este es un archivo hexadecimal estándar con el contenido de la ROM. Por cierto, este es solo un nombre de ROM. Está implementado en RAM pero no hay una interfaz para escribir en él, por lo que desde el punto de vista del proyecto es de solo lectura. Sin embargo, no es involuntario. Se reescribirá cada vez que reinicie la FPGA.

    Nuevamente, todo esto se organizó respondiendo algunas preguntas en un asistente de IP. Debería poder abrir la IP para cambiarla con el Editor de parámetros, pero parece que falta algún archivo para permitir esto o, quizás, el autor lo configuró manualmente. Sin embargo, puede ver el proceso si va al Directorio de IP en Quartus y abre Biblioteca | Funciones básicas | En memoria de chip | ROM: 1 puerto. Sería fácil reemplazar la ROM existente por la suya propia si quisiera practicar.

    El módulo superior

    El módulo superior tiene una interfaz para el reloj del sistema de 12 horas, el botón de usuario (que utiliza como reinicio) y los 8 LED. También contiene las señales para hablar con el acelerómetro SPI y 8 bits de E / S paralelas, que parece que se usan para depurar (el proyecto solo copia algunas señales internas a esos pines).

    Para decirle al software dónde deben ir esos puertos, debe establecer límites locales que el autor ya ha establecido. Hay muchas formas de hacerlo. Sin embargo, una forma es ubicar la sección de tareas de Quartus y seleccionar “Diseño completo”. Luego verá una carpeta para “Asignar límites”. Ábralo y seleccione Editar asignaciones de pines. Desde allí, puede configurar todos los pines de E / S para el módulo superior: sus nombres, el tipo de pin y exactamente a qué pin de la FPGA se asigna.

    Si lo prefiere, puede utilizar el elemento Asignar en el menú principal y seleccionar Asignar editor. Lo prefiero porque es como un formato de hoja de cálculo fácil de leer. Si aún no tenía el diseño inicial, ¿cómo sabría qué pines están encendidos los LED y las cosas? Estos datos se encuentran en el manual de referencia técnica de la placa. También hay una hoja de cálculo en el directorio que documenta las tareas.

    El resto del módulo crea el componente SPI y el componente de secuenciación. Si se da cuenta, el secuenciador tiene una “dirección” de salida única asignada a la señal dir en el módulo. Los otros enlaces son solo gestión como reloj y enlace al componente SPI.

    ¿Qué hacen los bloques?

    Hay una serie de bloques always en el resto del archivo. Estos generalmente corresponden a un bloque lógico y, cuando se combinan con las palabras clave posge o negedge, generalmente definen un circuito flip-flop.

always @(posedge CLK12M or negedge nrst) begin
	if (!nrst) begin
		divider <= 32'b0;
		divider_out <= 1'b0;
	end else begin
		if (divider != div_coef) begin
			divider <= divider + 1;
			divider_out <= 1'b0;
		end else begin
			divider <= 32'b0;
			divider_out <= 1'b1;
		end
	end
end

El primero simplemente divide el reloj porque 12 MHz es un poco más rápido. Puede ajustar la velocidad cambiando el valor de div_coef cerca de la parte superior del archivo. El segundo bloque se ocupa del direccionamiento de la ROM. Cada carácter está a 5 bytes consecutivos de la ROM. Entonces addr_lsb cuenta de 0 a 4 y luego rueda, estableciendo char_inc en 1 como una señal para pasar al siguiente carácter.

always @(posedge CLK12M or negedge nrst) begin
	if (!nrst) begin
		addr_lsb <= 3'b0;
		char_inc <= 1'b0;
	end else begin
		if (divider_out) begin
			if (addr_lsb == 3'b101) begin
				addr_lsb <= 3'b0;
				char_inc <= 1'b1;
			end else begin
				addr_lsb <= addr_lsb+1;
				char_inc <= 1'b0;
			end
		end else begin
			char_inc <= 1'b0;
		end
	end
end

Otro bloque siempre se ocupa de la dirección del letrero. Hay 16 caracteres guardados en la tabla foo. La variable pos comienza en cero y aumenta cuando se establece char_inc. Obtiene 16. Esta es una buena programación defensiva, porque puede cambiar el número 16 por otro. Sin embargo, el contador de 4 bits funcionaría de todos modos 16, así que en este caso es un poco superfluo y no me sorprendería si las herramientas optimizan esa lógica de todos modos.

always @(posedge CLK12M or negedge nrst) begin
	if (!nrst) begin
		addr <= 10'b0;
	end else begin
		if (dir) begin
			addr <= {foo[4'b1111 - pos] - 'h20, 3'b101 - addr_lsb};
		end else begin
			addr <= {foo[pos] - 'h20, addr_lsb};
		end
	end
end

La tabla foo es donde puede cambiar el mensaje. Realmente no es una matriz en el sentido más estricto. Hay solo unas pocas tareas indexadas. Eso significa que no puede cambiar el mensaje en este momento sin reconstruir la FPGA, pero lo arreglaremos en la próxima entrega. Sin embargo, el verdadero corazón de todo es el siguiente bloque siempre. Forma una dirección donde los bits superiores son el carácter actual menos 20 hexadecimales. Esta resta corta los signos no imprimibles. Los bits inferiores son los 3 bits que cuentan de 0 a 4. Esto significa que el primer lugar en la ROM es el espacio y ocupa las primeras 5 palabras. Luego, el resto son los caracteres ASCII en orden, cada uno con sus propias 5 palabras.

Sin embargo, la dirección tiene una propiedad extraña. Si el acelerómetro establece el bit de directorio, el signo que da los bits superiores es el final de la resta “invertido” restando el índice en foo de 1111 binario. Los bits inferiores también se invierten restándolos de 5. Esto provoca el índice foo 15, 14, 13 … en lugar de 0, 1, 2 … y también hace que el recuento de líneas se invierta.

Entonces, si dir es 0, el mensaje se reproduce de izquierda a derecha y si dir es 1, se reproduce al revés. El resto del archivo es simple. El código crea la ROM y asigna sus salidas a los distintos LED.

Y el resto …

Te dejaré explorar los archivos spi_master.v y sequencer.v por su cuenta. Sin embargo, señalaré que el secuenciador es un buen ejemplo de máquina de estados. Hay 11 estados y el circuito se mueve de uno a otro para enviar y recibir los datos que necesita del acelerómetro. Entonces, por ejemplo, aquí está el código para los primeros tres estados:


case (state)

// 1. Read WHO_AM_I register (Addr 0x0F)
STATE_Whoami: begin
state <= STATE_Whoami_Wait;

spi_request <= 1'b1;
spi_nbits <= 6'd15;
spi_mosi_data <= 31'b10001111_00000000;
end

STATE_Whoami_Wait: begin
if (spi_ready) begin
state <= STATE_Init;
led_out <= spi_miso_data[7:0];
end
spi_request <= 1'b0;
end

// 2. Write ODR in CTRL_REG1 (Addr 0x20)
STATE_Init: begin
state <= STATE_Init_Wait;

spi_request <= 1'b1;
spi_nbits <= 6'd15;
spi_mosi_data <= 31'b00100000_01110111;
end

Tenga en cuenta que led_out es para depurar y, en el código final, esa salida no está relacionada con nada. La estructura general de cada estado debe realizar alguna acción y establecer el siguiente estado o esperar a que se lleve a cabo alguna acción y luego establecer el siguiente estado. Muy fácil. Por supuesto, las máquinas de estados más complejas pueden tener que decidir qué estado sigue, pero no en este caso. El trabajo real está en el estado STATE_Compare:

			// 6. Compare X_OUT of the accelerometer to know the swipe direction
			// The acceleration is maximum at the edges of the swipe, detect that
			// and change direction accordingly.
			STATE_Compare: begin
				state <= STATE_Read;
				
				if (saved_acc < -8'Sb0010_0000) begin
					led_out <= 8'b1110_0000;
					direction <= 1'b0; end else if (saved_acc >  8'Sb0010_0000) begin
					led_out <= 8'b0000_0111;
					direction <= 1'b1;
				end else begin
					led_out <= 8'b0001_1000;
				end
			end
		endcase

No olvide que led_out no se usa en el proyecto real, fue solo para depurar. Cuando la señal de aceleración cambia más allá de un cinturón muerto, el bit directo cambia. Sencillo.

Configuración

Sabes que quieres cambiar el mensaje para que diga algo más, así que sigue adelante y modifica el código donde está foo. Al hacer doble clic en la tarea del proyecto de compilación se generará un archivo SOF y POF. El archivo SOF enviará la configuración a la placa pero no la guardará. Si reinicia o inicia, perderá esa configuración en el tablero. Debe programar el archivo POF para que la placa recargue obedientemente la configuración al inicio.

Si hace doble clic en la entrada Dispositivo de programa en la lista de tareas, obtendrá una ventana separada para el programador. Puede seguir las instrucciones de la guía del usuario del MAX1000 para obtener los detalles exactos, pero la idea es asociar el archivo SOF o POF con el FPGA en la cadena JTAG. Si ve el dispositivo en el programador, está bien, pero si no, siempre puede Detectar automáticamente. Solo asegúrese de tener el hardware configurado para Arrow USB Blaster y el modo configurado en JTAG. Es posible que también necesite controladores para su diseño particular, así que consulte la guía del usuario.

La única parte difícil es que cuando programa un archivo POF, debe asegurarse de que la casilla de verificación de Configuración del programa esté marcada. Luego presione Inicio y estará en camino.

Envoltura

Aprender FPGA puede dar miedo. En última instancia, necesita aprender un programa complejo, y necesita aprender Verilog (o VHDL) y acostumbrarse a una nueva mentalidad de resolución de problemas. Además de eso, están las cosas habituales que necesita aprender sobre cómo se conectan los dispositivos y cómo descargar un “programa” en la placa. Pero jugar con ejemplos familiares como este es una excelente manera de tener una idea intuitiva de cómo funciona todo.

Con tanto que aprender, el [vpecanins] un tutorial puede no ser su primer paso. Pero no sería un mal segundo paso. Puede consultar nuestro campamento básico FPGA si desea una introducción más fluida. Los primeros 3 campos de entrenamiento son independientes del hardware, por lo que lo que aprenda se aplicará al MAX1000. Intel tiene mucha capacitación disponible para aprender sobre Quartus. De hecho, hay tanta formación que a veces es difícil saber por dónde empezar.

La próxima vez, le mostraré cómo agregar UART al proyecto para que pueda cambiar la pantalla inmediatamente mientras está en el puerto USB. Suena difícil, pero usaré algunos trucos para hacerlo relativamente fácil. Si desea probar algo fácil, considere cambiar el código para usar los LED como un gráfico de barras para mostrar la aceleración que lee.

  • agdijo dice:

    Aquí en Polonia necesitas permiso del gobierno para poseer y usar FPGA, ya que se consideran “partes importantes de un arma”. Supongo que me quedaré en AVR de 8 bits 🙁

    • Vadear dice:

      ¿Puede vincular a información sobre la ley en cuestión? No puedo encontrar una mención de esto en Google.

    • jpa dice:

      tme.eu (que tiene su sede en Polonia) parece bastante feliz de vender FPGA sin ningún permiso solicitado.

    • Jr4om3d dice:

      Compré programas FPGA en un minorista polaco (Kamami). No podría decirte si los enviaron desde Polonia o solo se aplica a los polacos, pero creo que deberías comprobarlo.

  • Atle dice:

    “La instalación completa de Intel FPGA Complete Design Suite v18.0 requiere aproximadamente 14 GB”

    Cómo es eso posible ?!
    Es bueno notar que Intel no se ha olvidado de Linux.
    También verifique el uso de RAM, estoy impresionado con este bloatware.

    https://www.intel.com/content/www/us/en/programmable/support/support-resources/support-centers/licensing.html
    Muchas herramientas de software Intel® FPGA y software de propiedad intelectual (IP) requieren un archivo de licencia para funcionar. (…) En su archivo de licencia, verá dos fechas: la duración de un límite de mantenimiento y la fecha de vencimiento de una licencia. La fecha de vencimiento de la licencia rige la cantidad de tiempo que se puede utilizar un producto. La licencia deja de operar cuando expira. “

    Sí, la licencia® es un problema grave que debe ser atendido, con mucho cuidado, fácil de quemar®.
    No es de extrañar por qué faltan los documentos®, las personas que hacen bricolaje parecen tener otras opciones.

  • Carl Smith dice:

    Cuando leo un código como ese en lugar de aprender algo, simplemente me enojo con las personas que escriben código con líneas como “el final comienza de otra manera”.

  • js dice:

    Parece que wd5gnr.com no se ha actualizado desde hace tiempo.

    • Al Williams dice:

      No, no tiene …

  • Nathan McCorkle dice:

    Qué “Dispositivos” necesita instalar con Quartus Lite (en la página de descarga me pregunta) … las opciones son: Arria, Cyclone, Stratix … ninguno de ellos aparece como palabras clave en la hoja de datos MAX10

    • Nathan McCorkle dice:

      Recuerde, de alguna manera volví a hacer clic en los menús desplegables y vi MAX10 en la lista de dispositivos.

      Escribí esta pequeña herramienta para descartar el archivo font5x7.hex e imprimir los caracteres en una pantalla:
      https://gist.github.com/nmz787/6a9681d93fd67e4b58ffb5caab257b82

      • Nathan McCorkle dice:

        Bueno, la descripción del enlace que vinculé ciertamente no se esperaba, ¡perdón por la larga salida!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *