Recuperando un viejo proyecto para pequeñas OLEDs

212 views
Skip to first unread message

Democrito

unread,
Apr 6, 2025, 7:28:16 AMApr 6
to FPGAwars: explorando el lado libre
Hola,

Hace algunos años publiqué un proyecto muy sencillo para OLEDs monocromática de 128x64 pixeles pero sólo funcionaba para la SSD130x. Existe otra pantalla, la SH1106, de mismas características y es más barata pero sólo soporta un tipo de funcionamiento que se llama "paginación". En aquella época pensaba que todas funcionaban igual, hasta que el usuario y colaborador de este foro llamado @Joaquim me advirtió de que a él no le funcionaba correctamente. Tras investigar comprendí lo que sucedía.

Total, que en aquella época al final conseguí que funcionase en las dos tipos de pantalla, pero ya con otros proyectos más avanzados como el dibujo de líneas.

Lo que os presento es volver a los inicios, se trata de tomar un mapa de bits (1024 bytes) y volcarlo en una OLED, siendo compatible con ambas patallas.

Así es como me ha quedado en Icestudio.

presentacion icestudio de proyecto memoria a oled.png
En la patilla "Choose" podéis elegir qué tipo de pantalla vas a usar. Por defecto he dejado que sea para una SH1106. Y si no lo sabéis probad con 0 y 1 para ver que no se visualiza nada extraño.

De momento esta demo sólo está para I2C.

Tenéis 5 ejemplos para mostrar en la pantalla. Sólo tenéis que unir la caja bitmap que os interese a la entrada de arriba que pone "bmp" (bitmap). Por defecto está conectada a la caja "Atary_chars".

En las fotos que muestro a veces sale una línea gruesa negra que borra esa parte, esto no se verá en la pantalla, además que de será mucho más nítido que lo que os muestro.

* Mapa de caracteres estilo ASCII de Atary.

ASCII Atary.jpg

* Uno de los logotipos de FPGAwars.

logo FPGAwars.jpg

* Dibujo de una caricatura de un búfalo o toro.

caricatura toro.jpg

* La cabeza del Pato Donald.

donald.jpg

* Y la pareja Mikey & Minnie.

Mikey Minnie.jpg

Os dejo con un enlace que aunque está enfocado en la creación de líneas, se explica en detalle cómo hacer para que sea compatible ambas pantallas. Ya sea I2C ó SPI los comandos siempre son los mismos.


Por otra parte, si hacéis doble click al módulo, dentro veréis una memoria que si la sabéis manejar podréis representar lo que queráis en la pantalla. Todo lo referente a la escritura en la memoria está a cero pero si la sabéis manejar, una vez cargada la memoria, le dais a "print" y se pintará en la pantalla.

Saludos.


Dumping_memory_to_screen.ice

Democrito

unread,
Apr 6, 2025, 7:35:12 AMApr 6
to FPGAwars: explorando el lado libre
Vaya... la imagen de mapa ASCII de Atari me he dado cuenta después que no es de Atari, sino uno convencional.

Democrito

unread,
Apr 6, 2025, 7:44:47 AMApr 6
to FPGAwars: explorando el lado libre
En este proyecto no se usa tri-estados en la parte I2C porque la OLED siempre es receptora, es decir, siempre escribimos en la OLED. Por tanto no necesita resistencias pull-up.

Democrito

unread,
Apr 6, 2025, 8:16:11 AMApr 6
to FPGAwars: explorando el lado libre
Observad esta imagen.

memory.png

Vemos la memoria y esto está dentro del módulo (es una parte de sus tripas). Ahora mira las patillas "aw" (dirección de escritura), "dw" (dato a escribir) y "wr" (tic de escritura). Todos esos pines están a 0. Pero si vosotros añadís hardware para escribir en la memoria, podréis hacer lo que queráis, desde un editor de textos a crear líneas, o lo que deseéis.

Lo que quiero decir con todo esto es que la parte que vuelca a la memoria a través de I2C ya está resuelto, lo único (que no es poco) que tenéis que hacer es saber escribir en la memoria.

Cada vez que escribas algo en la memoria obtendrás un tic en la salida "wexe" como confirmación de que el dato ha sido escrito.

Y ahora os explico algo que es un poco más avanzado. Si haces doble click al módulo de la memoria verás esto.

graph.png

Hay un pin que por defecto lo puse a 0 que es "graph" . Con ese pin se puede controlar que lo que metas en memoria se "sume" o se "aplaste encima". Según el proyecto esta característica puede ser importante y ya la tienes en el caso de que lo necesites. Por defecto está para que se "aplaste encima" de lo que ya existe.

Cualquier cambio que hagáis a los módulos recordad que primero hay que clonar el módulo (copiar con "Control C" y luego clonar con "shiht+control+V"). Modificar un módulo sin antes haber clonado sólo da problemas.

charli va

unread,
Apr 6, 2025, 4:11:25 PMApr 6
to fpga-wars-explora...@googlegroups.com
Muchas gracias por retomar este proyecto Demócrito! seguro que le sacamos miga ;) !!

--
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...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/ba23cd2b-0508-45c3-8173-1065dbe2c45bn%40googlegroups.com.

Democrito

unread,
Apr 6, 2025, 4:53:52 PMApr 6
to FPGAwars: explorando el lado libre
Con todo lo explicado, te aseguro que puedes hacer migas sin esperar a llover. Aquí (o quizás es más en mi familia) decimos que cuando hace mal tiempo es momento de comer unas buenas migas. Por cierto, a mi me salen muy buenas y las hago con cebolla muy troceada. La cebolla da un toque dulce muy rico, y lo mismo aplico al tomate frito: lo frío con cebolla y luego le paso la minipimer. De esta forma no es necesario echar azúcar para corregir la acidez.

charli va

unread,
Apr 6, 2025, 5:23:25 PMApr 6
to fpga-wars-explora...@googlegroups.com
Yo creo que va a haber que hacer directamente un apartado de "recetas" tanto bit a mi. me da hambre ;) y esas migas parecen cosa fina ....

Democrito

unread,
Apr 6, 2025, 5:39:37 PMApr 6
to FPGAwars: explorando el lado libre
jejeje

Jo mo

unread,
Apr 7, 2025, 3:27:29 AMApr 7
to FPGAwars: explorando el lado libre
Ola Democrito,

Gracias for the recipes for the poor times ;-). we may need them one day, if nobody stops the "orange face american guy"! ;-)
And thanks for the revival of the Oled screen subjet !

This new block looks really nice!, i will try playing with it a bit !


a hug and have a great week guys !

Democrito

unread,
Apr 7, 2025, 10:53:59 AMApr 7
to FPGAwars: explorando el lado libre
Thanks for your comment Joaquim.

oled spi 128x64 monocromo fpga control.png

I'm now attaching the same thing, but for 128x64 monochrome SPI OLED displays. The operation is exactly the same, and everything explained above applies to this circuit.

Maybe the next thing I'll do is take out all the pins on the memory so they can be manipulated externally.

Greetings.

Dumping_memory_to_SPI_screen.ice

Democrito

unread,
Apr 7, 2025, 5:55:30 PMApr 7
to FPGAwars: explorando el lado libre
Ya he sacado los pines necesario para escribir en la memoria, tanto en el módulo I2C como en el SPI. Pongo como ejemplo el I2C por tener menos patillas, sin embargo todos los pines son los mismo excepto los pines que van enganchado al tipo de pantalla correspondiente (I2C o SPI).

memory manager.png
Es el esquema la escritura en la memoria está deshabilitada (todo lo referente a la memoria está puesto a cero), pero son esos pines los necesarios para poder escribir en la memoria si sabes manejarla.

Paso a explicar cuáles son esos pines en específico y qué función tienen.

* "aw" (addres write ) Dirección de memoria a escribir.
* "dw" (data write) Dato a escribir.
* "wr" (write) Validación de escritura (tic).
* "graph" (modo de graficar) Si este pin lo pones a 0 graba tal cual, pero si lo pones a 1 hace una OR con el dato que contuviese antes de escribirlo. Esto último sirve para (dado el caso) poder superponer varios objetos o dibujos. O dicho de otra manera, con '0' machacas, y con '1' superpones.
* "print" (con un tic vuelca la memoria en la OLED) El contenido de la memoria se transfiere a la OLED.
* "wexe" ("exe" de escritura en la memoria) Dará un tic cuando el byte haya sido escrito en la memoria, como diciendo, pásame el siguiente dato si lo hubiera.

Por otra parte, los pines:

* "done" avisa con un tic que la transferencia de la memoria a la OLED ha sido completada.
* "initic" avisa con un tic que la configuración de la OLED ha sido completada y ya puede recibir datos para pintar (desde la memoria).
* "choose", con un '1' le estás diciendo que la pantalla que vas a usar es una SH1106, si y pones un '0' le estás diciendo que vas a usar una SDD130X.

Como decía arriba, ahora mismo el manejo de la memoria de escritura está deshabilitada, aquí eres tú el que ha de crear lo que necesite para escribir en la memoria y eso sea representado. De todas formas, con tiempo, meteré algún ejemplo.

