Problemas tecladiles (7)

¡¡Hace unos días me han llegado las placas de PCBWay!! Pero como estuve fuera, hasta hoy no he podido poner nada.

Se trata de la versión 1.17 del teclado, que frente al diseño 1.0 de los teclados que construí hasta ahora, tiene tres NeoPixels, huella para el protector ESD, correcciones de compatibilidad con Teensy, serigrafía en los pines de programación, y algunos otros detallitos menores (como el maravilloso recuadro blanco para escribir anotaciones). Y el acabado es, sencillamente, perfecto. ¡Un 10 para PCBWay!

Después de la experiencia que he tenido, creo que estos teclados los voy a construir con pulsadores Cherry «de verdad». Iré contando.

Problemas tecladiles (5)

Recientemente estuve haciendo algunos cambios extra en el diseño. Por ejemplo, combiné en ambos diseños la tecla SHIFT corta + tecla de «menor y mayor» de las distribuciones ISO, junto con la tecla SHIFT larga de las distribuciones ANSI. Esto permite combinar distribuciones, algo que puede ser interesante para aquellos que prefieran la tecla de RETURN americana, pero quieran usar una distribución española, por ejemplo.

También aproveché para añadir dos NeoPixeles más en los dos huecos que había entre F4 y F5, y F8 y F9, lo que permite aumentar las posibilidades.

Por supuesto, llegó también el momento de diseñar la carcasa, para lo que decidí aprovechar los resultados de un cursillo de diseño e impresión 3D que hice hace tiempo (¡¡¡¡Gracias por convencerme para ir, Miguel!!!!). No tendría que ser demasiado difícil…

El primer problema que me encontré fue que el teclado mide 32cm de ancho, pero las impresoras 3D normales tienen una cama de entre 20 y 30cm, lo que significa que no podía imprimirlo todo de una sola vez sino que tendría que dividir la carcasa en dos mitades que se pudiesen pegar. Ante esto comencé con el primer diseño:

Como base no estaba mal, pero faltaban las patas y cubrir los huecos entre las teclas. Para ello se me ocurrió que podía utilizar una pieza que se añadiese por detrás.

Menos mal que se me ocurrió probar a imprimirla antes… ¡Menudo desastre! Se suponía que la parte delantera, que es la que queda hacia el fondo en la imagen, tenía unos huecos en donde la placa se introducía para quedar fijada; por desgracia, para imprimirlos hacía falta utilizar soportes, los cuales no había manera de quitar en una zona tan estrecha como una placa de circuito impreso. Ante esto, decidí probar un segundo diseño:

En este nuevo diseño, el bloque principal de la carcasa estaba compuesto por cuatro piezas en lugar de dos (a mayores hay dos piezas extra para hacer una pata que va de un extremo a otro). Las dos piezas traseras se imprimirían «planas», pero las delanteras, en donde estaba la ranura en donde encajaría la PCB, se imprimiría «hacia arriba», con el frontal apoyado en la cama. De esta manera se podían evitar los soportes.

Por desgracia, aún era demasiado complicado, pues la parte de la pata consumía muchísimo filamento y no era nada sencilla de montar. Además, la alineación de las cubiertas para las zonas entre las teclas era crítica, pues hay menos de un milímetro de margen: un error, por pequeño que sea, haría que las teclas rozasen o, peor aún, no pudiesen bajar… como de hecho me ocurrió.

Finalmente, tras darle muchas vueltas se me ocurrió que podía simplificarlo muchísimo si separaba las cubiertas de los huecos de la carcasa, de manera que fuesen piezas independientes. De aquí salió el diseño de arriba: las dos piezas traseras se imprimen rotadas 90 grados, mientras que las dos piezas delanteras se imprimen «tal cual», de manera que no hace falta ningún tipo de soporte. El diseño lo hice sin la base para ahorrar plástico, pues quería usar un trozo de lámina de polietileno recortada para abaratar costes y reducir el tiempo de impresión.

Las piezas para cubrir los huecos entre las teclas de función las imprimí aparte, con la intención de pegarlas directamente en la PCB. Esto no sólo simplificaba mucho el diseño, pues no había que hacer malabares para evitar tener que usar soportes, sino que, además, eliminaba completamente los problemas de falta de precisión:

El diseño tenía buena pinta, pero aún no me acababa de convencer, pues había que pegar cuatro piezas para construir la carcasa, lo que no era muy cómodo. Además, la idea de ahorrar costes utilizando una lámina de polietileno como base no resultó: para empezar, las ranuras que había en el diseño para que ésta encajase eran demasiado estrechas, algo que, además, dependería de la impresora en sí. Pero además, si quería que las piezas se imprimiesen bien, no me quedaba más remedio que imprimir una «balsa», con lo que el ahorro no era tal, pues al final estaba imprimiendo la base igual, sólo que la tiraba a la basura.

Finalmente, llegué al diseño actual, que es éste:

