El caso de los firmwares corruptos. SPI EEPROM 25Qxx

Un amigo me ha dejado un TV de marca ANSONIC (marca de Hipercor) para reparar. Aunque el televisor es una marca genérica la electrónica es Vestel, que es un gran fabricante de electrónica de consumo. La misma placa, modelo 17MB55, se usa en televisores Telefunken y otras marcas conocidas.

Los síntomas son que el TV se mantiene en standby, al encenderlo no hace nada de nada. La primera sospecha es de alimentaciones, pero todas son correctas. Comprobando los relojes y reset todo es correcto, pero sique sin arrancar. Si tiene alimentación, tiene reloj y no esta reseteado el procesador debería comenzar a ejecutar el programa y arrancar el TV, pero no… Por último sospecho del propio programa ¿y si es incorrecto?.
Esta placa usa dos memorias EEprom SPI de 8 patas para almacenar el programa, es facil encontrar los puntos de test para leerlas y progrmarlas por ICSP, pero yo prefiero desmontarlas y pincharlas directamente al lector/grabador porque me es mas rápido que preparar un cable ICSP específico para esta placa.

Añadiendo unos hilillos a las memorias SO8 puedo insertar las memorias en el lector/grabador para DIL. Leo las memorias y hago un backup, importante!, que nunca se sabe…

A continuación busco en distintos foros de internet dedicados al servicio técnico de Audio y Video, pero no encuentro el firmware exacto para esta Ansonic. Hay que buscar “Dump” no “firmware” porque lo que la gente sube a la web no es el firmware tal y como lo proporciona el fabricante sino un volcado binario de lo que se lee de las propias eeprom. Por suerte encuentro un firmware para esta placa Vestel, pero para un televisor Telefunken: http://remont-aud.net/dump/lcd_pdp_tv/telefunken/telefunken_d32h125n3_shassi_main_board_vestel_17mb55/378-1-0-31790 Flasheo las memorias y las sueldo provisionalmente en su sitio:

PERFECTO. El TV vuelve a funcionar, aunque ahora los menús son los de Telefunken.

Ya solo queda desoldarlas, quitar las patillas y soldarlas de forma definitiva.
Todavía me quedaba por averiguar la razón de la corrución de los datos… un amigo bromeó que había sido un rayo cósmico, pero yo pensaba que era un error del firmware que al grabar algún parámetro había sobreescrito el bloque equivocado.

Cuando devuelvo el TV a mi amigo y le explico la avería, muy contento, me dice que esta podía ser también la avería de otro TV que tenía. Es cierto, hacía unos meses habíamos estado intentando reparar un Blaupunkt BLA-236/173J con lector de DVD pero nos había sido imposible. Él lo solucionó comprando otro igual pero con el TFT roto y cambiando la placa base. Pero el cambio le funcionó unos meses y de nuevo muerto…
Recuperamos los restos de los TV del trastero y nos ponemos a ello. A ver que sacamos partiendo de dos Blaupunkt iguales averiados con el mismo problema en la placa base, modelo T.MSD309.B66B:

Esta placa base solo tiene una EEPROM, pero la técnica es la misma: desoldarla, leerla, buscar un firmware nuevo adecuado, grabarla, resoldarla para pruebas y soldarla definitivamente, si todo va bien.

Buscando por aqui: http://remont-aud.net/dump/lcd_pdp_tv/blaupunkt/blaupunkt_bla_23207i_gb_3b_hkdp_uk_b23u207thdd_shassi_main_board_t_msd309_b66b/380-1-0-37955
Encontré algunos que mediofuncionaban, aunque no manejaban adecuadamente el modelo de panel que este TV usaba:

Encontré otross que funcionaron bien, lo que confirmaba que el problema era el firmware corrupto, pero ninguno tenían soporte para DVD:

Pensando que el problema era un bloque de eeprom incorrecto, me pongo a comparar todas los firmwares .bin que había descargado con el backup que había leído, intentando buscar un bloque discrepante. Estos firmwares son modulares y dentro contienen secciones con el bootloader, el driver del panel, sintonizador, etc y los menús que cada fabricante personaliza.
Después de mucho comparar no pude ver diferencias en la estructura entre el backup corrupto y los firmwares operativos. Todo parecía estar en su sitio y no había bloques borrados.
Pero la casualidad, que a veces ayuda, me hace ver, en un bloque vacío, un dato discordante:

Un cuatro (04 hexadecimal, que es 00000100 en binario) en medio de un bloque de ceros… Un bit que debia estar a cero esta a uno!!! ¿Es este el problema? Pues SI! después de cambiar este 04 a 00 y grabar la memoria de nuevo el TV vuelve a funcionar como al principio, y con soporte para el lector de DVD! Es mucha casualidad haber encontrado un bit cambiado en 32 millones, pero estaba en una zona de buena visibilidad. Si el bit eeróneo hubiera estado en una zona con datos habría sido imposible identificarlo. Aunque el bit estaba en una zona vacía es común que el firmware realize un autochequeo con un checksum y si no es correcto no arranque, por seguridad.