Esto es un módulo que trata de facilitarte la vida para el envío de información a la OLED (ya sea SPI o I2C, ya sea una SH o una SDD) a través de una memoria intermedia, es su único propósito.

Adjunto los dos circuitos (SPI e I2C)

Saludos.
Dumping_memory_to_SPI_screen.ice
Dumping_memory_to_I2C_screen.ice

Democrito

unread,
Apr 7, 2025, 6:03:26 PMApr 7
to FPGAwars: explorando el lado libre
Si alguien lo prueba, dale directamente a subir. Cuando le das a "Verificar" sólo comprueba la sintaxis verilog, y en la versión actual da error si encuentra salidas no asignadas, pero esto no significa que esté mal, es una cuestión de versiones del lenguaje de descripción verilog. De hecho Yosys de momento acepta la salida de registros sin asignar como asignados y por eso podemos subir los circuitos sin problemas.

charli va

unread,
Apr 8, 2025, 4:04:27 AMApr 8
to fpga-wars-explora...@googlegroups.com
Buenas Demócrito! lo primero muchísimas gracias por compartir todo esto.

Te hago unos comentarios por si te gustaran  y te apeteciera implementarlos, son sólo sugerencias tómalas como mejor creas.

En cuanto a nomenclatura y como te digo, es nomenclatura pura y dura por lo que es un tema de "gustos" te hago sugerencias por cosas que creo que mejorarían la lectura y podrían aproximar más los nombres a otro tipo de displays y estándares en los conceptos de temas gráficos.

- AW y DW como nunca va a haber simultáneamente  lectura y escritura, yo personalmente vería más claro literalmente poner Address y Data (o Pixel para este último, depende de si lo quieres mostrar como memoria o darle una connotación gráfica).
- WR en la hoja de datos he visto que es activo bajo para escritura, como bien tienes en el diseño, a mi en general si una señal es activa baja me gusta que comience por n , por ejemplo nWR, pero esto es cosa mía. En cualquier caso como este módulo sólo escribe, yo  la ocultaría en el toplevel si más adelante hace falta porque se añade lectura la sacaría, pero inicialmente la quitaría de todas las interfaces superiores que realmente sólo arrastren el 0. La idea es ¿para qué poner una señal que nunca se va a utilizar? 
- graph, lo cambiaría por overlay_mode o simplemente overlay, creo que sería el concepto más cercano a la superposición que gestiona. Si alguien lee "graph" no va a saber que es lo que hace. Mi intención cuando hago bloques es que sean lo más autoexplicativos posibles, como el código. Si el nombre de las señales es claro no hace falta en muchos casos leer explicaciones, por el nombre ya intuyes de que va el invento.

- Ahora mismo n tiene mucho sentido porque solo hay una señal de configuración como es "graph" pero de cara a futuro podrías contemplar que eso fuera un registro de configuración ene l que cada bit sea un flag de configuración (por ejemplo si usáramos un byte para este registro, el bit 0 podría ser el overlay). Esto me gusta mucho cuando hay varias señales de configuración porque encapsulas todas en un único registro en vez de tener un montón de señales dispersas. Como te digo ahora mismo puede que no tenga sentido pero tenlo en cuenta para futuro.

-print, lo cambiaría por dump, copy o stream , esta como todos los anteriores es un tema personal. para mi print, como se usa en muchos lenguajes tipo basic, implica en general el pintar un caracter, un pixel... Como lo que haces es una operación masiva, creo que el nombre de la señal debería dar esa connotación de "ahí va todo el bitmap!".
-wexe, lo cambiaría por alto tipo wdone o wready (podría ser interesante que tuvieras esta señal a 1 por ejemplo si la memoria está lista para poder lanzar un dato y bajarlo a 0 durante todo el proceso de escritura. Desde fuera se debería detectar este cambio de estado o monitorizar el estado de la señal pero de este modo podrías saber en cualquier momento si estamos listos o no para poder escribir (ahora realmente el módulo no informa de en qué estado está) esto quizá es algo rebuscado pero facilita mucho integraciones a futuro.

-initic lo cambiara por un isReady, ready o lcdReady o algo así, igual que antes más que un tic yo apostaría por una señal a 1-0 y desde fuera ya que cada uno se apañe (se puede usar uno de los bloques de obijuan de lanzar un tic si detectas transición por ejemplo). El tema es que si integras el módulo con otros bloques ese tipo de señales es muy útiles para vincularlas con un reset y cosas así.

- Echo de menos un reset.

- Sobre el choose, me parece útil tener un bloque para ambas pantallas aunque  de cara a un "producto final" donde se ha integrado el bloque junto a otros y que hay un hardware concreto creo que podría estar muy bien tener dos bloques uno para cada pantalla, Sé que ahora puede ser un rollo importante porque si hace suncambio en uno no lo arrastras a los otros, esto pronto lo tendremos mucho mejor resuelto en cuanto acabe unas cosas en icestudio pra poder vincular bloques y que hereden los cambios que hagas en los ficheros originales, pero te lo ocmento para que lo tengas en mente. porque sin haber indagado mucho en el código entiendo que hay un consumo de recursos importante si lo separaras (a no ser que realmente la decisión entre uno y otro sea una auténtica tontería y apenas implique un extra de recursos, como te digo no he podido verlo en profundidad , lo haré ;) )

Si te motivara una mejora podría ser intentar simular el concepto de una vga, pintando en continuo los frames y scando unas señales de hsync, vsync, hpos,vpos para que el usuario pueda saber por dónde va y actuar en consecuencia con la escritura de los pixels en memoria, es un concepto diferente, ahora mismo el usuario rellena, pinta, espera a que se pinte y si quiere vuelve a pintar. El otro concepto es el módulo pinta y el usuario que se suba al carro cuando pueda XD, como te digo es otro concepto sólo por si quieres plantearlo, el módulo como tal es ya super útil.

Muchas gracias por el trabajo!


Democrito

unread,
Apr 8, 2025, 8:16:35 AMApr 8
to FPGAwars: explorando el lado libre
Hola Carlos,

Sobre la nomenclatura tomo nota y para cuando suba esto a GH (y mucho antes de eso, en las próximas publicaciones) ya llevarán esos nombres que me has comentado. Nunca se me ha dado bien poner nombres a las cosas.

Y sobre el resto, ahí es donde patino porque los que conocéis el funcionamiento de una VGA ya sabéis cómo ha de ser cada cosa para (como en este caso) compatibilizar una OLED como si fuese una VGA. No tengo idea de cómo funciona una VGA, sólo sé el concepto de pasar un haz de luz o electrones barriendo la pantalla, pero los detalles técnicos los desconozco por completo.

La intención de publicar este módulo era precisamente para que los que controláis el tema de la VGA o saber escribir dentro de una memoria os ahorraseis todo lo relacionado al envío de datos a la OLED y esa parte ya estuviese automatizada.
Se puede optimizar mucho el circuito, especialmente el manejo de la memoria, ya que para escribir en ella consume al menos 3 ciclos de reloj, y las razones son varias, pero la que creo más importante es que en verilog todo puede ser más eficiente que utilizar módulos prefabricados. Para hacer eficiente esta parte habría que "recodificar" en verilog lo relacionado con la memoria.

Comencé la casa por el tejado con otras publicaciones (líneas en movimiento y demás)  y no era por saber lo que estaba haciendo, sino que delante tenía un reto que "conquistar". Pero pasa el tiempo y seguía teniendo el gusanillo que recome-come por dentro de que por muy espectacular que fuese algo, no había dónde meter mano y discernir sus partes o aprovechar algunas de ellas.

Por ello me decidí a abrir este hilo, comenzar desde el principio y que se pueda ver mejor todo. Incluso sin saber cómo funciona algo en concreto (en detalle), poder separarlo y hacerlo funcionar.

Cualquier cosa que esté dentro de mis conocimientos y que se pueda mejorar ya sabéis que aquí estoy.

Por si las moscas necesito hablar de este tema:
Sé que hay gente muy celosa de sus circuitos y autoría, yo soy todo lo contrario, podéis hacer lo que queráis con ellos, están ahí para eso; para mejorarlos, modificarlos e incluso re-hacerlos (servir como inspiración en este caso). Las pocas veces que he visto que alguien ha usado, mejorado, modificado, etc. algo que haya creado, me ha dado una alegría enorme, porque de alguna manera ha abierto un camino para otra persona, o le he ahorrado algo de trabajo.

Saludos y muchas gracias por tus comentarios!

charli va

unread,
Apr 8, 2025, 8:30:16 AMApr 8
to fpga-wars-explora...@googlegroups.com
Pues cuenta con mi ayuda en lo quepueda aportarte Demócrito, en cuanto pueda lo testeo y preparo un esqueleto para jugar con el.

Un abrazo y gracias!

Democrito

unread,
Apr 8, 2025, 8:33:28 AMApr 8
to FPGAwars: explorando el lado libre
Lo de la compatibilidad entre pantallas (SH & SDD) no se gana nada si se quisiera separar como módulos diferentes, quizás te ahorras dos pequeños multiplexores. En esa parte sólo hay que tocar dos registros (4 bits por un lado y otros 4 por otro) que valen para lo mismo. Se trata de decidir si cierto registro de configuración vale '0' ó '2'.

