Proyectos básicos en Icestudio

812 views
Skip to first unread message

Lorea Aldabaldetreku

unread,
Jan 21, 2017, 4:41:16 AM1/21/17
to FPGAwars: explorando el lado libre
Hola,
he subido a Github los archivos de los proyectos en Icestudio. Mi propósito es desarrollar proyectos básicos para trabajar con alumnos de secundaria la electrónica digital y github se me presenta como la plataforma ideal para tener actualizados los trabajos. Sería estupendo intercambiar ideas con otros profes de secundaria:) Un saludo,
Lorea

Diego Fernandez Gonzalez

unread,
Jan 21, 2017, 4:56:49 AM1/21/17
to FPGAwars: explorando el lado libre
Muy buen proyecto, ya me habría gustado aprender electrónica digital de una forma tan gráfica y con una FPGA en la mano.

Un saludo y mucho ánimo...

Juan Gonzalez Gomez

unread,
Jan 21, 2017, 5:08:12 AM1/21/17
to FPGA-WARS: explorando el lado libre
Eso es estupendo Lorea!!! Gracias por compartir  :-)

Yo también voy a empezar a hacer circuitos muy sencillos y tutoriales para que los chavales puedan aprender electrónica digital. Os iré informando de todos los avances para crear contenidos entre todos

Estoy usando la versión 0.3-beta2,, que acaba de liberar Jesús y que entre otras cosas alucinantes incluye la posibilidad de crearte tus propias colecciones de componentes. Yo estoy haciendo componentes muy muy simplificados

Saludos, Obijuan

El 21 de enero de 2017, 10:56, Diego Fernandez Gonzalez <diego...@gmail.com> escribió:
Muy buen proyecto, ya me habría gustado aprender electrónica digital de una forma tan gráfica y con una FPGA en la mano.

Un saludo y mucho ánimo...

--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/98290788-f76a-46b2-8874-913642972905%40googlegroups.com.

Para acceder a más opciones, visita https://groups.google.com/d/optout.

Jose Antonio Vacas Martinez

unread,
Jan 21, 2017, 3:27:03 PM1/21/17
to FPGAwars: explorando el lado libre
Muchas gracias por compartir Lorea

Julián Caro Linares

unread,
Jan 21, 2017, 4:04:18 PM1/21/17
to FPGAwars: explorando el lado libre
Que idea tan estupenda.

¡Nos tienes que mantener informado de cómo se desarrolla!

¡Muchas gracias por compatir :)!


El sábado, 21 de enero de 2017, 10:41:16 (UTC+1), Lorea Aldabaldetreku escribió:

tecnologiap...@gmail.com

unread,
Feb 14, 2017, 12:36:10 PM2/14/17
to FPGAwars: explorando el lado libre
Hola, es muy interesante esta plataforma para estudiar electrónica digital con los alumnos de secundaria y bachillerato. En cuanto tenga mi placa (me he apuntado a la próxima tirada) empezaré a aprender un poco y a poner en práctica alguno de los ejemplos que tienes en el github con mis alumnos y a explorar las posibilidades que esto ofrece.
Gracias por compartir.
Saludos.


El sábado, 21 de enero de 2017, 10:41:16 (UTC+1), Lorea Aldabaldetreku escribió:

Jose Pico

unread,
Mar 8, 2017, 4:45:05 PM3/8/17
to FPGAwars: explorando el lado libre


El sábado, 21 de enero de 2017, 10:41:16 (UTC+1), Lorea Aldabaldetreku escribió:
Hola:

Es fantástico!
Yo no he podido esperar y me he comprado una Ice40-HX8k y  una IceStick para empezar a probar cosas.
Soy un estudiante frustado que siempre ha visto una falta de práctica en la educación enorme, pienso que toda la ciencia se debería de dar de forma práctica  ( lo que se hace se aprende ) .
Este mundo nos permite infinidad de cosas.
Estaré atento a todos vuestros moviemientos y en cuanto tenga conocimiento para aportar, lo haré!

Mi idea es poder por ejemplo, crear módulos que se usan en simulink de matlab para pasarlos a una módulos en icestudio de forma que se puedan implementar físicamente en fpgas.
Por otra parte me gustaría también poder, usando una herramienta llamada Xfuzzy desarrollada por la universidad de Sevilla implementar sistemas de lógica difusa, inteligencia artificial en estas placas fpgas libres.

Saludos y Gracias a todos








 

Juan Gonzalez Gomez

unread,
Mar 9, 2017, 12:16:58 AM3/9/17
to FPGA-WARS: explorando el lado libre
Hola Jose!

¡Estupendo!  :-)  Esas son unas aportaciones muy buenas!  Muchas gracias

Saludos, Obijuan

--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.

Lorea Aldabaldetreku

unread,
Mar 12, 2017, 1:45:45 PM3/12/17
to FPGAwars: explorando el lado libre

Hola,

he estado trabajando con el display de 4 dígitos para diseñar un cronómetro. Me interesa mucho este tema porque es una aplicación que se puede usar en muchos proyectos en combinación con otros circuitos. Querría trabajar esta función con los chavales de bachiller (ya el curso que viene). Mi pregunta o consulta va al final.

El circuito debe funcionar de la siguiente manera:
  • comienza con las décimas de segundo (1. dígito), segundos (2. dígito, y 3. dígito),  minutos 4. dígito
  • La función RESET (sw1 de la placa) pone a 0 el cronómetro
  • La función PAUSE (sw2): al apretar una sola vez el cronómetro se para (pero internamente sigue contando) al volver a apretar otra vez reanuda  el cronómetro.
El funcionamiento se ve en el Vídeo.
La imagen del archivo es:

El bloque de los contadores de 4 bits  (1., 2. y 3. bloque) tiene este código:

// 4 bit counter 
// reset eta pause funtzioak
//dos contadores, coun y counpause. coun para cuando pause no está activado y counpause para cuando pause  está activado
//hasi para inicializar el dígito siguiente (superior o de mayor peso)
reg coun = 0;                                         
reg counpause = 0;
reg hasi = 0;

always @(posedge clk) begin
    if (rst==0) begin
     coun<= 0;
     counpause <= 0;
     hasi <= 1;
   end
   if ((pause==0) && (coun == MAX)) begin
     coun <= 0;
     counpause <= 0;
     hasi <= 1;
   end
   else if ((pause==0) && (rst ==1)) begin
     coun <= coun+1;
     counpause <= coun+1;
     hasi <= 0;
   end
    if ((pause==1) && (coun == MAX)) begin
     coun <= 0;
     counpause <= counpause;
     hasi <= 1;
   end
   else if ((pause==1) && (rst ==1)) begin
     coun <= coun+1;
     counpause <= counpause;
     hasi <= 0;
   end
  end
 
 assign has = hasi;

el bloque de los selectores tiene este código: (selecciona el contador que se visualizará en el display)

// si se activa reset se visualiza el contador "coun (c)"
// Si la función pause está activada se visualiza el contador "counpause (cp)" sino el contador "coun (c)"

reg [3:0] bal;

always @(posedge clk) begin
 if (rst ==0) 
 bal = c;
 else if (pause ==0) 
        bal = c;
 else if (pause ==1)
      bal = cp;
    
end

assign {z3, z2, z1, z0} = bal;

El circuito funciona, pero me parece complicado y enrevesado. Es hasta donde he llegado. Mi cabeza y mis conocimientos de electrónica no dan más de sí. Me basé en un circuito que diseñó Demócrito con la ICEstick, muchas gracias Demócrito -:).  

Ahora, mis preguntas y dudas son las siguientes: 

¿cómo puedo simplificar ambos bloques? ¿es posible conseguir en un solo bloque las dos funciones, contadores y selectores? (yo no lo he conseguido, no sé cómo) O quizás a alguien se le ocurre otro camino, otro diseño diferente, más simple y limpio.

Y otra duda es la de las conexiones: he usado resistencias de 1K. El circuito funciona, en los arduino las conexiones son así, pero ya sé que en la Icezum la cosa cambia. ¿es correcto o adecuado el valor de las R, 1K? el display es un KYX-5461AS


Bueno, a ver si alguien me ayuda a mejorar. Muchas gracias y un saludo -:)
adjunto archivo del circuito



Kronometroa.ice

una...@gmail.com

unread,
Mar 12, 2017, 3:06:22 PM3/12/17
to FPGAwars: explorando el lado libre
Ahora mismo no puedo extenderme, pero te dejo la siguiente idea: separa cada contador en dos procesos, y el resto que sean sentencias concurrentes. En VHDL sería:

process(CLK) begin if rising_edge(CLK) then
  if RST then
    cnt <= 60;
  else
    cnt <= cnt_next;
  end if;
end if; end process;  end if;

cnt_next <= 60 when cnt=0 else cnt+1;

process(CLK) begin rising_edge(CLK) then
  if RST then
    cntreg <= 0;
  elsif EN then
    cntreg <= cnt;
  end if;
end if; end process;