Ahora ya no me parece tan raro lo del rayo cósmico, aunque es raro… También puede deberse a una mala calidad de la memoria EEPROM o un proceso de grabación incorrecto. La eeprom de este modelo era una GD25Q32 de GigaDevice: http://www.gigadevice.com/product/detail/5/365.html?locale=en_US.

Lo claro es que flasheando este firmware parcheado en las dos EEPROM se repararon las dos placas base del Blaupunkt y el TV funcionó de nuevo. Ya hora con una placa base de repuesto!

Si puede serle de ayuda a alguien, este es el firmware leido y reparado para esta placa T.MSD309.B66B del Blaupunkt BLA-236/173J-GB-4B-FHKDUP-EU: T.MSD309.B66B uf11 GD25Q32 Leida Reparada

Actualización 24/11/2017
Parece que la epidemia de datos corruptos en memorias SPI se extiende a otros aparatos, y a memorias I2C. Ayer reparé un (bastante caro) medidor de espesores por ultrasonidos Krautkramer Branson DM4E.
El aparato es muy parecido a este:

Mide espesores mediante una sonda de contacto por ultrasonidos de entre 1Mhz a 10Mhz. El aparato mostraba “FAIL” en la pantalla y un proveedor nos ofertó repararlo por casi 2000€. Por suerte teníamos otro igual para comprobar…
El problema estaba en una EEPROM I2C Microchip 24lc65.

Por alguna extraña razón el medidor interpretaba que los datos contenidos en la memoria, a penas 64 bytes de los 8K bytes disponibles, no eran correctos y se negaba a trabajar. Un “transplante” de datos desde la EEPROM del otro medidor que funcionaba correctamente y una nueva calibración y reparado!

Usando CIS (Contact Image Sensor) con Arduino y Processing

En construcción.
Esta semana estoy trabajando un poco la ingenieria inversa, a ver si soy capaz de sacar algo en claro de los CIS Contact Image Sensor).
Tengo un puñado de ellos, incluido uno enorme y antiguo para DIN A3 TCD120AC.

Desgraciadamente no hay mucha información técnica pública en internet. De lo poco que he podido encontrar esta hoja de datos de Dyna Image es muy interesante: https://www.tvsat.com.pl/pdf/D/dl100_dyna.pdf
Parece ser que son dispositivos muy personalizables y los fabricantes de escáners los encargan a medida. http://www.csensor.com/M118_CIS.htm
Los sensores CIS son mucho mas fáciles de usar que los CCD (que requieren varios clock y tiempos muy precisos y la salida necesita preamplificador etc). La salida de los CIS suele ser de entre 2,5V a 5V de fondo de escala. Podemos introducirla directamente en un A/D de cualquier micro.
Los elementos sensores son CMOS y eso les da unas características electro ópticas bastante buenas. No he podido encontrar las curvas de sensibilidad espectral de los elementos supongo que serán las típicas de los fotodiodos para luz visible.
Los fabricantes estan empleando CIS para sustituir los CCDs en los escáneres, faxes etc porque les simplifica y abarata los diseños: ya no neceesitan complejas ópticas con espejos y delicados ajustes.
Eso también ayuda a usarlos con facilidad a nivel de aficionado que sean grandes, 216mm (ancho del papel DIN A4), y que tengan bastantes elementos (mínimo unos 8 por mm, 1728 en total).

De todos los que tengo no he podido encontrar hoja de datos de ninguno, algunos se ve claramente que el código marcado es un código de cliente…
Por suerte tengo dos Dyna Image similares a los de la hoja de datos.
Uno es un DL100-10AFJK con conector de 12 pines y el otro un DL100-05EUJK con conector de 7 pines que parece coincidir con la hoja de datos.

Preparo un programa para ARDUINO uno sencillo, para tratar de comunicar con él.
Parece ser que todos usan un sistema muy parecido, la salida es analógica y de un nivel compatible con un A/D de 5V fondo de escala. Solo hay que proporcionar dos señales para la lectura:
Pulso SP, (Start pulse) que señala el comienzo de línea y
Pulsos SP o CLK (Clock) que generan la salida del valor analógico de cada punto de imagen.

Para la visualización de las líneas capturadas uso un programa en Processing en un PC con Windows:

Fuentes para probar la lectura de datos de diversos CIS Contact Image Sensor), para Arduino UNO. En el PC la lectura de datos del arduino y la visualización con Processing.
CISReader
Lectura de CIS DynaImage DL100-05EUJK a baja velocidad:

Lectura de CIS DynaImage DL100-05EUJK a alta velocidad:

Lectura de CIS SS30009B de color RGB:

El caso de las fuentes de alimentación zombies