La carcasa en sí está compuesta por solo dos piezas, las cuales, además, son muy fáciles de pegar. La superficie principal de la base tiene un grosor de sólo 0,6 milímetros, lo que significa que se gasta la misma cantidad de filamento que si se utilizase una «balsa» con el diseño anterior; sin embargo, la resistencia es la misma, pues en los bordes el grosor aumenta para darle rigidez. Las patas se imprimen aparte y se pegan en el borde trasero. Esto tiene la ventaja de que es posible imprimir patas de distinta altura para ajustarlo a las preferencias de cada uno. Por último, las cubiertas se imprimen aparte, como se ve, y además hay tres piezas extra que también se pegan entre las teclas y que sirven como «tuercas» para atornillar la placa a la carcasa (aunque en los dos teclados que hice no fue necesario, pues quedaron perfectamente ajustadas).

Y el resultado final es éste:

Documentando con los pies (2)

En la entrada anterior expliqué cómo construí un pedal para tomar fotografías desde el móvil y así simplificar el documentar proyectos hardware. Por desgracia, cuando llegó el momento de usarlo por primera vez me encontré con un problema: resulta que la aplicación de cámara de Android se cierra automáticamente al cabo de dos minutos de no hacer nada con ella. Esto es un problema porque entre foto y foto bien puede pasar mucho más tiempo, lo que me obligaría a acercarme al móvil y lanzar la aplicación de nuevo. Esto no tiene nada que ver con el apagado automático de la pantalla: aunque le ponga media hora para que apague la pantalla, la aplicación de la cámara vuelve a la pantalla principal a los dos minutos de estar «sin hacer nada».

Obviamente esto es completamente inaceptable, así que decidí agarrar el toro por los cuernos y escribir una pequeña aplicación de cámara para Android que no tuviese este problema. Para ello partí de un ejemplo de cómo utilizar la cámara en Android, escrito en Kotlin. Reconozco que no es un mal lenguaje, pero no le acabo de pillar el punto (todo lo contrario que Go… pero esa es otra historia).

Tras una primera prueba, conseguí que funcionase de manera constante. Sin embargo, me encontré con la desagradable sorpresa de que el tener la cámara funcionando constantemente hace que el móvil se caliente un montón, cosa que no me hacía nada de gracia (de hecho, al buscar por qué la aplicación oficial de cámara se cerraba a los dos minutos, uno de los motivos que decía era ese; me parecía muy extraño, teniendo en cuenta que sí puedes grabar vídeo durante más tiempo, pero visto lo visto, podría ser una de las razones).

Ante esto, tuve que complicar un poco la aplicación, haciendo que la cámara se desactive al cabo de un tiempo sin hacer nada, pero dejando la aplicación en primer plano y activando de nuevo la cámara tan pronto se pulsa uno de los botones de volumen para tomar una foto. De esta manera el móvil no se recalienta.

Como comienzo no estuvo mal, pero claramente tenía un problema: ¿cómo puedo saber si una foto es buena, o tengo que repetirla? La solución fue relativamente sencilla: añadir la posibilidad de enviar cada foto tomada a mi portátil, que estaría en un sitio donde podría ver fácilmente el resultado. Así, añadí dos campos de texto en la app en los que teclear la dirección IP del portátil y un puerto (por defecto usa el 9000), y en éste correr una pequeña aplicación en python que se limite a escuchar por dicho puerto, y cuando se abra, recibir los datos de la imagen en formato JPEG, descomprimirlos, y mostrarlos en la pantalla.

El resultado era bastante bueno, pero tenía un problema aún: la cámara de mi móvil es de 4160×3120 pixels, un tamaño exageradamente grande que resulta en ficheros muy grandes. El resultado es que entre que pulso el pedal y aparece la foto en el portátil pasan unos nueve segundos (tres de los cuales son debidos a tener que encender la cámara). Para resolverlo añadí un campo de «resolución», que permite poner un tamaño deseado (yo le pongo 2048), de manera que el móvil escogerá la resolución más cercana a ese valor entre los que permita la cámara. Con esto, el tiempo baja a cuatro segundos si la cámara estaba apagada, y un segundo si la cámara estaba encendida (por ejemplo si no nos gusta la foto y decidimos sacar otra, la cámara estará ya encendida y será muchísimo más rápido).

El código fuente (compilable con Android Studio) está disponible en mi repositorio GIT: https://gitlab.com/rastersoft/footcam. Hay un paquete APK para Android ya compilado que se puede descargar desde la sección Tags, simplemente pinchando en el número de versión. En el repositorio principal se puede descargar el programa de visualización remota, llamado «receiver.py«. Para utilizarlo, además de Python3 es necesario WxPython.

Documentando con los pies

Me gusta hacer proyectos de electrónica, pero documentarlos… ¡ay! Eso ya es otro cantar. A fin de cuentas, para ello tengo que decidir cuando sacar alguna foto, y eso me obliga a parar lo que estoy haciendo, sacar el móvil, encuadrar con una mano mientras con la otra sostengo lo que estoy haciendo… un cristo.