Por un lado generas el contador, al que sólo le afecta el RST, el pause le da igual. Fíjate, que cuento de 60 hacia abajo, en lugar de contar hacia arriba. En hardware (y en software también, pero se nota menos), comparar números con cero es mucho más eficiente que compararlos sin 'baldintzas'. Comparar con cero es sólo mirar sí hay algún bit a uno (una OR de toda la palabra).

Por otro lado, mientras esté pulsado PAUSE, la señal EN estará activa, y la salida tomará el valor del contador. ¿Quieres que sólo detecte el flanco ascendente o te vale así?

Por último, puedes unir los dos grupos de dieciséis señales a la salida, y usar un único multiplexor. No sé si Icestudio permite concatenar señales.

Un saludo

una...@gmail.com

unread,
Mar 13, 2017, 1:00:54 AM3/13/17
to FPGAwars: explorando el lado libre
Kaixo,

Con un poco más de tiempo. El ejemplo que has escogido es muy bueno, porque permite ver toda la complejidad del diseño de circuitos síncronos con FPGAs, sin ser demasiado pequeño y que parezca muy fácil, ni excesivamente complejo. Bueno, sobre esto último igual cambiamos de opinión. Depende de cómo lo gestiones, tienes para medio cuatri con este circuito ;).
  • En los circuitos eléctricos las señales tienen que 'viajar' por lo cables, por lo que dos electrones que partan del mismo punto llegan a destiempo al final del circuito si han tomado diferentes cambinos. Hay dos formas de lidiar con ello:
    • Sistemás asíncronos: durante el diseño se deben tener en cuenta tanto la funcionalidad como los retardos. Estos últimos hay que aprovecharlos en nuestro beneficio, o impedir que estropeen el funcionamiento. Cada tipo de componente tiene un retardo diferente, que puede cambiar con la temperatura, la tensión, si el bit sube o baja... Lo más parecido al infierno para la mayoría de mortales.
    • Por eso trabajamos con sistemas síncronos: introducimos 'fronteras' entre diferentes partes del sistema con unos componentes llamados registros. Estos impiden que las señales avancen, salvo cuando se lo indica una señal especial llamada 'reloj'.  De esta forma, nos da igual que las señales necesiten más o menos tiempo para llegar de un registro a otro, siempre que lo hagan antes del siguiente 'tick' del reloj.
LECCIÓN 1: el reloj es SA-GRA-DO

Lo cual quiere decir que nunca, nunca, nunca, absolutamente bajo ningún concepto se puede manipular. Es una señal que viene de fuera de la FPGA, entra, y se conecta directamente a todos los registros del sistema (en paralelo). Si se hace así, después de la síntetis, al hacer el place and route, se utilizarán unas pistas especiales dentro de la FPGA para garantizar que cada tick del reloj llega exactamente al mismo tiempo a todos los registros que lo necesiten.

Esto es necesario porque, como he comentado antes, los electrones tienen que moverse por los cables, y no todas las esquinas de la FPGA son igual de accesibles. Lo ideal es que todas las pistas fueran ultrarrapidas. Pero como no se puede, es importante aprovecharlas para relojes y resets globales.

COLLEJA

¿Por qué digo esto? Porque has metido el reloj en el primero contador, pero no en ninguno de los otros. En su lugar, creas señales lógicas que no serán tratadas como relojes. El reloj de fuera, sólo va al primero.
  • Icestorm no se queja porque es una herramienta experimental y básica, pero cualquier sintetizador comercial te freiría a warnings por 'mancillar' el reloj.
  • Estás trabajando con frecuencias de reloj muy bajas, por lo que no se aprecia que las señales están llegando cuando no deberían. Si mantienes esta forma de diseño con más de 50MHz, empezarán a pasar cosas raras y no entenderás por qué.
  • Motivo de suspenso directo. Si alguien te lo hubiera explicado antes, claro ;).
EL PORQUÉ

Has hecho lo más 'natural' por la costumbre del software. Has 'llamado a la función contador' sólo cuando tenías que incrementarlo. Pero... estamos diseñando hardware, y esto no funciona así:
  • No hay una seríe de funciones en memoria a las que tú llamas para que se ejecuten.
    • Podrías imitarlo, pero tendrías que usar un solo sumador y compartirlo para llevar las cuatro cuentas. Más adelante profundizamos.
  • Lo que has descrito son cuatro contadores: hay físicamente cuatro registros y cuatro sumadores.
    • En realidad hay ocho registros y ocho sumadores/incrementadores (usas dos '+' en cada contador). Más adelante optimizamos eso.
Por lo tanto, desde que arranca la FPGA y hasta que se apaga, las cuatro 'funciones' se ejecutan automáticamente una vez cada ciclo de reloj. Aunque no quieras, el reloj va a llegar, y los registros se van a actualizar. Así, tú lo único que puedes hacer es decidir en cada ciclo si no quieres que hagan nada, o si les toca hacer algo.

LA SOLUCIÓN

Utilizar señales de habilitación
. Los flip-flops (registros) de las FPGAs tienen, al menos cinco señales:
  • CLK: reloj
  • RST: reset
  • EN: enable
  • D: entrada
  • Q: salida

always @(posedge clk) begin
  if (rst==0) begin

     q <= 0;
  elsif en then
     q <= d;
  else
     q <= q;
  end
end


Puede que la sintaxis no sea correcta, pero espero que se entienda. Nótese que en el 'if' he declarado todos las posibles combinaciones, incluido 'q <= q' que puede parecer redundante. No sé cómo será en Verilog, pero en VHDL el estándar exige hacerlo así para síntesis. De otra forma, corremos el riesgo de que se sintetice un 'latch' en lugar de un 'flip-flop'.

La funcionalidad de EN resulta evidente después de las explicaciones anteriores: un módulo sólo actualizará su salida cuando haya un flanco ascendente de reloj y, además, la señal 'enable' habilite la operación.

Como verás, el único cambio que tienes que hacer en el circuito es añadir esta señal EN, conectar a este puerto lo que ahora tienes a los relojes (hasi). Después, conectar el reloj a todos los puertos de reloj.

EXCEPCIÓN

Lo que has hecho se utiliza en casos muy concretos como técnica 'avanzada' de ahorro de energía:  si 'matas' la señal de reloj de un módulo con una operación lógica, ese módulo no tiene consumo dinámico. Pero claro, tampoco sabes exactamente qué va a pasar con el contenido de todas las LUTs y registros. No debería cambiar, pero cualquier ruido, radiación, etc. puede hacer que 'bailen' algunos bits y cuando vuelvas a alimentarlo el contenido no sea el esperado.


Unai Martinez

unread,
Mar 13, 2017, 1:08:52 AM3/13/17
to FPGA-WARS: explorando el lado libre
LECCIÓN 2

Si no eres capaz de dibujar con papel y boli el circuito resultante del código que estás escribiendo, no le des a programar. Las FPGAs se queman. No sólo porque las conectes mál, como los Arduinos. Especialmente porque si el resultado de la síntesis no coincide con el de la simulación tu circuito va a hacer algo totalmente diferente a lo que esperas, y no lo sabes hasta que no es tarde.

Todo se puede hacer con registros, multiplexores, sumadores/multiplicadores, registros/memorias y puertas lógicas. Si no puedes, coge otra tarea/circuito más sencilla. Entiéndela, asegúrate de saber qué valor debe tener cada señal relevante en cada momento. Acostúmbrate a despreciar las señales que no son relevantes en un periodo concreto. Métete en el circuito. Estoy siendo muy incisivo. Pero realmente es vital.

En este caso en concreto, sabes perfectamente qué señales quieres generar y cómo quieres hacerlo. No hay que cambiar de circuito. Supongo que has partido de un contador sin pause y has querido añadirle el pause. Como no has cogido papel y lapiz para dibujar, a ojo te ha parecido que lo podías hacer utilizando los mismos módulos. Pero esa es la opción más ineficiente. Es funcional, pero consumo entre dos y ocho veces más recursos de los necesarios. Como esto ya está quedando largo, voy a ignorar aquí los dos bloques de entrada y todo lo que tiene que ver con los displays y la secuenciación de los diodos. Nos centramos sólo en los contadores y la multiplexación:

Puede que me haya dejado algo, pero esta es la representación RTL de tu módulo "contador":

Imágenes integradas 1


A pesar de que no está muy bien dibujado, se observan varias cuestiones:

  • El número de puertos de los registros coun y counpause es cinco.
  • No sabemos decir exactamente qué, pero hay puertas lógicas que sobran.
  • Hay dos contadores, pero por la descripción de la aplicación sólo llevas una cuenta. Por lo que uno de los dos sólo repite información. Sin embargo, estamos usando recursos como si ambos fueran útles.
  • El registro 'hasi' no tiene realimentación, porque la señal EN pone la salida a 1 y RST a cero.
  • Al tratar de dibujarlo te habrías tirado de los pelos comprobando que realmente cada situación del código está representada en el diagrama. (Yo tampoco lo he hecho exhaustivamente

Tomando la idea del mensaje de ayer, vamos a replantearlo. El objetivo es dibujarlo lo más sencillo posible, pero completo. Cuanto más simple sea el dibujo, más fácil será describirlo después:

Imágenes integradas 2

  • counpause ya no es un contador, sino un simple registro que copia el valor de count mientras pause=1. Si no, mantiene el último valor.
  • rst y pause no están negadas. Si hay que hacerlo, mejor hacerlo fuera del 'contador' una sola vez, en lugar de inferir dos puertas not en cada instancia del módulo.
  • hasi ya no es un registro, es sólo el resultado del comparador. A esta salida se le suele llamar 'terminal count'. Tal como aparece ahí, está activo mientras el contador no cambie su valor, no un solo ciclo de reloj.
Como he comentado antes, es más eficiente comparar con cero. Para eso el valor de reset del registro tiene que ser MAX, e incluir un decrementador (restador) en vez del incrementador (sumador). Esto te lo dejo como ejercicio ;).