No sé que pensará George A. Romero del título de esta entrada. A mi me suena bien, pero no es acertado. Realmente estas fuentes no son zombies sino que son fantasmas: estan muertas pero ellas no lo saben. También he conocido fuentes verdaderamente zombies: que estaban muertas y volvían a la vida pero no es el caso.
Quedamos en que son fuentes fantasmas. Fuentes muertas pero que no lo saben… hasta que lo descubren y mueren definitivamente.
¿Como las identificamos? Fácil. Tenemos un dispositivo electrónico que lleva incorporada una fuente de alimentación conmutada. Actualmente casi todo, desde TVs, ordenadores personales, cargadores de télefonos, fuentes de laboratorio… Funciona perfectamente pero, en un momento determinado, necesitamos moverlo de sitio. Lo desenchufamos de la alimentación y lo volvemos a enchufar en otro lugar, pero ya no funciona mas. O sufrimos un corte de suministro eléctrico y varios aparatos de la casa no vuelven a funcionar al recuperar la ennergía.
Otras veces vemos que la fuente proporciona pulsos cortos de alimentción y sospechamos de un cortocircuito que dispara la autoprotección. A veces se pueden ver esos pulsos cortos en algún LED indicador que flashea.

Lo primero que pensamos es que un transitorio durante la restitución de la alimentación los ha quemado.
ERROR: Lo que ocurre es que las fuentes ya estaban muertas, pero eran fantasmas de si mismas, que continuaban trabajando después de haber sufrido un fallo interno. Quizás el fallo se produjo hace dias, o meses, pero ellas seguian trabajando como si nada. Hasta que la falta de alimentación descubrió el fallo y ya no funcionaron mas.
Cuando vamos a reparar estas fuentes enontramos que los componentes que fallan mas habitualemente: fusible, rectificador, filtro, conmutador de potencia y en el secundario los diodos y condensadores de filtro estan todos bien. Es una avería chunga si no sabes de antemano donde buscar.

A mi me ha pasado en muchas ocasiones, pero la mas llamativa fue este verano. Durante un corte de energía programado, para para el mantenimiento anual de las estaciones transformadoras, murieron nada menos que 31 inyectores poe (SMCPWR–INJ4)!

Ahora vamos con la parte técnica del asunto.
Las fuentes de alimentación conmutadas suelen tener todas una topología similar en la cara del primario: filtro EMI (las mas modernas o potentes también compensación PFC), las grandes NTC, rectificador, filtro, elemento de control, conmutador de potencia y trafo. Después del trafo la parte del secundario con sus rectificadores, fltros, algunas reguladores y el circuito de realimentación.
Esto es a grandes rasgos una fuente conmutada. Mas o menos este diagrama de bloques:

Bloques

Los diseñadores de fuentes conmutadas step-down se encuentran siempre con el mismo problema: si vamos a reducir unas tensión alta (220V a 12V, por ejemplo), ¿como alimentamos el chip controlador PWM? Antes de que la fuente entre en funcionamiento solo hay 310V (220V rectificados y filtrados) en el primario. Con eso no podemos alimentar un chip controlador, que normalmente funcionan con tensiones de alrededor de 12V (algunos hasta 36V).
Basta con un simple cálculo par ver que un divisor resistivo es inapropiado. Por poco que consuma el controlador la disipación será muy alta. Un pequeño transformador convencional también presenta inconvenientes… La solución óptima, la que usan prácticamente todas las fuentes, es alimentar el chip controlador usando un secundario adicional en el trafo de potencia de la propia fuente, con un rectificador y filtro, y usar un circuito especial de arranque (start up). Este circuito es necesario para el momento en que conectamos la fuente y todavía no ha podido entrar en funcionamiento para autoalimentarse. Solo funcionará durante unos cientos de milisegundos al energizar la fuente, luego ya no será necesario porque el controlador PWM se alimentará a si mismo por el secundario citado anteriormente.
Y si ese circuito se avería la fuente continúa funcionando, hasta que se desalimenta, que ya no es capaz de arrancar.
Ya tenemos la explicación para nuestras fuentes fantasmas: el circuito de start-up.

Lo vemos en esta uente de ejemlo, tomada de aqui: http://www.circuitdiagramworld.com/power_supply_circuit_diagram/70_W_switching_power_supply_10316.html

