Archivo de la categoría: Memoria

EEPROM

La EEPROM es una memoria no volátil que dispone el microcontrolador de Arduino que nos permite guardar datos para poder recuperar en caso de pérdida de alimentación de nuestro dispositivo.

La gran desventaja que tiene la EEPROM es que tiene un número limitado de escrituras, por lo que debemos calcular cuántas veces se va a escribir en ella para calcular su vida útil con nuestro programa. Además la velocidad de lectura y escritura en inferior que en la SRAM y Flash.

Más información en: http://en.wikipedia.org/wiki/EEPROM

Las celdas de memoria de una EEPROM están constituidas por un transistor MOS, que tiene una compuerta flotante (estructura SAMOS), su estado normal está cortado y la salida proporciona un 1 lógico.

Aunque una EEPROM puede ser leída un número ilimitado de veces, sólo puede ser borrada y reprogramada entre 100.000 y un millón de veces.

Además de la memoria EEPROM integrada en el chip del microcontrolador, hay disponibles memorias EEPROM externas. Estos dispositivos suelen comunicarse mediante protocolos como I²C, SPI y Microwire.

La memoria flash es una forma avanzada de EEPROM.

La librería EEPROM nos permite leer y escribir bytes de la EEPROM de Arduino. La EEPROM en cada MCU tiene un tamaño diferente, en nuestro caso con el Arduino UNO es de 1024 bytes. Esta librería solo me permite leer y escribir a nivel de byte, por lo que si quiero guardar variables cuyo tamaño sea mayor de 1 byte, deberemos hacer operaciones.

Librería http://arduino.cc/en/Reference/EEPROM

Una EEPROM tarda unos 3,3 ms en completar una escritura y para Arduino se ha especificado una vida de 100000 ciclos de escritura/borrado.

Tutorial lectura EEPROM: http://en.wikipedia.org/wiki/EEPROM

Tutorial escritura EEPROM: http://arduino.cc/en/Tutorial/EEPROMWrite

Tutorial limpiado EEPROM: http://arduino.cc/en/Tutorial/EEPROMClear

Para grabar estructuras de datos en la EEPROM de una forma muy sencilla podemos usar EEPROMAnything.h. http://playground.arduino.cc/Code/EEPROMWriteAnything

AVR Libc dispone de métodos de la librería <avr/eeprom.h> para manejar la EEPROM: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__eeprom.html

La librería EEPROMex es una extensión de la librería EEPROM que amplía sus funcionalidades:

El acceso entre la EEPROM y la CPU se hace mediante los registros:

  • EEPROM Address Registers: EEARH y EEARL
  • EEPROM Data Register: EEDR
  • EEPROM Control Register: EECR

Más información en la página 36 del http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf

Cosas a tener en cuenta con la EEPROM: https://engineerzero.wordpress.com/2013/07/11/five-things-to-remember-pun-about-arduino-eeprom/

  • Los datos deben guardarse en formato byte para ser usados
  • EEPROM puede los datos de configuración de usuario
  • Dañar la EEPROM no es un problema grave
  • Dañar la EEPROM puede ser un problema si no se tiene cuidado
  • Dañar la EEPROM no es el fin del mundo

Muy buen tutorial de Luis Llamas: https://www.luisllamas.es/guardar-variables-entre-reinicios-con-arduino-y-la-memoria-no-volatil-eeprom/

Un uso típico con la EEPROM es crear un firmware único muchos dispositivos y guardar las variables de cada dispositivo en la EEPROM, por ejemplo la IP, MAC, identificador, número de sondas conectadas, etc… De esta forma con un único firmware único que en el setup() lee la configuración de la EEPROM, se personaliza el comportamiento de cada dispositvo.

Comprobación de EEPROM no corrompida: https://www.arduino.cc/en/Tutorial/EEPROMCrc

La verificación por redundancia cíclica (CRC) es un código de detección de errores usado frecuentemente en redes digitales y en dispositivos de almacenamiento para detectar cambios accidentales en los datos. https://es.wikipedia.org/wiki/Verificaci%C3%B3n_de_redundancia_c%C3%ADclica

Calculo CRC: http://www.lammertbies.nl/comm/info/crc-calculation.html

Sketch para grabar en la EEPROM en diferentes celdas y no machacar una misma zona de memoria, comprobando el nivel de desgaste de las celdas de la EEPROM: http://blog.blinkenlight.net/experiments/counting-resets/wear-leveling/

EEPROM Externa

Para proteger un arduino que queremos comercializar y que no se pueda replicar el programa en otros microcontroladores Atmel.

Un ejemplo es usar una EEPROM externa usado como “mochila” donde guardamos un número único. Este mismo módulo lo podríamos usar como contador o con otras funcionalidades.

Práctica: Volcado EEPROM

Si estamos depurando un proyecto de Arduino usando EEPROM, es posible que queramos ver la EEPROM para entender lo que está pasando.

Si tenemos un programador ISP como el USBtinyISP de Adafruit, siempre se puede utilizar avrdude para volcar la EEPROM a un archivo. Por ejemplo, el siguiente código crea un archivo denominado e2data.ee con contenido de EEPROM.

 
$ avrdude -p m328p -c usbtiny -P usb -U eeprom:r:e2data.ee:r

Otra opción es usar un sketch que nos saque por el puerto serie el contenido de la EEPROM.

Solución: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio23-leeEEPROM

Práctica: Termómetro con Máximas y Mínimas.

Partiendo del ejercicio https://aprendiendoarduino.wordpress.com/2017/06/24/ejemplo-sensor-de-temperatura/ hacer que guarde los valores máximos y mínimos en las direcciones de memoria 100 y 200 respectivamente.

Para recuperarlo pulsar en el monitor serie M para máximo y m para mínimo. Para inicializar los valores de max y min pulsar R.

Como las temperaturas máximas y mínimas son de tipo float, usar los métodos:

Uso sensor tmp36: http://www.prometec.net/sensor-tmp36/

Solución: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio24-Temperatura_Max_Min

Memoria Arduino

