
Todo comenzó con la adquisición por parte del autor de un dispositivo interesante en el mercado secundario: Smart Response XE (). Está destinado a escuelas: cada alumno en la clase recibe un dispositivo que se asemeja a un cuaderno electrónico o un traductor de los noventa, el maestro formula una pregunta y los alumnos escriben las respuestas en los teclados de los dispositivos, que se envían a través de un canal de radio (802.15.4) a un receptor conectado a la PC del maestro.
El soporte para estos dispositivos se interrumpió hace varios años, y lo que las escuelas compraban por 100-200 dólares cada uno ahora aparece en eBay por 10 o menos. El 'hardware' es realmente adecuado para experimentos geeks:
- teclado de 60 teclas
- pantalla con resolución de 384×136, 2 bits por píxel — similar a BK, CGA, pero 4 no son colores, sino niveles de brillo
- microcontrolador ATmega128RFA1 (128 kB de memoria flash, 4 kB de EEPROM, 16 kB de RAM, transceptor estándar 802.15.4)
- memoria flash externa (en relación al microcontrolador, no a todo el dispositivo) de 1 megabit (128 kilobytes) con interfaz SPI
- compartimento para 4 elementos AAA.
Por el nombre del microcontrolador, es evidente que pertenece a la familia AVR, lo que significa que hacer que el dispositivo sea compatible con Arduino es una tarea más que trivial...
De una noticia en el autor se enteró de que esto (en este mismo enlace se explica cómo conectar cada cosa), obteniendo la posibilidad de ejecutar juegos para Arduboy:

Pero al autor le interesa más la posibilidad de no solo jugar en el dispositivo, sino de estudiar:
- memoria flash con interfaz SPI en serie
- bootloaders para AVR
- estándar 802.15.4
El autor comenzó escribiendo (GPL v3), que permite inicializar la pantalla, mostrar texto y rectángulos, así como acceder a la memoria flash con interfaz SPI. Luego comenzó a idear ideas para el uso práctico del dispositivo: un terminal compatible con VT-100 de bolsillo, juegos multijugador. Después de modificar tres dispositivos, decidió 'enseñarlos' a recibir sketches 'por aire'. Lo que sería no solo interesante, sino también muy conveniente: abrir el cuerpo del dispositivo cada vez es complicado, y debajo de la tapa del compartimento de la batería solo hay orificios que permiten conectar un programador JTAG a la placa.

Esto es suficiente para cargar el cargador de Arduino, pero no el sketch; el puerto serie no está habilitado, por lo que es inevitable abrir la carcasa. Además, las líneas TX0 y RX0 del primer puerto serie están combinadas con las líneas de lectura de la matriz del teclado, es decir, aquellas que se utilizan para escanear las teclas de función a los lados de la pantalla. Pero qué se le va a hacer: el autor ha creado lo siguiente:

Ahí ha conectado las líneas JTAG, y ahora no es necesario abrir el compartimento de la batería. Y para poder cargar también los sketches, ha conectado en este mismo conector ambos puertos serie, añadiendo también un interruptor, ya que con las baterías instaladas, el dispositivo no se puede apagar físicamente de otra manera.
Se requirió bastante tiempo trabajar con un soldador, un cúter y una pistola de pegamento. En general, cargar sketches "por aire" es significativamente más conveniente; hay que inventar urgentemente algo para esto.
La Arduino IDE utiliza el programa para cargar sketches . Se comunica con el microcontrolador a través del protocolo , que permite la transferencia de archivos en ambas direcciones. Es poco compatible con los canales donde pueden existir retrasos variables, distorsiones y pérdidas de datos. Si hay algo que se mueve o cruje en el canal serie, puede volverse loco buscando la causa. Una vez, el autor estuvo lidiando durante medio día hasta que se dio cuenta de que todo se debía a un mal cable, así como a un caprichoso convertidor de interfaz CP2102. Incluso un microcontrolador con un convertidor de interfaz integrado, como el ATmega32u4, puede comportarse así a veces. Cada usuario de Arduino ha notado que los errores al cargar sketches no son tan raros. A veces la escritura se realiza correctamente, pero al leer para verificar se descubre un error. Eso no significa que hubo un fallo en la escritura, el fallo fue en la lectura. Y ahora imagina que al trabajar "por aire" ocurrirá lo mismo, pero mucho más a menudo.
Después de probar diferentes maneras de superar este problema, el autor ideó lo siguiente. El dispositivo tiene 128KB de memoria flash con interfaz SPI: recibimos los datos por cables (recordemos que uno de los dispositivos con un conector lateral ya lo tiene el autor), usamos esta memoria como búfer y enviamos los datos a otro dispositivo a través del canal de radio. Un saludo de Cybiko.
Después de escribir el código para trabajar con el canal de radio, así como la fuente, el cargador se alargó a más de 4 kilobytes. Por lo tanto, el valor de HFUSE tuvo que cambiar de 0xDA a 0xD8. Ahora el cargador puede tener una longitud de hasta 8 kilobytes, y la dirección inicial se estableció en 0x1E000. Esto se refleja en el Makefile, pero también debe tenerse en cuenta al cargar. con avrdude.
El transceptor estándar 802.15.4 en el ATmega128RFA1 se diseñó originalmente para operar bajo el protocolo , que es bastante complejo, por lo que el autor decidió simplemente transmitir paquetes en su lugar. Esto está implementado de forma hardware en el ATmega128RFA1, por lo que se necesitará poco código. Además, para simplificar, el autor decidió usar un canal fijo, sin permitir que se seleccionara manualmente. El estándar 802.15.4 admite 16 canales numerados del 11 al 26. Están bastante saturados, algunos también superponen canales WiFi (los canales ZigBee están marcados en rojo, y los de WiFi en azul, verde y amarillo).

