TUTORIAL: ¿Por qué mi programa en Arduino se reinicia, falla, se bloquea, ... ?

Me gustaría usar este post para mencionar un par de cosas que creo que son muy útiles y que he ido descubriendo como suele ser habitual a base de horas y quebraderos de cabeza, junto con lecturas infinitas de foros, etc...
Esto va dirigido a los menos avanzados (como yo) que poco a poco nos ponemos con proyectos mas grandes y mas complejos.

Cuando realizamos un proyecto pequeño nos olvidamos de ciertas limitaciones que tienen estos pequeños microcontroladores, nos olvidamos que no son ordenadores con grandes capacidades de memoria o calculo. Conforme ampliaba un proyecto que empece cuando todavía encender un led era motivo de sonrisa de satisfacción, empece a tener problemas de estabilidad en mi programa. No entendía porque de forma aleatoria se reiniciaba mi Arduino, se bloqueaba, fallaban las lecturas etc.

Poco a poco he aprendido 3 o 4 puntos importantes que me gustaría mencionar aquí para todos aquellos que se identifiquen con mi caso, seguro que a alguno le ahorra una infinidad de horas y de quebraderos de cabeza....que yo sufrí.

Vamos a utilizar como ejemplo el Arduino UNO ya que es el mas utilizado comúnmente, aunque esto es aplicable a otras placas.

Flash Memory 32 KB (ATmega328) of which 0.5 KB used by bootloader
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)

Nota: No voy a entrar a la explicación técnica de cada uno de estos puntos porque esta documentado en la red y yo no soy ningún experto y seguro que me dejo cosas.

Punto 1: Memoria SRAM
Cuando incluimos en nuestro programa lineas como las siguientes...

 Serial.println(" ------------------------- Iniciando Arduino --------------------------");

Estamos ocupando memoria SRAM que resulta ser la mas escasa en nuestro pequeño microcontrolador. Si no controlamos el espacio libre llegaremos a machacar la memoria con datos unos encima de otros lo cual finalmente se traducirá en inestabilidad del programa y el reinicio del Arduino

Solución
Con un pequeño código podemos controlar la memoria SRAM disponible en cualquier momento. Yo suelo hacer que me muestre este valor al final del setup() y luego lo pongo el el loop() y compruebo que el valor no disminuye con el tiempo.

      #include <MemoryFree.h>
    Serial.print("freeMemory()=");        Serial.println(freeMemory());

Crear la libreria con estos dos archivos. No los pongo como adjuntos porque al ser tan cortos creo que es mejor tener el código aquí por si se eliminan los adjuntos.

File: MemoryFree.cpp

extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;

#include "MemoryFree.h";