Arduino y todos los microcontroladores tienen varios tipos de memoria integradas en el mismo chip, en el caso de Arduino y los microcontroladores AVR de Atmel usan tres tipos de memorias:

  • SRAM (static random access memory): Variables locales, datos parciales. Usualmente se trata como banco de registros y memoria volátil. Es la zona de memoria donde el sketch crea y manipula las variables cuando se ejecuta. Es un recurso limitado y debemos supervisar su uso para evitar agotarlo.
  • EEPROM:  Memoria no volátil para mantener datos después de un reset. Se puede grabar desde el programa del microcontrolador, usualmente, constantes de programa. Las EEPROMs tienen un número limitado de lecturas/escrituras, tener en cuenta a la hora de usarla. Esta memoria solo puede leerse byte a byte y su uso puede se un poco incómodo. También es algo más lenta que la SRAM. La vida útil de la EEPROM es de unos 100.000 ciclos de escritura
  • Flash: Memoria de programa. Usualmente desde 1 Kb a 4 Mb (controladores de familias grandes). Es donde se guarda el sketch ya compilado. Sería el equivalente al disco duro de un ordenador. En la memoria flash también se almacena del bootloader. Se puede ejecutar un programa desde la memoria flash, pero no es posible modificar los datos, sino que es necesario copiar los datos en la SRAM para modificarlos.
    La memoria flash usa la misma tecnología que las tarjetas SD, los pen drives o algunos tipos de SSD, esta memoria tiene una vida útil de unos 100.000 ciclos de escritura, así que cargando 10 programas al día durante 27 años podríamos dañar la memoria flash.

Memorias en Arduino:

La memoria flash y la EEPROM son no volátiles, es decir, la información persiste tras el apagado del Arduino.

Memoria de Arduino UNO:

  • Flash  32k bytes (of which 0.5k is used for the bootloader)
  • SRAM   2k bytes
  • EEPROM 1k byte

Memoria de Arduino MEGA:

  • Flash  256k bytes (of which 8k is used for the bootloader)
  • SRAM   8k bytes
  • EEPROM 4k byte

Memoria de Arduino MKR1000:

  • Flash  256k bytes
  • SRAM   32k bytes
  • EEPROM no. Dispone de EEPROM emulation en la memoria flash (ver documentación del microcontrolador)

Memoria ESP8266:

  • 64 KiB of instruction RAM, 96 KiB of data RAM
  • External QSPI flash – 512 KiB to 4 MiB (no dispone de memoria Externa)

La memoria SRAM es un recurso escaso que debe gestionarse, especialmente si se usan los strings o cadenas de caracteres de forma intensiva. Si un Arduino se queda sin memoria SRAM, el sketch compilará bien y se cargará en el Arduino sin problema, pero se producirán efectos inesperados.

En caso de usar muchos strings, una técnica para evitar agotar la memoria SRAM es guardar en la memoria flash los strings que no se modifiquen en tiempo de ejecución, usando PROGMEM: https://www.arduino.cc/en/Reference/PROGMEM

Desde la versión 1.0 del IDE de Arduino, se introdujo la macro F(). Esta sintaxis se usa para almacenar strings en la memoria flash en lugar de en la memoria SRAM. No es necesario cargar ninguna librería para usar la macro F().

  • Serial.println(«This string will be stored in flash memory»); //este print ocupará 42 bytes de memoria SRAM con el contenido de la constante string
  • Serial.println(F(«This string will be stored in flash memory»)); //el string dentro de del println no se carga en la SRAM y se lee de la flash

En el caso que el sketch ocupe más memoria flash, el IDE te avisa de que no puede cargarlo en Arduino.

Desde las últimas versiones del IDE de Arduino tras compilar el sketch, aparece un resumen de la memoria flash que ocupa el programa y la memoria ocupada por las variables globales en la SRAM y el espacio que queda para las variables locales. Como recomendación, si se supera el 70%-75% de la  SRAM con las variables globales es muy probable que Arduino se quede sin memoria RAM.

Recordar que al incluir una librería, estoy añadiendo variables y tamaño al programa, lo que aumentará el uso de memoria SRAM y flash. Algunas librerías hacen un uso grande de la memoria SRAM y flash.

Memoria en Arduino:

Un buen tutorial para aprender como funcionan las memorias de Arduino: https://learn.adafruit.com/memories-of-an-arduino/you-know-you-have-a-memory-problem-when-dot-dot-dot

Toda la información de las memoria del ATMega328p está en la página 34 del datasheet http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf

Más información de las memorias de Arduino

Para profundizar sobre el uso de memoria en los microcontroladores AVR de Atmel, memoria dinámica, reserva y liberar memoria, visitar los siguientes enlaces:

Memoria SRAM

Al ser el recurso más escaso en Arduino hay que entender bien cómo funciona. La memoria SRAM puede ser leída y escrita desde el programa en ejecución.

La memoria SRAM es usada para varios propósitos:

  • Static Data: Este bloque de memoria reservado en la SRAM para todas las variables globales y estáticas. Para variables con valores iniciales, el sistema copia el valor inicial desde la flash al iniciar el programa.
  • Heap: Es usado para las variables o elementos que asignan memoria dinámicamente. Crece desde el final de la zona de Static Data a medida que la memoria es asignada. Usada por elementos como los objetos y los Strings.
  • Stack: Es usado por las variables locales y para mantener un registro de las interrupciones y las llamadas a funciones. La pila crece desde la zona más alta de memoria hacia el Heap. Cada interrupción, llamada de una función o llamada de una variable local produce el crecimiento de la memoria.
    La mayor parte de los problemas ocurren cuando la pila y el Heap colisionan. Cuando esto ocurre una o ambas zonas de memoria se corrompen con resultados impredecibles. En uno casos se produce un “cuelgue” del programa y en otros casos la corrupción de memoria puede notarse un tiempo después.

A partir de la versión 1.6 del IDE al compilar un sketch nos da el tamaño que va a ocupar en la flash el proyecto y el espacio que va a ocupar en la SRAM las variables globales, es decir, la zona de static data.

