sábado, 20 de agosto de 2011

Adaptador de control de SNES a MapleBUS (Las vacaciones han terminado).

En efecto, las vacaciones de verano han llegado a su fin, y con ello, el deadline del proyecto de vacaciones (que de hecho empezó desde las vacaciones de Semana Santa) ha sido alcanzado. Pues, con una semana de retraso, por fin realicé las pruebas finales y el proyecto funcionó.

MapleBUS es una interfaz de comunicación bidireccional digital half-duplex (es decir, en un instante dado sólo puede transmitir información en un sólo sentido) que es capaz de transmitir información a una tasa de 2[Mb/s]. A nivel físico, la interfaz cuenta con cinco terminales:
  • 1.- SDCKA (Serial Data and ClocK A) Rojo
  • 2.- VCC (5[V]) Azul
  • 3.- Ground (0[V]) Negro
  • 4.- Sense (0[V]) Verde
  • 5.- SDCKB (Serial Data and ClocK B) Blanco

A nivel lógico, para la transferencia de información se emplean las terminales SDCKA y SDCKB. De forma general, cuando una de las terminales cambia su nivel de voltaje desde nivel alto (3.3[V]) a GND (es decir, ocurre un flanco de bajada), la interfaz detecta un ciclo de reloj y recoge como dato el nivel de voltaje que tiene la otra terminal. Por ejemplo, supongamos que tanto SDCKA como SDCKB tienen un nivel de 3.3[V], si SDCKA cambia de 3.3[V] a GND, la interfaz toma como dato el nivel de voltaje en SDCKB, en este caso 3.3[V] o "1 lógico". De esta forma se alternan los roles de las terminales SDCKA y SDCKB, ya que mientras una es "reloj", la otra es "dato". Esto permite que a pesar de que la frecuencia de cada señal es de aproximadamente 1[MHz], la interfaz tenga una frecuencia de 2[MHz].

Es una interfaz relativamente compleja de implementar en un microcontrolador, debido a que la mayoría de los microcontroladores de bajo costo sólo permiten leer niveles de voltaje en sus puertos. Algunos permiten detectar cambios de niveles o flancos (tanto de subida como de bajada), lo cual puede activar una interrupción y da la posibilidad al microcontrolador de actuar en consecuencia a los cambios de nivel. Sin embargo, el manejar interrupciones da lugar a un proceso relativamente complejo y lento que no es adecuado para una interfaz veloz.

Por ejemplo, supongamos un microcontrolador AVR trabajando a una frecuencia de 20[MHz] (el límite nominal para muchos ATTINY y ATMEGA), la detección de un flanco de bajada por alguna de las terminales INT0 o INT1 lleva 3 ciclos de reloj, el salto a la interrupción lleva 3 ciclos más, el recoger el dato del puerto lleva un ciclo, almacenarlo en alguna variable puede llevar uno o dos ciclos dependiendo del destino, volver al flujo del programa desde la interrupción lleva 4 ciclos de reloj. El procedimiento anterior consume 12 ciclos de reloj en el mejor de los casos (ya que en el ejemplo no se discrimina entre flanco de subida o bajada ni tampoco se ordena el bit en algún latch), lo cual es demasiado lento, ya que leer dos bits llevaría 24 ciclos de reloj. Dado que la interfaz transmite 2 bits cada [us] y el microcontrolador trabaja a 20 ciclos por [us], es posible notar el déficit de velocidad.

Es posible utilizar registros de corrimiento SIPO (Serial Input - Parallel Output) y latches para capturar los datos y retenerlos mientras el microcontrolador los procesa o leer los datos a través de la técnica de "polling". El polling consiste en monitorizar en un ciclo el estado de una variable o puerto y actuar acorde a él sin emplear interrupciones. Esta técnica es muy ineficiente, sin embargo es una alternativa viable en términos de velocidad y complejidad de circuito.

Gracias a la información otorgada por Marcus Comstedt y Sodor (A.K.A. leucemidus) fue posible implementar esta interfaz.

El primer (y hasta el momento único prototipo) utiliza sólo un ATTINY25... y nada más n_n. De hecho, pueden agregarse resistencias para proteger los pines conectados a la interfaz (47 o 68 omhs deben estar bien), un capacitor electrolítico de 10[uF] entre VCC y GND para proteger al microcontrolador de los transitorios al momento de conectar la interfaz y un capacitor cerámico de 0.1[uF] entre VCC y GND para quitar el ruido inducido por la longitud de los cables. El esquema de conexiones es el siguiente:

La configuración de fusibles es la siguiente:
  • Low fuse: 0xE1
  • High fuse: 0xDD

El firmware lo pueden encontrar en la siguiente liga:
Firmware
Pueden grabar en el chip de un solo golpe tanto el firmware como los fusibles usando el avrdude, con un enunciado como el siguiente:
avrdude -c "PONGA AQUI EL NOMBRE DE SU PROGRAMADOR" -p attiny25 -U flash:w:main.hex -U hfuse:w:0xdd:m -U lfuse:w:0xe1:m -U efuse:w:0xff:m


En mi caso, la línea de comando queda:
avrdude -c usbtiny -p attiny25 -U flash:w:main.hex -U hfuse:w:0xdd:m -U lfuse:w:0xe1:m -U efuse:w:0xff:m


Ahh, como nota al pie, el botón SELECT del control no hace nada. En mis pruebas, reutilicé uno de los ATTINY25 que empleé en el adaptador a USB, por lo que su valor en el registro OSCCAL no era de 0xFF, sino de 0x57. Sin embargo, aún con un valor de 0xFF en OSCCAL no debería dar problemas.

Por si hay alguien que se pregunte qué hace esto, la respuesta es simple: sirve para conectar un control de SNES a la Dreamcast n_n. Ahora todo tiene sentido para los que se preguntaban ¿Para que necesita el pseudo-nerd llevar la frecuencia del control de SNES de sus cómodos 83.33[kHz] hasta 1[MHz] en una interfaz USB que sólo pide el estado de los botones 100 veces por segundo? El adaptador para USB en realidad sólo era el banco de pruebas de este proyecto.

¡Feliz 2021! El retorno del debraye pandémico (Edición "Rompemuros").

Hola, ¿Cómo han estado? Espero que estén con bien, con buena salud y con muchas ganas de aburrirse una vez más con una ronda de debrayes. Es...