Pasemos a cómo encadenar los contadores con un reloj común y esta nueva descripción:

Imágenes integradas 3
  • El pause está negado a la puerta de los contadores y no lo está en el multiplexor. Puede que no deba estarlo para ninguno, o que deba estarlo sólo para el multiplexor y no para los contadores. Depende de cómo decidas dejar al final las señales. Intercambiar las conexiones en un multiplexor es como negar su entrada de selección.
  • He añadido una puerta 'and' para que el las señales 'hasi0', 'hasi1' y 'hasi2', que están activas durante varios ciclos de reloj, no vuelvan locos a los contadores 1, 2 y 3, respectivamente.
    • Esta puerta se podría haber incluido en el diagrama anterior, es decir, dentro de cada contador. Al ponerlas fuera nos ahorramos la última (a la salida de contador 3), pero es una diferencia insignificante.

Si comparas este último diseño con el esquemático de un registro de desplazamiento (https://en.wikipedia.org/wiki/File:4-Bit_SIPO_Shift_Register.png), observarás que diseñar circuitos digitales síncronos es hacer continuamente shift-registers, con la particularidad de que entre uno y otro se hace alguna operación, no sólo retener un dato. A eso se le llama 'pipeline'. No es muy diferente de la cadena de producción en cualquier nave industrial. Hay diferentes puestos, y la cinta transportadora va llevando los datos de uno a otro.

PARA NOTA

Con los cambios que hemos visto, podemos imaginar otras soluciones aún más eficientes. Por ejemplo:

  • Se puede añadir un registro entre MUX 32:16 y MUX 16:4. Sería un registro de 16 bits, por lo que en la práctica es quitar los registros 'counpause'  de dentro de los contadores y dejarlo sólo ahí.
    • La idea es la misma: los contadores generan una única cuenta, y el registro de 16 bits está continuamente actualizándose. Cuando cambiamos la posición de 'pause' el registro deja de actualizarse, por lo que el display se congela. El contador no se entera de nada y sigue generando salidas como si estuvieramos haciendo caso.
    • En este diagrama, además he incluido las puertas and dentro de los contadores.
Imágenes integradas 4
  • Como el reloj de la FPGA es millones de veces más rápido que lo que estás contando, puedes hacer millones de sumas antes de necesitar una sola. En otras palabras, puedes hacer que tu reloj vaya cuatro veces más rápido que las milésimas de segundo que quieres contar. Así, en lugar de utilizar cuatro sumadores, puedes utilizar cuatro registros, un multiplexor, un solo sumador y un solo comparador. A cambio necesitas un contador de dos bits, que es bastante más barato.
    • Si vais a utilizar este componente cómo módulo en otros sistemas, creo que esta es la solución que menos área requiere.
    • He coloreado algunos grupos de señales. Las rojas y moradas son las encargadas de habilitar cada uno de los registros cuando toca. No he hecho un análisis exhaustivo, por lo que es muy probable que haya que retocar algo.
Imágenes integradas 5
  • La última vuelta de tuerca es utilizar un solo registro de 6 bits para almacenar los segundos. Siguiendo la lógica de acelerar el reloj, puedes hacer que vaya 6 veces más rápido que el de los contadores e implementar este algoritmo: http://www.eng.utah.edu/~nmcdonal/Tutorials/BCDTutorial/BCDConversion.html
    • Para este caso en particular, esta solución será menos eficiente. Pero si en un futuro quieres contar módulos mayores que 60, sería interesante analizar qué ocupan más: n contadores BCD o un contador binario + conversor iterativo.
TONTERÍAS

  • Los procesos en los bloques de las dos entradas son sensibles al único puerto de entrada, ya que no hay reloj. Por lo tanto, puedes sustituir todo el código por una puerta NOT: <assign c = ~ a;>
    • Los interruptores y pulsadores mecánicos suelen tener rebotes en la señal cuando se accionan. Estos suelen durar entre 10-40ms. Tal como lo tienes ahora es posible que cuando pulsas el reset una vez, se active una docena de veces seguidas. Lo mismo con pause. Aunque esté sucediendo, no lo notas, porque es muy rápido y tu circuito se comporta igual.
    • Creo que la Alhambra tiene filtros en los pulsadores para evitarlo. En cuyo caso estarás más o menos segura.
    • En cualquier caso es interesante introducir un pequeño circuito de debounce. El más sencillo que conozco es un registro de desplazamiento de 4 bits con un enable de 10ms. Si cualquiera de ellos es uno, la salida es uno.
  • No he mirado los divisores de frecuencia (maiztasun zatitzaileak). Es de aplicación aquello de que 'el reloj es sagrado'. Por lo tanto, la salida de estos bloques debería ser una o varias señales EN, pero todas dependientes del mismo reloj.
    • Alternativamente, las FPGA tienen recursos específicos para variar la frecuencia del reloj recibido por una patilla externa. Además permiten cambiar su duty-cycle y limpiar la señal. Pero creo que en las Lattice para esto sólo están las PLL, por lo que no creo que las estés utilizando.

Y, al fin, esto es todo. Como ves, lo de que las FPGAs ofrecen infinitas posibilidades en comparación con un Arduino empieza a ser literalmente cierto. ¡Y eso que este circuito parecía fácil!

Espero que te resulte útil. No dudes en preguntar si te queda alguna duda.

Ondo izan

--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.

Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.

Lorea Aldabaldetreku

unread,
Mar 13, 2017, 3:58:36 AM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Kaixo Unai,

mila esker azalpenengatik. Ya intuía que me circuito no era nada limpio (más programación que diseño digital), pero no pensaba que estuviera tan desastroso, suspenso merecido por tanto:). Lo pondré como ejemplo de lo que no se debe hacer. 

Ahora toca volver a empezar. Está claro que le tengo que dar unas cuentas vueltas. Iré paso a paso: lo primero habilitaré el reloj para los registros y el enable.
Iré probando y ya os consultaré. Eskerrik asko, un saludo

Lorea

una...@gmail.com

unread,
Mar 13, 2017, 2:53:09 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Aupa Lorea,

Ez dago zergatik. Tampoco te martirices, que no es 'tan desastroso'. Es simplemente el riesgo de utilizar lenguajes que te permiten describir tanto hardware como software. Tú código es perfectamente válido para simulaciones, ya que es funcionalmente correcto. Lo del 'suspenso' es para que le des mucha importancia cuando se lo expongas al alumnado. Este hilo puede resultarte útil para tener un contexto más amplio del porqué:

Por otro lado, tengo la sensación de que sólo has recibido un tercio :S. Tuve problemas al enviarlo, creo que por las imágenes. Dividí el mensaje en varios correos, pero por lo visto en el grupo sólo se ve el primero. Te he reenviado el resto a ti solo, a ver si llega. Mientras tanto, voy a  intentar ir poniéndolo aquí por trozos. Espero que no te importe recibirlo por duplicado. Creo que es un contenido interesante para que esté público.

Cuando lo recibas, verás que he propuesto media docena de versiones diferentes. Evidentemente, sólo tienes que implementar una. Pero me parece importante que las 'veas' todas y después pilles la que más te guste. A mayores, si les explicas una versión cada día/semana, y vais implementándolas en clase y observando las diferencias del resultado de síntesis... ahí tienes el medio cuatrimeste ;).

Un saludo

una...@gmail.com

unread,
Mar 13, 2017, 2:53:48 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com

una...@gmail.com

unread,
Mar 13, 2017, 2:54:57 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com

una...@gmail.com

unread,
Mar 13, 2017, 2:57:20 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com

Tomando la idea del mensaje de ayer, vamos a replantearlo. El objetivo es dibujarlo lo más sencillo posible, pero completo. Cuanto más simple sea el dibujo, más fácil será describirlo después:

Auto Generated Inline Image 1

una...@gmail.com

unread,
Mar 13, 2017, 2:58:36 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Pasemos a cómo encadenar los contadores con un reloj común y esta nueva descripción:
Auto Generated Inline Image 1

una...@gmail.com

unread,
Mar 13, 2017, 3:00:01 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com

PARA NOTA

Con los cambios que hemos visto, podemos imaginar otras soluciones aún más eficientes. Por ejemplo:

  • Se puede añadir un registro entre MUX 32:16 y MUX 16:4. Sería un registro de 16 bits, por lo que en la práctica es quitar los registros 'counpause'  de dentro de los contadores y dejarlo sólo ahí.
    • La idea es la misma: los contadores generan una única cuenta, y el registro de 16 bits está continuamente actualizándose. Cuando cambiamos la posición de 'pause' el registro deja de actualizarse, por lo que el display se congela. El contador no se entera de nada y sigue generando salidas como si estuvieramos haciendo caso.
    • En este diagrama, además he incluido las puertas and dentro de los contadores.