Como ya se ha visto anteriormente, en la memoria SRAM también se encuentran los registros que ocupan las primeras 256 direcciones de memoria. Por lo tanto la SRAM empieza a partir de la dirección 0x0100.

Los registros al estar en la SRAM son volátiles y no conservan su valor después de un reset. Mirando la documentación del microcontrolador se puede ver cuales son los valores por defecto de los registros.

Si vemos a fondo la memoria SRAM de Arduino a partir de la dirección 0x0100:

  • .data variables is the first RAM section and it is used to store program static data, such as strings, initialized structures and global variables.
  • .bss variables is the memory allocated for uninitialized global and static variables.
  • heap is the dynamic memory area, and this is the playground area for malloc (and alike). The heap can grow (when new allocation is made) or «possibly» decrease in size (when memory is released, as for example when using free) based on the requirements.
  • stack is the memory area located at the end of the RAM and it grows towards the heap area. The stack area is used for function calls, storing values for local variables. Memory occupied by local variables is reclaimed when the function call finished.
  • external RAM is only available to some of the MCUs and it means that it is possible to add RAM in a kind of similar way that we do for a PC. Usually this is expensive (a few KB of external RAM costs in general more than the MCU) and requires also advanced hardware and software skills.
  • free available memory is the area between heap and stack and this is what we need to measure in order to detect problems caused by not enough RAM resources.When this area is either too small for the required tasks, or is missing at all (heap meets stack), our MCU starts to missbehave or to restart itself.

Más información sobre heap y stack:

Calcular Memoria SRAM Libre

El siguiente código permite calcular la memoria libre en bytes para un Arduino y funciona tanto con el IDE de Arduino como con Atmel Studio:

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

uint16_t getFreeSram() {
  uint8_t newVariable;
  // heap is empty, use bss as start memory address
  if ((uint16_t)__brkval == 0)
    return (((uint16_t)&newVariable) - ((uint16_t)&__bss_end));
  // use heap end as the start of the memory address
  else
    return (((uint16_t)&newVariable) - ((uint16_t)__brkval));
};

