Archivo de la etiqueta: fuses

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

Anuncios

Software Arduino a fondo

Programación Arduino

El lenguaje de programación de Arduino es C++, aunque es posible programarlo en otros lenguajes. No es un C++ puro sino que es una adaptación que proveniente de avr-libc que provee de una librería de C de alta calidad para usar con GCC (compilador de C y C++) en los microcontroladores AVR de Atmel, denominado avr-gcc, y otras muchas funciones específicas para las MCU AVR de Atmel.

El lenguaje de los AVR es un entorno C para programar los chips de Atmel, la mayor parte del lenguaje o core de Arduino está escrito con constantes y funciones AVR y hay bastantes cosas que no son fáciles de hacer con el lenguaje de Arduino sin el uso de código AVR de la avr-libc.

Como el entorno de Arduino usa GCC para compilar el código, todas las variables de los puertos y de los registros de una MCU de Atmel son soportadas por el IDE de Arduino.

Las herramientas necesarias para programar los microcontroladores AVR de Atmel son avr-binutils, avr-gcc y avr-libc y ya están incluidas en el IDE de Arduino, cuando compilamos y cargamos un sketch estamos usando estas herramientas.

Para usar un microcontrolador ATmega8  de la familia AVR de 8 bits de Atmel, sin usar el IDE de Arduino, podemos programarlos usando C y C++ mediante una versión muy extendida de GCC (http://es.wikipedia.org/wiki/GNU_Compiler_Collection) denominda AVR-GCC http://winavr.sourceforge.net/ y http://sourceforge.net/projects/winavr/files/.

Una vez compilado el programa de C/C++ en un binario para AVR con AVR-GCC, necesitaremos “quemarlo” en el microcontrolador. Esto puede hacerse con AVRDUDE http://www.nongnu.org/avrdude/ o UISP http://www.nongnu.org/uisp/ o Atmel Studio http://www.atmel.com/tools/atmelstudio.aspx

Para Linux son necesarias estas herramientas:

  • gcc-avr
  • binutils-avr
  • gdb-avr
  • avr-libc
  • avrdude

Más información: http://playground.arduino.cc/Main/AVR

Un ejemplo de uso de funciones AVR que no dispone el entorno de Arduino es cuando queremos hacer delays muy pequeños. La función delayMircoseconds() puede hacer el delay más pequeño con el lenguaje de Arduino que es de 2 microsegundos.

Para delays menores es necesario usar ensamblador y en concreto la función ‘nop’ (no operation. Cada llamada a ‘nop’ ejecuta un ciclo de reloj que para 16 MHz es un retraso de 62,5 ns.

__asm__(“nop\n\t”);
__asm__(“nop\n\t””nop\n\t””nop\n\t””nop\n\t”);  \\ gang them up like this

También como hemos visto anteriormente, manipular los puertos y pines con el código AVR es más rápido que usar digitalWrite(). Más información https://www.arduino.cc/en/Reference/PortManipulation

Otro ejemplo es el uso de los métodos AVR cbi y sbi que se usan para hacer set o clear de bits el PORT y otras variables. Puedes encontrar estos métodos de código AVR en muchos sitios y ambos deben ser definidos en el sketch de Arduino para ser usados. Pegar este código al inicio del sketch y para usarlo simplemente poner una variable del puerto y el pin para hacer set o clear.

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

Pero para programar el 99% de lo que necesitemos en proyectos sencillos con Arduino, todo esto se puede resumir en que para programar nuestro lenguaje de programación de Arduino es el “Arduino Reference”, que es donde debemos recurrir para cualquier duda de programación que surja. Puesto que Arduino provee de unas librerías que facilitan la programación del microcontrolador. http://arduino.cc/en/Reference/HomePage

A medida que nuestro programa se hace más complejo o necesitamos que sea más rápido o queremos que tenga un uso de memoria más eficiente, entonces es cuando tendremos que recurrir a los comando AVR de la avr-libc.

El gran éxito de Arduino en parte se debe a que el IDE nos permite programar una MCU sin tener que saber todo lo anterior y nos da unas herramientas sencillas y específicas para programar los microcontroladores que suministra en sus placas. Por ejemplo veamos las funciones que nos ofrece para comunicar por el puerto serie: http://arduino.cc/en/Reference/Serial

El IDE de Arduino está basado en Processing: https://processing.org/, es un lenguaje de programación y entorno de desarrollo integrado de código abierto basado en Java, de fácil utilización, y que sirve como medio para la enseñanza y producción de proyectos multimedia e interactivos de diseño digital.

La librería Arduino está basada en wiring: http://wiring.org.co/ y es de donde nacieron las funciones que conocemos como digitalRead(), Serial.println(), etc…

Web del proyecto de Proccesing: https://processing.org/

Processing en github: https://github.com/processing/processing

Web del proyecto Wiring: http://wiring.org.co/

Wiring en github: https://github.com/WiringProject

Processing es útil cuando queremos comunicar Arduino con un ordenador y mostrar datos o guardar datos, pero también podemos usar python, .NET o cualquier otro lenguaje de programación que conozcamos.

Arduino trae algunos ejemplos para trabajar con Processing en el apartado communication, por ejemplo para hacer una gráfica de datos en http://arduino.cc/en/Tutorial/Graph

Ver el reference y la librería Serial de processing: https://processing.org/reference/ y https://processing.org/reference/libraries/serial/

También disponemos de una librería de Arduino para processing que nos permite interactuar entre processing y arduino: http://playground.arduino.cc/interfacing/processing

Por supuesto Arduino se puede programar en otros lenguajes y desde otros entornos de programación. Cabe destacar scratch como un lenguaje visual que hace innecesario saber programación o Atmel Studio que es la herramienta que proporciona Atmel. Más información en: https://aprendiendoarduino.wordpress.com/2014/11/20/tema-4-conceptos-basicos-de-programacion/

Más información: http://wittyrobo.com/mcu328p/c01_p01.html

Fuses

Los fuses son una parte muy importante en la programación de un microcontrolador. Solo es necesario configurarlos una vez, pero si no se hace correctamente podemos tener problemas.

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, 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 fuses están documentados en los datasheets, para el Arduino UNO ver página 348 de http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf

Con los fuses seleccionamos el comportamiento de:

  • Clock Source: puede ser un reloj externo, un reloj interno o un cristal externo.
  • Clock Startup: es el tiempo que necesita la fuente de reloj para estabilizarse.
  • Clock Output: habilita una salida de reloj en el PORT C2
  • Clock Divide: Divide por 8 el reloj
  • Reset Disable: convierte el pin de reset en un pin normal, habilitar este fuse hace que no se pueda programar por ISP
  • Brown-out Detect (BOD): selecciona a que voltaje hace disparar la protección de brownout. Para una MCU brownout es el voltaje al que es demasiado bajo para que funcione de una forma fiable a la velocidad de reloj.
  • Selecciona si se usa bootloader o no.
  • Selecciona cuánta memoria se reserva para el bootloader
  • Deshabilitar programación por el puerto serie

Con los fuses podemos bloquear algunos aspectos importamte de la MCU y podríamos brickearlo.

Los 3 bytes de los fuses son:

  • low byte fuse
  • high byte fuse
  • extended fuse

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 los fuses el 1 significa no usado y 0 usado.

Low Byte Fuses

High Byte Fuses

Extended Fuse Bits

Los valores por defecto el ATmega328p son:

  • Low fuse = 0x62 (B01100010)
  • High fuse = 0xD9 (B11011001)
  • Extended fuse = 0xFF (B11111111)

Los valores de los fuses de Arduino con el ATmega328p son:

  • Low fuse = 0xFF (B11111111)
  • High fuse = 0xDA (B11011110)
  • Extended fuse = 0x05 (B00000101)

En caso de usar el Optiboot bootloader, cambia el valor en el high byte fuse porque el tamaño del bootloader es inferior.

Más información de cada fuse en: http://www.martyncurrey.com/arduino-atmega-328p-fuse-settings/

Pero la mejor forma de ver los fuses es examinar AVR fuse calculator: http://www.engbedded.com/fusecalc/

Luego con los datos de los 3 bytes de los fuses, se pasan como argumento en el avr-dude al cargar el sketch y configurar los fuses. La configuración de los fuses es parte del proceso de cargar un bootloader. Editando el fichero boards.txt en la carpeta del IDE de Arduino en la ruta C:\Program Files (x86)\Arduino\hardware\arduino\avr se puede configurar el valor de los fuses.

Discusion en foro sobre el uso de fuses para proteger el binario de un sketch:  http://www.todopic.com.ar/foros/index.php?topic=44794.0. Es tan simple como agregar “-Ulock :w:03c:h” al final del comando que se le envía a avrdude.exe. Se configuran los lock bits como 1100 0011 (ojo que cambian los bits más significativos y menos significativos)

fuses

Cargar un programa desde el ide de arduino al microcontrolador. Luego desde el programa que mencionado ejecutar el mismo comando enviado por el ide de arduino a avrdude, pero cambiando la ruta del archivo .hex por un programa distinto y agregando al final “-Ulock :w:03c:h” Avrdude muestra en pantalla el avance en el proceso, pero al tratar de verificar el archivo enviado con el que recibe del microcontrolador, la comprobación falla. El microcontrolador se reinicia y ejecuta el programa nuevo correctamente, lo que demuestra que el Arduino no entregará el programa y que avrdude no es capaz de extraerlo del microcontrolador, ni tampoco con esta configuración es posible cargar ningún programa.

Ver el estado de los fuses de un Arduino se puede hacer con avr-dude y un programador, para ello hay que ejecutar el comando “avrdude -c arduino -p m328p -P COM3 -b 19200 -v”

Con AVR studio se puede leer y escribir los valores de los fuses. Pero si queremos cambiar los valores de los fuses con el IDE de Arduino podemos hacerlo de dos formas:

  • Option 1. El “quemado del bootloader” configura los fuses. Para configurar los fuses el ATmega328p se puede hacer en el proceso de cargar bootloader y toma la configuración de los fuses que hay en el fichero boards.txt de la placa correspondiente.
  • Option 2. Configurar los fuses manualmente, sin cargar un bootloader. Para ello necesitaremos la herramienta avr-dude mediante el comando.
    avrdude -c stk500v2 -p m328p -P /dev/ttyACM0 -b 19200 -U lfuse:w:0xFF:m -U hfuse:w:0xDE:m -U efuse:w:0x05:m”

Más información en:

IDE Arduino

El IDE de Arduino es open source y por lo tanto tenemos su código fuente y también podemos hacer nuestra propia versión del IDE. El proyecto del IDE de Arduino en github es: https://github.com/arduino/Arduino y las instrucciones para construir el binario desde el fuente está en https://github.com/arduino/Arduino/wiki/Building-Arduino

El software de Arduino se puede descargar en https://www.arduino.cc/en/Main/Software

Para actualizar Arduino y mantener las configuraciones, en Windows simplemente ejecutar el instalador, este desinstala la versión anterior y mantiene las librerías y sketchs siempre y cuando no hayamos guardado o modificado algo en el directorio de instalación.

También es posible tener varias versiones del IDE instaladas, simplemente usar la instalación manual con el archivo .zip

Para añadir al IDE Arduino soporte de placas de terceros: https://learn.adafruit.com/add-boards-arduino-v164?view=all

Lista no oficial de placas de terceros soportadas por el IDE de Arduino:

https://github.com/arduino/Arduino/wiki/Unofficial-list-of-3rd-party-boards-support-urls#list-of-3rd-party-boards-support-urls, que son ficheros json para añadir en el IDE y dar soporte con el nuevo gestor de placas.

Ruta donde se instalan los cores: C:\Users\enrique\AppData\Local\Arduino15\packages

La explicación de cada parámetro en configuración IDE: https://code.google.com/archive/p/arduino/wikis/Platforms.wikien la ruta: C:\Program Files (x86)\Arduino\hardware\arduino\avr

  • boards.txt: The Arduino environment supports multiple target boards with different chips (currently, only AVRs), CPU speeds, or bootloaders. These are defined in boards.txt. A board is specified by multiple variables prefixed with the same keyword (shown here as BOARD). The file consists of multiple lines with the format key=value. Lines that start with a # are comments and ignored.
  • programmers.txt: Programmers may be specified in the programmers.txt file in a platform. This file has a format similar to the boards.txt file, but with the other variables.
  • The bootloaders sub-folder of a platform contains the bootloaders for the boards in the platform. These should appear as .hex files in a sub-folder of the bootloaders folder. Often, the source code for the bootloader is also included, along with a Makefile for building the .hex file.
  • A core is a set of .c, .cpp, and .h files that implement the basic Arduino functions for a platform. Each core appears as a sub-folder of thecores sub-folder of a platform.

Guia para cambiar estilo IDE Arduino:

AVR libc

Es posible usar comandos estándar de C++ en la programación de Arduino siempre que estén incluidos en el avr libc, así como otros comandos propios para las MCUs AVR tambiñen incluidos en en avr-libc:

Dispositivos soportados por avr-libc: http://www.atmel.com/webdoc/AVRLibcReferenceManual/index_1supp_devices.html

Cuando creamos un programa en Arduino, automáticamente carga varios módulos como stdlib.h, math.h, etc…

Por ejemplo math.h:

El equivalente para linux de avr-libc es la glibc:

glibc como se puede ver tiene versiones para diferentes arquitecturas de los ordenadores como i386, i686, etc… para usar las instrucciones de cada una de sus arquitecturas.

Más información sobre MCUs AVR:

WinAVR

WinAVR es una herramienta importante para el desarrollo de MCUs AVR, incluso después de instalar Atmel Studio como IDE, es recomendable instalar WinAVR.

WinAVR (pronunciado “whenever”) es una suite compuesta de herramientas de desarrollo opensource para los microcontroladores AVR sobre plataforma Windows. Incluye el compilador GNU GCC para C y C++.

Herramientas WinAVR:

  • avr-gcc (compiler)
  • avrdude (programmer)
  • avr-gdb (debugger)
  • avr-libc (with a good HTML help Documentation)
  • and more …..

Web del proyecto:

Más información:

Tutoriales de programación AVR:

Interesante información sobre avr-lib en Wiring y Arduino: https://ccrma.stanford.edu/~juanig/articles/wiriavrlib/wiriavrlib.html

Proceso de compilación

GCC es un conjunto de compiladores que se considera el estándar para los Sistemas Operativos derivados de UNIX y requiere de un conjunto de aplicaciones conocidas como binutils que son unas herramientas de programación para la manipulación de código de objeto.

GCC soporta varios lenguajes y diferentes arquitecturas de HW::

Como GCC está construido para ejecutarse en un sistema como Linux, Windows o mac OS, pero para generar código para un microcontrolador AVR, entonces se denomina avr-gcc que es una versión de GCC solo para arquitecturas AVR. avr-gcc es el compilador que usa el IDE de arduino para convertir el sketch en C++ a un fichero binario (.hex) que es el que se carga en la flash del MCU y que ejecuta.

avr-gcc se puede usar directamente o a través de un IDE como el de Arduino o el Atmel Studio.

En el caso de Arduino el proceso de construcción para que el código escrito llegue a la placa es el siguiente:

  • El IDE verifica el código y comprueba que la sintaxis del código es correcta en C y C++
  • Luego pasa al compilador avr-gcc, que convierte el código en C++ en instrucciones que entiende el microcontrolador.
  • Después el código es combinado con las librerías estándar de Arduino, que son las que ofrecen las funciones básicas como digitalWrite() o Serial.println().
  • El resultado es un fichero hex que contiene los bytes que van a ser grabado en la memoria flash de Arduino.
  • Finalmente el fichero es cargado en la placa Arduino transmitiendolo sobre el USB o la conexión serie si hay un bootloader cargado o sino con un hardware externo (programador).

Cuando un sketch contiene múltiples ficheros, es compilado y los ficheros con extensiones .c o .cpp se compilan de forma separada y los ficheros con otras extensiones se concatenan juntos al fichero del sketch principal antes de pasarlo al compilador. Para usar ficheros con extensión .h, es necesario incluirlos con #include usando “comillas dobles” y no <>

El entorno de Arduino, antes de compilar también hace algunas modificaciones como añadir al principio del sketch #include “Arduino.h”. También el entorno de Arduino busca las definiciones de las funciones en el sketch principal y crea las declaraciones (prototypes) para ellas, estas se insertan después de los comentarios y las directivas de preprocesamiento, pero antes del resto de código, esto significa que si se quiere usar un tipo de dato como argumento de una función, debe declararse dentro de un fichero de cabecera separado.

El entorno de Arduino soporta múltiples placas con diferentes MCUs (no solo AVR), todo los datos de la placa están definidos en el fichero boards.txt en C:\Program Files (x86)\Arduino\hardware\arduino\avr. A la hora de compilar las opciones se toman del fichero boards.txt en la opción de build.

Cuando se compila desde el IDE de Arduino cono avr-gcc, las rutas donde se busca cuando se hace un include son:

  • El directorio del core de la placa <ARDUINO>/hardware/core/<CORE>/
  • El directorio de avr include <ARDUINO>/hardware/tools/avr/avr/include/
  • Cualquiera de los directorios de librerías <ARDUINO>/hardware/libraries/ o C:\Users\<USER>\Documents\Arduino\libraries

Cuando un sketch se verifica, se genera el fichero compilador en un directorio temporal del SO. Todos los ficheros .c y .cpp son compilados y la salida es un fichero .o (object file), tanto el del sktech final como otros que haya en el directorio del sketch o los de las librerías incluidas. Los fichero .o son enlazados todos juntos en una librería estática y el fichero del sketch principal. Solo las partes de las librerías necesitadas para el sketch son incluidas en el fichero final .hex, reduciendo el tamaño de la mayoría de los sketches.

El fichero .hex es la salida final de la compilación y es cargado en la memoria flash de Arduino. Este .hex es cargado en Arduino mediante avrdude y este proceso es controlado por las variables de las placas en el fichero de boards.txt dentro de las opciones “upload”

Para que me guarde los hex en una carpeta concreta: http://forum.arduino.cc/index.php?topic=142706.0

Durante el proceso de compilación se genera un fichero intermedio con extensión .elf que contiene el código máquina y otra información relacionado con información de la memoria y debug. El fichero elf (Executable and Linking Format), es el formato estándar para ficheros ejecutables, objetos de código y librerías compartidas. Elf es como una dll y consiste en unos enlaces simbólicos y tablas que pueden cargarse en una zona de memoria. Los fichero elf tienen varias secciones como datos, textos, etc.. Este fichero se suele usar para debug con emuladores.

Durante el proceso de compilación y carga, el IDE de Arduino muestra mucha información (hay que activarlo antes, ver https://aprendiendoarduino.wordpress.com/2016/06/26/instalacion-software-y-configuracion/) que puede resultar de ayuda para saber lo que está pasando durante el proceso. La herramienta que convierte el fichero .elf a .hex es avr-objcopy.

Más información:

Cómo compilar un sketch de Arduino con makefile:

Opciones de compilación:

Esta imagen muestra todo el proceso:

Información sobre las binutils: http://www.atmel.com/webdoc/AVRLibcReferenceManual/overview_1overview_binutils.html

Arduino también nos ofrece la posibilidad de una herramienta de línea de comandos para compilar los sketches de Arduino llamada Arduino Builder: https://github.com/arduino/arduino-builder, siendo uan herramienta muy intersante para hacer integración continua https://github.com/arduino/arduino-builder/wiki/Doing-continuous-integration-with-arduino-builder o testeo de nuestro softwatre (TDD).

También hay interfaces gráficos para GCC:

Probar/Ejercicio: El compilador de avr-gcc cuando detecta lineas iguales de Serial.print() no aumenta la memoria del static data porque lo reconoce y la guarda una sola vez en RAM y la repite al llamarla. Tampoco aumenta el tamaño del hex.

Ensamblador

Ensamblador es un lenguaje de bajo nivel. Consiste en una lista de instrucciones que no son de ninguna manera comparable a cualquier otro lenguaje como C, Basic o Pascal. El AVR tiene alrededor de 130 instrucciones, dependiendo del tipo, periféricos y tamaño del microcontrolador. En este link está el manual de las instrucciones con su respectiva explicación, y en este otro link se encuentra la guia de usuario de AVR Assembler. Se puede encontrar más información en http://www.avrbeginners.net/ y en http://www.avrfreaks.net/

Como ya hemos visto Arduino podemos programarlo en C puro, pero también podríamos programarlo en ensamblador, aunque no es una opción recomendable. Sin embargo como veremos podremos obtener el código en ensamblador de nuestro sketch.

Sin embargo, podría ser útil en determinadas situaciones insertar código en ensamblador dentro de nuestro sketch de Arduino. El compilador GNU C para procesadores Atmel AVR RISC procesadores permite incrustar el código de lenguaje ensamblador en programas C. Esta característica se puede utilizar para optimizar manualmente las partes críticas de tiempo del software o utilizar una instrucción de procesador específico, que no están disponibles en el lenguaje C.

Las instrucciones de cada procesador se pueden ver en los datasheet correspondientes y para el caso de los AVR de 8 bit en:

AVR Assembler User Guide: http://www.atmel.com/Images/doc1022.pdf

Para insertar instrucciones de ensamblador en C ver: Inline assembler cookbook: http://www.nongnu.org/avr-libc/user-manual/inline_asm.html, simplemente poner en el código C la instrucción asm volatile(); pasando como parámetro el código entre comillas.

Más información:

Proceso de Carga del Sketch

Una vez compilado y obtenido el fichero binario, hay que cargarlo en la memoria flash de Arduino, para ello el IDE de Arduino usa una herramienta llamada avr-dude.

Cuando tenemos problemas al cargar un sketch de Arduino, el problema suele venir de avrdude y en este enlace habla de los problemas y sus soluciones http://elcajondeardu.blogspot.com.es/2016/03/avrdude-nos-lo-explica-rufian-rufian-en.html

Página del proyecto avr-dude:

Manual del AVRdude:

Hay versiones con GUI para avr-dude que nos permiten cargar el sketch con la opciones que queramos.

Usar avr-dude con atmel studio y Arduino: http://wittyrobo.com/mcu328p/c04_p01.html

Uso de Arduino uploader:

Tutorial para usar AVRdude:

Adicionalmente se disponen de otras herramientas para la MCUs de AVR:

Soporte a tarjetas no oficiales con IDE Arduino

Al igual que hemos visto las herramientas necesarias para programar los microcontroladores AVR de Atmel y que necesitamos de una librería avr-libc, un compilador avr-gcc y un programa para cargar el .hex al microcontrolador, lo que compone el soporte en el IDE de Arduino para estos microcontroladores, en caso de querer programar otras MCUs, necesitaremos instalar las correspondientes herramientas para estos microcontroladores.

El proceso de dar soporte a otras tarjetas/microcontroladores en el IDE de Arduino se ha facilitado mucho, disponiendo de unos ficheros json que se descarga el IDE de Arduino y con ellos el IDE se descarga las herramientas necesarias y configura el IDE de Arduino para esas MCUs.

Instalar soporte IDE a otras placas:

IMPORTANTE: especificaciones de formato a usar en el IDE de Arduino para soporte de nuevas placas: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification

Arduino ARM

Por ejemplo las herramienta usadas por Arduino para las placas basadas en microcontroladores ARM como el Arduino MKR1000, son las GNU ARM Embedded Toolchain https://launchpad.net/gcc-arm-embedded que es mantenido por los empleados de ARM. Usa gcc y newlib: https://sourceware.org/newlib/ y accesible el codigo fuente vía git en https://sourceware.org/git/gitweb.cgi?p=newlib-htdocs.git y git://sourceware.org/git/newlib-cygwin.git

Para programar la flash en los microcontroladores Atmel ARM de la familia SAM usar BOSSA: http://www.shumatech.com/web/products/bossa y su código fuente está en https://sourceforge.net/p/b-o-s-s-a/code/ref/master~/

También se usa otra herramienta llamada OpenOCD (Open On-Chip Debugger) http://openocd.org/ y ofrece soporte a la programación y debug, soportando muchos hardware debuggers.

Documentación: http://openocd.org/documentation/

Código fuente: https://sourceforge.net/p/openocd/code/ci/master/tree/