'0' significa que es para una SSD y '2' que es para una SH.

Democrito

unread,
Apr 9, 2025, 2:03:54 PMApr 9
to FPGAwars: explorando el lado libre
He buscado crear el ejemplo más sencillo posible de manejo de la memoria con algún propósito. Y se me ocurrió enviar texto a la pantalla desde una terminal serie. Digamos que la OLED hará como pantalla de texto, pero para ayudar a comprender mejor el circuito, está muy simplificado. No responde al "Enter" ni hará scroll, sólo "representa" lo que has pulsado. La intención es que se comprenda lo que hace cada una de las partes.

En la siguiente imagen vemos un esquema. Se trata de la parte que captar un ASCII (cualquier alfanumérico o símbolo) desde un terminal serie, y traducirlo a píxeles dentro de la memoria que represente lo que has pulsado.

convert ascii to bytes memory.png
Cada ASCII se compondrá de 8 bytes (8 píxeles de alto por 8 de ancho). Dentro de una pequeña memoria contenida en este módulo están todos los ASCII en ese formato.

Cuando reciba un ASCII se multiplicará por 8 para dar con la dirección de memoria donde comienza ese ASCII y luego una máquina de contar se encarga de contar 8, y por cada byte que "decodifica" produce un tic de escritura en la memoria. Esto sucede 8 veces y dejará grabada en la segunda memoria (la que luego se volcará en el OLED) el ASCII que hemos pulsado.
Para saber en qué lugar de la memoria ha de grabar necesitamos un contador simple (arriba en el esquema) que direcciones la memoria y lo hace uno por uno, sólo ha de ir contando cada uno de los bytes que se ha enviado a la memoria a través de la entrada "wnext".

Si ya tienes ciertos conocimientos de esto, cuando veas la imagen de abajo intuirás perfectamente el funcionamiento. Recuerda que lo único que estamos haciendo es escribir en una memoria.
Para terminar, cuando a acabado de escribir en la memoria el ASCII (en forma de 8 bytes), dará un tic de imprimir pantalla (srcPrint) y hará el volcado a la OLED.

serial text to OLED screen.png
Aquí vemos el viejo módulo del que hablamos en post arriba, y a la izquierda está el módulo que se encarga de escribir en la memoria, en plan editor de texto ultra capado.

* "address" direcciona la memoria.
* "data" es el byte que queremos grabar.
* "write" en forma de tic guarda el dato en la memoria.
* "wnext" será el tic que confirma que se ha grabado y pide el siguiente.
* "scrPrint" es un tic que sale cuando ya quieres hacer el volcado de la memoria a la OLED.
* "tickReady" emitirá una sola vez un tic, luego ya no emite más, y será cuando transcurra 500 ms después de poner en marcha el circuito.

disable flush on enter.png

Recomiendo usar el terminal serie del propio Icestudio porque tiene la opción de enviar carácter a caracter o sólo cuando hagas "enter". Recomiendo probar las dos formas, pero especialmente la de carácter a carácter. Para ello has de deshabilitar la casilla que marco en rojo en la imagen (Flush on Entrer).

ola k ase.gif
(aquí va un gif animado que pesa bastante, igual tarda en cargar)

Adjunto ICEs, para OLEDs monocromáticas 128x64 I2C y SPI.

Saludos.

Minimal_I2C_text_editor_OLED_128x64.ice
Minimal_SPI_text_editor_OLED_128x64.ice

charli va

unread,
Apr 9, 2025, 3:26:58 PMApr 9
to fpga-wars-explora...@googlegroups.com
Está muy chulo Demócrito! ¿cómo ves meterle el teclado ps2 en vez del terminal serie? por eso de que sea "autónomo".

Ya he localizado hoy dos pantallitas de estas que no encontraba, me ha sorprendido que son muy diferente de tamaño, espero que sean las buenas, se me acumula la faena XD



--
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...@googlegroups.com.

Democrito

unread,
Apr 9, 2025, 5:11:18 PMApr 9
to FPGAwars: explorando el lado libre
Hecho!

Te adjunto la sustitución del terminal serie por el teclado PS/2.

En el módulo PS/2 he detectado un mini-bug. Todo funciona bien excepto la tecla 'U'. He escrito todo el abecedario en mayúsculas y minúsculas y números y símbolos principales, y todo sale bien menos la 'U'.

He comprobado con el ejemplo PS/2 a Serial (de aquel hilo) y también sale. Luego he probado a enchufar el teclado PS/2 al PC abriendo un editor de texto y ahí sale bien. También he comprobado que en el verilog apunta correctamente a la letra 'U' y es 'h3C como código de letra, y está bien. Mañana miraré este tema pero sólo falla con esa tecla aunque hay que mirar por qué.

Dejo ejemplos SPI e I2C para probar con la pantalla OLED. Todo va bien menos esa puñetera 'U'. Y para que no tengas que buscar, por si te da por probarlo también te adjunto el viejo ejemplo de PS/2 a terminal serie.

PS2_to_I2C_OLED_128x64_editor.ice
PS2_to_SPI_OLED_128x64_editor.ice
example_ps2_to_serial_terminal.ice

Jesus Arias

unread,
Apr 10, 2025, 2:57:47 AMApr 10
to FPGAwars: explorando el lado libre
Hola
Es curioso que sea precisamente la 'U' (en binario es 01010101 )

Democrito

unread,
Apr 10, 2025, 3:22:19 AMApr 10
to FPGAwars: explorando el lado libre
Curioso eso.

Creo que acabo de localizar el bug de la 'U'. El código de tecla de la 'U' es 'h3C y está repetido. Pilla (por jerarquía en la decodificación) la comilla simple antes que la 'U' y por eso nunca sale la 'U'.

Democrito