Explicación del código:

  • extern en un cualificador de variables que indica al compilador de la existencia de variables globales definidas en otros fichero de cabecera que hemos incluido (#include) y no es necesario definirlas en nuestro fichero.
    extern int x; le dice al compilador que un objeto llamado x de tipo int existe en algún sitio.
  • La función getFreeRam define una nueva variable (llamada NewVariable), que se se almacenará una variable local de una función en la pila (stack). Debido a que el área de memoria de pila crece hacia el heap, la dirección de memoria de esta nueva variable es la última dirección de memoria utilizada por la pila en el momento de llamar a este método.
  • El *__brkval es un puntero a la última dirección de memoria (hacia la pila) utilizado por el heap. No tenemos que preocuparnos acerca de la gestión de __brkval ya que esto se hace internamente.
  • También tenemos que estar seguros de que heap no está vacío, porque entonces __brkval no se puede utilizar (que es un puntero NULL). Si el heap está vacío, entonces usamos __bss_end que es una variable definida internamente, y se almacena en la última parte de la zona de memoria RAM variables de .bss
  • La cantidad de memoria libre de RAM es la diferencia entre las direcciones de memoria usada por la nueva variable newVariable y dirección referenciada por __brkval o la dirección de _bss_end si la zona de heap está vacía.
  • El resultado es el número de bytes en MCUs de 8 bits como en Arduino uno. En el caso de MCUs de 32 bits como el Arduino DUE, que son bloques de 32 bits.

Más información: http://web-engineering.info/node/30

Este código está disponible en la librería: https://github.com/maniacbug/MemoryFree

Y la versión revisada: https://github.com/McNeight/MemoryFree

En el playground de Arduino hay más información sobre el cálculo de memoria disponible: https://playground.arduino.cc/Code/AvailableMemory

Un código más simple de calcular la memoria libre:

 
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Códigos para cálculo de memoria libre SRAM

Como medir a memoria libre flash, SRAM y EEPROM: https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory  

I/O Memory

El espacio de memoria I/O de los registros son un conjunto de registros adiciona a los registros de propósito general.

Los 32 (32x8bits) registros de propósito general están directamente conectados con la ALU.

Todas las I/Os (Inputs/Oputputs) y periféricos están localizados en el espacio de memoria I/O. Todas las localizaciones de los registros I/O pueden ser accedidos mediante las instrucciones LD/LDS/LDD y ST/STS/STD, transfiriendo datos entre los registros de propósito general y el espacio I/O.

Instrucción LDS (Load Direct from Data Space): http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_lds.html

Instrucción SBI (Set Bit in I/O Register): http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_sbi.html

Instrucción CBI (CBI – Clear Bit in I/O Register): http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_CBI.html

Lista de instrucciones en ensamblador:  http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_instruction_list.html

Los registros I/O en el rango 0x00-0x1F son accesible directamente mediante las funciones SBI y CBI.  En estos registros el valor de los bits puede ser leído con las instrucciones SBIS y SBIC.

Memoria Flash

La memoria flash —derivada de las siglas EEPROM— permite la lectura y escritura de múltiples posiciones de memoria en la misma operación. Gracias a ello, la tecnología flash, siempre mediante impulsos eléctricos, permite velocidades de funcionamiento muy superiores frente a la tecnología EEPROM primigenia, que sólo permitía actuar sobre una única celda de memoria en cada operación de programación. Se trata de la tecnología empleada en los dispositivos denominados memoria USB.

Más sobre la memoria flash.

En Arduino la memoria flash o espacio de programa es donde el sketch de arduino en binario es almacenado.

La memoria flash en Arduino está dividida o particionada en dos zonas  una para el bootloader y otra para almacenar el sketch.

El bootloader se trata de un programa especial y puede leer datos de una fuente externa como UART, I2C, CAN, etc… para reescribir el programa guardado en la memoria flash del microcontrolador. El bootloader es un programa que se ejecuta inmediatamente antes de ejecutar el programa que hay en la memoria flash al que cede el control cuando finaliza su ejecución.

Más información sobre el bootloader en: https://aprendiendoarduino.wordpress.com/2016/11/09/bootloader/

Incluso se podría particionar la memoria flash para dejar una zona con un sistema de ficheros donde se podrían almacenar archivos, como ya se hace en algunos casos con el ESP8266.

PROGMEM

PROGMEM se usa para guardar en memoria flash en lugar de en la SRAM y ahorrar espacio en la SRAM, especialmente cuando se usa gran cantidad de cadenas de caracteres. La palabra PROGMEM en un modificador de variable que debe usarse solo con los tipos de datos definidos en pgmspace.h. Al usarlo le dice al compilador que ponga la información de la variable en la memoria flash en lugar de la SRAM, donde iría normalmente.

PROGMEM es parte de la librería pgmspace.h http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html que solo está disponible para la arquitectura AVR, así que para usarlo hay que inclirla al principio del sketch con #include <avr/pgmspace.h>

Más información:

  • sizeof() – devuelve el número de bytes en una variable o el número de bytes ocupados por un array.
  • PROGMEM

En muchos casos, una gran cantidad de RAM es ocupada por la memoria estática, como resultado del uso de variables globales (tales como cadenas o números). Siempre que estos datos no se vayan a cambiar, puede ser fácilmente almacenado en la llamada PROGMEM (memoria de programa o flash). Esto ocuparía un trozo de la memoria flash, y es bueno saber que, en general, la memoria flash es mucho más grande que la memoria RAM (por ejemplo, Atmega2560 tiene 8 KB de RAM y flash de 256 KB). Una desventaja de usar PROGMEM podría ser la velocidad de lectura, que es más lento en comparación con la lectura de los mismos datos de la RAM, aunque la diferencia de velocidad no es mucha.

La verdadera utilidad de PROGMEM es en bloques de datos grandes que necesitan ser almacenados en la flash. El uso de PROGMEM se hace en dos pasos, después de hacer que la variable se guarde en la flash, necesitamos de varios métodos definidos en la librería pgmspace.h, para leer los datos de la flash y cargarlos en la SRAM.

IMPORTANTE: para el uso de PROGMEM, las variables deben ser o bien definidas de forma global o definidas como static.

La sintaxis de uso de PROGMEM es:

 
const dataType variableName[] PROGMEM = {};   // use this form
const PROGMEM  dataType  variableName[] = {}; // or this form
const dataType PROGMEM variableName[] = {};   // not this one

Más información sobre PROGMEM en Arduino:

La macro F() se puede usar para facilitar el manejo de PROGMEM en las instrucciones print, de forma que todo el texto a imprimir (ya sea en Serial, Ethernet u otra librería) se lea de la Flash y no ocupando tamaño en la SRAM. Esta macro está incluida en el core de Arduino.

Cuando un sketch tiene problemas de memoria SRAM, el primer y más sencillo paso a aplicar es poner todos los print con la macro F.

Sintaxis:

 
Serial.print(F("Write something on the Serial Monitor that is stored in FLASH"));

Más información sobre la macro F y consideraciones a tener en cuenta al usarla: https://www.baldengineer.com/arduino-f-macro.html

Ver librería Flash que facilita el uso de PROGMEM: http://arduiniana.org/libraries/flash/

Fuses & Lock Bits

Ya sabemos lo que es la flash, EEPROM y RAM como parte de la MCU, pero no se ha mencionado anteriormente que hay 3 bytes de memoria permanente llamados fuses. Los fuses determinan cómo se va a comportar el microcontrolador, si tiene bootloader, a que velocidad y voltaje va a funcionar la MCU, etc… Notar que a pesar de llamarse fuses (fusibles) puede configurarse una y otra vez y no tienen nada que ver con la protección de sobrecorrientes.

Los tres bytes que conforman los fuses en el ATMega328p:

También hay un cuarto byte que se usa para programar los lock bits. Los lock bits pueden ser usados para restringir la lectura/escritura en la memoria de programa (flash), la zona de boot y la de aplicación tienen sus propios lock bits y es posible controlar el acceso a ellos de forma separada.

Para cambiar la configuración de los fuses, puede usarse el avrdude.Tutorial para cambiar la configuración de los fuses: http://www.instructables.com/id/How-to-change-fuse-bits-of-AVR-Atmega328p-8bit-mic/

Arduino default fuse settings: http://www.codingwithcody.com/2011/06/25/arduino-default-fuse-settings/

Calculadora de Fuses:

Más información:

Práctica: Uso de Memoria en Arduino

Para entender el uso de la memoria, hagamos una práctica añadiendo y quitando elementos del sketch y viendo la ocupación de memoria.

Función para calcular memoria libre en Arduino:

 
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Paso 1: Calcula memoria RAM y Flash en Arduino UNO de un programa que solo ejecute la función freeRam en el loop cada 30 segundos y muestre el dato por el monitor serie.

Solución Ejercicio14_1: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio14-Memoria_1

Paso 2: Calcula memoria RAM y Flash en Arduino UNO de un programa que imprima por el monitor serie en cada loop cada 30 segundos el siguiente texto:

“Arduino es una plataforma de hardware libre, basada en una placa con un microcontrolador y un entorno de desarrollo, diseñada para facilitar el uso de la electrónica en proyectos multidisciplinares. El hardware consiste en una placa con un microcontrolador Atmel AVR y puertos de entrada/salida. Los microcontroladores más usados son el Atmega168, Atmega328, Atmega1280, ATmega8 por su sencillez y bajo coste que permiten el desarrollo de múltiples diseños. Por otro lado el software consiste en un entorno de desarrollo que implementa el lenguaje de programación Processing/Wiring y el cargador de arranque que es ejecutado en la placa.Desde octubre de 2012, Arduino se usa también con microcontroladoras CortexM3 de ARM de 32 bits,5 que coexistirán con las más limitadas, pero también económicas AVR de 8 bits. ARM y AVR no son plataformas compatibles a nivel binario , pero se pueden programar con el mismo IDE de Arduino y hacerse programas que compilen sin cambios en las dos plataformas. Eso sí, las microcontroladoras CortexM3 usan 3,3V, a diferencia de la mayoría de las placas con AVR que generalmente usan 5V. Sin embargo ya anteriormente se lanzaron placas Arduino con Atmel AVR a 3,3V como la Arduino Fio y existen compatibles de Arduino Nano y Pro como Meduino en que se puede conmutar el voltaje.”

Solución Ejercicio14_2: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio14-Memoria_2

Paso 3: Calcula memoria RAM y Flash en Arduino UNO del programa del paso 2 pero usando la macro F en el Serial.print.

Solución Ejercicio14_3: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio14-Memoria_3

Práctica: Velocidad Memoria en Arduino

Hacer un programa para hacer una comparativa de la velocidad de lectura de la memoria SRAM, Flass y EEPROM.

Solución Ejercicio15: https://github.com/jecrespo/aprendiendoarduino-Curso_Arduino_Avanzado_2017/tree/master/Ejercicio15-Velocidad_Memoria

Para ampliar ver ejercicio de llenar memoria: https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Otros/llenarMemoria

Memoria Flash, SRAM y EEPROM

Arduino usa tres tipos de memorias:

  • SRAM (static random access memory): Variables locales, datos parciales. Usualmente se trata como banco de registros (PIC) y memoria volátil. Es la zona de memoria donde el sketch crea y manipula las variables cuando se ejecuta. Es un recurso limitado y debemos supervisar su uso para evitar agotarlo.
  • EEPROM:  Memoria no volátil para mantener datos después de un reset. Se puede grabar desde el programa del microcontrolador, usualmente, constantes de programa. Las EEPROMs tienen un número limitado de lecturas/escrituras, tener en cuenta a la hora de usarla.
    Esta memoria solo puede leerse byte a byte y su uso puede se un poco incómodo. También es algo más lenta que la SRAM. La vida útil de la EEPROM es de unos 100.000 ciclos de escritura
  • Flash: Memoria de programa. Usualmente desde 1 Kb a 4 Mb (controladores de familias grandes). Donde se guarda el sketch ya compilado. Sería el equivalente al disco duro de un ordenador. En la memoria flash también se almacena del bootloader. Se puede ejecutar un programa desde la memoria flash, pero no es posible modificar los datos, sino que es necesario copiar los datos en la SRAM para modificarlos.
    La memoria flash usa la misma tecnología que las tarjetas SD, los pendrives o algunos tipos de SSD, esta memoria tiene una vida útil de unos 100.000 ciclos de escritura, así que cargando 10 programas al día durante 27 años podríamos dañar la memoria flash.

La memoria flash y la EEPROM son no volátiles, es decir, la información persiste tras el apagado del Arduino.

Memoria de Arduino UNO:

  • Flash  32k bytes (of which 0.5k is used for the bootloader)
  • SRAM   2k bytes
  • EEPROM 1k byte

Memoria de Arduino MEGA:

  • Flash  256k bytes (of which 8k is used for the bootloader)
  • SRAM   8k bytes
  • EEPROM 4k byte

Memoria de Arduino MKR1000:

  • Flash  256k bytes
  • SRAM   32k bytes
  • EEPROM no. Dispone de EEPROM emulation en la memoria flash (ver documentación del microcontrolador)

La memoria SRAM es un recurso escaso que debe gestionarse, especialmente si se usan los strings o cadenas de caracteres de forma intensiva. Si un Arduino se queda sin memoria SRAM, el sketch compila bien y se cargará en el Arduino sin problema, pero se producirán efectos inesperados.

En caso de usar muchos strings, una técnica para evitar agotar la memoria SRAM es guardar en la memoria flash los strings que no se modifiquen en tiempo de ejecución, usando PROGMEM: https://www.arduino.cc/en/Reference/PROGMEM

Desde la versión 1.0 del IDE de Arduino, se introdujo la macro F(). Esta sintaxis se usa para almacenar strings en la memoria flash en lugar de en la memoria SRAM. No es necesario cargar ninguna librería para usar la macro F().

 
Serial.println("This string will be stored in flash memory"); //este print ocupará 42 bytes de memoria SRAM con el contenido de la constante string
Serial.println(F("This string will be stored in flash memory"));

En el caso que el sketch ocupe más memoria flash, el IDE te avisa de que no puede cargarlo en Arduino.

Desde las últimas versiones del IDE de Arduino tras compilar el sketch, aparece un resumen de la memoria flash que ocupa el programa y la memoria ocupada por las variables globales en la SRAM y el espacio que queda para las variables locales. Como recomendación, si se supera el 70%-75% de la  SRAM con las variables globales es muy probable que Arduino se quede sin memoria RAM.

Recordar que al incluir una librería, estoy añadiendo variables y tamaño al programa, lo que aumentará el uso de memoria SRAM y flash. Algunas librerías hacen un uso intensivo de la memoria SRAM y flash.

Memoria en Arduino:

Un buen tutorial para aprender como funcionan las memorias de Arduino: https://learn.adafruit.com/memories-of-an-arduino/you-know-you-have-a-memory-problem-when-dot-dot-dot

Memoria SRAM

Al ser el recurso más escaso en Arduino hay que entender bien cómo funciona. La memoria SRAM puede ser leída y escrita desde el programa en ejecución.

La memoria SRAM es usada para varios propósitos:

  • Static Data: Este bloque de memoria reservado en la SRAM para todas las variables globales y estáticas. Para variables con valores iniciales, el sistema copia el valor inicial desde la flash al iniciar el programa.
  • Heap: Es usado para las variables o elementos que asignan memoria dinámicamente. Crece desde el final de la zona de Static Data a medida que la memoria es asignada. Usada por elementos como los objetos.
  • Stack: Es usado por las variables locales y para mantener un registro de las interrupciones y las llamadas a funciones. La pila crece desde la zona más alta de memoria hacia el Heap. Cada interrupción, llamada de una función o llamada de una variable local produce el crecimiento de la memoria.
    La mayor parte de los problemas ocurren cuando la pila y el Heap colisionan. Cuando esto ocurre una o ambas zonas de memoria se corrompen con resultados impredecibles. En uno casos se produce un “cuelgue” del programa y en otros casos la corrupción de memoria puede notarse un tiempo después.

A partir de la versión 1.6 del IDE al compilar un sketch nos da el tamaño que va a ocupar en la flash el proyecto y el espacio que va a ocupar en la SRAM las variables globales, es decir, la zona de static data.

Hardware Arduino

Los Arduino y en general los microcontroladores tienen puertos de entrada y salida y puertos de comunicación. En Arduino podemos acceder a esos puertos a través de los pines.

Otro aspecto importante es la memoria, Arduino tiene tres tipos de memoria:

  • SRAM: donde Arduino crea y manipula las variables cuando se ejecuta. Es un recurso limitado y debemos supervisar su uso para evitar agotarlo.
  • EEPROM:  memoria no volátil para mantener datos después de un reset o apagado. Las EEPROMs tienen un número limitado de lecturas/escrituras, tener en cuenta a la hora de usarla.
  • Flash: Memoria de programa. Usualmente desde 1 Kb a 4 Mb (controladores de familias grandes). Donde se guarda el sketch.

Veamos a fondo la placa Arduino Uno:

Especificaciones detalladas de Arduino UNO: http://arduino.cc/en/Main/ArduinoBoardUno

Microcontroller & USB-to-serial converter ATmega328P & Atmega16U2
Operating Voltage 5V
Input Voltage (recommended) 7-12V
Input Voltage (limits) 6-20V
Digital I/O Pins 14 (of which 6 provide PWM output)
Analog Input Pins 6
DC Current per I/O Pin 40 mA
DC Current for 3.3V Pin 50 mA
Flash Memory 32 KB (ATmega328) of which 0.5 KB used by bootloader
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)
Clock Speed 16 MHz