Resultó que los canales 15 y 26 son los menos susceptibles a interferencias de WiFi. El segundo de ellos fue el que eligió el autor. Descargo de responsabilidad: el traductor no sabe si está permitido simplificar así ZigBee. ¿Quizás debería programarse un poco más y realizarlo completamente?
En el primero de los dispositivos, se debe implementar una máquina de estados que transmita datos bajo el protocolo STK500. En su mayoría, los mensajes enviados y recibidos son autosuficientes, pero algunos están vinculados a los que pasaron por el canal anteriormente. La descripción del diálogo se proporciona. .
Una parte crucial de este diálogo es la transmisión de paquetes destinados a ser grabados en la memoria flash del dispositivo de destino. En los microcontroladores simples de la familia AVR, el tamaño de la página es de 128 bytes, pero en el ATmega128RFA1 es de 256. Y en la memoria flash que se conecta a través del protocolo SPI, también es el mismo. El programa en el primer dispositivo al cargar el sketch no lo envía directamente al segundo, sino que lo escribe en esta memoria. Cuando el Arduino IDE verifica la correcta escritura, se le envía lo que se ha grabado. Ahora es necesario transmitir los datos obtenidos a través del canal de radio al segundo dispositivo. Durante este proceso, el cambio de recepción a transmisión y viceversa ocurre con bastante frecuencia. El protocolo STK500 es indiferente a las demoras, pero no tolera la pérdida de datos (es extraño, ya que se mencionó anteriormente que las demoras en la transmisión de datos también afectan). Y las pérdidas en la transmisión inalámbrica son inevitables. El ATmega128RFA1 tiene una implementación de hardware para solicitudes de reenvío en caso de dudas sobre la precisión de la transmisión, pero el autor decidió implementar lo mismo programáticamente por sí mismo. Desarrolló un protocolo en el que se transmiten muchos más datos en una dirección que en la otra.
No es perfecto, pero todo funciona. La página de 256 bytes se divide en cuatro segmentos, cada uno de los cuales se transmite a través del canal de radio en forma de paquete. Un paquete puede contener hasta 125 bytes de datos más un byte para la longitud y dos para el CRC. Así que fragmentos de 64 bytes junto con los números de página y segmento (del 0 al 3) se colocan allí. En el dispositivo receptor hay una variable que permite rastrear cuántos segmentos han sido recibidos, y cuando llegan los cuatro, se envía una confirmación al dispositivo transmisor de que toda la página ha sido recibida. Si no hay confirmación (CRC no coincide), se envía toda la página de nuevo. La velocidad resultante incluso es mayor que al transmitir por cable. Vea:

Pero en realidad, sería conveniente prever un método fácil de conexión a los dispositivos mediante un cable para cargar los sketches a través de él. Por ejemplo, colocar dentro un convertidor de interfaz como el CP2102, como en la foto, y pegarlo a la placa de forma que soporte el esfuerzo al conectar y desconectar el cable Micro USB.

También cuenta con un regulador de 3,3 voltios (y cómo aplicarlo en un dispositivo con alimentación de 6 voltios — siempre que haya un regulador igual, se pueden agregar dos diodos para elegir automáticamente de cuál de ellos se alimentará el dispositivo). Es necesario desoldar los tres LED de la placa del convertidor de interfaz, de lo contrario, sobrecargarán las baterías al funcionar con ellas y también interferirán en la lectura del teclado y en el funcionamiento de la memoria flash con interfaz SPI.
Perseguir el objetivo resultó ser incluso más interesante que alcanzarlo (y no necesito el chiste sobre el autobús). El autor aprendió muchas cosas nuevas sobre los cargadores para AVR, la memoria flash con interfaz SPI, el protocolo STK500 y el estándar 802.15.4.
Todo el resto del código además de la biblioteca mencionada anteriormente — , y también está bajo GPL v3. El Twitter del autor es — .
Fuente: habr.com