Auto Generated Inline Image 1

una...@gmail.com

unread,
Mar 13, 2017, 3:01:38 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
  • Como el reloj de la FPGA es millones de veces más rápido que lo que estás contando, puedes hacer millones de sumas antes de necesitar una sola. En otras palabras, puedes hacer que tu reloj vaya cuatro veces más rápido que las milésimas de segundo que quieres contar. Así, en lugar de utilizar cuatro sumadores, puedes utilizar cuatro registros, un multiplexor, un solo sumador y un solo comparador. A cambio necesitas un contador de dos bits, que es bastante más barato.
    • Si vais a utilizar este componente cómo módulo en otros sistemas, creo que esta es la solución que menos área requiere.
    • He coloreado algunos grupos de señales. Las rojas y moradas son las encargadas de habilitar cada uno de los registros cuando toca. No he hecho un análisis exhaustivo, por lo que es muy probable que haya que retocar algo.

Auto Generated Inline Image 1

una...@gmail.com

unread,
Mar 13, 2017, 3:03:26 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
TONTERÍAS
  • Los procesos en los bloques de las dos entradas son sensibles al único puerto de entrada, ya que no hay reloj. Por lo tanto, puedes sustituir todo el código por una puerta NOT: <assign c = ~ a;>
    • Los interruptores y pulsadores mecánicos suelen tener rebotes en la señal cuando se accionan. Estos suelen durar entre 10-40ms. Tal como lo tienes ahora es posible que cuando pulsas el reset una vez, se active una docena de veces seguidas. Lo mismo con pause. Aunque esté sucediendo, no lo notas, porque es muy rápido y tu circuito se comporta igual.
    • Creo que la Alhambra tiene filtros en los pulsadores para evitarlo. En cuyo caso estarás más o menos segura.
    • En cualquier caso es interesante introducir un pequeño circuito de debounce. El más sencillo que conozco es un registro de desplazamiento de 4 bits con un enable de 10ms. Si cualquiera de ellos es uno, la salida es uno.
  • No he mirado los divisores de frecuencia (maiztasun zatitzaileak). Es de aplicación aquello de que 'el reloj es sagrado'. Por lo tanto, la salida de estos bloques debería ser una o varias señales EN, pero todas dependientes del mismo reloj.
    • Alternativamente, las FPGA tienen recursos específicos para variar la frecuencia del reloj recibido por una patilla externa. Además permiten cambiar su duty-cycle y limpiar la señal. Pero creo que en las Lattice para esto sólo están las PLL, por lo que no creo que las estés utilizando.

Y, al fin, esto es todo. Como ves, lo de que las FPGAs ofrecen infinitas posibilidades en comparación con un Arduino empieza a ser literalmente cierto. ¡Y eso que este circuito parecía fácil!

Espero que te resulte útil. No dudes en preguntar si te queda alguna duda.

Ondo izan

PD: Creo que, ahora sí, se han enviado todas las imágenes bien, excepto la primera de todas: la que corresponde a tu código actual. La adjunto en este último mensaje.

Auto Generated Inline Image 1

una...@gmail.com

unread,
Mar 13, 2017, 3:19:03 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
MATRÍCULA DE HONOR

Ahora que he reenviado todos, me he dado cuenta de un superbonus: en el diagrama de los colores, sustuir los cuatro registros de la parte superior izquierda por un registro de desplazamiento. Así, podemos ahorrarnos el multiplexor que está a la entrada del contador. Esto simplifica muy notablemente las conexiones:

  • Dejamos de tener cuatro señales en paralo que van de cada registro a un solo módulo. En su lugar, cada señal va de un registro al siguiente, y sólo uno de los cuatro tiene que estar conectado al sumador.
  • Tampoco necesitamos las cuatro señales del deco, ya que las operaciones se realizarán siempre sobre el mismo registro (el último, o el primero).
  • Posiblemente pueda hacerse lo mismo con los cuatro bits 'hasi', pudiendo eliminar el deco por completo.
  • Se podría sustituir el contador de dos bits por otro shift-reg de 4 posiciones y un solo bit.

Y ya está. Ahora sí que lo dejo ;).

una...@gmail.com

unread,
Mar 13, 2017, 6:57:30 PM3/13/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Respondiendo aquí, me he fijado en estas dos figuras de la datasheet (hoja de características, iCE40LPHXFamilyDataSheet.pdf) de las iCE40:



donde se muestra lo 'simple' que es la architectura de esta familia, y por qué es tan adecuada para aprender.





En esta segunda imagen se entiende por qué he puesto tanto énfasis en dibujar los circuitos. Cuanto más parecida sea nuestra descripción en Verilog (o dibujo en icestudio) a este diagrama, más fácil será el trabajo del sintetizador y más posibilidades habrá de obtener el resultado deseado. No tenemos que ser capaces de imaginar cómo será cuando usemos señales de n bits, ni cómo se hacen las realimentaciones. Sólo entender que el orden es: función/operación lógica, después registro y por último multiplexación.
  • En la tabla 2-1 (página 2-2) se indican las 5 señales básicas, además del carry-in y carry-out que se utilizan para formar palabras.
  • Nótese que en los diagramas anteriores la señal de reloj es compartida por todos los CLBs en una columna.
  • En la página 2-3 se explican las líneas especiales para reloj, reset y enable.

Auto Generated Inline Image 1
Auto Generated Inline Image 2

Lorea Aldabaldetreku

unread,
Mar 14, 2017, 3:43:58 AM3/14/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Kaixo Unai,

no sé como agradecerte todo el trabajo que te has tomado. Es una clase magistral de electrónica digital. Los gráficos de la descripción de los circuitos son fantásticos para entender las relaciones entre las diferentes señales. Me has dado unos ejemplos con una visión del diseño digital nueva para mí. Desde luego me tengo que tomar un tiempo para comprender y estudiar los diseños. No sé hasta donde voy a llegar pero desde luego me pongo a ello. Mi conocimiento de la electrónica digital es muy básico y tengo todo que aprender, pero me parece un mundo fascinante. 

Bueno, pues seguro que te doy la matraca Unai.

Esan bezala, mila esker laguntzagatik. Ondo izan,

una...@gmail.com

unread,
Mar 14, 2017, 9:26:06 PM3/14/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Aupa Lorea,

Fue en DBH cuando decidí que quería estudiar electrónica (y no informática), gracias a que el profesor de tecnología me dio acceso libre al laboratorio. Sólo había resistencias, condensadores y conmutadores. Pero, con un par de lámparas y un trozo de cristal que me dio el bedel, monté una insoladora y fabriqué mi primer circuito: un LM3914 con 10 LEDs, para convertir el LED que parpadea en el ordenador en la boca de Kitt el coche fantástico! La satisfacción de diseñar el circuito, rutar la placa, imprimir, insolar, atacar, soldar y que funcione, es difícil de olvidar. Naturalmente, necesité y tuve mucha ayuda en foros (especialmente modpc.com). Por eso, sabiendo en qué contexto lo quieres aplicar, qué menos que devolver el favor al colectivo de profesores que se mojan.

En diez años ha cambiado mucho la electrónica, pero. Y hoy día es mucho más probable que acaben 'programando' FPGAs y procesadores empotrados, que diseñando placas. De hecho, creo que es interesante como introducción mencionar lo siguiente:
  • Desde hace más de veinte años las FPGA se utilizan como 'glue-logic'. Es decir, para evitar tener que hacer PCBs complicados, conectamos todo a una FPGA y ahí dentro hacemos las conexiones como queremos. De hecho, al principio sólo se usaban para eso. Nadie metía contadores, ni conversores para displays de 7 segmentos, ni nada así.
  • Por otro lado, hace diez años en los microcontroladores (PICs, ATmega, etc.), lo que ahora conocemos como Arduino, cada patilla era para una sola función. En algunos casos podía tener un par de usos, pero poco más.
Hoy en día:
  • No es raro encontrar microcontroladores en los que puedes asociar el periférico que quieras (ADC, Timer, PWM, input-capture, etc.) prácticamente a la patilla que te dé la gana. No es el caso de ningún arduino, que yo sepa. Pero sí el de varios PIC que cuestan lo mismo. ¿Cómo hacen esto? Incluyendo una mini-FPGA dentro del chip, que permite hacer glue-logic entre el núcleo y cada una de las patillas.
  • Las FPGA, a su vez, han crecido en densidad, por lo que es posible describir microcontroladores completos, además de poder conectar todo como quieras, y encima pudiendo añadir módulos hardware adicionales.
  • Ya hay empresas que venden 'esquemas de FPGAs', para que los fabricantes de chips puedan incluir mini-FPGAs en cualquier tipo de circuito.