Aspectos más destacados de Arduino UNO.

  • No necesita de un cable FTDI para conectarse al MCU, en su lugar usa una MCU especialmente programado para trabajar como conversor de USB a serie.
  • Alimentación: vía USB, batería o adaptador AC/DC a 5V, seleccionado automáticamente. Arduino puede trabajar entre 6 y 20V, pero es recomendado trabajar entre 7 y 12V por las características del regulador de tensión.
  • Puerto Serie en los pines 0 y 1.
  • Interrupciones externas en los pines 2 y 3.
  • Built-in LED en el pin 13.
  • Bus TWI o I2C en los pines A4 y A5 etiquetados como SDA y SCL
  • El MCU ATmega328P tiene un bootloader precargado que permite cargar en la memoria flash el nuevo programa o sketch sin necesidad de un HW externo.
  • Arduino Uno dispone de un fusible autoreseteable que protege el puerto USB de nuestro ordenador de cortocircuitos y sobrecorrientes. Si se detectan más de 500mA salta la protección.

Placas Arduino

Arduino dispone de una amplia variedad de placas y shields para usar dependiendo de nuestras necesidades.

Arduino Uno

Web: http://arduino.cc/en/Main/ArduinoBoardUno

Es la placa estándar y posiblemente la más conocida y documentada. Salió a la luz en septiembre de 2010 sustituyendo su predecesor Duemilanove con varias mejoras de hardware que consisten básicamente en el uso de un USB HID propio en lugar de utilizar un conversor FTDI para la conexión USB. Es 100% compatible con los modelos Duemilanove y Diecimila. Viene con un Atmega328 con 32Kbytes de ROM para el programa.