Pero a la vez tengo claro que quiero documentarlo, por un lado por mí, porque así tengo un registro de las cosas que he hecho y me puede servir en el futuro («¿Cómo había hecho aquello…?), y también porque puede ser útil para otras personas.

Tras darle varias vueltas, se me ocurrió una idea: dado que tengo un trípode con soporte para el móvil, podría montarlo y encuadrar una zona concreta de la mesa de trabajo, ya con luz adecuada y demás, y cada vez que quiera sacar una foto sólo tendría que pulsar un botón.

Por supuesto, queda la cuestión de cómo conectar ese botón, pero afortunadamente es algo que hace cualquier palo selfie que se precie, por lo que sólo tenía que conectarlo a la entrada de cascos. Rebusqué en internet y encontré las especificaciones oficiales 3.5 mm Headset: Accessory Specification y 3.5 mm Headset Jack: Device Specification. Estas dos especificaciones indican cómo se deben conectar los altavoces, micrófono y pulsadores en un móvil Android, y qué funcionalidad debe tener cada uno.

Una lectura rápida nos indica que los botones están conectados entre el terminal 3 y 4 del jack, en paralelo con el micrófono, y que las cuatro funcionalidades posibles se consiguen presentando un valor concreto de resistencia entre dichos terminales. Así, si aparecen 0 ohmios (o sea, si se cortocircuitan), la función es la A (play/pausa/descolgar si es una pulsación corta; asistente si es una pulsación larga, o siguiente canción si son dos pulsaciones cortas); con un valor de entre 210 y 290 ohmios la función será la B (subir volumen); un valor de entre 360 y 680 ohmios activará la función C (bajar volumen); por último, un valor entre 110 y 180 ohmios activará la función D, que es una funcionalidad «reservada». Dado que la cámara se puede activar con cualquiera de los botones de volumen, bastaba con poner una resistencia adecuada en serie con un pulsador entre los terminales 3 y 4 del jack y estaría listo.

Decidí hacer una prueba rápida con un único botón, y para mi sorpresa… ¡¡¡no funcionó!!! Ante esto, decidí hacer un montaje un poco más completo con las funciones A, B y C:

Con los valores del esquema, el botón A cortocircuita los pines 3 y 4 del jack; el botón B muestra 240 ohmios, y el C 480 ohmios.

Y seguía sin funcionar: el móvil detectaba que había algo conectado, pero no hacía absolutamente nada: ni subir y bajar el volumen, ni responder a una llamada… ¡nada! Revisé los valores de resistencia con el polímetro, probé otros valores para activar otras funciones… pero nada, no quería funcionar. Era rarísimo.

Decidí buscar a gente que hubiese hecho un montaje similar y encontré un par de ejemplos documentados, pero ambos hacían exactamente lo mismo que yo.

Me releí una y otra vez la documentación, y entonces caí en un detalle: se indica que el micrófono tiene que tener una impedancia en continua superior a 1000 ohmios. Yo había dado por supuesto que podía dejarlo «desconectado», pues infinito es mayor que 1000 ohmios, pero, por si acaso, decidí poner en paralelo una resistencia de 2Kohmios, así:

¡Y ahora sí que funcionó! Está claro que al menos mi móvil espera que haya una cierta impedancia, y no un valor «infinito».

Con esto claro, hice algunos cálculos y el circuito definitivo es éste:

Cuando el pulsador está abierto, el móvil ve una resistencia de 2 Kohmios, y cuando se pulsa, al poner en paralelo un valor de 320 ohmios, el valor que ve es de 1 / (1/2000 + 1/320) = 275,8 ohmios, lo que activa la función B (subir volumen).

Ahora llegó el momento de decidir cómo activar la cámara. Aunque la primera opción sería tener un pulsador en algún lugar cómodo, eso seguiría implicando soltar lo que esté haciendo, así que decidí que tenía que ser algo que pudiese activar sin las manos. Y la opción obvia es un pedal. Aunque podía comprar uno, preferí aprovechar cosas que ya tenía por aquí y montarme uno yo mismo. Para ello utilicé unos pulsadores de circuito impreso que tenía en casa y unas protoboards.

Los cuatro pulsadores están conectados en paralelo, así que basta con que se active cualquiera para que el móvil detecte la función «subir volumen». Obviamente, la placa va al revés de como se ve, con los pulsadores hacia el suelo, y hago presión por el lado de las soldaduras… algo nada recomendable (ni para las soldaduras, ni para el pie si se hace descalzo), así que le pegué una segunda placa por el lado opuesto para taparlo todo.

Y este es el resultado:

Problemas tecladiles (4)