int freeMemory() {
  int free_memory;

  if((int)__brkval == 0)
     free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

File: MemoryFree.h

// memoryFree header

#ifndef	MEMORY_FREE_H
#define MEMORY_FREE_H

#ifdef __cplusplus
extern "C" {
#endif

int freeMemory();

#ifdef  __cplusplus
}
#endif

#endif

Se aconseja disponer al menos de 200 bytes de memoria SRAM libre durante la ejecución del programa para evitar problemas.

¿Como liberar espacio?
Para utilizar la Memoria Flash en lugar de la SRAM que es mucho mas escasa, podemos utilizar PROGMEM, esta todo descrito aquí:
http://arduino.cc/es/Reference/PROGMEM

Punto 2: Flash Memory.
En el caso de sobrepasar la memoria flash para almacenar el programa nos sera imposible subirlo a la placa, al intentarlo obtendremos un error.

Binary sketch size: 27242 bytes (of a 32256 byte maximum)

El problema es que en el compilador nos indica que tenemos kB totales para nuestro programa. No obstante hay un fallo en el IDE por el cual obtendremos un error que nos impedirá subir nuestro programa al Arduino con programas de tamaño ligeramente menor a ese valor, lo cual puede confundirnos respecto al origen del problema.
El tamaño total que puede tener nuestro programa es de

28672 bytes

sobrepasado este valor, no podremos subir el programa y el error que nos aparece no da mucha idea del motivo por el cual esta fallando. Así que recordarlo !

**Punto 3: Reinicios del Arduino debido a perdida de internet**[/size][/u]
Usando el Ethernet Shield Oficial.
En ocasiones debido a un problema de conexión a internet cuando usamos el Ethernet Shield se puede ocasionar reinicios del Arduino. Añadiendo unas lineas podemos limitar el tiempo de espera que el Arduino intentara establecer la conexión y si no lo consigue seguirá con el programa.
Para ello añadiremos la librería.
[/u] [u]  #include <utility/w5100.h>     // Advance Ethernet functions[/u] [u]
En el setup() de nuestro programa añadiremos estas dos lineas
[/u] [u]  W5100.setRetransmissionTime(0x07D0);  //setRetransmissionTime sets the Wiznet's timeout period, where each unit is 100us, so 0x07D0 (decimal 2000) means 200ms.  W5100.setRetransmissionCount(3);      //setRetransmissionCount sets the Wiznet's retry count.[/u] [u]
De esta forma cuando hagamos...
[/u] [u]if (client.connect()) {[/u] [u]
evitaremos que se quede colgado si la conexión no es exitosa.
Punto 4: Utilizar Watchdog.
Esta es una función muy útil para evitar que nuestro Arduino se quede en un bucle infinito o bloqueado en alguna parte del código. No voy a entrar en describirlo ya que esta muy documentado en la red pero si me parece importante mencionar que si disponemos de un Arduino duemilanove tendremos que actualizar el bootloader ya que el que viene de serie tiene un fallo que en esencia hara que cuando se ejecute el watchdog, se establezca un valor de reinicio de muy bajo tiempo por lo que el Arduino se reiniciara constantemente.
Para solucionarlo si nos pasa esto no nos queda otra que crear un programa "vació" con un setup() y loop() y probar y probar a subirlo al arduino hasta que entre.
Al margen de esto, el Watchdog se asegurara que no tengas que ir y manualmente reiniciar el Arduino en caso de fallo eventual. Muy útil cuando el Arduino se encuentra trabajando en una localización de difícil acceso o desatendido.
Punto 5: Tipos de Variables
Es muy importante cuando declaremos variables y cuando metamos datos en ellas que recordemos la capacidad de cada variable y el tipo. Esto también nos sera útil para ahorrar SRAM cuando sea posible, declarando variables de tamaño acorde al dato que ira dentro.
Aquí podéis ver que valores engloban cada variable y su tamaño.
[u]http://sites.google.com/site/mechatronicsguy/arduinocheatsheet/Arduino%20cheet%20sheet%20v02bsmall.png[/u]
> Datatype RAM usage
> void keyword N/A
> boolean 1 byte
> char 1 byte
> unsigned char 1 byte
> int 2 byte
> unsigned int 2 byte
> word 2 byte
> long 4 byte
> unsigned long 4 byte
> float 4 byte
> double 4 byte
> string 1 byte + x
> array 1 byte + x
> enum N/A
> struct N/A
> pointer N/A
Espero que esto le sea de ayuda a alguien ya que sin duda a mi me habria ahorrado muchisimas horas de "que esta pasando!!" al no entender porque mi Arduino no se comportaba como yo esperaba.
Por favor, cualquier error o información adicional que penseis que puede ser util hacermelo saber y podemos ampliar todo lo aquí expuesto.
En cuanto lo revise una vez mas lo pasare a ingles por cubrir mas audiencia :wink:
Un saludo,
Sergegsx

1 Like

Wow! Estupendástica recopilación de trucos! Clap, clap, clap
Seguro que nos salva de una cuantas horas de tirarnos de los pelos a muchos de nosotros :smiley:

Lo meto en mi cuaderno de arduino. Gracias Sergegsx

1 Like

muy bueno!

Gracias

al Playground? => Arduino Playground - FAQ

Gracias!

:wink:

NO ME FUNCIONA.LO COMPILE ARDUINO 0022, ME TIRA ESTE ERROR

"In file included from sketch_nov18c.cpp:7:
sketch_nov18c:-1: error: previous declaration of 'int freeMemory()' with 'C++' linkage
MemoryFree.h:7: error: conflicts with new declaration with 'C' linkage
"

=( =( =( =( =( =( =(

Sergegsx:
Punto 2: Flash Memory.
En el caso de sobrepasar la memoria flash para almacenar el programa nos sera imposible subirlo a la placa, al intentarlo obtendremos un error: Binary sketch size: 27242 bytes (of a 32256 byte maximum)
El problema es que en el compilador nos indica que tenemos kB totales para nuestro programa. No obstante hay un fallo en el IDE por el cual obtendremos un error que nos impedirá subir nuestro programa al Arduino con programas de tamaño ligeramente menor a ese valor, lo cual puede confundirnos respecto al origen del problema.
El tamaño total que puede tener nuestro programa es de: 28672 bytes
sobrepasado este valor, no podremos subir el programa y el error que nos aparece no da mucha idea del motivo por el cual esta fallando. Así que recordarlo !

Creo que eso lo soluciona el nuevo Bootloader de WestfW (Optiboot 4.4), que ya viene incluido en el IDE 0023.

Razorblade:

Sergegsx:
Punto 2: Flash Memory.
En el caso de sobrepasar la memoria flash para almacenar el programa nos sera imposible subirlo a la placa, al intentarlo obtendremos un error: Binary sketch size: 27242 bytes (of a 32256 byte maximum)
El problema es que en el compilador nos indica que tenemos kB totales para nuestro programa. No obstante hay un fallo en el IDE por el cual obtendremos un error que nos impedirá subir nuestro programa al Arduino con programas de tamaño ligeramente menor a ese valor, lo cual puede confundirnos respecto al origen del problema.
El tamaño total que puede tener nuestro programa es de: 28672 bytes
sobrepasado este valor, no podremos subir el programa y el error que nos aparece no da mucha idea del motivo por el cual esta fallando. Así que recordarlo !

Creo que eso lo soluciona el nuevo Bootloader de WestfW (Optiboot 4.4), que ya viene incluido en el IDE 0023.

estupendo porque a mi me hizo perder 2 o 3 horas hasta que encontre porque no subian los sketch.
no sabia que existe la versión 23, descargandola....
a ver si encuentro que cambios tiene el Optiboot 4.4.
gracias por el aviso.

También viene incluido en la versión del IDE 1.0-rc2.
Lo que soluciona el bootloader de westfw (ahora el oficial) está escrito en el tema del foro al respecto.
En concreto sería el problema de "optiboot has problems uploading sketches bigger than about 30 KB". También es interesante que con su bootloader ya se puede usar el Uno como programador ISP, solucionando el problema "Optiboot does not support ArduinoasISP programmer".

Por cierto, ya se ha publicado el esquema y fotos de la nueva placa Uno R3, aunque de momento ni en la propia tienda oficial Arduino la venden, sólo en las tiendas americanas RadioShack.
El tema es que quitando las tonterías sacaperras (cambiar el color de la placa, cambiar la posición del pulsador reset, duplicar los pines TWI, añadir un pin sorpresa y un pin para compatibilidad con el Due), la modificación que han hecho al final para solucionar el problema del Reset de las Uno R2 (pico de tensión), es colocar un diodo entre Reset y +5V.
La modificación casera sería (supongo que con un 1N4148):

me baje el 0023, pero me sigue tirando el mismo error, no estoy poniendo p agregando codigo al codigo original.

AlexRodriguez, a ver si contesta Sergegsx, que yo nunca he usado esa librería.
El problema viene de mezclar C con C++.

Cual es ese pin sorpresa que lleva la R3?

Intenta averiguarlo xD
http://www.flickr.com/photos/jeremyblum/6162915410/

Aunque esa versión parece distinta de la R3, que parece que sigue siendo similar a la R2
http://www.flickr.com/photos/jeremyblum/6162915410/

segun lo q puede leer dice IDREF, Q signifiaca, ni idea.

=( =( =( =(

Puede ser un selector automático de tensión para los shields. Es decir detectar si se alimentan a 3.3V o 5V y alimentarlos adecuadamente o seleccionar el regulador para alimentar a todo. Viendo el cirio que han montado con los operacionales para seleccionar la fuente de alimentación.

El pin sorpresa será sorpresa hasta que le den una utilidad. De momento creo que es que no está ni conectado a nada. Pero vamos, igual pasado mañana sacan la R4 que ya no lo lleve.
El otro pin que decís es efectivamente para determinar la tensión, por compatibilidad con el Arduino Due. Vamos, para que las futuras Shield sepan si tienen que funcionar a 5 o a 3.3 V.

OLLE Razorblade, POR LO VISTO SABES MAS Q YO, POR LO MENOS NO ENTIENDO,JA.
PODRIAS PASARTE POR ESTE LINK, NO PUEDO ENCONTRAR UNA SOLUCION,GRACIAS!!

http://arduino.cc/forum/index.php/topic,78927.0.html

Eres un crack y me acabas de evitar horas de búsqueda. Sabía que mi problema era la memoria, pero no que las cadenas estáticas utilizaban SRAM.
Muchas gracias.

El problema que nos queda, es que arduino no tiene depuración paso a paso ni puntos de inspección, con lo que tenemos que seguir utilizando los Serial.print si queremos enterarnos de lo que pasa, para evitar que consuman memoria podeis utilizar directivas de preprocesador

#define DEBUG

#ifdef DEBUG

#endif

El solo se compila si existe #define DEBUG antes, si no no se compila
Para aplicarlo a funciones podeis eliminar la definicón con #undef DEBUG

Si no hacemos un pequeño esfuerzo por comentar la solución de nuestros problemas en los foros no aportaremos nada.

Gracias

Hola a todos, si lucho con la Ram de Arduino, pero me di cuenta de algo, que nadie ha mencionado, solo carguen la libreria SD.h, y veran que la RAM sube mas del 30% es una locura. Estaba haciendo un proyecto algo grande en un 328, Bluetooth, SD, Display, y mucho pero no demaciado codigo, me decia poca memoria, me canse de borrar y resumir codigo, pero no entendia, cuando elimine la libreria SD.h, increiblemente bajo de 80% a 20%, me parece una locura pensar que logicamente un modulo SD te ayuda con la memoria, te quite tanta en ram, hasta ahora no encontre ninguna libreria alternativa, tambien probe en bajar la version a 1.0 y muy extrañamente sigue ocupando lo mismo

Hermano me salvaste el día!. Comento por si a alguien le sirve: necesitaba crear archivos con nombre en una SD y a veces los creaba y a veces no, un error muy aleatorio, había visto el cartel de "poca memoria disponible se pueden producir problemas de estabilidad arduino" pero no pensé que fuera TAN crítico; ni bien borre un cartel que imprimía por el puertos serial y liberé bastante memoria... se solucionó el problema :slight_smile: :slight_smile: :).