Este es el Arduino que vamos a usar en el curso.

Esquematico: http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

Microcontrolador: http://www.atmel.com/devices/atmega328p.aspx

Planos del Arduino UNO: https://www.arduino.cc/en/Main/ArduinoBoardUno#documentation

Arduino Mega

Web: http://arduino.cc/en/Main/ArduinoBoardMega2560

Es con mucha diferencia el más potente y el que más pines i/o tiene, apto para trabajos ya algo más complejos aunque tengamos que sacrificar un poco el espacio, cuenta con el microcontrolador Atmega2560 con más memoria para el programa, más RAM y más pines que el resto de los modelos.

Esquematico: http://www.arduino.cc/en/uploads/Main/arduino-mega2560_R3-sch.pdf

Microcontrolador: http://www.atmel.com/devices/atmega2560.aspx

Planos del Arduino MEGA: http://www.arduino.cc/en/Main/ArduinoBoardMega2560

Arduino Leonardo

Web: http://arduino.cc/en/Main/ArduinoBoardLeonardo

La diferencia de este arduino con el resto es que trae un único MCU ATmega32u4 que tiene integrado la comunicación USB, lo que elimina la necesidad de un segundo procesador. Esto tiene otras implicaciones en el compartimento del arduino al conectarlo al ordenador, lo que no lo hace apto para iniciarse con él.

Microcontrolador: http://www.atmel.com/devices/atmega32u4.aspx

Arduino Micro

Web: http://arduino.cc/en/Main/ArduinoBoardMicro

También basado en el ATmega32u4 pero mucho más compacto.

Ejemplo de placa para uso de Arduino pequeños: https://spiercetech.com/shop/home/17-arduino-nano-30-controller-terminal-breakout-board.html

Arduino 101

Web: https://www.arduino.cc/en/Main/ArduinoBoard101 es el sucesor del Arduino UNO con procesador Intel Curie Quark de 32 bit diseñado para ofrecer el mínimo consumo de energía, 384 KB de memoria flash, 80 KB de SRAM, un sensor DSP integrado, bluetooth de baja energía, acelerómetro y giroscopio de 6 ejes.

Genuino MKR1000

Web: https://www.arduino.cc/en/Main/ArduinoMKR1000 version para IoT con procesador Atmel ARM Cortex M0+ de 32bits ATSAMW25 que es el mismo procesador que Genuino Zero pero con wifi integrado, chip de cifrado y antena integrada.

Un listado con todos los Arduinos puede verse en: https://aprendiendoarduino.wordpress.com/2016/09/25/novedades-arduino/

Shields Arduino

Las shields son placas de circuitos modulares que se montan unas encima de otras para dar funcionalidad extra a un Arduino. Esta Shields son apilables.