EDITADO. Como ya comenté, decidí reemplazar el cargador original del Atmega32U4, llamado DFU y que se puede descargar desde la página de Atmega, por Ubaboot, un bootloader reducido que sólo ocupa 512 bytes y que es muy sencillo de utilizar. A mayores envié dos parches para simplificarlo aún más:

Para instalar Ubaboot, lo primero que hay que hacer es editar el fichero config.h y configurar los parámetros de nuestra placa. En el caso de mi teclado, hay que descomentar OSC_MHZ_16 (pues el reloj es de 16MHz), y USB_REGULATOR:

Una vez hecho esto, hay que programar los fuses del microcontrolador para un bootloader de 512bytes, además de asegurarnos de configurar bien el resto. En el caso de mi teclado, la configuración es la siguiente:

Fuse LOW: 0x5E

  • CKDIV8 0
  • CKOUT 1
  • SUT1/0 = 0x01
  • CKSEL3/0 = 0x0E

En este bloque básicamente no tocamos nada.

Fuse HIGH: 0xDC

  • OCDEN 1 (desactivado)
  • JTAGEN 1 (JTAG desactivado)
  • SPIEN 0 (programación por SPI activada)
  • WDTON 1 (watchdog desactivado)
  • EESAVE 1 (preservar EEPROM al borrar la memoria)
  • BOOTSZ1/0 0x10 (bootloader de 512 bytes)
  • BOOTRST 0 (vector de reset apunta al bootloader)

En este bloque básicamente desactivamos el JTAG, pues no lo necesitamos para nada, ponemos la dirección de inicio del cargador a 512 bytes antes del final de la memoria, y por último configuramos el vector de reset para que salte al cargador directamente. Esto último es muy importante, pues el propio cargador detecta si estamos arrancando «en frío» (en cuyo caso saltará a nuestro código directamente) o si hemos pulsado el botón de reset (en cuyo caso entrará en modo programación).

Fuse EXTRA: 0xFE

  • RESERVADO 7/4 tienen que estar todos a 1 (0xF)
  • HWBE 1
  • BODLEVEL2/0 0x1 (EDITADO)

El entorno de Arduino me había cambiado el BODLEVEL a 110 (1,8 a 2,2 voltios), en lugar del original 011 (2,4 a 2,8 voltios). Tras algunas pruebas, y en base a mi experiencia, he decidido que es más seguro ponerlo a 001 (3,3 a 3,7 voltios). Esto es algo que he cambiado en este artículo después de haberlo publicado.

El siguiente paso es conectar un programador SPI al teclado a través de los pines correspondientes. Yo uso un BusPirate que me prestaron, para lo cual tuve que editar el fichero Makefile y sustituir usbtiny -B10 por buspirate -P /dev/ttyUSB0 -b 115200, además de instalar AVRdude y el resto de utilidades de AVR. Con esto ya sólo me queda conectarlo al teclado y ya puedo leer el estado con

avrdude -c buspirate -P /dev/ttyUSB0 -b 115200 -p m32u4

borrar todo el estado para desprotegerlo con

avrdude -c buspirate -P /dev/ttyUSB0 -b 115200 -p m32u4 -e

grabar los fusibles con

avrdude -c buspirate -P /dev/ttyUSB0 -b 115200 -p m32u4 -U efuse:w:0xFE:m
avrdude -c buspirate -P /dev/ttyUSB0 -b 115200 -p m32u4 -U hfuse:w:0xDC:m
avrdude -c buspirate -P /dev/ttyUSB0 -b 115200 -p m32u4 -U lfuse:w:0x5E:m

y hacer make y make program para grabar el Ubaboot. Con él grabado, sólo tengo que pulsar el boton de RESET del teclado y se pone automáticamente en modo programación por USB, con lo que ya no necesito más el BusPirate.

Y ya, por último, instalé Arduino y Teensyduino para disponer de las bibliotecas de USB. Sin embargo, hice un pequeño cambio para integrar la programación mejor. Los cambios concretos están descritos en el fichero README del segundo parche que envié a Ubaboot.

Y con esto escribí la primera versión del software de mi teclado, pero eso lo comentaré con calma en otra entrada.

Problemas tecladiles (2)

Acabo de subir la revisión 1.7 de la placa del teclado. Uno de los cambios más importantes ha sido conectar una de las columnas del teclado desde el puerto PE2 al PB7. Para entender el motivo, primero necesitamos entender cómo es el proceso de arranque del Atmega32Ux.

El procesador Atmega32Ux permite añadir un bootloader y arrancarlo en determinadas circunstancias. Hay varias posibilidades:

  • Llamarlo manualmente desde el programa principal (útil para cambiar a modo programación de manera «manual»)
  • Llamarlo siempre que se resetee el procesador
  • Llamarlo tras un reset si se da cierta condición externa

Y esta última es la clave: esa condición externa es que el pin PE2 esté a nivel bajo en el momento de ocurrir el reset. Esto permite que, por defecto, se arranque el código principal, pero si se desea arrancar el bootloader, sólo haya que conectar dicho pin a masa y pulsar reset.