En este esquema controlador PWM y el conmutador de potencia son un único chip: KA2S0880
El circuito de start-up de esta fuente esta formado por la resistencia R2 de 220K y el condensador electrolítico C6 de 47uF. Existe otro condensador cerámico C7 de 0.1uF para filtrar altas frecuencias. Con estos dos componentes se genera la tensión de alimentación para la patilla 3 del controlador PWM.
La resistencia serie en cualquier fuente será una resistencia de entre 56K a 1M y 1/2 a 5W de potencia. Muchas veces se usa una cadena de resistencias, cuando son SMD, para evitar arcos eléctricos (estarán sometidas a 300V de ddp). El condensador electrolítico será de entre 4,7uF hasta 100uF y una tensión relativamente alta: de 25V hasta 63V. En algunas fuentes hay un zéner de 12V a 18V en paralelo con el condensador electrolítico. En esta fuente el zéner esta integrado en la patilla 3 del controlador KA2S0880 y es de 36V.
El circuito de autoalimentación lo forma el diodo D2 FR207 y el bobinado de la patillas 1 y 4 del transformador.
Esto se puede ver repetido casi de forma exacta en todas las fuentes conmutadas…
El funcionamiento es sencillo: al energizar la fuente tenemos 320V a la salida del rectifcador, poco a poco cargan el condensador C6 a través de la resistencia R2. Cuando la tensión sobrepasa la tensión de arranque del controlador PWM este comienza a oscilar y proporciona potencia al transformador. La tensión en C6 cae unos voltios al producirse consumo, pero eso lo tiene previsto el fabricante del chip controlador que tiene una histéresis de varios voltios en la alimentación: arranca con 15V pero una vez que esta trabajando puede hacerlo incluso con tensiones tan bajas como 10V (Start threshold voltage y Minimum operating voltage en la hoja de datos del KA2S0880). Una vez que ha arrancado la bobina del secundario del trafo de potencia (terminales 1 y 4) proporciona una tensión de alrededor de 12V que se rectifica con C6 (para esta tarea esta sobredimensionado, son pulsos de alta frecuencia) y autoalimenta al KA2S0880.
En estas condiciones, si falla R2 (cierto, he visto resistencias abiertas por arco eléctrico) o el condensador C6 pierde capacidad por envejecimiento, la fuente continuará funcionando autolimentada por D2 y filtrada por la poca capacidad que le quede a C6.
Pero cuando la desconectemos necesitamos de nuevo que R2 proporcione la carga inicial a C6, y que C6 tenga capacidad suficiente para almacenar la energía necesaria para arrancar el controlador y mantenerlo en funcionamiento hasta que la tensión en el transformador pueda autoalimentalo por D2. Algunas veces la capacidad de C6 es baja y la histéresis del controlador de pocos voltios y podemos ver que la fuente intenta arrancar y se para. Se puede observar un diente de sierra en C6 subiendo hasta la tensión de arranque y bajando hasta a mínima de funcionamiento. La fuente proporcioa pulsos cortos de alimentación pero no trabaja en contínuo.

Generalmente el malo de esta película es el condensador electrolítico, C6 de 47uF en este esquema.

En este otro esquema con el popular UC3842 se puede ver también el circuto de startup, formado por un aresistencia de 150K, un condensador de 10uF, un zéner de 18V y un diodo rectifiacor 1N4148 (aqui con una resistencia de 150 Ohmios en serie):
Fuente con UC3842
En esta otra el sospechoso sería el condensador de 10uF.

Voy a ver si este es el problema de los inyectores poe. Abrir estas fuentes es fácil, si sabes como. Se aprientan cerca de la unión de las carcasas con un tornillo de banco y se apalanca con un destornillador para hacer saltar el pegamento:

Se localiza el componente sospechoso. Hay que buscar un condensador electrolítico pequeño en el primario, cerca de un diodo:

En este caso el diodo rectificador para la autoalimentación es uno negro a la derecha del condensador sospechoso. También hay un diodo zéner de cristal a la izquierda. Mejor revisar las pistas para asegurarse de esta fuente lleva este tipo de circuito de startup:

Efectivamente el condensdor esta muy bajo de capacidad, a cambiarlo en todas:

Y ya funcionan de nevo:

Como no tengo claro si voy a usarlas así o integrarlas en algún otro aparato no las voy a pegar definitivamente, que sería lo mejor para su uso normal como inyectores poe:

Todavía me quedan unas horas de trabajo por delante!

Lector, copiador y borrador de tarjetas RFID MIFARE

Estoy liado con varios proyectos que involucran lectores de tarjetas RFID tipo MIFARE de NXP https://www.nxp.com/products/identification-and-security/mifare-ics/mifare-classic:MC_41863 con lectores MFRC522 https://www.prometec.net/producto/rfid-kit-arduino y Arduino UNO

MFRC522

Uno de los probemas que he encontrado es que, cuando trabajas con montones de tarjetas y varios proyectos a la vez, es muy facil confundir tarjetas o incluso programar keys incorrectas. En esas condiciones las tarjetas pueden quedar inútiles (es imprescindible conocer las keys internas para usarlas o borrarlas).

Este programa para Arduino UNO (posiblemente funcione en otros) nos permite averiguar las keys programadas en las tarjetas para luego borrarlas o copiarlas sin preocuparnos de buscar las keys exactas que fueron programadas dentro.
Para ello es necesario compilar el programa con la lista de las keys comunmente usadas en nuestros proyectos. El programa intenta autentificarse en cada sector con cada una de las keys programadas y crea una lista de keys y secores. Esto nos permite luego borrar la tarjeta y dejarla en condiciones de fábrica o copiarla a otra vacía.
Es necesaria la librería de arduino MRFC522 que puede instalarse desde el gestor de librerías del arduino IDE o de aqui: https://github.com/miguelbalboa/rfid

El conexionado necesario es muy sencillo:

Fos ficheros del proyecto: HeliMifareClonner.zip

Para usar el programa se abre con el IDE de arduino y se carga en el arduino. Luego se abre el “monitor serie” y se configura a 115200 baudios y “sin ajuste de linea”. Aparecerá un menú con 5 opciones, que es autoexplicativo:
1: PROBAR las Keys conocidas. Intenta averiguar que key, de la lista incluida en el programa, corresponde con cada sector de la tarjeta.
2: LEER Tarjeta: Lee la tarjeta usando la lista de keys averiguada anteriormente.
3: VER DATOS de tarjeta: Muestra el bloque de datos (1024 bytes) que ha podido leer con la opción 2
4: ESCRIBIR nueva tarjeta: Escribe una tarjeta vacía, que este con las keys de fábrica a FFFFFFFFFFFF, con los datos leidos anteriormente y luego instala las keys averiguadas en cada sector. Esto crea una tarjeta clon de la leíada anteriormente. El bloque 0, que contiene el UID y otros datos del fabricante, no se copia. Aunque algunas tarjetas de fabricantes alternativos (No NXP) permiten escribir en el bloque 0 usando una secuencia de comandos especial, este programa no lo hace (la línea de código necearia esta comentada en el programa) porque no he podido probar que funcione correctamente.
5: COMPROBAR Tarjeta con datos Compara los datos leidos previamente con los datos de otra tarjeta. Si las keys no son las mismas en las dos tarjetas los bloques trailer no podrán coincidir y habrá otros sectores que no podrán leerse y quedarán sin comparar “SIN DATOS”.
6: BORRAR tarjeta: Borra una tarjeta usando las keys averiguadas para dejarla tal y como vienen de fábrica, con las keys a FFFFFFFFFFFF (“transport keys”).

Como optimizar el consumo de memoria en programas de Arduino

El compilador que usa el entorno Arduino es muy óptimo y es dificil escribir el programa de forma que genere menos código: el compilador optimiza automáticamente independientemente de como lo esribamos.
Pero hay algunos detalles que permiten ahorrar bytes de RAM o de FLASH, cambiando un poco el enfoque de los programas!

Uno es usar el macro F() para las variables de cadena que pasamos a algunas funciones, principalmente Serial.print().
Usando como ejemplo el programa http://heli.xbot.es/?p=501 podemos cambiar la línea 61 de:
        Serial.println (“Testing AnalogKeyPad”);
a
        Serial.println (F(“Testing AnalogKeyPad”));

Compilando con el IDE de Arduino 1.8.5 para Arduino UNO (Atmega328p),
la primera forma genera un programa de 1958 bytes que usa 269 bytes de RAM y
la segunda forma genera un programa de 1998 bytes que usa 249 bytes de RAM.
Hemos ahorrado 20 bytes de ram (de los 2048 disponibles) pero el programa ha crecido en 40 bytes!
Que no cunda el pánico, ahora optimizamos mas todavía:
cambiamos la línea 70 de:
        Serial.print (“Pulsado “); Serial.println (b);
a
        Serial.print (F(“Pulsado “)); Serial.println (b);
Ahora el programa ocupa 2004 bytes y usamos 239 de RAM, el programa solo ha crecido en 6 bytes y hemos ahorrado 10 bytes de RAM.

El programa sobre el que estamos trabajando es muy sencillo y no tiene mas cadenas constantes, no podemos seguir mejorándolo, pero cualquier cadena que convirtamos en constante en el futuro ahorraría aproximadamente su longitud en RAM incrementando solo 6 bytes de código en FLASH.

¿Y por que es así?
Porque el micro ATMEGA328P, y toda la familia aTMEGA, son micros con Arquitectura Harvard y eso significa que los DATOS y las instrucciones de PROGRAMA se almacenan en espacios separados y se acceden usando instrucciones de programa distintas.
Eso representa un problema para el compilador porque tiene que generar un código distinto para manejar datos variables (en RAM) y datos constantes (en memoria de programa FLASH).
El compilador que usa el entorno de Arduino es el AVR-GCC y soluciona este problema copiando en RAM las constantes y usando siempre funciones que trabajan sobre RAM.
Esto tiene el inconveniente de que cada constante que declaramos en nuestro programa ocupa una cantidad igual de memoria de programa y de RAM.
Y esto no tiene facil solución porque, para manejar datos que solo esten en memoria de programa, hacen falta funciones distintas que sepan manejar los datos residentes en ese espacio de memoria.
En arduino existe el macro F() que permite instruir al compilador para que almacene una cadena constante solo en FLASH.
Además la función Serial.print() esta sobrecargada de forma que se compila de forma distinta para cadenas variables que para cadenas constantes.
La primera vez que usamos la función Serial.print(F()) el compilador añade el código de la librería necesario para manejar cadenas constantes y por eso el programa crece un poco. Los siguientes usos de la función solo incrementen un poco el código debido a la diferente gestión de los datos.
Lo importante es que cada uso de F() ahorra una cantidad de RAM igual a la longitud de la cadena usada! Y en RAM es donde mas justo esta el Atmega328p.

Podemos usar esta técnica para otras constantes, pero si la función que las ha de usar no esta adecuadamente sobrecargada (es decir, no tienen definida función para trabajar con datos en espacio de programa) no será posible. Tenemos que escribir nuestro propio código para acceder a esos datos en memoria de programa… pero es sencillo.

Este es un array normal, cada dato (int) ocupa dos bytes de FLASH y dos de RAM.
        const int KeyVals[nKeys+1] = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};

La forma de decir al compilador que queremos que almacene un array en memoria de programa es esta:
        const int KeyVals[nKeys+1 ] PROGMEM = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};

Pero al usar la segunda forma ya no podemos hacer:
if (Val >= KeyVals[i]) break;

porque el manejo de variables array solo puede trabajar con datos en RAM. ATENCION el compilador no informará de un error!!! pero el programa no funcionará. Los datos estarán almacenados en un espacio de memoria pero el programa intentará usar punteros a ese espacio de memoria en otro espacio de memoria distinto, con lo que apuntará a datos distintos y no funcionará!! Debe usarse la función adecuada para leer los datos almacenados en la memoria de programa, usando los punteros a memoria de programa ha generado el uso de PROGMEM: pgm_read_word(), porque los datos son de tipo int (ocupan 16 bits):
        if (Val >= pgm_read_word(KeyVals+i)) break;

Para el otro array, que es tipo char (8 bits), se debe usar la función
        pgm_read_byte(Keys+i);

NO se puede usar el índice [i] en un array PROGMEM ya que su gestión esta definida para trabajar con variables RAM. Debe usarse +i que sirve para punteros a RAM o a FLASH.

Después de aplicar estas dos optimizaciones al programa (dos líneas con F() y dos arrays cambiados a PROGMEM) el programa que antes ocupaga 1958 bytes de FLASH y usaba 269 de RAM ahora ocupa 1992 bytes de FLASH pero solo usa 189 bytes de RAM.
Ha crecido en 34 bytes de 32768 disponibles (~ 0.1%) pero ha bajado el uso de ram en 80 bytes de 2048, casi un 4% de mejora.

https://www.arduino.cc/en/Reference/PROGMEM

El programa optimizado: AnalogKeyPad1

Teclado de matriz 4×4 analógico para arduino

Aunque ya hay teclados de matriz analógicos comerciales y librerías para arduino (este, por ejemplo: https://www.sparkfun.com/products/12080) es interesante convertir los teclados de matriz que ya tenemos por casa a analógico.
Las placas Arduino tienen entradas analógicas de 10 bit y solemos tener alguna sin usar…
Siguiendo esta idea: http://www.technoblogy.com/show?NGM puede hacerse con 7 restencias normales del 5% de tolerancia con este esquema:

Código:
/*
* AnalogKeyPad: Teclado de matriz para lectura analógica
* segun esquema: http://www.technoblogy.com/show?NGM
*
* (c) Heli Tejedor, http://heli.xbot.es, Octubre 2017
*
* Este Software se distribuye bajo licencia
*
* Creative Commons 3.0 Reconocimiento, No Comercial, Compartir Igual (CC BY-NC-SA 3.0)
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es_ES
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
*/

// Configuracion del teclado
#define nKeys 16

#define NO_KEY 0
#define KEYPAD_PIN A0

// Tecla de la matriz 4×4: NINGUNA S1 S5 S9 S13 S2 S3 S4 S6 S7 S8 S10 S11 S14 S12 S15 S16
const int KeyVals[nKeys+1] = { 693, 665, 624, 573, 544, 491, 463, 432, 393, 353, 308, 249, 188, 157, 117, 79, 0};
const char Keys[nKeys+1] = {NO_KEY, ‘7’, ‘4’, ‘1’, ‘A’, ‘8’, ‘9’, ‘F’, ‘5’, ‘6’, ‘E’, ‘2’, ‘3’, ‘0’, ‘T’, ‘C’, ‘P’};

// ===============================================================================
// Retorna caracter de la matriz
// ===============================================================================
char GetKey (int Val)
{
char i=0;
for (; i= KeyVals[i]) break;
return Keys[i];
}

// ===============================================================================
// Lee el teclado, retorna caracter de la matriz o NO_KEY
// ===============================================================================
char ReadKeyPad()
{
static char OldKey = NO_KEY;
char KeyPressed;
char FirstKey = GetKey (analogRead(KEYPAD_PIN));

// Necesita 10 lecturas validas seguidas durante 10ms
for (char i=0; i<10; i++) { KeyPressed = GetKey (analogRead(KEYPAD_PIN)); if (KeyPressed != FirstKey) return NO_KEY; delay (1); } if (KeyPressed == OldKey) return NO_KEY; OldKey = KeyPressed; return KeyPressed; } // =============================================================================== void setup(void) { Serial.begin (115200); Serial.println ("Testing AnalogKeyPad"); } // =============================================================================== void loop(void) { char b = ReadKeyPad(); if (b != NO_KEY) { Serial.print ("Pulsado "); Serial.println (b); } delay(100); }

Todos los ficheros del proyecto estan aqui:
http://heli.xbot.es/wp-content/uploads/2017/11/AnalogKeyPad.zip
junto con una tabla de excell para calcular los valores analógicos en función de las resistencias elegidas.

Actualización 2/11/2017: Una mejora que puede hacerse es montar la resisitencia de pullup de 15K Ohmios directamente en la entrada analógica, junto al arduino. De esta forma se evita que un mal conexionado del teclado provoque pulsaciones fantasma de las teclas. Además se elimina un cable del conexionado del teclado: ahora es solo de dos hilos!

Usando viejos displays LED 7 segmentos con SDA2131 desde arduino

Tengo una caja llena de viejos display de 7 segmentos LED, muchos de máquinas pimball, otros de básculas industriales…
Todos tienen más de 25 años y usan para controlar los displays chips Siemens SDA2131. Hoja de datos del SDA2131.

Cada uno de estos chips SDA2131 puede manejar 16 segmentos LED directamente, sin resistencias limitadoras, y la información se carga usando un bus serie síncrono. No es muy dificil escribir un programa que pueda manejarlos.
Usando partes de otro programa para LED de 7 segmentos (YL-3) http://heli.xbot.es/?p=151 que ya había escrito antes he escrito un pequeño programa para Arduino uno que controla estos displays: SDA2131 con Arduino

Usando un display de matriz LED indocumentado CDM102

Haciendo limpieza he desmontado y tirado una docena de viejos switches ethernet 10baseT de Nortel Networks “Baystack 102”. Specs Baystack 102

A parte de mucho hierro tienen unas fuentes de alimentación fabricadas por Delta SMP43ep-5 muy interesantes.
https://www.usbid.com/assets/datasheets/C5/smp43ep.pdf
Proporcionan 5V hasta 11A, 12V 3A y -12V 0,5A aunque la potencia total es de 43W.

También son muy interesantes los displays de matriz de 12 * 5 LED bicolores. La pega es que no hay mucha información acerca de su funcionamiento. Llevan impreso el código “CDM102”, pero parecen ser diseñados a medida y no existe información pública sobre ellos.

En google he encontrado algo de información, que coincide con mis primeros análisis: http://home.earthlink.net/~drbarrall/CDM102.html

El interface es série síncrono al estilo del SPI. El uso de cada uno de los 6 pines es el siguiente:

1: LOAD Load data (Active low)
2: V+ 5V
3: SDCLK Data Clock (Active high)
4: Ground
5: SDDATA Data
6: Reset (Active low)

Despues de probar los comandos publicados por DrBarral he llegado a la conclusión de que este display es un diseño a medida para Nortel, fabricado por Siemens – Infineon – OSRAM y derivado de los displays estándar SCDQ554x http://www.osram-os.com/Graphics/XPic1/00052446_0.pdf o SCD551x http://www.osram-os.com/Graphics/XPic4/00045726_0.pdf.
CDM102 podría ser Custom Display Module 102.
La principal diferencia es que se trata de una matriz doble de 6 x 5 mientras que los displays citados son de matriz de 5 x 5.

El juego de comandos es bastante sencillo, basado en una única palabra de 8 bits:
00 – 7F: 5 bits de datos para las columnas, bit 0 es el LED de mas arriba. Se incrementa el puntero automaticamente.
Hay 6 columnas
80 – 9F: Nop
A0 – A5: Selecciona bloque de columnas. Hay 2 bloques de 6 columnas. Bloque par color ROJO, impar color VERDE.
El bit 4 no importa. El primer bloque es el de la izquierda.
A6 – AF: Select none
B0 – B5: Selecciona bloque de columnas. Hay 2 bloques de 6 columnas. Bloque par color ROJO, impar color VERDE.
El bit 4 no importa. El primer bloque es el de la izquierda.
B6 – BF: Seleccionar NADA
C0 – DF: Test: rellena filas con rojo+verde: bit 0 = primera columna, bit 1 = segunda etc
E0 – EF: Ajustar brillo en 8 steps, el bit 3 no importa
F0 – FF: Ajustar brillo en 8 steps, el bit 3 no importa

He escrito un software de prueba que permite escribir caracteres en un número arbitrario de displays puestos lado con lado, bien de forma vertical como horizontal. Tembién contiene un ejemplo para usarlo como barra gráfica de 12 barras berticales x 5 LED o 5 barras horizontales de 12 LED.
He aprovechado los bitmap que ya tenía escritos hace años para los SCDQ554x, sirven igual pero solo son de 5 x 5 pixel, dejo sin uso una línea de LED en este display de 6 x 5.
Prueba para CDM102 con Arduino/Teensy

El montaje de pruebas ha quedado así:

Las funciones que he incluido dentro del programa de pruebas son las mismas que ya usé en el display YL-3: http://heli.xbot.es/wp-admin/post.php?post=151
Aunque he añadido un par de comandos para cambiar la orientación del texto y el color “ºh , ºv, “ºr y ºg.

Mini algoritmo de cifrado XXTEA para arduino

Estoy metido en tres fregados simultáneos de IOT (ahora se llama así, antes solo eran redes de sensores distribuidos) y estaba buscando un algoritmo de encriptación aceptable para dispositivos embebidos (no hay que perder de vista la seguridad de la IOT, que luego vienen los disgustos..)
De momento estoy usando Arduino Uno (Atmega328) y había reciclado un DES que usé en otro proyecto (librería de arduino http://spaniakos.github.io/ArduinoDES) pero como voy justo de memoria y tiempo de ciclo pensé en mejorarlo.

Valoré un AES del que también tengo librería para arduino https://github.com/DavyLandman/AESLib pero ocupaba demasiado espacio en flash.

Entonces me encuentro la sorpresa, viendo avr-crypto-lib un listado de algoritmos para micros AVR de atmel, veo que existe uno llamado XTEA muy sencillo de implementar y pensado para dispositivos embebidos. Desgraciadamente la implementación de avr-crypto-lib es muy básica y no es la versión mejorada XXTEA
Buscando por la red he encontrado algunas librerías de XXTEA para Arduino, pero son un calco de la publicación original y no aportan mejoras.

Después de un cortapega de la wikipedia y de machacar el teclado un rato he dejado el algorítmo bastante óptimo para Arduino.

En los test que he realizado, un arduino Uno a 16Mhz tarda en cifrar y descifra un bloque de 64 bytes:
Con DES en modo CBC tarda 284568us y ocupa 2572 bytes de flash
Con XTEA en modo CBC tarda 11008us y ocupa 916 bytes de flash
Con XXTEA tarda 4168us y ocupa 1086 bytes de flash
O sea que es rapidísimo y pequeñito…

La KEY es de 128 bits (mejor que el DES que solo es de 56) aceptable para mi aplicación. Se conocen ataques pero se basan en usar mas de 2^59 “textos planos escogidos”, también aceptable!!

El código es extremadamente sencillo, la única desventaja es que sobreescribe los datos planos con los datos encriptados, aunque he preparado una versión con un simple memcpy que soluciona este problema con unas decenas de microsegundos de trabajo extra.

El código fuente con DES, XTEA y XXTEA y algunas pruebas: XxteaTest

Mini programa para iniciar la EEprom del ATmega328 del Arduino UNO

Llevo bastante tiempo liado desarrollando aplicaciones para Arduino…
En algunos proyectos me encuentro que es dificil inicalizar la EEprom del Arduino (ATmega328). El IDE arduino (la version actual es 1.8.2) no genera los ficheros .eep que necesita avrdude para grabar el atmega, entonces declarar variables con EEMEM e inicializarlas en el IDE no sirve para nada.

Para solucionar este problema he escrito un pequeño programa que se carga en el arduino UNO (valdría para otros modelos con algunas modificaciones) y mediante comandos por el puerto serie permite leer o escribir la EEprom y dejarla ya inicializada. Luego se carga el programa que se necesite y se encuentra las EEprom inicada con los valores adecuados.

El proceso es el siguiente:
Se carga este programa en el Arduino UNO (renombrarlo a .ino):

SetEEprom.ino

A continuación se abre el monitor serie y se configura a 115200 baudios y enviar CR LF.
En el monitor serie se pueden escribir los comandos adecuados para ir iniciando la EEprom a los valores deseados. Lo mejor es prepararlo en un archivo de texto y hacer corta-pega sobre el monitor serie.
Estos son los comandos disponibles en el programa:

SetEEprom.txt

Por ejemplo se puede borrar toda ea EEprom (ponerla a 0xFF) con:
Write Init EEprom

Y luego iniciar una cadena de 10 caracteres en la dirección 0 con el valor “hola mundo”
Write String 0 10 Hola Mundo

y un bloque de 10 datos en la dirección 20:
Write EEprom 20 10 0F0302B1421CA7485823

Una vez iniciada la EEprom se carga el programa que necesitamos en el Arduino UNO y cuando arranque se encontrará la EEprom ya iniciada con los valores que introdujimos.