unread,
Apr 10, 2025, 3:32:20 AMApr 10
to FPGAwars: explorando el lado libre
Confirmado, era eso, por estar repetido el código de tecla. Y lo curioso es que la "comilla simple" en el teclado español es `h55 (el binario que puso Jesús) y en el teclado inglés es 'h52.

Democrito

unread,
Apr 10, 2025, 4:22:27 AMApr 10
to FPGAwars: explorando el lado libre
He modificado más cosas y lo he dejado como teclado español pero sin la 'Ñ'. Como quiero modificar más cosas lo dejo para futuro, incluso incluir otros teclados en otros idiomas.

Adjunto ejemplos de PS/2 corregido con OLED.

PS2_to_SPI_OLED_128x64_editor.ice
PS2_to_I2C_OLED_128x64_editor.ice

charli va

unread,
Apr 10, 2025, 10:39:54 AMApr 10
to fpga-wars-explora...@googlegroups.com
Que grande Demócrito! tiene una pinta estupenda, lo estoy preparando para probar.

Buscando si mis pantallas eran i2c o spi porque la verdad no me acuerdo y en su día no las organicé bien, resulta que he encontrado este documento y me ha sorprendido:


no sé si afectará a cualquier pantalla pero según ese documento todas son spi + i2c y básicamente cambiar de un modo u otro depende de un par de resistencias que si se quitan y se puentea la pista la pantalla funcionará en un modo y si no en el otro. No lo he probado , tengo una pantalla qu ecreo que stá rota y si cumple esta configuración igual lo pruebo por dejarlo documentado.

Buena tarde!

charli va

unread,
Apr 10, 2025, 10:44:51 AMApr 10
to fpga-wars-explora...@googlegroups.com
Acabo de buscar un pelín más y el documento anterior sólo es válido para las oled que tienen 7 pines que son duales spi/i2c las de 4 pines son puras i2c.

Democrito

unread,
Apr 10, 2025, 11:51:37 AMApr 10
to FPGAwars: explorando el lado libre
Experimenté con una y le hice eso hará unos 5 años y funcionó bien. Sólo lo hice por experimentar un poco.

charli va

unread,
Apr 10, 2025, 1:29:32 PMApr 10
to fpga-wars-explora...@googlegroups.com

Ya tengo las OLED operativas, he hecho un setup con las 2 oled en paralelo , aunque una se ve sustancialmente peor que la otra (pegué la esquina rota y aparentemente ya sale todo aunque la calidad de la de la izquierda como podéis observar es infinitamente peor que la de la derecha. He pensado en que así será muy útil para comparar arquitecturas diferentes, framerate, aliasing y demás efectos visuales, creo que podemos sacar conclusiones interesantes en los próximos días.

IMG_2430.jpg

La resolución es exactamente igual, lo único la de la derecha tiene las primeras páginas en color amarillo, para tratar la pantalla como una pantalla entera es una cag... pero para algunas aplicaciones en las que se quiera tener una barra de estado o similar, es muy interesante (yo la compré así sin darme cuenta la verdad, el pedido de estas oled hace unos años fue un caos, pedí varios modelos por aliexpress y uno de los paquetes en los que había varias de ellas resultó ser una estafa así que nunca llegaron y solo me quedé finalmente con estas dos), las dos son i2c. Voy a hacerme con alguna spi y con los dos drivers por tener un poco el set para las pruebas pero de momento con esto tiramos.

La primera como os he comentado tiene una esquina rota y antes de pegarla generaba algunos artefactos raros, no sé si el interlineado es fruto de eso, pero me da que en este mundo de las oled de aliexpress habrá muchas calidades.

Pasad buena tarde!


charli va

unread,
Apr 10, 2025, 1:48:55 PMApr 10
to fpga-wars-explora...@googlegroups.com
Jugando con los ice de Demócrito he visto claramente el artefacto generado por la rotura de la esquina, es simplemente la línea de pixels de la parte izquierda, es tira está siempre encendida y le falta algún pixel....tendré que vivir con ello XD Así que ahora sí confirmada la mala calidad de esa OLED, como podéis ver en las imágenes (y eso que se ven relativamente en la foto) la de la derecha es super nínida y mucho más luminosa.

IMG_2433.jpg.      IMG_2432.jpg

Buena tarde!

Democrito

unread,
Apr 10, 2025, 3:11:42 PMApr 10
to FPGAwars: explorando el lado libre
Muchas gracias por las pruebas Carlos. Has montado un setup muy chulo con Lego incluido!

La mayoría de las veces es casi imposible saber qué tipo de pantalla tenemos porque la gran mayoría no lo pone en la serigrafía. Me refiero a saber si es una SH1106 o una SSD130X. Con el pin choose (o "typeScreen) se puede elegir esa opción. Te lo comento porque si en algún momento ves que algo no encaja del todo bien en la imagen significa que está en la selección incorrecta. Por defecto dejé configurada en todos los ejemplos la SH1106, y si es una SSD, pues pones ese pin a 0 y listos.

En tu caso, la pantalla izquierda se ve así porque está mellada, a mí también me sucedió con una al tratar de matar un mosquito, la pantalla saltó por los aires y al caer al suelo se melló en una esquina y dejó de funcionar bien, teniendo los mismo síntomas que la tuya.

Tu pantalla bicolor (aunque en realidad es monocromática, es decir, con zonas de color fija) tiene una línea negra en la parte de arriba y es así a propósito. Esa línea es normal, ahí no hay píxeles. Lo comento por si alguien no lo sabe.

Y poco más que comentar de momento.

Gracias por los testeos!

charli va

unread,
Apr 10, 2025, 3:22:29 PMApr 10
to fpga-wars-explora...@googlegroups.com
Gracias a ti Demócrito! por relanzar esto, nos lo vamos a pasar bien :)

Lo de la línea negra lo tengo contemplado, pero buen apunte por si alguien compra una, realmente esa franga amarilla como bien dices es color por defecto de la pantalla, no es que le digamos el color amarillo o azul, para ciertas aplicaciones puede ser muy útil, al final estas pantallas son ultra baratas y dependiendo de la aplicación esa línea te vale para separar dos áreas y destacar información de un modo diferente.

Ando mirando la documentación de los oled porque aunque quiero usar tus bloques a alto nivel quiero entender mínimamente como funcionan y sus limitaciones por si puedo ayudar a mejorar algo.

Sobre las piezas de lego, son breadboards con conectores "tipo lego" porque no son compatibles, pero son muy cómodas, a mi me gustan mucho, tienes los bloques tipo breadboard de diferentes tamaños y luego los paneles rojos donde pincharlos, proyecto en mente totalmente encolado pero que algún día retomaré de mecanizar los bloques para que desde la propia placa se pueda tomar alimentación e incluso pensar alguna forma sencilla de interconectar los bloques sin cables, pero bueno eso es otra historia para algún rato de aburrimiento XD

Democrito

unread,
Apr 10, 2025, 3:28:38 PMApr 10
to FPGAwars: explorando el lado libre
He ampliado la primera foto y ahí sucede lo que comentaba arriba:

choose.jpg

Si te fijas he señalado con un recuadro naranja lo que sucede al tener la pantalla seleccionada incorrecta. Cambia el pin "choose" que por defecto está a 1 y lo cambias a 0. Verás que saldrá perfecto. Me parece que tus pantallas son SSD.

Democrito

unread,
Apr 10, 2025, 3:41:35 PMApr 10
to FPGAwars: explorando el lado libre
Por si las moscas lo señalo en el circuito

pin choose.png

charli va

unread,
Apr 10, 2025, 3:44:42 PMApr 10
to fpga-wars-explora...@googlegroups.com
Efectivamente Amigo!en la rota sigue saliendo un artefacto de pixels perdidos pero se ha desplazado todo a la izquierda desapareciendo la banda que comentabas.

Lección aprendida! ;)

El jue, 10 abr 2025 a las 21:41, Democrito (<spo...@gmail.com>) escribió:
Por si las moscas lo señalo en el circuito

pin choose.png

--
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...@googlegroups.com.

Democrito

unread,
Apr 10, 2025, 4:30:55 PMApr 10
to FPGAwars: explorando el lado libre
Sobre cómo se configura y hacer funcionar este tipo de pantallas, te lo resumo brevemente aquí:

En I2C funciona así:

Pero antes de pasar a ello, hay que explicar una cosa sobre la dirección en I2C. La dirección en I2C son siempre de 7 bits, tanto para escribir como para leer (así es en Arduino). Pero si manejamos a pelo (en la FPGA por ejemplo) la dirección siempre ha de ser de 8 bits, que es lo que realmente vamos a enviar.
Ese bit que añadimos lo hacemos en el bit menos significativo (lsb). Y ese bit se llama R/W. Ponemos un 0 si vamos a escribir, y ponemos un 1 si vamos a leer.
En la Oled siempre vamos a escribir, nunca leer.

Si sabemos que estas pantallas I2C tiene la dirección 'h3C (que es de 7 bits) nosotros le añadimos un 0 al final (lsb) si vamos a escribir y se convierte en 'h78, ahora ya tenemos la dirección de 8 bits. Para hacer esto sólo hay que multiplicar por 2 y sale automáticamente.
3C * 2 = 78 (todo es hexadecimal)

La dirección es 78, el siguiente byte es un comando y sólo necesitamos saber dos comandos.

El 'h00 que significa = Todo los bytes que me siguen son comandos de configuración.
Y el 'h40 que significa = Todos los bytes que me siguen son para pintar en la Oled.

Al ponerse en marcha la Oled primero hay que configurarla y hacemos lo siguiente.

Le envío esto:

78 00 y todo esto que sigue:

AE // Turn off the screen
D5 // Oscillator speed
80 // the number on the left, if the value is too high, random dark intermittent horizontal lines appear. The figure on the right affects the refresh rate of the screen.
A8 // Set max rows to 0x3F = 63
3F // that is, it will go from 0 to 63, therefore we have 64 rows of pixels.
D3 // offset
00 // = 0.
40 // Set start of line to 0.
8D // Activate the 'charge pump'
14 // ?
20 // Horizontal writing mode;
00 // = 0.
A1 // Invert or not the X axis of the screen. With 'A0' reverse to how you see it.
C8 // Invert or not the Y axis of the screen. With 'C0' reverse to how you see it.
DA // Map COM pins
12 // if the mapping doesn't work for you with '12', try '02'.
81 // Contrast,
DF // in theory this value has to be between 0x00 (min) and 0xFF (max).
D9 // ?
F1 // ?
DB // ?
40 // ?
A4 // What is in memory is what it has to represent.
A6 // A6 Puts the screen in Normal mode; A7 puts the screen in inverted mode, in the sense of a photographic negative.
AF // Turn on screen.
00 // ?
10 // ?
40 // ?

Terminado de configurar la Oled ya podemos pintar en ella, pero como está configurada por paginación (esto se hace para hacer compatibles la SSD y la SH)
hemos de dar dos pasos y son los siguientes.

Primero le decimos en qué número de página escribimos y qué tipo de pantalla estás usando (SH ó SDD) se hace con comandos de esta manera y luego pintamos los 128 bytes de esa página:

Has de sabe que Bx la 'x' es la página, y el útimo "02" significa que escribes sobre una SH, si fuese una SSD en vez de "02" pondrías "00". En este ejemplo sería para una SH:

78 00 B0 10 02 <-- command for switching to page 0 (B0).
78 40 ..... Paint 128 bytes.

78 00 B1 10 02 <-- command for switching to page 1 (B1).
78 40 ..... Paint 128 bytes.

..... idem for pages 3,4,5,6

78 00 B7 10 02 <-- command for switching to page 7 (B7).
78 40 ..... Paint 128 bytes.

Y esto es todo lo que se necesita saber para manejar una pantalla Oled I2C.
----------------------------------------------------------------------------------------------------------------------
Ahora pasamos a las pantallas SPI.

En pantallas SPI no enviamos dirección, porque no tiene. Y para distinguir comandos de datos para pintar se hace a través del pin físico llamado DC (Data/Command)

Pues es hacer lo mismo que hemos hecho con el I2C, pero no enviamos 'h78, y para distinguir comandos de datos para pintar lo hacemos sobre el pin DC. Eso es todo.

Un croquis:

Democrito

unread,
Apr 10, 2025, 4:48:43 PMApr 10
to FPGAwars: explorando el lado libre
En muy pocos lugares te vas a encontrar esta explicación porque ya te lo dan todo hecho, por ejemplo en Arduino. Y en FPGA tengo diseñados los módulos I2C y SPI que eliminar la necesidad de conocer esos protocolos, y además son independientes de la longitud de bytes que quieras enviar.

Cuando me puse con esto sólo sabía dos cosas; que si enviabas 78 00 ...... eran comandos, y si enviabas 78 40 ....... era pintar en la Oled.

Lo que hice fue ver las señales a través de PulseView y analicé los patrones, al final comprendí que todo era mucho más sencillo de lo que parecía. El DataSheet puede servir pero hay que ser un dinosaurio y mucha experiencia que te respalde para llegar a comprender de verdad lo que el autor de forma extremadamente ortodoxa trata de explicarte.

charli va

unread,
Apr 10, 2025, 4:49:39 PMApr 10
to fpga-wars-explora...@googlegroups.com
Sin mirarme el módulo aún pero ya que estás explicando las tripas aprovecho XD

Entiendo que mandas 1vez la configuración y luego siempre pintas páginas una tras otra ¿es así?

Democrito

unread,
Apr 10, 2025, 5:05:31 PMApr 10
to FPGAwars: explorando el lado libre
Sí y no, te explico.

La primera vez que toqué este tema (hace años) pensaba que todas las pantallas eran iguales, yo tenía una SSD y con las SSD sí te permite hacer eso, configuras una sola vez y luego sólo pintas, esto último era enviando 1024 bytes a la vez.

Cuando descubrí que existía otro tipo de pantalla (la SH), ésta sólo funciona por paginación. La SSD también se puede manejar por paginación (te acepta los dos modos). Entonces, para hacerlas compatibles, desde entonces sólo trabajo con paginación. En Arduino también funciona así porque matas dos pájaros de un tiro.

Si funcionas por paginación (es un poco más complicado), primero has de indicar la página y modelo de pantalla (SH ó SSD) identificado como comando, como indiqué en el anterior post y luego has de enviar los 128 bytes que pinta esa página, identificando como datos para pintar. Esto se repite 8 veces, y en el comando identificas la página a pintar.



charli va

unread,
Apr 10, 2025, 5:07:15 PMApr 10
to fpga-wars-explora...@googlegroups.com
La verdad que al sacar este tema me han saltado unmontón de dudas y temas que dejé abiertos en su día, como por ejemplo los fps máximos. He estado viendo el datasheet y me ha sorprendido. En vídeos de youtube y demás he visto que la gente se tira al SPI porque dicen que va más rápido , incluso he visto vídeos con demos que efectivamente comparn uno y otro y va muy diferente (mucho más rápido el spi). Peeero viendo el datasheet y echando unos cálculos a las fórmulas que vienen, no tiene sentido. De echo creo que eso se debe a una mala implementación o auna limitación del micro.

Por qué digo esto, porque echando cálculos, contando con paquetes de comandos, etc,etc en i2c me salen unos 42FPS teóricos y en SPI una parbaridad....(simplemente por la velocidad posible teórica de comunicación pasas de ms a us en tiempos de actualización).

Por lo que por ahí dirías ok, es lo lógico, pero resulta que la pantalla tiene una frecuencia máxima interna de actualización que depende del oscilador interno y aunque faltan algunos parámetros, tomando valores estándar para los uqe no están definidos me sale que la pantalla va a refrescar entre 15 y 20fps como muchísimo.

Es decir en i2c y en spi debería de ser exactamente igual, poruqe el cuello de botella es la propia pantalla y no la comunicación como nos esperaríamos.

Como de momento no tengo una spi es todo teoría igual os pido hacer alguna prueba cuando lo tenga claro.

El tema es que quiero hacer dos cosas, por un lado usar tu módulo tal cual, lo que pasa que lo que he ido viendo se aleja de la naturaleza de refersco constante (está claro que la oled con la interfaz spi e i2c se aleja de la naturaleza de una pantalla tipo VGA, por lo que hay conceptos que no podrmos replicar pero en parte para optimizar los fps igual hay que cambiar cosas de la arquiectura que has planteado).

Siento el coñazo son pensamientos al aire. Buenas noches!

Democrito

unread,
Apr 10, 2025, 5:10:15 PMApr 10
to FPGAwars: explorando el lado libre
Tengo en mi GitHub una breve explicación de todo esto, que viene a ser lo que he comentado.

charli va

unread,
Apr 10, 2025, 5:21:34 PMApr 10
to fpga-wars-explora...@googlegroups.com
Creo que empiezo a entender cosas.... de echo que hayas hecho el ejercicio de ingeniería inversa con la pantalla y el arduino es muy interesante.

Si te he entendido bien usas el Page addressing Mode porque es el que tienen los dos drivers es así?

Sin embargo si usáramos el Horizontal Addressing Mode  sería mucho más óptimo, si la librería de arduino hace esto para compatibilizar las dos pantallas es un claro punto que hará que vaya más lento en i2c que en spi ya que se mandan comandos por cada línea (o uno de los motivos). con el modo de direccionamiento horizontal sólo se manda el comnado y luego los 1024 bytes del tirón. Si las dos pantallas soportaran este modo, sería super interesante la migración y olvidarte de las páginas.

Si no ya haremos una versión optimizada para las SD con este modo y lo compararemos, ahora estoy tirando solo dudas e ideas, no hagas mucho caso.



Democrito

unread,
Apr 10, 2025, 5:23:34 PMApr 10
to FPGAwars: explorando el lado libre
Para compatibilizar con una VGA ya sabes que no tengo idea, como tampoco detalles muy técnicos sobre estas pantallas. Pero está claro que como mínimo vas a necesitar una que funcione a través de SPI, al menos las comunicaciones son mucho más cortas, y no hay necesidad de enviar dirección ni comando.

A las malas, se podría hacer pruebas con una SSD que funciones con SPI, que te permite enviar 1024 bytes de golpe para pintar la pantalla. Esto sería lo más rápido posible. El problema: No se podría usar pantallas SH, no soporta el modo "bulk" (a saco paco), sólo paginación.

charli va

unread,
Apr 10, 2025, 5:25:07 PMApr 10
to fpga-wars-explora...@googlegroups.com
Luego otra cosa por lo que he visto en la docu, se podría probar (igual ya lo has hecho) en el comando D5 dela inicialización a poner un valor más alto , por ejemplo :

78 00 D5 F0   

Esto nos daría un valor cercano a los 20FPS máximos de la pantalla, habría que probar porque igual es muy alto y la pantalla genera artefactos porque no le da la vida, pero si funciona seguro que ganamos una manita de fps de lo que hasta ahora esté pintando. Esto es un tema simplemente de probar y ver que pasa con algo animado.


charli va

unread,
Apr 10, 2025, 5:30:52 PMApr 10
to fpga-wars-explora...@googlegroups.com
Si es lo que me imaginaba, como te digo el tema VGA en sí no tiene sentido, si el usar conceptos que valen para cualquier tema gráfico y podemos usar esto para ilustrarlo.

Lo del modo "bulk" es lo que denominan horizontal mode, mis pantallas son ssd así que lo probaré.

Y lo que te decía, según la docu no tiene ningún sentido el tema de que la velocidad mejore por spi o i2c, la pantalla no pinta a la velocidad que el i2c podría volcar paginando incluso. El tema es que en un micro pequeño como el spi acaba antes, el micro se libera para hacer cosas, con el i2c se queda bloqueado hasta que termina el envío y por eso  aparentemente parece que va más lento, pero en sí no es por el pintado sino por el micro, pero en nuestro caso que vamos a usar la fpga en modo "hardware" haremos cosas en paralelo y no se atascará esperando a nada como haría un micro secuencial, por lo que deberíamos obtener la misma velocidad con uno que con otro.

Si queremos usar esto como algo educativo estaría genia que algún ejemplo incluso lo hagamos en arduino si tu tienes experiencia con ello y asi podamos ver todas las opciones ventajas y desventajas.



Democrito

unread,
Apr 10, 2025, 5:32:09 PMApr 10
to FPGAwars: explorando el lado libre
Sobre ese comando tengo apuntado:

D5 // Velicidad del oscilador
80 // la cifra de la izquierda, si el valor es demasiado alto aparecen líneas horizontales aleatorias y oscuras intermitentes. La cifra de la derecha afecta al refresco de la pantalla.

Democrito

unread,
Apr 10, 2025, 5:36:23 PMApr 10
to FPGAwars: explorando el lado libre
Mañana tengo un día complicado, especialmente por la tarde, pero este fin de semana haré las pruebas de rendimiento, en Arduino y en FPGA

charli va

unread,
Apr 10, 2025, 5:48:35 PMApr 10
to fpga-wars-explora...@googlegroups.com
Si es lo que te comentaba, la pantalla tiene un oscilador interno, en la docu viene la relación de los fps que dependen de ese oscilador:

Captura de pantalla 2025-04-10 a las 23.42.23.png
Yo me he echado los cálculos y el valor que pasas es el valor estándar (entre 300 y 400Khz) no me queda muy claro en la docu los valores he tirado un poco de imaginación, la idea es que si del valor que colocas ahora que es por decirlo de alguna manera el valor estándar, lo vamos incrementando, podemos llegar a encontrar el máximo límite (que debería estar  entre 15-20fps como mucho). El tema es que si sobrepasamos el valor máximo que físicamente la pantalla puede pintar, se generarán artefactos (líneas, zonas sin pintar, efectos de aliasing....) . El valor que te paso es una idea, hay que probarlo, si con ese valor falla, se podría probar a ir bajándolo hastaque se vea bien.

Un ejemplo donde podrías testar esto es con la pantalla spi con el ejemplo del triángulo y ver si al subir los fps, mientras no se rompa la imagen si mejora la visualización.

Democrito

unread,
Apr 10, 2025, 7:22:00 PMApr 10
to FPGAwars: explorando el lado libre
Te comento las sensaciones.

- He tomado el ejemplo de rotación de triángulo, con una pantalla Oled SH por SPI. Recuerda que en la configuración por defecto es D5 80.
- He modificado la velocidad de rotación, de 20 ms lo he puesto al mínimo en milisegundos, 1 ms.
- Lo subo, y veo que gira muy rápido.

- Ahora he modificado D5 80 por D5 F0. Todo lo demás sigue igual (1 ms por fotograma).
- Lo subo
- Veo que gira muy rápido y se ve bien, sin problemas aparentes, y ocurre otra cosa más, da la sensación de que ahora, por girar tan rápido, sale el efecto ese como las ruedas de los coches en las pelis, que parece que gira al revés (esto es un efecto porque no es continuo sino por fotogramas)

Después he probado en I2C con una SSD (es decir, como la tuya).
En I2C he repetido lo mismo, todo sale bien (sin nada raro) pero no noto diferencia entre D5 80 y D5 F0.

Todo esto lo verás mejor cuando lo pruebes, porque trabajar así es como la peli aquella de "No me chilles que no te veo"

Para modificar ese dato (D5 80 vs D5 F0) y estando con pantalla I2C y con SSD, lo puedes hacer así.

Abres el módulo principal y verás esto.

config D$ F0.png
Y verás en las primeras líneas

D5
80

y el 80 lo cambias a F0

Te sales y pruebas a ver si sale algo extraño.

Te adjunto el circuito ya puesto a 1 ms, sólo has de modificar el comando D5. Es para I2C.

Nota, pese a que en la caja de configuración pongo "cfg-sh", lo puse así porque es por paginación, no por la pantalla en sí. Es una nomenclatura que quedó así por despiste, se tendría que haber llamado simplemente "config".

Te adjunto el ICE I2C puesto a 1 ms, pero te adelanto que no se nota la diferencia el tema de la configuración (D5 ...). En SPI si se nota algo. Cuando tengas la pantalla SPI y podamos hacer pruebas en paralelo es como mejor podemos coordinarnos.

repito, con D5 F0 no me ha salido nada extraño, tanto en SPI como en I2C, al menos con este ejemplo de triángulo que gira.
Example_Spinning_triangle_I2C.ice

Democrito

unread,
Apr 10, 2025, 7:31:01 PMApr 10
to FPGAwars: explorando el lado libre
Perdona Carlos, el adjunto (ICE) no es el correcto, es este que te pongo ahora. Es para la SSD y los pines SDA y SCL como D1 y D0 respectivamente.
Example_Spinning_triangle_I2C.ice

Democrito

unread,
Apr 11, 2025, 3:28:02 AMApr 11
to FPGAwars: explorando el lado libre
Acabo de hacer pruebas de rendimiento en FPGA.

He improvisado un frecuencímetro a la salida de "done" del módulo que controla la pantalla. Para ver la frecuencia sólo hay que abrir el terminal serie. Ahí nos dará la frecuencia máxima en la que está trabajando.

Conclusiones:

- Lo de cambiar de 20 ms a 1 ms no tiene ningún efecto, es un efecto óptico. No tiene nada que ver con la pantalla en sí, sólo con el gráfico que ha de representar, que en este caso es un triángulo que rota.

- En I2C (el tuyo) me da una frecuencia de refresco de pantalla de 34 veces por segundos. Si modifico lo de "D5 80" a "D5 F0" no afecta en absoluto, sigue marcando 34 veces por segundo.

- En SPI me da una frecuencia de refresco de pantalla de 279 veces por segundo. Si modifico lo de "D5 80" a "D5 F0" no afecta en absoluto, al igual que en I2C

- En ambos casos (I2C y SPI) he probado a poner "D5 FF" sin resultado; como tratando de poner ese parámetro a tope.

Te adjunto los circuitos de prueba con el añadido de la improvisación del frecuencímetro. Para ver la frecuencia has de abrir el terminal serie. Está por defecto a 115200 baudios.
Rendimiento_SPI.ice
Rendimiento_I2C.ice

Democrito

unread,
Apr 11, 2025, 3:30:04 AMApr 11
to FPGAwars: explorando el lado libre
En el caso del SPI, la tengo configurada como SH porque es lo que tengo. Para I2C sí es como la tuya y es una SSD

Democrito

unread,
Apr 11, 2025, 3:36:29 AMApr 11
to FPGAwars: explorando el lado libre
Ten en cuenta que dentro del módulo OLED hay un algoritmo de Bresenham y le damos 4 puntos para representar una línea. Lo que quiero decir es que esa parte resta algo de tiempo porque hasta que no se "computa" las líneas y las mete en la memoria no se representa.

Esto significa que si sólo tratamos de volvar la memoria en la OLED a máxima frecuencia, seguramente irá más rápido.

Se me acaba de ocurrir una idea, ahora vengo. 

Democrito

unread,
Apr 11, 2025, 3:51:01 AMApr 11
to FPGAwars: explorando el lado libre
Acabo de hacer una prueba de la velocidad máxima y... apenas cambia.

Cuando la pantalla termina de imprimir (por tanto, visualizarse) sale un tic por "done". Ese tic lo uso para hacer "print", es decir, que están en realimentación contínua. Una y otra vez imprime la imagen.

En I2C me sale (en vez de 34) casi 35. Esto significa que en el ejemplo que puse del triángulo que gira, calcula las líneas de forma muy rápida.

Te adjunto el ICE que he usado.

a_saco_paco_I2C.ice

Democrito

unread,
Apr 11, 2025, 4:00:55 AMApr 11
to FPGAwars: explorando el lado libre
En SPI me sale (en vez de 279) 318, de frecuencia de muestreo por segundo.

Adjunto ICE con el que he realizado la prueba.

Democrito

unread,
Apr 11, 2025, 4:08:29 AMApr 11
to FPGAwars: explorando el lado libre
ups, falta el adjunto. Lo dejo aquí añadido.
a_saco_paco_SPI.ice

charli va

unread,
Apr 11, 2025, 4:28:23 AMApr 11
to fpga-wars-explora...@googlegroups.com
Menudos tests! Enhorabuena! Lo único tienes algunos conceptos equivocados no se puede medir así la frecuencia.

Ahora me es imposible pero esta tarde respondo con calma sobre tus ejemplos e intentaré explicar los problemas de concepto.

Vamos a exprimir la oled al máximo!

charli va

unread,
Apr 11, 2025, 5:51:05 PMApr 11
to fpga-wars-explora...@googlegroups.com
Buenas a todos, este mensaje igual es largo, intentaré no ser pesado y alargarme más de la cuenta, pero creo que es importante si queremos exprimir la pantalla y llevarla más allá de sus límites comerciales 😉🙌 entender cómo funciona (además de que hablaremos de conceptos que se pueden llevar a otros dispositivos y sistemas gráficos). La verdad que el hilo me motiva mucho si salen cosas interesantes se merecerá un buen documento técnico.

A ver, voy a intentar explicar por qué te he comentado que aunque las pruebas que has hecho tienen una buena intención, no valen realmente para medir los fps de la pantalla.

Primero hay que entender como funciona la OLED. El objetivo de esta pantalla para sus fabricantes posiblemente no buscan que te vayas a ver una película o te montes algo muy complejo visualmente, al final son pantallas muy baratas y de una gran simplicidad de manejo que buscan que al usuario le sea fácil crear pantallas visuales, informativas....

Sea por interfaz SPI o I2Cl, la pantalla da sensación al usuario de ser persistente, es decir, si lanzas una imagne, una fuente, una línea, esta se queda ahí fija mientras no sobreescribas esos pixels. El usuario desde donde la programe, sea una FPGA o un arduino, no tiene que preocuparse de repintar la pantalla continuamente, simplemente manda los pixels a pintar en un momento dado y no tienes que preocuparte más. 

En otros displays, como una pantalla VGA la complejidad es mayor porque no existen comandos como tal para pintar o limpiar la pantalla sino que hay que hacer todo el trabajo a mano. En qué consiste el flujo en una VGA? vamos a verlo porque es clave entenderlo para entender bien la OLED.

En la VGA hay un sistema electrónico que recorre cada pixel de la pantalla por lineas , de arriba a abajo, es decir empieza por la esquina superior izquierda, avanza hasta el final, vuelve al inicio pero bajando una línea de pixels, avanza hasta el final, vuelve al inicio bajando otra línea ..... y así hasta completatr todos los pixels de la resolución en la que estemos trabajando.

Esto recrea el tubo de rayos de los monitores antiguos, los monitores tenían un cañón que recreaba este movimiento en zig-zag, línea a línea recorriendo la pantalla. Hoy en día no hay cañón de rayos pero las pantallas recrean este funcionamiento.

Para que podamos pintar los pixels en su sitio correspondiente y a tiempo , la pantalla nos da una serie de señales de sincronización. Nos manda una señal cuando termina de pintar una línea (refresco horizontal) y una señal cuando termina de pintar toda la pantalla (refresco vertical)  (el pintado va de forma autónoma, la pantalla no está esperando a que le digamos ¡pinta!, sino que ella va pintando y somos nosotros los que tenemos que darle los datos en el momento preciso).

Con estas dos señales ya sabemos cuándo tenemos que empezar a pintar (por ejemplo después de un refresco vertical), o cuando tenemos que cambiar de línea. 

Pero nos falta algo importante que es, cómo sabemos cuando hay que cambiar de pixel, para poder ir dándole pixel a pixel, justo cuando lo necesite. Esto se obtiene con el reloj de pixel o como se quiera llamar que va relacionado con el refresco de la pantalla.

Cuando leemos por ejemplo "resolución VGA 640x480 a 60Hz", esto quiere decir que vamos a pintar visualmente 640x480 pixels 60 veces por segundo, es decir vamos a pintar 307200 pixels cada 1/60 segundos (a esto en vga hay que sumarle áreas de pixels que no se ven en las áreas exteriores de la pantalla pero ahora por simplicidad las vamos a obviar, lo importante es el concepto.

Eso quiere decir en un segundo quiero pintar: 307200 píxeles/cuadro×60 cuadros/segundo=18432000 píxeles/segundo.

Eso quiere decir que simplificando si queremos pintar cada pixel en un ciclo de reloj necesitaremos una frecuencia de 18.432 Mhz

Entonces recapitulando, tenemos nuestro sistema ficticio a una resolución de 640x480 pixels a 18.432Mhz lo que no permite pintar la pantalla 60 veces por segundo lo que hace que el movimiento sea super natural, no haya flicks de pantalla,etc (si habéis visto alguno de los últimos hilos de VGA veréis que el reloj es mayor, esto es por lo que os comentaba que en un sistema VGA hay que contar con pixels no visibles, pero insisto en que esto es una simplificación para entender el concepto).

Seguimos con los conceptos ya sabemos lo que implica pintar los pixels a esta resolución, entonces ahora viene un típico lío mental ¿qué son los FPS? si os fijais muchas veces se mezclan los dos conceptos (en videojuegos, etiquetas en monitores....)....

Por un lado está el sistema de la pantalla, que SIEMPRE, va a pintar 60 pantallas por segundo, cambie o no cambie la información. Teneis que imaginaros como si fuera una máquina en bucle que va cogiendo de la memoria cada pixel y lo pone en pantalla, uno tras otro sin parar y cuando acaba vuelve a empezar y así infinitamente.

Esto como quien dice es incontrolable por nuestra parte, la pantalla no va a parar de pintar jamas ni la podemos frenar ni acelerar.

Ahora bien, entra en juego la aplicación del usuario, aquí el ejemplo de Demócrito viene perfecto, cuando dice que dentro del módulo está el algoritmo de bresemhan y tarda un rato en procesarlo.....

Se abre un nuevo "espacio-tiempo",  es como si se desdoblara la realidad y tuviéramos dos universos paralelos a diferente tiempo, uno, en el que vive la pantalla qeu va como una moto y nada le frena y pinta y pinta sin parar.  Y por otro está el universo de la aplicación del usuario que tiene que hacer cosas antes de "mandar a pintar".

Vamos a ver el sistema completo con un único reloj, el de los 18.432Mhz. Como la pantalla y el aplicativo se rigen por la misma velocidad quiere decir que para pintar a 60 FPS, tendría que poder decidir que pintar en cada pixel en 1 ciclo de reloj, lomismo que la pantalla pinta. Aquí algo ya chirría... necesitaríamos empezar 1 ciclo antes que la pantalla, imaginaos coloco en la primera dirección de memoria el primer pixel, y cuando detecto la señal de sincronización vertical (se ha acabado de pintar un cuadro y empezams de nuevo a pintar), entonces escribo el pixel 2 de forma que cuando la aplicación escribe el pixel 2 la pantalla está pintando el 1, cuando yo escribo en memoria el pixel 3 la pantalla pinta el pixel 2 (la pantalla nos persigue). De esta formasi en un caso ideal en el que por ejeplo tengo los frames de una película almacenados en una memoria en la que puedo acceder frame a frame y pixel a pixel en 1 ciclo de reloj, podría pintar a 60 FPS, es decir FPS a mi me gusta verlo como los frames por segundo del usuario.

Como veis esto sería un caso ultra ideal, pero en la realidad es algo imposible. Al mismo ciclo de reloj por ejemplo, sólo en acceder a memoria se nos iría más de un ciclo y si hay que hacer algún cálculo , por ejemplo para la línea con el algoritmo de bresenham se nos irá más de uno y dos ciclos por cada pixel.

De esta forma la aplicaciónd el ussuario va a tener menos FPS que Hz de la resolución, es decir si por ejemplo tardamos el doble de tiempo en preparar una pantalla que en pintarla pues nos dará tiempo a pintar a 30FPS. Esto se ve claramente cuando en un equipo antiguo se pone un videojuego moderno, de repente va todo a "tirones" por qué pues porque nuestro equipo no es capaz de hacer los cálculos necesarios para pintar a 24-30FPS mínimo que da una fluidez natural, en cuanto baje a 15-12FPS  el usuairo notará que va a trompicones y ya si el cálculo es muy pesado y bajamos a 10-5-1FPS pues literlamente no se podrá jugar. En todos esos casos , desde el de 50, 30, 15-1FPS la pantalla sigue pintando a 60Hz, es decir 60 pantallas por segundo, lo único que pinta varias veces la misma pantalla.

Otra opción que por ejemplo ocurre en equipos modernos o contarjetas gráficas más modernas es que el reloj del sistema y el de la pantalla son diferentes. La pantalla sigue llendo a sus 18.432Mhz pero elsistema va mucho más rápido por lo que en un momento dado podría pintar los 60FPS que se necesitan para pintar los 60Hz (imaginemos por ejemplo qu eel sistema va a cientos de Megaherzios o a gigaherzios).

Como veis es un tema de sincronización, a groso modo eso es en lo que se basa todo el tema de display gráfico.


En el ejemplo estamos suponiendo que la misma memoria destinada a almacenar lo que se ve en pantalla es la que se recorre para plasmarse físicamente en la pantalla que vemos. Como podemos intuir se pueden dar varios problemas. Los más comunes:

- Tearing, puede ser por defecto o por exceso. Imaginemos que la aplicación rellena más rápido la memoria que la pantalla pinta. En este caso lo que ocurre es que la pantalla va pintando y por ejemplo si la aplicación rellena la memoria al doble de velocidad que la pantalla pinta, se da el caso que a mitad de pantalla (hemos pintado ya la mitad superior de el frame 1), la aplicación ya ha rellenado la memoria con el frame 2, de este modo la pantalla a a pintar la mitad inferior con el frame 2, es decir tendremos simultáneamente la mitad del frame 1 y la mitad del frame2 y a´si sucesivamente. 

Y puede pasar al revésque rellenemos más lentos de lo que la pantalla pinta y la pantalla nos coma.

en cualquiera de los dos casos lo que ocurre es que empiezan a generar artefactos visuales inconsistentes , si hay movimiento pueden darse superposiciones, flicks o sensaciones visuales raras.

En este vídeo se ve muy bien el ejemplo:


Como en el scroll se come el frame a mitad o antes de acabar el anterior las barras se sienten "partidas".

- Aliassing, este efecto es como lo que decía Demócrito de la bicicleta, aquí lo que ocurre es que rellenamos la  memoria mucho más rápido de lo que la pantalla pinta, entonces qué ocurre que por ejemplo empezamos a pisar frames y si por ejemplo tenemos imaginemos un video de una rueda de bicicleta dando vueltas, en vez de pintar los frames 1,2,3,4....al pisarlos porque pintamos muy rápido, lo que se pinta en pantalla es el 1,3,6,8,11.... es decir se saltan frames lo que visualmente genera el efecto de la rueda que parece que empieza a ir para atrás (Esto ocurre porque nuestro cerebro no puede procesar todos los "frames" de la rueda girando a mucha velocidad y al saltárselos se genera ese efecto visual de cambio de dirección) O por ejemplo habréis visto alguna vez el típico vídeo en el que el agua slaiendo de un grifo parece estar congelada, esto es porque se sincroniza el framerate dela grabación de la cámara con el de la velocidad del agua y al saltarse frames  de forma sincronizada, el agua parece no moverse en el vídeo y así mile de ejemplos (helicópteros volando con las aspas paradas.....) Aquí tenéis unejemplo de undersampling https://www.youtube.com/watch?v=ByTsISFXUoY , si no queréis ver todo el vídeo lo podéis ver en el minuto y treinta y siete segundos aproximadamente donde la hélice parece estar parada.

Todo estos son problemas de sampleado que se da en los ADC  por ejemplo (todo converge siempre a niquist XD ).

Para evitar esto habréis oído hablar del "doble buffer" en temas de vídeo, esto básicamente es tener dos memorias, una en la que la aplicación va creando el siguiente frame y otra en la que está el frame que se está pintando. De este modo se solucionan muchos problemas porque el aplicativo puede tardar lo que necesite en terminar el siguiente frame en la memoria que no se ve, y cuando acaba, lanza una copia de esa memoria a la de pintado (sincronizado con el refresco vertical para que se empiece el nuevo frame desde la esquina superior izquierda ). 

Como podéis intuir esto hace que todo vaya más suave y sincronizado, aquí solo aparece el problema de bajos FPS, es decir que tarde mucho en pintar y aunque vaya sincronizado te tengas que saltar frames naturales. El aliassing desaparece porque el ritmo va marcado por las sincronizaciones verticales y eso "frena" al sistema si tiene capacidad de ir muy rápido, así nunca se pisan frames, es decir con doble buffer en principio sólo tenemos el problema de no dar de si y que la aplicación se sienta lenta.

En cualquier caso sigo insistiendo en tener claro que la pantalla se pinta a 60Hz, el buffer de pintado no frena , va como un reloj suizo.


Teniendo esto claro , espero haberme explicado bien, vamos a retomar el caso de la oled de 128x64

en este caso la oled "oculta" al usuario los problemas de sincronización. La pantalla lleva un pequeño micro que gestiona todas las señales de pintado y los sincronismos y lo que expone al usuario es una interfaz i2c o spi de forma que el usuario sólo se tiene que preocupar de enviar pixels y direcciones de memoria de dónde pintar.

Como he dicho anteriormente para aplicaciones sencillas, que no necesiten FPSs altos (displays con números , mensajes de texto, etc) es más que suficiente, si enlazáis con lo anterior, no hay ningún tipo de sincronización entre pantalla y datos.

Internamente el micro de la OLED tiene su propio oscilador que define la frecuencia de pintado (nuestros famosos 60Hz anteriores), la fórmula es la que os comenté en un post anterior y que viene en la documentación, echando cuentas no debe tener un refresco mayor a 15-20Hz es decir la pantalla OLED en el mejor de los casos va a pintar 20 imágenes por segundo.

Este oscilador es el que podemos tocar con el registro D5, lo que pasa que está bastante mal documentado y por lo que he podido investigar cada pantalla de cada fabricante puede tener un oscilador a diferente frecuencia (unos puede ir a 300Khz otros a 400Khz..pero todos entorno a estos valores).

Este micro, hace la labor del sistema de pantalal denuestro ejemplo. La pantalla OLED tiene su propia memoria (una SDRAM) que es la que se rellena con los datos ue mandamos por i2C o SPI. 

El micro una vez inicializado, hace la labor de nuestro sistema de pantalla del ejemplo, PINTA SIN PARAR, es decir empieza por la dirección de memoria 0 y se la recorre entera desde la esquina superior izquierda hasta la esquina inferior derecha (independientemente de modo de pintado seleccionado en el I2C). 

Es decir la pantalla nos genera una ilusión de pantalla persistente, pero físicamente no lo es (no es como una pantalla de tinta electrónica en la que físicamente se reconfiguran las propiedades de los pixels y cambian de estado). Para dar la sensación de que la información no se va aunque desde el arduino o la FPGA no mandemos información , simula esa persistencia con el micro interno, que pinta y pinta sin parar.

Todo el tema de paginación etc es una interfaz de cara a los usuarios de la pantalla (nosotros) internamente como os digo la pantalla funciona de forma similar al eejmplo que os he puesto.

De este modo aquí existen dos universos paralelos. Por un lado está el universo del micro que vive en la pcb de la pantalla que pinta a a10-15-20Hz en función de lo configurado en el registro D5 y la marca de la pantalla. y por otro lado está el universo de nuestra aplicación en la FPGA, en el Arduino.... Como son dos universos paralelos, Demócrito que habita en el universo SPI que va a toda velocidad, se lia a mandar frames a diestro y siniestro pero en el universo de la pantalla no va a pintar más rápido. Lo que ocurre es que Demócrito está pisándose sus propios frames, cuanto más rápido pinte más frames se va a saltar porque la pantalla irá a su ritmo y nosotros no haremos más pisar la memoria.

Por este mismo motivo aparecen artefactos raros , flicks, etc (no vamos sincronizados).

Gente que está usando esta pantalla para pequeños ordenadores educativos y cosas similares se enfrentan a este problema porque cuando quieres hacer animaciones en estas pantallas la sincronización no es posible de forma natural.

Viendo la documentación, resulta que hay un pin que marca la sincronización de la pantalla (como lo hace el sincronismo vertical en la VGA) pero resulta que no está expuesto en el conector soldado de la parte trasera, está junto al microtras la pantalla o debajo de ella (el micro muchas veces está debjo de la pantalla en la propia tira flexible bajo un pegote negro.

Esta semana no tengo equipamiento a mano pero si os interesa ( a mi me ha picado) en cuanto tenga a mano mi equipo igual disecciono la pantalla que tengo rota e intentamos pinchar el pin de sincronización para ver el refresco real y su relación con  el parámetro D5 y así saber claramente a qué frecuencia vamos.

Otra forma de probarlo así "cutre" sería tomar dos imágenes muy distintas para notar el cambio e ir probando diferentes frecuencias y cambiar cada segundo una por otra (ir probando a 5fps,10fps,etc...) hasta ver en cual el cambio es natural y no se parte hace algun raro. Lo que pasa que surge el problema de saber cuando empieza cada frame. Es complicado la verdad he estado mirando bastante y no hay soluciones buenas si se quiere hacer cosas chulas con esta pantalla.

Le ando dando vueltas a esto porque tengo varias ideas chulas que quiero probar y dependen de poder sincronizarnos (la verdad que daba por hecho que existiría uncomando o algo que nos permitiera saber cuando se hace el sync del frame pero me he llevado una buena sorpresa).

Retomando lo anterior y mi mensaje antes de las pruebas de Demócrito en estas pantallas tanto en SPI como en I2C da igual porque en ambos los FPS máximos son perfectamente asumidos por la velocidad de los dos buses (siempre que quieras ir sincronizado más o menos y no comerte  frames).

La diferencia y por eso en muchos vídeos tiran del spi a tope es porque en micros tipo arduinos en los que la programación es básicamente secuencial o pseudoparalela, la aplicación espera a pintar para seguir procesando, entonces en ese caso el spi es mucho mejor, porque al transmitir más rápido nos libera para poder seguir procesando y en muchos casos puede hacer que en spi la aplicación vaya super fluida (orque transmite en menos de 1ms un frame y ya te puedes poner a calcular el segundo y en i2c tarda 23ms por frame por lo que has perdido todo ese tiempo para calcular cosas lo quepuede implicar que tardes más en calcular y al final pierdas frames efectivos.

En la FPGA cambia bastante el panorama, porque podemos paralelizar el proceso de la información y el envío y crear un pipeline no bloqueante (un ejemplo estupendo de la ventaja de una FPGA frente a un arduino por ejemplo en una aplicación de este tipo que es una cosa mítica que la gente suele preguntar muchas veces,....esto también lo hago con un Arduino...). En este caso como el sistema que traslada a la pantalla va paralelo a generar el frame, la velocidad de transmisión no es cuello de botella para los Hz máximos de la pantalla.

En conclusion, las pruebas ue ha hecho demócrito prueban el ancho de banda del bus gráfico pero no del refresco de la pantalla (es decir has medido lo rápido que puedes mandar frames en un sistema y en otro, aunque en cualquiera de los casos se pinte al mismo FPS).

Me ha quedado más largo que la biblia en verso, espero que al menos al que le interese le haya sido ilustrativo  y ayude a aclarar conceptos super importantes tanto para la OLED como para cualquier otro display gráfico.

En la OLED quiero hacer algún ejemplo animado sencillo para familiarizarme con el módulo de Demócrito y ando leyendo documentación a ver si se me ocurre como sincronizarnos verticalmente, que tengo una idea peregrina que creo que puede funcionar pero tengo que experimentar un poco antes de contaros. Una pena que no sea fácil de pinchar el pin de sincronización, nos haría la vida mucho más fácil.


Vamos avanzando iré compartiendo avances en cuanto los vaya teniendo, espero que aunque largo os haya servido de algo.

Buenas noches!

Jesus Arias

unread,
Apr 12, 2025, 4:59:16 PMApr 12
to FPGAwars: explorando el lado libre
Hola, buena clase nos has dado (sólo han faltado las pantallas vectoriales, como la de "Asteroids"... Aquí los FPS siempre cuadran ;)
Quería añadir otro video curioso con el "subsampling" , o como otras veces lo hemos llamado: "efecto estroboscópico". (El detalle está en las cuerdas de la guitarra)
Saludos

charli va

unread,
Apr 12, 2025, 5:20:42 PMApr 12
to fpga-wars-explora...@googlegroups.com
Cuando terminé el correo dije... madre mía...... esto no se lo va a leer nadie XD 

Buenísimo el videoclip, a parte del tema musical, un crack el que ideo el videoclip y como ejemplo para estos artefactos visuales me lo apunto porque me ha encantado.

Las pantallas vectoriales son tecnología marciana, jeje , una pasada la verdad, en algún momento tendremos que sacarlas a la palestra.....

Reply all
Reply to author
Forward
0 new messages