Pues bien, hasta ahora yo utilizaba dicho pin para una de las columnas del teclado simplemente por comodidad de diseño: al hacer el enrutado de las pistas, era más sencillo utilizar ese pin que otro.

El problema es que la placa Teensy 2.0, que es la que lleva el mismo procesador, tiene ese pin permanentemente conectado a masa a través de un pull-down y, además, no está conectado al exterior. Eso significa que en las bibliotecas de teensyduino no está disponible la opción de utilizar dicho pin.

Por simplicidad, yo quería mantener la compatibilidad con la Teensy 2.0 porque me da un entorno de programación y bibliotecas listas para utilizar, lo que simplifica mucho el trabajo, pero este problema me obligaba a rediseñar la placa, algo que no me apetecía mucho porque ya mandé fabricarlas y, aunque la versión actual es mucho más avanzada que la que tengo físicamente, los cambios hechos hasta ahora eran cosméticos y no afectaban a la lógica en sí, mientras que éste sí implicaba un cambio en la lógica de funcionamiento.

Decidí ver qué alternativas tenía, y descubrí que las placas Arduino Leonardo y Arduino Micro también utilizaban el mismo micro, así que decidí echar un vistazo a ver si podía utilizarlas. Al principio tenía buena pinta porque el bootloader estaba disponible, por lo que podía convertir mi teclado en un Arduino «con todas las de la ley». Por desgracia, la alegría no duró mucho: en el caso del Micro, el pin PE2 tampoco estaba conectado al exterior, con lo que estaba en las mismas. Aún peor: otros dos de los pines que utilizo en el teclado están asignados a LEDs, con lo que probablemente no tendría mucha libertad a la hora de utilizarlos. En el caso del Leonardo, tres cuartos de lo mismo.

Al final no me quedó otra que cortar la pista que conectaba PE2, y añadir dos puentes: uno entre PB7 y la pista original, y otra entre masa y una resistencia conectada a PE2.

Probando otros bootloaders

A pesar de todo, decidí probar el bootloader de Arduino, por si era más cómodo que el ubaboot que estaba utilizando hasta ese momento. Arranqué el editor Arduino IDE, configuré una placa Leonardo, le indiqué que tenía un programador Bus Pirate, y le di a Quemar bootloader. Varios minutos (sí, sí… tarda un muy buen rato y no muestra nada en pantalla que indique progreso) finalizó la grabación. Lo primero que descubrí es que me había cambiado los fuses del Atmega, algo que no me gustó mucho porque algunos flags eran… raros. Por ejemplo, me activaba el divisor entre ocho del cuarzo, lo que supone que la CPU va más lenta. Pero lo más raro es que pone a cero los bits 4 y 5 del byte extendido, los cuales se supone que no se deben escribir, y deben estar siempre a 1. Lo peor es que no soy capaz de devolverlos a su estado normal.

Tras varias pruebas, no me acabó de convencer el bootloader, así que volví al ubaboot de nuevo, pero esta vez quería asegurarme de corregir un par de problemas que tenía, y es que al pulsar el botón de reset para entrar en modo programación, no siempre funcionaba, sino que normalmente tenía que darle dos o tres veces antes de que el identificador USB fuese el de OpenMoko en lugar del de Teensy. Por otro lado, al darle la orden de reiniciar desde el programador ubaboot, el USB dejaba de funcionar.

Al final, tras echar un vistazo al código fuente, me di cuenta de que este bootloader espera ser llamado siempre durante el arranque, lo que significa que hay que poner a cero el bit 0 del Fuse High Byte, el flag BOOTRST. De esta manera, siempre arrancará desde el bootloader, y si éste detecta que el procesador está arrancando por haber sido conectado a la corriente, saltará directamente al código principal, y sólo entrará en modo bootloader si se pulsó el botón de reset.