Por lo tanto, cada vez habrá menos aislamiento entre arquitectos de sistema, diseñadores de software embebido y diseñadores de ASICs. Ya que un sólo chip incluye ahora lo que hasta hace unos pocos años era un ordenador entero. Al mismo tiempo, habrá más distancia con respecto a los diseñadores de PCBs, que serán minoría. Esto es porque las frecuencias de reloj a las que pueden trabajar estos dispositivos, las potencias que hay que gestionar y el número de patillas complican notablemente el diseño de los PCBs en sí.


Así, que las chavalas y chavales puedan 'hacer' sus propios circuitos digitales con la Alhambra o el Icestick, creo que es el mejor equivalente contemporáneo a la experiencia que yo tuve. Aunque un poco menos tangible, es suficientemente práctico con circuitos externos como el que has usado de prueba. Y, sobre todo, les enseña más del mañana que del ayer.

Animo! Bakizu nun topau.

Juanma Rico

unread,
Mar 15, 2017, 11:53:48 AM3/15/17
to FPGAwars: explorando el lado libre, una...@gmail.com
Perdón si me inmiscuyo en vuestro hilo... pero siempre es un placer leerte Unai, a veces tengo que leerte un par de veces porque tengo que procesar... :-)
pero siempre un placer... a ver para cuando un libro... :-P

Saludos

OSWALDO MERCHAN

unread,
Mar 16, 2017, 4:51:59 AM3/16/17
to FPGAwars: explorando el lado libre
Clase magistral... Quede impactado con este grupo... Muy bueno mis felicitaciones y mis mejores deseos a todos los colaboradores

Lorea Aldabaldetreku

unread,
Mar 26, 2017, 5:25:58 AM3/26/17
to FPGAwars: explorando el lado libre
Kaixo Unai,

después de una semana larga de reuniones de evaluación ya he tenido tiempo de retomar mi trabajo con el cronómetro. 

Le he dado varias vueltas al tema y me he tenido que leer una y otra vez tus apuntes. Hay conceptos que no tengo claros pero he pensado que para empezar voy a intentar diseñar el siguiente circuito:


La función Pause la he desplazado para controlar el display tal como me proponías en uno de los diseños. Me parece más lógico. Por tanto los contadores tienen solo la función reset. Ahora estoy diseñando los contadores. Ya sé que me recomendaste comparar con 0 en vez de con MAX pero prefiero abortar ese reto una vez tenga despejadas ciertas dudas.

Bien aquí empiezan mis dudas. 

Mi primer diseño para el contador sería éste: (lo que yo hubiera hecho de buenas a primeras)

Sin embargo, entendí por lo que me explicaste que debía plantear el contador de otra manera, es decir, pasando por registro y luego asignando los valores. Nunca he trabajado con registros y puede que lo que aquí plantee sea totalmente incorrecto. Me he tenido que hacer un esquema para entender el contador y claro, no sé si el diseño es correcto.





Bueno, en tal caso mi diseño sería el siguiente:


// Zenbatzailea reset funtzioarekin
// Contador con función reset

reg r_reg, r_next;

always@(posedge clk) begin
if (~rst)
   r_reg <= 0;
else 
   if (en)
     r_reg <= r_next;
   else
     r_reg <= r_reg;
end

// Hurrengo egoeraren logika
// Lógica estado futuro
// Maximora iritsi bada 0n jarri, bestela bata gehitu
// Si ha alcanzado el máximo poner a 0, sino sumar 1

always@(r_reg) begin                                     no sé si es correcto
 r_next = (r_reg == MAX)? 0 : r_reg + 1;
end

// Irteera logika
// Lógica de salida

assign counter = r_reg;
assign enout = (r_reg == MAX)? 0 : 1;

¿Es correcto el diseño? 
Por otro lado, en el cronómetro he añadido los debouncer y  biestables tipo T a los pulsadores. También he añadido los AND a la entrada de los enable. El modulo del display lo abordaré después, una vez tenga claro los contadores.

Beno ba, aldez aurretik mila esker Unai, bai zuri eta baita zure teknologia irakasle ohiari ere. :) Ondo izan,

Lorea

Juan Gonzalez Gomez

unread,
Mar 26, 2017, 6:18:47 AM3/26/17
to FPGA-WARS: explorando el lado libre
Hola Lorea,

Un contador binario, de 8 bits, con un reset síncrono, sería así

Imágenes integradas 1


Si quieres limitar la cuenta para que al llegar a un número vuelva a comenzar, sería así:

Imágenes integradas 2

En este ejemplo llega hasta 18 y luego vuelve a comenzar desde 0

Saludos, Obijuan

--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.

Juan Gonzalez Gomez

unread,
Mar 26, 2017, 6:20:42 AM3/26/17
to FPGA-WARS: explorando el lado libre
Tu primer diseño del contador, con enable, está bien. Así es como se implementan

Saludos, Obijuan

Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-lib...@googlegroups.com.

Lorea Aldabaldetreku

unread,
Mar 26, 2017, 11:02:55 AM3/26/17
to FPGAwars: explorando el lado libre
Muchas gracias Juan. Un saludo,
Lorea
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.

Unai Martinez

unread,
Mar 26, 2017, 1:26:16 PM3/26/17
to FPGA-WARS: explorando el lado libre
Aupa Lorea,
  • En el primer diagrama introduces una constante, '1', en todas las puertas AND. Al hacer eso las AND son inútiles. Si miramos la tabla de la verdad,
00 0
01 0
10 0
11 1

donde las columnas, son de izquierda a derecha: la que viene de la etapa anterior, un '1' y la salida. Fíjate que, por la constante, la tabla de la verdad real será:

01 0
11 1

Es decir, la salida tendrá el mismo valor que la señal de la etapa anterior, como si quitaras la AND y la constante. El efecto será que todos los contadores cuenten a lo loco (mucho y muy rápido), en lugar de respetar la secuenciación por décadas. Haz la prueba con un simulador para entender mejor a qué me refiero.

La solución es que, excepto en la primera, en el resto sustituyas la constante por la salida de la AND anterior. Echa un vistazo al diagrama que puse. Aunque no estaba muy claro, podrás apreciar ese detalle concreto.
  • El resto tiene muy buena pinta, y el diagrama es muy claro. Zorionak.
  • El segundo diagrama, el del contador, es impecable. Ese es el esquema de referencia para un contador que guarde un valor de reset "interno".
    • Algunas FPGAs tienen una capa RAM y otra capa ROM (bueno, medio RAMROM). El caso es que en el bitstream defines un valor de reset, y luego durante la ejecución cada vez que se active la señal se carga ese valor. Lo normal es que sea cero, pero puede ser cualquier otro.
    • Cuando las FPGAs no tienen esa opción, a mí me gusta conectar la señal de reset como una entrada al bloque "lógica de siguiente estado", de forma que el contador propiamente dicho no tenga señal de reset, sólo clk y enable. En ese caso, la "lógica de siguiente estado" está compuesta por un sumador, comparador y multiplexor (como antes), pero se añade una puerta OR: la señal de reset comanda también el multiplexor, decidiendo entre la salida del sumador o la constante (ver más abajo).
--------

Creo que te has olvidado un par de "end" aquí (los marco con harridura ikurra):

always@(posedge clk) begin
 if (~rst)
    r_reg <= 0;
 else
   if (en)
     r_reg <= r_next;
   else
     r_reg <= r_reg;
   
!end
 
!end
end

Aunque puede ser mi inexperiencia con Verilog y que no sean necesarios :S

Por otro lado, esta parte


always@(r_reg) begin                                     no sé si es correcto
 r_next
= (r_reg == MAX)? 0 : r_reg + 1;
end

Yo la escribiría así:

assign r_next = (r_reg == MAX)? 0 : r_reg + 1;

o

r_next <= (r_reg == MAX)? 0 : r_reg + 1;

Pero esto puede ser mi vicio del VHDL y que no sean soluciones sintácticamente correctas en Verilog. Si tu proceso funciona, es correcto.

Relacionándolo con mi comentario anterior, si quieres incluir el reset en la lógica de siguiente estado, esta sería mi propuesta:

always@(posedge clk) begin
 if (en)
   r_reg <= r_next;
 else
   r_reg <= r_reg;
 
!end
end

r_next <= ((r_reg == MAX) || ~irst) ? 0 : r_reg + 1

Por último, estás "comparando" en dos sitios diferentes. Una vez en el trozo anterior y otra aquí:


assign counter = r_reg;
assign enout
= (r_reg == MAX)? 0 : 1;

Corres el riesgo de que el sintetizador genere dos comparadores diferentes para hacer la misma operación. Lo suyo es que lo optimice automáticamente. Pero para asegurarte explícitamente, puedes hacer crear un wire que sea el resultado de la comparación, y utilizarlo en ambos sitios:

always@(posedge clk) begin
 if en; r_reg <= r_next;
 else   r_reg <= r_reg; end
end

cmp <=
(r_reg == MAX) ? 1 : 0;
r_next
<= (cmp | ~irst) ? 0 : r_reg + 1;

assign counter = r_reg;
assign enout
= cmp;

Como ves el objetivo es que un ojo, aun con muy poca experiencia, sea capaz de hacer un dibujo que represente este último trozo de código:
  • Cada señal en un proceso es un registro. Todas las demás son wire.
  • Cada "?" es un multiplexor.
  • "=" son cables.
  • "==" es un comparador.
  • "+" es un sumador.
Todo tiene una equivalencia directa en un diagrama sin necesidad de "cajas negras".


El modulo del display lo abordaré después, una vez tenga claro los contadores.

Cuando lo hagas, puedes pasarte por este hilo: https://groups.google.com/forum/#!topic/fpga-wars-explorando-el-lado-libre/hI-CtOJrieM
Hay múltiples formas de hacer la conversión BCD a 7 segmentos, entre ellas un desarrollo paso a paso para hacerlo sólo con puertas lógicas. Creo que es un ejercicio muy interesante para aplicar principios basicos de álgebra de Boole y tablas de Karnaugh. Igual no quieres impartir la lógica digital a ese nivel (que es la forma clásica). En ese caso, está el ejemplo con una tablar de conversión directa.
 
Por lo de contar de forma descendente en lugar de ascendente, olvídalo por el momento. Es absolutamente irrelevante para este ejercicio, y cambiaría el orden de la cuenta, por lo que tendrías que hacer una conversión para que el cronómetro fuera ascendente (en vez de una cuenta antrás). Simplemente está bien que lo sepas para cuando sea irrelevante el módulo del contador y sólo utilices el pulso de salida (hasi o enout).

Cuando domines este ejercicio, si quieres, miraremos cómo adaptarlo para usar contadores up/down y hacer un cronómetro multifuncional. O cómo utilizar una pequeña memoria o grupo de registros para guardar varios valores de pausa y no uno sólo. Ya te comenté que, si quieres, esto se puede alargar para todo un cuatri XD. Las nociones que te di las hice pensando en facilitar este tipo de adaptaciones. Evidentemente, zure kaxara, ikasleak ez dauz inork zuk baino hobe ezagutzen.

Zorionak, berriz ere. Halako "ikasle"-ekin plazer hutsa da azalpenak ematea. Animo ta hurrengora arte!

Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-lib...@googlegroups.com.


--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.

Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.

Lorea Aldabaldetreku

unread,
Mar 31, 2017, 12:29:07 PM3/31/17
to FPGAwars: explorando el lado libre
Kaixo,

muchísimas gracias por tu ayuda y ánimos, nunca hubiera llegado hasta aquí sin tu ayuda.

Gracias por las correcciones que me haces, (aunque la sintaxis de los códigos  está correcta). 

La siguiente explicación me la apunto: 
  • Cada señal en un proceso es un registro. Todas las demás son wire.
  • Cada "?" es un multiplexor.
  • "=" son cables.
  • "==" es un comparador.
  • "+" es un sumador.
Todo tiene una equivalencia directa en un diagrama sin necesidad de "cajas negras".

Es una aclaración de las asignaciones simple y genial.

Pero este hilo es demasiado para mí  (oso konplexua niretzat), quizás con mucho tiempo y varias cañas: Cuando lo hagas, puedes pasarte por este hilo: https://groups.google.com/forum/#!topic/fpga-wars-explorando-el-lado-libre/hI-CtOJrieM

Cuando esté definitivamente correcto este diseño  me apunto a tu sugerencia: 

Cuando domines este ejercicio, si quieres, miraremos cómo adaptarlo para usar contadores up/down y hacer un cronómetro multifuncional. O cómo utilizar una pequeña memoria o grupo de registros para guardar varios valores de pausa y no uno sólo.

Al final he tenido que hacer correcciones en muchas partes del diseño, incluido el diseño de los contadores (barkau Unai pero al final he diseñado los contadores siguiendo los ejemplos de los tutoriales, tanto para mí como para los chavales es más fácil así de entenderlos, me refiero al diseño con reset interno, no lo he seguido). No he podido resistirme y he ido haciendo pruebas. El circuito funciona :) pero te agradecería que le echases un vistazo por si hay que corregir cosas. He hecho lo siguiente:

- He corregido el fallo (el más potolo) que me indicabas: En el primer diagrama introduces una constante, '1', en todas las puertas AND. Al hacer eso las AND son inútiles.
- He tenido que modificar los divisores de frecuencia. (ahora tienen enable)
- Corregir errores de diseño en los contadores.
- diseñar el módulo del control del display con pause
- diseñar el MUX 16:4


Los códigos son los siguientes:

Divisor de frecuencia con enable (Enablea duen maiztasun-zatitzailearen kodea)

Obtenido en el enlace: Baudgen.v: Modificación del divisor curso verilog cap. 22



//--M Maiztasun zatitzailea

//--M divisor de frecuencia


localparam N = $clog2(M);


reg [N-1:0] divcounter = 0;


always @(posedge clk)


 if (clk_ena)

   //-- Funcionamiento normal

   divcounter <= (divcounter == M - 1) ? 0 : divcounter + 1;

 else

   //-- Contador "congelado" al valor maximo

   divcounter <= M - 1;


//-- Sacar un pulso de anchura 1 ciclo de reloj si el generador

//-- esta habilitado (clk_ena == 1)

//-- en caso contrario se saca 0

assign clk_out = (divcounter == 0) ? clk_ena : 0;



Contadores (z0, z1 y z3) (Zenbatzaileen moduloak (z0, z1 eta z2))


// Zenbatzailea reset funtzioarekin

// Contador con función reset


reg [3:0] counter;

reg out;

always@(posedge clk) begin


if (counter == MAX)

    out <= 1;

else

    out <= 0;  

if (~rst)

    counter <= 0;

else

  if (en)

    if (counter==MAX)

    counter <= 0;

    else

    counter <= counter + 1;

end


assign enout = out;

assign z0 = counter;


Contador último, z3 (Azkeneko zenbatzailearen, z3ren,  moduloa):


// Zenbatzailea (azkenekoa) reset funtzioarekin

// Contador (último) con función reset


reg [3:0] counter;


always@(posedge clk) begin


if (~rst)

  counter <= 0;

else

  if (en)

    if (counter==MAX)

    counter <= 0;

  else

    counter <= counter + 1;

end

assign z3 = counter;


Control del display función pause (Displayaren kontrola pause funtzioa bidez)


reg [3:0] a;

reg [3:0] b;

reg [3:0] c;

reg [3:0] d;

always @(posedge clk) begin

if (pause) begin

a <= a;

b <= b;

c <= c;

d <= d;

end

else begin

a <= z0;

b <= z1;

c <= z2;

d <= z3;

end

end

assign {a3, a2, a1, a0} = a;

assign {b3, b2, b1, b0} = b;

assign {c3, c2, c1, c0} = c;

assign {d3, d2, d1, d0} = d;


Mux 16:4


reg _z0;

reg _z1;

reg _z2;

reg _z3;


wire [1:0] _sel;


assign _sel = {sel1, sel0};


always @(*) begin

   case(_sel)

       0: begin

          _z0 = a0;

          _z1 = a1;

          _z2 = a2;

          _z3 = a3;

          end

       1: begin

          _z0 = b0;

          _z1 = b1;

          _z2 = b2;

          _z3 = b3;

          end

       2: begin

          _z0 = c0;

          _z1 = c1;

          _z2 = c2;

          _z3 = c3;

          end

       3: begin

          _z0 = d0;

          _z1 = d1;

          _z2 = d2;

          _z3 = d3;

          end

       default: begin

          _z0 = a0;

          _z1 = a1;

          _z2 = a2;

          _z3 = a3;

          end

   endcase

end


assign z0 = _z0;

assign z1 = _z1;

assign z2 = _z2;

assign z3 = _z3;


Mila esker berriro ere. Un saludo,

Lorea
Lorea

Lorea Aldabaldetreku

unread,
Mar 31, 2017, 12:31:23 PM3/31/17
to FPGAwars: explorando el lado libre
Perdón, se me ha olvidado añadir el archivo del diseño. 
Kronoresetpause.ice

Unai Martinez

unread,
Apr 1, 2017, 8:53:23 PM4/1/17
to FPGA-WARS: explorando el lado libre
Aupa,


La siguiente explicación me la apunto: 
  • Cada señal en un proceso es un registro. Todas las demás son wire.
Si te la apuntas, ten en cuenta que es "un proceso dependiente de clk", no cualquier proceso. Por otro lado, no es conveniente usar procesos que no dependen del clk, de ahí que omitiera el detalle ;).

En cuanto al diseño, no hay nada incorrecto, pero me parece que hay demasiado contenido para lo que hace. No sé si es porque Icestudio te obliga a hacerlo, pero diría que todas las señales del multiplexor puedes agruparlas en arrays de cuatro, incluso en arrays de dos dimensiones.

En cualquier caso, como tenías razón al comentar que algunas de las sugerencias de sintaxis eran incorrectas, he aprovechado este circuito como excusa para cacharrear con iverilog, gtkwave y yosys. Concretamente, para utilizar una imagen de docker que he creado. Este es el resultado al que he llegado:

La clave del diseño está en el contador, que al margen de la descripción concreta, tiene dos parámetros: el valor máximo al que llegar y el número de bits del registro. En principio, el número de bits se calcula automáticamente a partir del primer parámetro. Pero, si queremos, podemos definirlo.

module zenbatzailea (clk, rst, en, tc, z );
  parameter MAX
= 9;
  parameter WIDTH
= $clog2(MAX);

  input clk
, rst, en;
  output tc
;
  output
[WIDTH-1:0] z;

  reg
[WIDTH-1:0] r_reg;
  wire
[WIDTH-1:0] r_next;

  //Hemendik aurrera, zuk nahi duzun estiloa
  always@(posedge clk) begin
   
if (en | rst) begin r_reg <= r_next;
   
end else begin      r_reg <= r_reg;  end
 
end

  assign cmp
= (r_reg == MAX) ? 1 : 0;
  assign r_next
= (cmp | rst) ? 0 : r_reg + 1;

  assign z
= r_reg;
  assign tc
= cmp;
endmodule

Con ese contador, podemos hacer todo el circuito en 15 líneas (los dos divisores de frecuencia, los cuatro contadores, el contador de sel, el registro de pause y el multiplexor):

  zenbatzailea #(.MAX(599)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
  zenbatzailea
#(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );
  zenbatzailea
#(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );

  assign en
[0] = ens;

  genvar i
;
  generate
for (i=1; i < 5; i = i+1) begin
    assign en
[i]=en[i-1] & enout[i-1];
    zenbatzailea
#(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
 
end endgenerate

  always
@(posedge clk) begin if (~p) begin r <= z; end else begin r <= r; end

  assign o
= r[s];

Vamos por partes. Esto es lo que significa cada señal:

  input clk, rst, p;    //(p)ause
  output [3:0] o;       //irteera, 7-seg-era doana

  wire [4:0] en, enout; //enable eta zenbatzaile bakoitzaren tick-a
  wire
[3:0][3:0] z;    //(z)enbatzailea
  reg
[3:0][3:0] r;     //pause e(r)registroa
  wire
[1:0] s;         //(s)el
  wire ens
;             //1. zatitzailearen irteera

Empezamos por los divisores, que los hacemos con el mismo contador:

  zenbatzailea #(.MAX(59999)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
  zenbatzailea
#(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );
  zenbatzailea #(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );


Tienes un divisor de 60.000 y otro de 1.200.000. Por lo tanto, si coges el primero y pones uno de 20 detrás, tienes 60k*20=1200k=1.2M. Como sólo interesa el indicador de final de cuenta y no el módulo (número), se queda sin conectar, ".z()", en los dos divisores (zat1 y zat2). Esto es una práctica habitual para reducir el tamaño de los contadores, ya que es muy preferible uno de log2(60k)=16 bits y otro de log2(20)=5 bits, que uno de log2(1.2M)=21. La razón es que todas las señales de cada registro tienen que avanzar en paralelo, y cuantas más sean, más difícil resulta. Pero es que en este caso, además, te es útil la señal intermedia.

Por otra parte, no quieres que al contador de dos bits (sel) le afecte el segundo divisor, por lo que los conectas en paralelo (tiene el mismo enable, "ens", que zat2). No obstante, de éste lo que te interesa es el módulo y no el final de cuenta, así que ".enout()" y ".z(s)" es sel.

Es decir, lo que tenemos son 6 contadores encadenados: los dos primeros los utilizamos como divisores y no utilizamos el número, y los últimos cuatro son los del cronómetro en si. Hay un séptimo en una rama paralela, que surge del primero.

"enout[0]" será el enable efectivo que entre al primer contador del cronómetro. Concretamente, para seguir el mismo patrón que el resto, una puerta "and" entre esta señal y ens:
 
 assign en[0] = ens;

Así, los cuatro contadores de verdad podemos instanciarlos con un generate for. Parece un for secuencial, pero lo que hace es añadir múltiples copias de un circuito:

  genvar i; generate for (i=1; i <= 4; i = i+1) begin
    assign en
[i]=en[i-1] & enout[i-1];
    zenbatzailea
#(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
 
end endgenerate
Lo anterior es exactamente equivalente a:
zenbatzailea #(.MAX(9)) zenb0( .clk(clk), .rst(rst), .en(en[1]), .tc(enout[1]), .z(z[0]) );
zenbatzailea #(.MAX(9)) zenb1( .clk(clk), .rst(rst), .en(en[2]), .tc(enout[2]), .z(z[1]) );
zenbatzailea #(.MAX(5)) zenb2( .clk(clk), .rst(rst), .en(en[3]), .tc(enout[3]), .z(z[2]) );
zenbatzailea #(.MAX(9)) zenb3( .clk(clk), .rst(rst), .en(en[4]), .tc(enout[4]), .z(z[3]) );

assign en[1]=en[0] & enout[0];
assign en[2]=en[1] & enout[1];
assign en[3]=en[2] & enout[2];
assign en[4]=en[3] & enout[3];
Bueno, no exactamene. Como todos los contadores cuentan hasta 9, menos uno, en el generate he utilizado una función "maxs" para definir el valor máximo de cuenta:
  function integer maxs ([3:0] i);
    case(i)
      3:       begin maxs = 5; end
      default: begin maxs = 9; end
    endcase
  endfunction
que, para este caso en particular, podría haber sido:
  function integer maxs ([3:0] i); maxs = (i==3) ? 5 : 9; endfunction
pero creo que el "case" es más didáctico.

NOTA: no es bueno utilizar funciones para partes del circuito que se espera sintetizar, porque es difícil entender cuál va a ser el resultado. Pero son muy útiles para todo tipo de cálculos o evaluación que van a realizarse inmediatamente antes, y van a tener un resultado constante. Como es este caso.
Seguimos con el registro de pause, que tal como se han definido las señales es:
  always @(posedge clk) begin if (~p) begin r <= z; end end
Y acabamos con el mux 16:4, que con las señales así definidas queda en:
assign l = r[s];
El diseño completo (contador, módulo principal y testbench) son 85 líneas:
module tb ( );
  reg clk, rst, p;

  initial begin
    $dumpfile("design.vcd");  // Emaitzak fitxategi batean gorde, gero ikusteko
    $dumpvars(0, tb);         // Seinale guzti-guztiak gorde
    p = 0;                    // Pauseren hasierako balioa
    clk = 0; forever begin clk = ~clk; #1; end //Erloju nagusia
  end

  always begin
    rst = 1; #30; rst = 0;    // Reset-a hasieran aktibatu eta 30 simulazio zikloren ostean desaktibatu
    #5000000; $finish;        // Hainbat zikloren ostean, simulazioa bukatarazi
  end

  always@(posedge clk) begin p = ~p; #120000; end // Pause seinalea, al tuntun, zeozer ikus dadin

  top uut( .clk(clk), .rst(rst), .p(p), .o() );   // Gure zirkuitu nagusia
endmodule


module top ( clk, rst, p, o );
  // Kontadoreen maximoa zehazteko funtzioa: beti 9, hirugarren izan ezik (honek 5).
  function integer maxs ([3:0] i);
    case(i)
      3:       begin maxs = 5; end
      default: begin maxs = 9; end
    endcase
  endfunction

  input clk, rst, p;     // (p)ause
  output [3:0] o;        // irteera, 7-seg-era doana

  wire [4:0] en, enout;  // enable eta zenbatzaile bakoitzaren tick-a
  wire [3:0][3:0] z;     // (z)enbatzailea
  reg [3:0][3:0] r;      // pause e(r)registroa
  wire [1:0] s;          // (s)el
  wire ens;              // 1. zatitzailearen irteera

  // Frekuentzia zatitzaileak
  zenbatzailea #(.MAX(599)) zat1( .clk(clk), .rst(rst), .en(1'b1), .tc(ens), .z() );
  zenbatzailea #(.MAX(19)) zat2( .clk(clk), .rst(rst), .en(ens), .tc(enout[0]), .z() );

  // Sel kontadorea
  zenbatzailea #(.MAX(3)) selzenb( .clk(clk), .rst(rst), .en(ens), .tc(), .z(s) );

  // Kronometroaren lau kontadoreak
  assign en[0] = ens;
  genvar i;
  generate for (i=1; i <= 4; i = i+1) begin
    assign en[i]=en[i-1] & enout[i-1];
    zenbatzailea #(.MAX(maxs(i)),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
  end endgenerate

  // Pause erregistroa
  always @(posedge clk) begin if (~p) begin r <= z; end end

  // Irteerako 16:4 mux-a
  assign o = m[s];
endmodule


module zenbatzailea (clk, rst, en, tc, z );
  parameter MAX = 9;
  parameter WIDTH = $clog2(MAX);

  input clk, rst, en;
  output tc;
  output [WIDTH-1:0] z;

  reg [WIDTH-1:0] r_reg;
  wire [WIDTH-1:0] r_next;

  always@(posedge clk) begin
    if (en | rst) begin r_reg <= r_next;
    end else begin      r_reg <= r_reg;  end
  end

  assign cmp = (r_reg == MAX) ? 1 : 0;
  assign r_next = (cmp | rst) ? 0 : r_reg + 1;

  assign z = r_reg;
  assign tc = cmp;
endmodule

Si copias todo este bloque en un fichero "kronosetpause.v", puedes hacer lo siguiente en una terminal:

iverilog -o design kronosetpause.v && ./design
gtkwave design.vcd &

A partir de ahí, si no cierras gkwave, puedes modificar el fichero y volver a ejecutar la primera línea. Con el icono de recarga de gtkwave se actualizará todo. A continuación algunas capturas de pantalla (de menos a más zoom). Los colores indican: contadores en naranja, registro pause en amarillo, salida en indigo:

Imágenes integradas 1 Imágenes integradas 2 Imágenes integradas 3 Imágenes integradas 4

Habria adjuntado el VCD, pero son 150MB XD.

Personalmente, creo que si las alumnas entienden el dibujo de tu mensaje anterior, deberían ser capaces de "ver" esta versión del código. Es exactamente la misma lógica y la misma estructura del circuito.


--
Has recibido este mensaje porque estás suscrito a un tema del grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este tema, visita https://groups.google.com/d/topic/fpga-wars-explorando-el-lado-libre/77Zw4ayF-DY/unsubscribe.
Para cancelar la suscripción a este grupo y a todos sus temas, envía un correo electrónico a fpga-wars-explorando-el-lado-libre+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a fpga-wars-explorando-el-lado-li...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/fpga-wars-explorando-el-lado-libre.

1138-4EB

unread,
Apr 1, 2017, 9:50:42 PM4/1/17
to FPGAwars: explorando el lado libre
Ahora bien, ¿cómo adaptar esto a Icestudio? Me temo que no es posible. Puedes meterlo todo en un solo bloque y a correr. Pero Icestudio creo que no es capaz de "desenrollar" el generate para mostrar cuatro bloques diferenciados. A mayores, cuando he ido a sintetizarlo con yosys, hay ciertas funcionalidades que no están soportadas. Concretamente la función, y los arrays bidimensionales (packed array):

https://www.reddit.com/r/yosys/comments/2cq8ip/multidimensional_arrays_in_verilog/
http://www.clifford.at/yosys/files/yosys_manual.pdf

He tenido que modificar la parte central por:

  genvar i;
  generate for (i=1; i <= 4; i = i+1) begin
    assign en[i]=en[i-1] & enout[i-1];
    if (i==3) begin
      zenbatzailea #(.MAX(5),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
    end else begin
      zenbatzailea #(.MAX(9),.WIDTH(4)) zenb( .clk(clk), .rst(rst), .en(en[i]), .tc(enout[i]), .z(z[i-1]) );
    end
  end endgenerate

  integer j;
  always @(posedge clk) begin
    for (j=0; j < 4; j = j+1) begin if (~p) begin r[j] = z[j]; end else begin r[j] = r[j]; end
  end end


Que es exactamente lo mismo, pero un poco más feo. Adjunto un fichero con la versión final que funciona en yosys.

Es muy interesante que la de las siete páginas de diagramas que genera yosys, seis son la repetición del contador con diferentes parámetros (es un gif animado):

Imágenes integradas 5
Aunque esté un poco liado, si te fijas podrás ver la estructura del código:
  • El registro a la izquierda ($ddf).
  • El comparador y el sumador a su derecha ($eq y $add)
  • En el centro, la señal cmp, que depende del resultado del bloque $eq, con un mux que asigna 0 o 1.
  • El reset y la comparación van a una puerta or, que define el $mux de "estado siguiente". Se ve que de ahí sale "r_next".
  • Por último, el multiplexor que entra al registro, que puede ser él mismo, o "r_next".
  • Además, los bloques "BUF" identifican cuáles son las salidas.

¡No esperaba que viera "tan bien"!


En cuanto a la primera página, donde está el otro contador y el resto de la lógica, no es tan fácil verlo...



Pero sí que se ven claramente en la parte inferior derecha los cuatro $dff que conforman el registro de pause. Y en la parte superior derecha el multiplexor 16:4.
En el centro están las cuatro puertas "and" de los contadores principales.

NOTA: he de decir que he tenido que hacer varias iteraciones hasta dar con un resultado tan claro. Lo cual ha sido muy útil para entender cuándo estaba escribiendo codigo de más, o comentiendo errores como registrar señales que deberían ser combinacionales.

Los resultados de síntesis son:

After packing:
IOs          7 / 96
GBs          0 / 8
  GB_IOs     0 / 8
LCs          89 / 1280
  DFF        36
  CARRY      12
  CARRY, DFF 9
  DFF PASS   16
  CARRY PASS 6
BRAMs        0 / 16
WARMBOOTs    0 / 1
PLLs         0 / 1

Y frecuencia máxima de operación del circuito:

Resolvable net names on path:
     
0.640 ns ..  1.769 ns z[0][0]
     
2.148 ns ..  2.737 ns $abc$1101$n86
     
3.186 ns ..  3.775 ns $abc$1101$n97
     
4.175 ns ..  5.136 ns $abc$1101$n115
     
5.514 ns ..  6.987 ns $abc$1101$n6
                  lcout
-> z[3][1]

Total number of logic levels: 5
Total path delay: 6.99 ns (143.12 MHz)

Y creo que esto es todo :D. Igual este salto a un sólo fichero en verilog te descoloca un poco al principio. Pero creo que ya has "machacado" suficiente el circuito como para entenderlo. Las estructuras generate con el corazón del HDL, es lo que permite hacer circuitos parametrizados. Parametrizar los tamaños de palabra esta bien, pero generar multiples variables de un módulo es donde está la potencia. Por ejemplo, en este caso, sólo con cambiar el número en for, podrías poner dos contadores más, para contar las horas. También podrías poner la parte del registro de pause dentro de un "generate if", de forma que si alguien no quiere usar esa funcionalidad, cambiando un parámetro no se sintetice ese registro.

Evidentemene, para poder cambiar el número del for, todas las señales de top deberían adaptarse. Es decir, habría que añadir un parámetro a top, por ejemplo, ZENKOP, y cambiar todos los "3" por "ZENKOP-1". Si quieres, es un ejercicio interesante.

Además, me parece muy interesante que te acostumbres a utilizar el simulador, porque da muchísma información sobre lo que está pasando en realidad, y permite ir comprobando las cosas de izquierda a derecha, verificando cada módulo paso a paso. Por eso te lo he facilitado en un fichero y te he indicado los comandos más directos. Lo que no sé es si utilizas GNU/Linux o Windows. Si es el segundo, ¿tienes acceso a algún equipo con linux o a una raspberry pi?

Badakit latza dala, hamar urte baino gehiagotan ikasitakoa pare astetan erdipurdi azaltzen ari natzaizu XD. Edozein momentutan gelditu eta atzera bueltatzea beharbazu, arazo barik esan. Edonola ere, kontuan izan "nire diseinurik onena" idatzi dudala oraingoan, nik neure proiektutan erabiliko nebana (falta den parametrizazioa bukatuz). Hau da, zirkuituak, funtzionaltasunik gehitu ezean, ez dauka mami gehiagorik. Zentzu hortan, lasai egon zaitezke, implementaziorarte heldu gara ta!

Ta zorionak neska! Detaile teknikoetan sartu naz zuzen-zuzen, eta martxan jartzeagatik zoriontzea ahaztu zait!

Ondo izan, animo, ta nahi duzunerako

kronoresetpause.v
Auto Generated Inline Image 1

1138-4EB

unread,
Apr 1, 2017, 9:52:11 PM4/1/17
to FPGAwars: explorando el lado libre
El gif animado que no se ha cargado correctamente en el mensaje anterior es:




Auto Generated Inline Image 1

1138-4EB

unread,
Apr 1, 2017, 10:04:57 PM4/1/17
to FPGAwars: explorando el lado libre
Nada, no quiere mostrarse. En cualquier caso, te he pasado todo el contenido por GitHub en un PR: https://github.com/Lorea-Aldabaldetreku/Icestudio_proiektuak/pull/1

Lorea Aldabaldetreku

unread,
Apr 2, 2017, 3:40:29 AM4/2/17
to FPGAwars: explorando el lado libre
Kaixo Unai, 

esker mila por toda la información, voy a tener que tomarme un rato largo (muy largo) para estudiarla y entenderla. Esango dizut, hurrenarte,

Lorea

Juanma Rico

unread,
Apr 2, 2017, 3:46:37 PM4/2/17
to FPGAwars: explorando el lado libre

Buenas Lorea... ¡Cómo te entiendo!

Unai hace que eso que pusiste en el título del hilo se convierta en una broma... jajajajajaja

Yo ya me he apuntado el hilo como favorito para intentar (y digo intentar) reproducir su trabajo a ver si aprendo algo, pero sospecho que para mi será un nuevo proyecto que me llevará horas (¡y eso que es un simple contador!)... jajajajaja

Gracias Lorea por compartir, un saludo y ánimo con esos chavales. :)



El domingo, 2 de abril de 2017, 9:40:29 (UTC+2), Lorea Aldabaldetreku escribió:
Kaixo Unai, 

esker mila por toda la información, voy a tener que tomarme un rato largo (muy largo) para estudiarla y entenderla...
 
Reply all
Reply to author
Forward
0 new messages