Las shields se pueden comunicar con el arduino bien por algunos de los pines digitales o analógicos o bien por algún bus como el SPI, I2C o puerto serie, así como usar algunos pines como interrupción. Además estas shields se alimenta generalmente a través del Arduino mediante los pines de 5V y GND.

En muchos casos nos encontraremos que los shields vienen sin soldar las patillas o en algunos casos sin algunos componentes soldados.

Cada Shield de Arduino debe tener el mismo factor de forma que el estándar de Arduino con un espaciado de pines concreto para que solo haya una forma posible de encajarlo.

Debemos tener en cuenta que cuando instalemos un shield, habrá que leer su documentación que nos dirá si inhabilita algunas de los pines I/O o si usa un bus y que requisitos tiene para su utilización. Generalmente las shields vienen con un ejemplo o una librería para su uso.

Ethernet Shield

Web: http://arduino.cc/en/Main/ArduinoEthernetShield

La placa Arduino se comunica con el módulo W5100 y la micro-SD utilizando el bus SPI (mediante el conector ICSP). Esto se encuentra en los pines digitales 11, 12 y 13 en el modelo UNO y en los pines 50, 51 y 52 del modelo MEGA. En ambas placas, el pin 10 es utilizado para seleccionar el W5100 y el pin 4 para la micro-SD. Estos pines no pueden ser utilizados para otros fines mientras la Ethernet Shield esté conectada. El en MEGA, el pin SS (53) no es utilizado pero debe dejarse como salida para que el bus SPI funcione correctamente.

Para su funcionamiento usa la librería Ethernet: https://www.arduino.cc/en/Reference/Ethernet

Arduino WiFi Shield 101

Web: https://www.arduino.cc/en/Main/ArduinoWiFiShield101

Este nuevo shield es una mejora de la anterior wifi shield desarrollada junto con Atmel que usa el módulo WINC1500 y también añade funciones de cifrado hardware gracias al chip de cifrado ATECC508A diseñado para el mercado de IoT. Los pines 5 y 7 son usados por este shield.

Usa una nueva librería llamada WiFi101 https://www.arduino.cc/en/Reference/WiFi101 que también usan otros Arduinos con wifi integrado como el MKR1000. Esta librería es muy compleja y ocupa más del 60% de la memoria disponible en el Arduino UNO, dejando poco espacio para los sketches. Si se van a realizar programas complejos, este shield es recomendable usarlo con Arduino Zero, 101 o Mega.

Arduino Motor Shield

Web: http://arduino.cc/en/Main/ArduinoMotorShieldR3. Permite manejar dos motores DC, controlando su dirección y velocidad. Está basado en un chip de doble puente H L298:

Este shield usa dos canales y cada canal usa 4 pines, en total nos ocupa 8 pines del Arduino

Un módulo con el mismo puente H pero sin formato shield: http://tienda.bricogeek.com/motores/285-controlador-de-motores-doble-puente-h-l298.html

Nuevas Shields Oficiales

Arduino.org ha lanzado otras shields y nuevas versiones de las ethernet y GSM. Todas las shields de arduino.org en http://www.arduino.org/products/shields

Grove Shield

Web: http://www.seeedstudio.com/depot/Grove-Base-Shield-p-754.html. Un Shield para el sistema grove que facilita la conexión de sensores y actuadores.

Relay Shield

Web: http://www.seeedstudio.com/depot/relay-shield-v20-p-1376.html?cPath=132_134. Este shield proporciona 4 relés para manejar dispositivos que no pueden controlarse directamente con las I/O de Arduino. Dispone de unos indicadores de uso de los relés.

En este caso se usan 4 pines digitales para usar cada uno de los relés.

Existen muchísimos shields que seguro que se adaptan a nuestro proyecto. En cada web de los fabricantes tenemos variedad donde elegir.

Un listado completo donde encontrar cualquier tipo de shield: http://shieldlist.org/

Breakout Boards

Además de los Shield, también tenemos disponibles módulos independientes (breakout boards) para conectar directamente a Arduino:

Ampliación Memoria Arduino

Cuando se desarrolla un proyecto con Arduino, es posible que a medida que crezca en tamaño y complejidad nos quedemos sin memoria, ya sea sin SRAM que es lo más sencillo, al ser un recurso escaso, y también lo más fácil de solucionar o sin EEPROM o sin memoria flash.

Si al compilar un sketch ocupa mucho espacio y no cabe en la memoria flash, lo primero que se debe hacer es optimizar el código siguiendo estas recomendaciones. https://learn.adafruit.com/memories-of-an-arduino/optimizing-program-memory. Hay que tener en cuenta que no es posible ampliar la memoria flash de Arduino con memoria externa. Una alternativa es que si el sketch tiene muchos strings de solo lectura, imágenes, ficheros, arrays de gran tamaño, etc…, una solución es mover toda esa gran cantidad de datos a una tarjeta SD externa y leer los valores sólo cuando se necesitan.

En caso de necesitar más EEPROM  de la que dispone el microcontrolador, es sencillo usar EEPROM externas conectadas por I2C o SPI, aunque también es posible almacenar los datos no volátiles en una tarjeta SD externa en lugar de la EEPROM.

Un buen ejemplo de uso de una EEPROM externa I2C, puede ser la EEPROM de microchip 24LC256 con una capacidad de 32K x 8 (256 Kbit). Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21203M.pdf. Tutoriales:

Otra alternativa para la expansión de memoria es dataflash https://en.wikipedia.org/wiki/DataFlash que es un protocolo serie desarrollado por Atmel para el acceso a memorias Flash http://www.mouser.es/Search/Refine.aspx?Keyword=dataflash.

Más información:

O también es posible usar SPI flash memory como 4MBIT W25X40CLSNIG que usa Moteino para almacenamiento de datos y la programación inalámbrica. La librería desarrollada es https://github.com/LowPowerLab/SPIFlash.

En caso de quedarnos sin memoria SRAM, lo primero es seguir estos consejos para optimizar su uso y mover a la memoria flash (si queda espacio) todas los strings y datos que no se modifican en tiempo de ejecución (read-only):  https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram.

Si con esto no es suficiente, entonces podemos ampliar la memoria SRAM. Obtener más SRAM es en realidad bastante sencillo. Hay módulos de SPI RAM (memoria volatil) como el microchip 23K256, data sheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22100D.pdf. Dispone de 32k de SRAM con un interfaz SPI. Se accede a ellos a través de SPI y hay la biblioteca SpiRAM para ayudar a su uso. Debe tenerse en cuenta que opera a 3,3V y no 5V y que no es posible usarla con Arduino Mega.

Dado que no es posible ampliar la memoria flash de Arduino, ampliando la memoria SRAM, podríamos reestructurar el sketch y reducir el tamaño del código a expensas de aumentar el tamaño de los datos, haciéndolo un poco más lento.

Más información:

Uso de tarjetas SD en Arduino

Una forma ampliar la capacidad de almacenamiento de un Arduino es añadir una memoria externa y la forma más sencilla y barata es mediante un lector de tarjetas SD. Esto nos permite añadir un almacenamiento local no volátil para por ejemplo guardar un log de temperaturas o los datos de configuración de nuestro programa.

Como hemos visto anteriormente, tanto si nos quedamos sin memoria SRAM, flash o EEPROM podríamos recurrir al uso de una tarjeta SD para tratar de solucionar el problema directa o indirectamente.

En teoría, se podría ir tan lejos como traducir todo el sketch en algún lenguaje interpretado, almacenar esa versión del sketch en una tarjeta SD, y luego escribir un intérprete para que el lenguaje que se ejecute en Arduino y recoja, interprete y ejecute esas instrucciones de la tarjeta SD. Por ejemplo http://playground.arduino.cc//CommonTopics/ForthOnArduino que puede ser usado como una shell para ejecutar comando interactivos.

Veamos el uso de tarjetas SD con Arduino. Para ello lo primero que necesitamos es un HW externo que nos proporcione un lector de tarjetas y luego una librería adecuada para usar ese HW adicional.

Con la Ethernet shield disponemos de un lector de tarjetas micro SD y es accesible gracias a la librería SD: https://www.arduino.cc/en/Reference/SD

Otros shield interesante es el Adafruit datalogger shield que dispone de un lector de tarjetas SD, un RTC (Real Time Clock), una zona de prototipado para soldar componentes adicionales y dos LEDs indicadores configurables.

Más información: https://learn.adafruit.com/adafruit-data-logger-shield/overview

Otro HW para tarjetas SD:

La librería para manejar los lectores de tarjetas SD es la librería SD, el reference está disponible en http://arduino.cc/en/Reference/SD.Casi todos los módulos usan esta librería porque el acceso a la tarjeta SD es mediante el bus SPI directamente a la tarjeta o mediante un voltage level shifter.

La librería SD está basada en la librería SDfat: https://github.com/greiman/SdFat. Es compatible con sistemas de archivos FAT16 y FAT32 entarjetas SD estándar y tarjetas SDHC. Utiliza cortos 8.3 nombres de los ficheros. Los nombres de los archivos pasados a las funciones de la librería SD pueden incluir la ruta usando el caracter “/”, por ejemplo «directory/filename.txt». El directorio de trabajo siempre es el root de la tarjeta SD.

Cuestiones a tener en cuenta cuando se usa la librería SD: https://www.arduino.cc/en/Reference/SDCardNotes

Tutoriales disponibles

  • Card Info: Obtiene información de la tarjeta SD.
  • Datalogger: Log data de tres entradas analógicas a la tarjeta SD.
  • Dump File: Lee un fichero de la SD card.
  • Files: Crea y borra un fichero de la SD card.
  • List Files: Imprime el listado de fichero en un directorio de la SD card.
  • Read Write: Lee y escribe datos de una SD card.

La librería SD tiene dos clases: SD que ofrece funciones para acceder a la tarjeta SD y manipular sus directorios y ficheros y la clase File que tiene los métodos para leer y escribir de ficheros individuales de la tarjeta SD.

Ver todos los métodos en https://www.arduino.cc/en/Reference/SD

Pineado de tarjetas SD:

Pin – Name – Description
1 – NC – not connected
2 – CS – Chip Select/Slave Select (SS)
3 – DI – Master Out/Slave In (MOSI)
4 – VDD – Supply voltage
5 – CLK – Clock (SCK)
6 – VSS – Supply voltage ground
7 – DO – Master In/Slave Out (MISO)
8 – RSV – Reserved

A la hora de conectar con Arduino, solo debemos definir en Arduino el pin CS (Chip Select). Antes de empezar a leer y escribir datos en la tarjeta SD de Arduino hay que utilizar la instrucción SD.begin(), determinando en el paréntesis el pin CS de tu shield de SD o del pin de la tarjeta SD. Esto quiere decir que si se utiliza una placa de Arduino UNO (o similar) se utiliza la instrucción SD.begin(10) pero si (por ejemplo) se utiliza el shield de Ethernet debe ponerse SD.begin(4).

Antes de utilizar la tarjeta SD de Arduino debes abrir el archivo sobre el que vayas a trabajar (verás cómo más adelante). Si por cualquier motivo pierdes la comunicación con dicho archivo antes de cerrarlo, podrías perder tus datos. Los datos solo se guardan cuando cierras el archivo o usas la función flush().

Más información:

Ejercicios con SD

Ejercicio30-SD: Grabar y leer en una tarjeta SD

Basarse en los tutoriales.

Solución:  https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Ejercicio30-SD

Ejercicio50-DAQ_SD:  Leer y guardar en una tarjeta SD cada 30 segundos la temperatura y humedad de una sonda DHT22. Los datos son guardados en un fichero llamado datalog.csv. Los datos también son mostrados por en una pantalla LCD modelo https://www.sparkfun.com/products/9395

Para leer los datos de la SD y sacarlos por el puerto serie, usar el sketck: https://www.arduino.cc/en/Tutorial/DumpFile

Modificar el sketch para que funcione con la sonda y el display LCD del curso:

Solución: https://github.com/jecrespo/Aprendiendo-Arduino/tree/master/Ejercicio50-DAQ_SD