Con estos cambios ya puedo programar fácilmente la placa del teclado: simplemente tengo que instalar Teensyduino para disponer de todas las bibliotecas, indicar al IDE que tengo un Teensy 2.0, y cada vez que compile, fijarme en donde ha almacenado el fichero hex con el código objeto (normalmente en /tmp/arduino_build_XXXXXX, y utilizar el comando

sudo ubaboot.py write path_al_fichero.hex

para programarlo.

Problemas tecladiles

Hace tiempo que quiero construirme un portátil/cyberdeck alrededor de una Raspberry Pi 4, y basado en el diseño del Z88 de Sinclair/Cambridge Computers. Sin embargo, algo que tengo muy claro es que quiero un teclado completo, no uno de portátil, pues, como programador, suelo utilizar mucho las teclas SUPR, INICIO, FIN, RePAG y AvPAG, y en los portátiles algunas necesitan combinarse con Fn.

La primera opción sería utilizar un diseño TenKeyless, también conocido como «teclado 87%», como éste (pero sin lucecitas):

Sin embargo, hay mucho espacio desaprovechado. Así que sopesé utilizar un diseño «75%», como éste de Keychron:

Pero no tenía a mano la tecla de Imprimir pantalla, que uso mucho, ni tampoco la de SysReq, que utilizo de vez en cuando, así que tampoco me convencía.

Al final, después de mucho pensarlo, me decidí por hacer mi propio diseño, y ésta es la distribución final que decidí:

Como se puede ver, tiene todas las teclas de un Tenkeyless, pero es muchísimo más compacto. E incluso tiene una tecla de Fn para funciones no tan comunes, como subir y bajar el volumen. Todo ventajas.

Decidí construir uno en plan «barato», y para ello utilicé pulsadores de circuito impreso y los capuchones de un teclado que compré en el chino el bazar de al lado de casa, y lo conecté directamente a los pines de E/S de la raspberry. Este fue el resultado:

La distribución era buena, pero el tacto… en fin… hace unos treinta años había construido un teclado para mi Spectrum utilizando el mismo tipo de pulsadores, y no recordaba que fuese tan malo 🤣

Pero ya tenía el gusanillo, así que decidí coger el toro por los cuernos y diseñar un teclado en condiciones. Para ello partí de un diseño básico creado mediante el programa Klepcbgen, de Jeroen Bouwens, al que hice varios cambios para permitir, entre otras cosas, utilizar diodos normales en lugar de la versión de montaje superficial. A partir de ahí seguí puliendo el diseño hasta llegar a la versión 1.5 de mi teclado, que está disponible en mi repositorio de gitlab.

En el diseño utilicé un Atmega32U4, el mismo que se utiliza en las placas Teensy 2.0. El motivo es que son las placas que más se utilizan para diseños de teclados propios, por lo que podría reutilizar mucho software. Además, incluí, como se puede ver en la imagen de arriba, dos filas de 10 pads cada una en donde están disponibles las filas y columnas del teclado. Esto permite conectar la misma placa a un microcontrolador externo (o, en mi caso, directamente a los pines de E/S de la Raspberry PI) en lugar de utilizar el incorporado en la placa.

La primera dificultad fue donde colocar el microcontrolador. Al principio junté todas las teclas de la primera fila hacia la izquierda y coloqué el microcontrolador y el conector USB arriba a la derecha, por el lado inferior de la placa. Esto tenía la ventaja de que las pistas del par diferencial del USB eran lo más cortas posible, y además me dejaba sitio para un NeoPixel en la esquina superior derecha, pero tenía el inconveniente de que la estética de la colocación de las teclas no era muy allá, además de que, por el espacio disponible, la placa sobresalía bastante por arriba.

Ante esto, decidí intentar mover el microcontrolador a otra zona, en este caso debajo de la barra espaciadora, donde había mucho espacio libre, y así poder mover el conector USB un poco más hacia las teclas. Sin embargo, me preocupaba que las pistas del par diferencial serían muy largas… ¿daría problemas con el USB?

Decidí informarme, así que me descargué la especificación del estándar USB 1.1 y descubrí que el par diferencial tiene que tener una impedancia de 90 ohmios +/- 15%. Ante esto, utilicé la herramienta de cálculo de Kicad para líneas de transmisión, y me salió que tenía que utilizar una anchura de pista de 0,9 milímetros (sí, bastante ancha):

De todas formas, mi intención era utilizar el modo low-speed, de 1,5Mbps en lugar del full-speed de 12Mbps, por lo que lo más probable es que incluso unas pistas sin ajustar funcionasen correctamente; pero decidí no arriesgarme e intentar hacer las cosas bien. Aquí, además, conté con la inestimable ayuda de mis compañeros de A Industriosa, que me resolvieron todas mis dudas sobre diseño con Kicad. A fin de cuentas, soy programador, no electrónico.

Para hacer bien un par diferencial, lo primero es definir una malla específica para él en las clases de red. De esta manera podremos estar seguros de que los parámetros de las pistas serán correctos:

Para trazar el par, tenemos que utilizar la herramienta específica. Ella nos permite asegurarnos de que ambas pistas están siempre a la distancia correcta:

Una vez trazado el par, veremos que los ángulos son rectos (de 45 o 90 grados), cosa que no es buena. Para solucionar esto sólo tenemos que escoger dos segmentos consecutivos, darle al botón derecho, y escoger pistas de filete. Nos preguntará un valor para el radio, y una vez aceptado, añadirá una esquina curva entre las dos pistas. Aquí tenemos un ejemplo de una esquina ya con el filete, y la esquina paralela aún sin él:

Yo utilicé un radio de 3 milímetros para las curvas internas. Sin embargo, es importante recordar que las curvas deben ser concéntricas, lo que significa que las curvas externas tienen que tener un radio mayor. Dicho radio debe ser radio_interior + ancho_de_pista + separación_de_pista. En mi caso, con un radio interior de 3 milímetros, un ancho de pista de 0,9 milímetros, y una separación de pista de 0,2 milímetros, el resultado es que para los radios exteriores tengo que utilizar un radio de 4,1 milímetros. Y así queda:

Sin embargo, si seleccionamos cada una de las dos pistas del par y nos fijamos en el parámetro Longitud enrutada de cada una, veremos que la longitud no es la misma. Aunque la diferencia es pequeña (casi dos milímetros), quise hacer las cosas bien, así que utilicé la herramienta de Afinar desvío de un par diferencial para asegurarme de que la diferencia de distancias estuviese por debajo de una décima de milímetro:

Esta herramienta añade unas ondulaciones en la pista, de manera que la distancia sea correcta a la vez que se mantiene la impedancia:

Distribuciones de teclado

Durante todo el diseño inicial mantuve una distribución ISO de las teclas, pues es la que yo voy a utilizar. Sin embargo, dado que iba a publicarlo todo bajo una licencia libre, decidí intentar hacer una placa dual, que permitiese montar también una distribución ANSI de teclas. Sin embargo, me encontré con el problema de que había un par de agujeros que quedaban bastante cerca y no veía claro que los estabilizadores que iban en ellos quedasen bien anclados, por lo que ese diseño no parecía una buena idea. Pese a todo, quería poder tener ambas distribuciones, así que al final se me ocurrió una idea relativamente sencilla: en main tendría la placa dual, y luego tendría dos ramas, una para cada distribución, que mantendría actualizadas a partir de main. Al principio era bastante peñazo porque, al quitar los pulsadores que sobraban, quedaban muchas pistas mal situadas, lo que me obligaba a ajustar bastante ambos diseños antes de poder hacer el merge; pero después de afinar la placa dual conseguí solucionar esos problemas, y ahora me lleva segundos actualizar cada rama.

Distribución ISO renderizada desde Kicad
Distribución ANSI renderizada desde Kicad

Otros detalles que añadí fueron un conjunto de pads para un programador de Atmega (ese grupo de dos por tres que se ven junto al microcontrolador), dos pads conectados a PE2 y masa para que, al cortocircuitarlos, se pueda entrar en el modo de carga del bootloader de Atmega (que son esos dos que se ven entre el pulsador del espacio y el microcontrolador, y que está etiquetado por debajo como bootloader), y dos pads más para dos pines de E/S que me quedaban libres (PE6 y PB0), pues puede ser interesante aprovecharlos. Teniendo en cuenta que PB1, PB2 y PB3 ya están disponibles en el conector del programador, el resultado es que casi todos los pines de E/S del microcontrolador están accesibles a través de pads. La única excepción es PB7, que se quedó tan encerrado que no encontré una manera razonable de extraer una pista. Es cierto que podría hacer sitio eliminando C7, el condensador de reset, pero la verdad es que no me parece tan necesario poder acceder a ese pin. Ese condensador lo añadí únicamente por si acaso, pero realmente no es buena idea ponerlo pues, al generar un reset automático al enchufar la placa, impide aprovechar la característica de entrar en modo depuración tras un reset del bootloader.

También incluí un rectángulo en blanco en cada lado de la placa, lo que permite hacer anotaciones con un rotulador.

Protección contra sobretensiones

Al principio no tuve en cuenta la necesidad de proteger contra sobretensiones en el bus USB. A fin de cuentas, aunque en la documentación del Atmega32U4 dicen que es recomendable añadirla, no aparecía en ninguno de los diseños de referencia que incluían. Es más: la propia placa Teensy 2.0 no incluye ningún tipo de protección, sino que los dos pines del microcontrolador van a pelo al conector.

Sin embargo, un compañero de AIndustriosa me recomendó encarecidamente que la añadiese, pues parece ser que es habitual que en los conectores USB de los equipos de sobremesa (cuya alimentación va directa a la fuente) haya picos de tensión en determinadas circunstancias. Le eché un vistazo a las opciones que me daba Kicad, y me encontré con que casi todas eran diminutas: algunos chips medían aproximadamente un milímetro de largo… algo imposible de soldar a mano. Afortunadamente había otras opciones, y al final me quedé con el USB6B1, pues además de estar pensado específicamente para USB, tiene un patillaje que simplifica el diseño.

Reloj, o no reloj… he ahí la cuestión

Cuando estaba haciendo el diseño original descubrí que el Atmega32U4 incluye un oscilador RC que viene calibrado de fábrica de manera que su precisión es suficiente para que el USB funcione en modo low-speed. Dado que meter un cuarzo de 16MHz me asustaba bastante (es una frecuencia relativamente alta, y yo no soy para nada un experto en diseño electrónico), decidí que sería mejor hacer un sistema sin cuarzo externo, y utilizar sólo el oscilador RC interno. Sin embargo, a la vez, temía que hubiese algún problema, así que al final decidí que no usaría cuarzo, pero dejaría hechas las pistas para poder poner uno de ser necesario.

¡Menos mal que lo hice! Cuando monté la primera placa y quise programar el micro, descubrí que no funcionaba. Al principio pensé que podía ser un problema con el programador que estaba utilizando, un Bus Pirate, pero después de probar y probar una y otra vez, y de leerme la documentación repetidamente, descubrí que la programación mediante el puerto SPI (que es lo que estaba usando) necesita que haya un reloj activo para funcionar. Pero para que el chip utilizase el RC interno necesitaba programar los fuses de configuración, para lo cual… necesitaba un reloj activo… El huevo y la gallina. Fue aquí cuando descubrí que se vendían dos modelos: el Atmega32U4 a secas, que viene configurado de fábrica para trabajar con un cuarzo externo, y el Atmega32U4RC, idéntico en absolutamente todo excepto en que, de fábrica, viene configurado para trabajar con el oscilador RC interno. Adivinad cual había encargado yo…

Decidí no desesperarme y buscar una solución, así que intenté utilizar la interfaz JTAG para programarlo, confiando en que esa no necesitase un reloj externo. A fin de cuentas, el Bus Pirate es un dispositivo programable, y soporta todo tipo de interfaces…

O no, porque como como estaban justos de espacio de código en el microcontrolador, en las últimas revisiones eliminaron el soporte de JTAG. A fin de cuentas, «era demasiado lento para ser útil» 😡

Afortunadamente había un fork del firmware del Bus Pirate mantenido por la comunidad que, supuestamente, incluía soporte de JTAG, así que lo descargué, lo compilé con el MPlabX, lo flasheé… y no había JTAG.

Revisé el código y ahí estaba… y además se estaba compilando en el binario que estaba grabando, pero no aparecía en la lista de protocolos soportados. No entendía qué estaba pasando.

Encima, leyendo bien la documentación descubrí que el oscilador RC está calibrado para una tensión de trabajo de 3 voltios, cuando yo estaba alimentando el Atmega con 5. Eso me obligaba a recalibrarlo antes de poder usarlo.

Al final me cansé, me fui a la tienda de electrónica de mi ciudad y me compré un cuarzo de 16MHz por 60 míseros céntimos de euro, lo soldé, y se acabaron mis problemas: el teclado aparece como un dispositivo OpenMoko (porque, además, antes del cuarzo de 16MHz le puse, por error, uno de 12MHz pensando que era esa la frecuencia correcta, en base a los 12Mbps del bus USB; pero no…), y como no aparecía el dispositivo, probé a grabar un bootloader diferente del que trae de fábrica: UdaBoot.

Moraleja: no compensa ahorrarse unos céntimos.

¿Y ahora?

Ahora me queda la parte de programar el micro para que se comporte como un teclado, además de ver cómo puedo publicar a través de HID el NeoPixel, de manera que sea fácilmente controlable mediante software. Una vez hecho esto, montaré dos teclados más, y diseñaré la carcasa para el portátil, y una carcasa independiente para poder utilizar este teclado en mis ordenadores de casa.

Cargando mis cascos (y 3)

Hace unos años escribí una entrada explicando cómo modifiqué mis cascos inalámbricos para que se cargasen sólo con colgarlos de un soporte. Hace algo menos de tiempo publiqué un nuevo diseño, con un mejor acabado pero aún algo chapucero. Hoy ha llegado el momento de mostrar el diseño de-fi-ni-ti-vo.

Este es el diseño en FreeCAD, el cual está disponible en mi gitlab:

Si lo comparamos con el diseño anterior, éste está mucho más pulido porque incluye las lengüetas de carga y agujeros para pasar los cables. También tiene una ranura por debajo, de manera que los cables quedan completamente ocultos.

El diseño, además, está completamente acotado, por lo que es muy sencillo ajustarlo para otros tamaños de cascos. Así, la diadema de mis cascos mide 35 milímetros de ancho, por lo que la separación entre las lengüetas está ajustada a 33 milímetros, de manera que se garantiza que siempre hará contacto al colgarlos. Pero si queremos utilizarlo con otros cascos, sólo tenemos que editar esa medida para ajustarlo al valor necesario.

Así quedó tras imprimirlo en un tono anaranjado que hace juego con la madera del mueble donde va a ir atornillado, y tras pegarle cinta adhesiva de cobre en las lengüetas para hacerlas conductoras:

El siguiente paso fue meter los cables del transformador por cada uno de los agujeros, y soldarlos al cobre. La mejor manera de hacerlo es estañar primero el punto en el que vamos a soldar el cable, cortar el cable a la longitud correcta, estañar la punta, meterlo por el agujero, y simplemente con un pequeño toque del soldador, unir ambas partes. Así evitaremos recalentar demasiado el plástico y que se derrita o deforme.

Por último, añadimos un poco de cola térmica en la guía de la base para que el cable quede firme y evitar que un tirón lo arranque de las lengüetas:

¡Y ya está! Éste es el resultado final: