Páginas

martes, 28 de enero de 2014

Del MCP23008 al MCP23017 (de 8 bits a 16 bits mediante el interfaz i2c)

En la entrada anterior expusimos el modo de utilizar el MCP23008 para ampliar las salidas digitales del Raspberry Pi, en 8 bits por circuito integrado. En esta nueva entrada expondremos el modo de utilizar el MCP23017 para extender aún más las entradas/salidas digitales, hasta un total de 16 bits, por MCP23017 utilizado.
No voy a partir de cero, por lo que recomiendo leerse con anterioridad la entrada de este mismo blog: Expandiendo las Entradas y Salidas Digitales de Raspberry Pi con el MCP23008.
En el montaje virtual que hemos realizado con el programa Fritzing, podemos observar dos bloques de 8 LEDs cada uno, los rojos están conectados al puerto A del circuito integrado MCP23017, y los verdes al puerto B del mismo chip. Como en la entrada del MCP23008, cada LED está serializado con una resistencia de 330 ohmios, Así evitamos un excesivo consumo de corriente, evitando que las salidas de la RaspPi no lleguen a dañarse, por un lado, y por el otro, que la propia RaspPi sea capaz de proporcionar el consumo necesario para encender a todos los LEDs simultáneamente.

Lista de materiales

EL material requerido para este montaje es el siguiente:

  • 1 MCP23017 (empaquetado en DIL28)
  • 16 resistencias de 330 ohmios
  • 8 LEDs rojos
  • 8 LEDs verdes
  • conector de expansión (desarrollado por mi) para conexión de la protoboard al RaspPi. Ver entrada anterior en este blog (Conectando la Raspberry Pi a una protoboard).

Evidentemente, para realizar las pruebas que queremos hacer, no se requieren que los LEDs sean del color indicado, ni que compremos tantos LEDs. Con poner algunos en ambos puertos, podremos comprobar que el montaje funciona.
En el montaje virtual he utilizado el mismo código de colores que en el montaje realizado para el MCP23008, por lo que no voy a extenderme en ello.

Características del MCP23017

Este chip, al igual que el MCP23008, tiene un espacio de direcciones que van desde 0x200x27, en función de los valores que vayan tomando los 3 bits de direccionamiento, A2, A1 y A0. En nuestro caso, estos tres bits están puestos a CERO.
Desde un punto de vista de programación, este chip dispone de 11 pares de registros, de 8 bits cada uno, con los que gestionamos su funcionalidad, leyendo/escribiendo en ellos a través del interfaz I2C. Uno de los registros (IOCONA/B) está compartido por ambos bancos. Esto significa que lo que hagamos en uno de ellos se reflejará en el otro. Este registro común nos permite configurar el modo de operar y de organizar los 22 registros.
Para este ejemplo, vamos a configurar los 11 pares de registros en dos bloques diferenciados, uno para el puerto A, direccionables por el interfaz i2c en el rango 0x00-0x0A, y el otro para el puerto B, en el rango 0x10-0x1A. La estructura de los registros una vez configurados convenientemente es la que mostrada en la siguiente imagen.
Pero esta disposición de registro no es la que tenemos nada más alimentarlo. Al darle tensión, todos los registros se inicializan a 0x00, excepto los IODIRA/B que lo hacen a 0xff, pasando a estar todos los bits de E/S en modo entrada. Tendremos que actuar, por tanto, sobre algunos bits del doble registro IOCONA/B para configurarlo tal como queremos:
  • IOCON.BANK = 1, registros agrupados por Banco A o B.
  • IOCON.SEQOP = 1, lectura/escritura de un byte (no secuencial).
  • IODIRA/B = 0x00, todos los bits de ambos puertos en modo salida.
Debemos tener en cuenta que, al arranque, la disposición de los registros es distinta (IOCON.BANK = 0) y el modo de operar es secuencial (IOCON.SEQOP = 0). Por tanto, al arranque, tendremos que considerar al doble registro IOCONA/B ubicado en la dirección como 0x0A/0x0B, direcciones que utilizaremos al dirigirnos a ellos por el protocolo i2c.
Los bits BANK y SEQOP corresponden a los bits B7 y B5 del registro IOCON. Por lo que para poner ambos bits a '1' escribiremos en el registro IOCON el valor 0xA0 (b10100000). Este registro se puede direccionar indistintamente tanto por el puerto A, en 0x0A, como por el puerto B, en 0x0B. Debemos tener muy en cuenta que, una vez configurado el circuito integrado del modo en el que lo hemos hecho, las direcciones de acceso al registro IOCON pasan a ser indistitamente 0x05 (IOCONA) o 0x15 (IOCONB).

El programa ejemplo mcp23017

Antes de proceder con el nuevo programa podemos hacer una prueba con los otros dos programas ejemplo que desarrollamos para el MCP23008, y comprobar que también se ejecutan. Eso sí, solo parpadeadarán los LEDs rojos, los del puerto A.
Si ejecutamos el programa mcp23017 con la opción de ayuda (-h, o también --help) se muestra la funcionalidad que se ha implementado. 
El programa permite gestionar el circuito integrado. Por ejemplo, la opción --show muestra la distribución de los registros internos, y sus valores:
Vemos claramente, con el bit IOCON.BANK activo, la distribución de los registros en dos bloques idénticos, equivalentes al bloque existente en el MCP23008, 11 pares de registros, un par direccionable entre 00h y 0Ah y el otro par entre 10h y 1Ah.  En cambio, si desactivamos el bit IOCON.BANK, el programa muestra otra distribución de registros:
En esta configuración los registros de cada bloque se van alternando, dentro de un rango de direcciones entre 00h y 15h. Podemos observar que tanto IOCONA (0Ah) como IOCONB (0Bh) contienen el mismo valor (0x28), distinto de lo que hemos grabado en él (0x29), porque el bit menos significativo, al leerlo, devuelve el valor '0'.
En la imagen anterior vemos el modo de alterar un registro que es indicando el registro (mediante la etiqueta correspondiente) al que queremos acceder y el valor a escribir.
La opción --mode nos muestra el valor del registro IOCON (A=B) o podemos alterarlo escribiendo en él un valor entre 0x00 y 0xFF (0 y 255).
FInalmente, podemos activar tres demos de activación de los LEDs con distintos patrones: random, counter y flash. En la demo random, en un bucle sin fin, escribimos dos valores aleatorios y distintos simultáneamente a ambos puertos (GPIOA y GPIOB), esperamos 'n' milisegundos, e iniciamos de nuevo el bucle. Si pulsamos <CTRL-C> abortamos el programa. La demo counter, los bits del puerto A muestran de forma binaria el valor de un contador que se incrementa cada 'n' milisegundos. El puerto B muestra de forma binaria a un contador decrementándose con la misma cadencia. Y por último, la demo flash va alternando cada 'n' milisegundos el encendido completo de cada puerto.
En Enlaces está la dirección del fichero mcp23017.rar, que una vez descomprimido se puede generar el ejecutable invocando desde un terminal de comandos make all.
Y eso es todo. En una próxima entrada hablaré de la gestión de las entradas y de las interrupciones.

Enlaces

- MCP23017/MCP23S17 datasheet
- I2C access examples
- Source Package: i2c-tools (3.1.0-2)
i2c - dev-interface
- Using I2C from userspace in Linux
- Raspberry pi and i2c gpios
- Expandiendo las Entradas y Salidas Digitales de Raspberry Pi con el MCP23008
- Fritzing
- MCP23017.fzz
- mcp23017.rar

sábado, 18 de enero de 2014

Expandiendo las Entradas y Salidas Digitales de Raspberry Pi con el MCP23008

En una entrada anterior en este blog (ver Reloj en tiempo real para Raspberry Pi) se explicaba de qué manera podíamos dotar al potente RaspPi de un reloj en tiempo real (RTC), ausente del mismo, cuando se nos antojaba que era un defecto fácilmente mejorable, y a un coste mínimo y asumible por cualquiera. Sí, seguro que en los primeros diseños de la RaspPi alguien pensaría en dotarle de un reloj en tiempo real, pero con la mente fija en minimizar costes, otro alguien diría que la puesta de fecha y hora podía ser más eficaz si la obtenía de Internet accediendo a un servidor NTP. Pero, no siempre podemos estar seguros de que cuando arranque el RaspPi tengamos operativo el acceso a Internet, y fue por esta razón que implementamos este módulo.
Otra limitación patente del hardware la RaspPi es el reducido número de entradas/salidas digitales (E/S), y de todo tipo. En la versión 2 de la RaspPi disponemos de un conector GPIO P1, de 2x13 pines, y la posibilidad de soldar otro, el conector P5, de 2x4.
En esta entrada expondremos el modo de ampliar de forma casi ilimitada el número de entradas y salidas digitales, utilizando el circuito integrado (CI) MCP23008, circuito que está dimensionado para manejar 8 E/S digitales. Esta misma solución la podemos extender fácilmente para que maneje 16 E/S digitales, sustituyendo el circuito por el MCP23017. Los circuitos integrados MCP23S08 y MCP23S17 utilizan el interfaz SPI en lugar del i2c.
En el esquema podemos observar, junto al módulo de reloj en tiempo real, desarrollado en la entrada anterior,  el módulo objeto de esta entrada: el interfaz de entradas/salidas digitales que en este caso se han configurado todas las 8 patillas de salida, permitiéndonos controlar individualmente el estado de los leds rojos.

Diseño y montaje del módulo de E/S digitales

Previo al montaje físico en una protoboard, he utilizado el programa Fritzing para realizar el diseño y montaje virtual del módulo, utilizando los siguientes componentes:

  • 1 MCP23008 (empaquetado DIL18)
  • 8 resistencias de 330 ohmios
  • 8 leds
  • conector de expansión (desarrollado por mi) para conexión de la protoboard al RaspPi. Ver entrada anterior en este blog (Conectando la Raspberry Pi a una protoboard)
En cuanto al código de colores utilizado por los conductores de este montaje:
  • Verde (SDA) y Rosa (SCL) corresponden al bus i2c.
  • Rojo a la alimentación de 5V, que se toma del conector de 2x13 pines. 
  • Negro, para puesta a tierra  (GND)
  • Azul conectan las patillas de entrada/salida del MCP23008 a las 8 resistencias de 330 ohmios.

IMPORTANTE: La patilla de RESET del MCP23008 debe ponerse a la tensión de alimentación del mismo. La no consideración de esta patilla puede hacerte perder mucho tiempo, como fue éste mi caso, que, por despiste y olvido, dejé la patilla al aire, sin conexión, y el módulo no me era reconocido por la RaspPi.
Las dos líneas del bus i2c están conectadas mediante unas resistencias de 1,8 kohms a la tensión de 3.3V de las RaspPi. Para el resto, utilizo la alimentación de 5V disponible en los pines 2 y 4 del conector P1 de 2x13 pines.
A partir del diseño virtual en Fritzing, pasamos a montarlo físicamente, comprobando que los conductores unen las distintas partes de acuerdo al diseño, y a implementar la parte de software requerido para la gestión del bus i2c en la Raspberry Pi.
CON EL EQUIPO SIN TENSIÓN DE ALIMENTACIÓN, conectamos la protoboard a la tarjeta RaspPi uniendo los dos conectores de 2x13 pines mediante un cable plano de 26 conductores.

Librerías a instalar en la Raspberry Pi

En principio, lo indicado en la entrada  Reloj en tiempo real para Raspberry Pi de este mismo blog es lo que podemos utilizar para instalar las librerías que requerimos en este nuevo caso. Por lo que recomiendo leer previamente esta entrada y seguir las instrucciones de instalación de librerías.

Manejando el MCP23008

Vamos a utilizar las mismas librerías descargadas en la entrada anterior, y programaremos el ejemplo en el lenguaje C.
La hoja de datos del circuito integrado nos permite averiguar el funcionamiento del mismo. Y basándonos en la misma vamos a tratar de controlar las patillas de salida.
Lo primero a tener en cuenta es la dirección del chip. En nuestro caso, al poner las tres patillas de direccionamiento a cero (A0,A1,A2), responderá a la dirección 0x20.
El MCP23008 tiene un total de 11 registros, a los que podemos acceder a través del interfaz i2c.
Para manejar estos registros, podemos utilizar las instrucciones i2cget e i2cset, que están disponibles al instalar la librería i2c-tools.
i2cget -y 1 0x20 REGISTRO
i2cset -y 1 0x20 REGISTRO VALOR
Aplicando estas instrucciones podremos observar el comportamiento del terminal de comandos y el estado de los LEDs conectados al MPC23008. Donde pone REGISTRO hay que poner la DIR (00h-0Ah) y en VALOR el que queremos que tenga el registro direccionado.
La primera instrucción, i2cget -y 1 0x20 0 , accede al registro IODIR, lee su estado, nos devuelve 0xff, lo que nos está diciendo que las patillas de E/S están en modo de Entrada.
La siguiente instrucción, i2cset -y 1 0x20 0 0x00 , pone todos los bits del registro IODIR a cero, con lo que estamos poniendo todas las patillas de E/S como Salidas.
La instrucción  i2cset -y 1 0x20 0x0A 0xff  enciende todos los LEDs conectados la MCP23008, mientras que la última, i2cset -y 1 0x20 0x0A 0x00  los vuelve a apagar.
Una vez que hemos experimentado con el montaje y las instrucciones de la librería i2c-tools vamos a realizar el programa que irá encendiendo y apagando de forma aleatoria los 8 LEDs conectados al MCP23008. El tiempo que se mantendrán encendidos lo p.asaremos, en milisegundos, como parámetro al programa.

El programa mcp23008aleatorio

En el apartado de enlaces se encuentra el enlace que apunta al fichero comprimido mcp23008aleatorio.rar. Hay que descomprimirlo, creándose una carpeta en donde lo hubiéramos descargado.
cd <carpeta en donde hemos descargado mcp23008aleatorio.rar>
unrar x mcp23008aleatorio.rar
cd mcp23008aleatorio
y al entrar en la carpeta, encontraremos los dos ficheros que necesitamos para generar el ejecutable:
mcp23008aleatorio.c
makefile
ejecutamos la sentencia desde un terminal, en la propia carpeta
make all
lo que nos generará un ejecutable, mcp23008aleatorio, que podremos ejecutar, desde un terminal y posicionados en su carpeta, de la siguiente manera:
./mcp23008aleatorio 150
si nos fijamos en los LEDs del montaje veremos que se encienden y apagan, varios a la vez, de forma aleatoria, mientras que en el terminal de comandos aparece línea tras línea, el registro y el valor que se envía al registro.
Del programa fuente, es importante resaltar el valor que hay que escribir en el registro IODIR. Para dejar el puerto del MCP23008 con todos los bits de salida, hay que escribir el valor 0x00. Si quisiéramos que el bit 1, 5 y 7 fueran de entrada y el resto de salida, escribiríamos el valor 0xA2, que corresponde el binario b10100010. Debemos tener en cuenta que el bit menos significativo es el bit 0, y el más significativo es el bit 7.
He añadido otro ejemplo, mcp23008contador.rar, que no aporta realmente nada nuevo al ejemplo anterior. Es una variación de la estructura anterior. El programa va incrementado un contador, el que se utiliza para ir encendiendo los LEDs del montaje.

Enlaces

- MCP23008/MCP230S8 datasheet
- MCP23017/MCP23S17 datasheet
- RPi Low-level peripherals
- Using MCP23008 8-bit I2C IO Expander on the Raspberry Pi
- dev-interface
- Using I2C from userspace in Linux
- Conectando la Raspberry Pi a una protoboard
- I2CTools – lm-sensors
- I2C and ISA Tools Documentation
- SMBus - System Management Bus
- How can I use I2C to talk to sensors?
- I2C (Inter-Integrated Circuit) Bus Technical Overview and Frequently Asked Questions
- I²C :: NXP
- SMBus Specifications
- mcp23008aleatorio.rar
- mcp23008contador.rar


miércoles, 8 de enero de 2014

Reloj en tiempo real para Raspberry Pi

En una aplicación que desarrollé hace ya algún tiempo, en donde un miniPC Android al que le instalé Linux gestionaba las salidas de una tarjeta Arduino, eché en falta la existencia de un reloj en tiempo real. Aunque el equipo se pensó para estar en conexión permanente a Internet, la realidad se muestra a veces en toda su crudeza y deja de ser lo que uno idealiza o desea que sea. ¿Qué porqué digo esto? Pues muy sencillo. Cuando lo que se pretende con la aplicación es activar unas salidas digitales conforme a una secuencia que se activa a una determinada hora del día, es preciso que el reloj interno del sistema esté en hora, ya que si no es así la secuencia se activará a una hora dependiente de la hora de reinicio del equipo.
Cuando he rediseñado la aplicación (y el hardware del equipo) lo primero que hice fue implementar un reloj en tiempo real por hardware, que pudiese ser puesto en hora por el sistema operativo, obteniéndola de un servidor de Internet, y que, en el caso de un reinicio no tuviésemos acceso a Internet, leyese la fecha y hora desde reloj en tiempo real.

Diseño y Montaje del módulo Reloj en Tiempo Real

Por brevedad, a partir de ahora, nombraremos el Reloj en Tiempo Reloj por su acrónimo en inglés RTC (Real Time Clock).
Después de consultar al Gran Hermano, que es Google, me decidí por utilizar el circuito integrado DS1307, manejándolo mediante el bus serie i2c. Este módulo se conectará a la tarjeta Raspberri Pi v2 a través del conector GPIO 2x13.
El prototipo lo montaremos en una protoboard y utilizaremos el programa Fritzing en el diseño previo al montaje real.
En la imagen anterior se muestran los componentes que hemos utilizado y los puentes que hemos tendido entre los componentes. Así, los conductores rojos corresponden a la tensión positiva de 5V que tomamos del RaspPi, los conductores negros van a 0V que también va unido a la tierra del RaspPi. El conductor amarillo alimenta el integrado DS1307 con los 3V de la batería. Y los azules corresponden al bus i2c, el que nos permitirá que el RTC y la RaspPi se comuniquen. Mediante un cable plano de 26 conductores uniremos el conector situado en la protoboard con el conector situado en la RaspPi.
Los componentes que vamos a utilizar son:
  • circuito integrado DS1307 (RTC)
  • cristal de 32.768 kHz
  • batería CR2032 (3V)
  • zócalo para batería
  • tarjeta de expansión de 2x13 pines (ver en este mismo blog Conectando Raspberri Pi a una protoboard)
Una vez montado el circuito, de acuerdo al ejemplo de la imagen anterior y comprobando que los conductores unen las patillas de los componentes y de la protoboard convenientemente, pasamos a implementar la parte de software en la Raspberry Pi. CON EL EQUIPO DESCONECTADO, conectamos la protoboard a la tarjeta RaspPi uniendo los dos conectores de 2x13 pines mediante un cable plano de 26 conductores.

Librerías a instalar en la Raspberry Pi

Tal como indicaba en una entrada antigua de este blog (ver http://elfrikidiletante.blogspot.com.es/2013/11/el-prometedor-mundo-raspberry-pi.html) mi tarjeta RaspPi tiene instalado el sistema operativo Raspbian, una versión de linux basado en Debian. Para que el RaspPi pueda manejar el RTC, en el caso de que no lo estén, instalaremos las siguientes librerías:
sudo apt-get install python-smbus
sudo apt-get install i2c-tools
Seguidamente, indicaremos al sistema operativo que cargue ciertos módulos que no fueron integrados en su kernel, para ampliar las capacidades que queremos que tenga. Para ello, editaremos el fichero /etc/modules
sudo nano /etc/modules
para que contenga, al menos, las siguientes líneas:
Después, si existe el fichero /etc/modprobe.d/raspi-blacklist.conf lo editaremos como sigue
sudo nano /etc/modprobe.d/raspi-blacklist.conf
comentando las líneas que hacen mención a los dos protocolos de comunicación i2c y spi, insertando '#' al inicio de las líneas,  ya que estos protocolos podrían venir bloqueados por defecto:
Si el fichero no existe, no debemos preocuparnos de crearlo y editarlo.
Finalmente, reiniciamos el equipo
sudo shutdown -r now
y comprobamos que funciona el protocolo i2c. ¿De qué manera?
Mediante la instrucción i2cdetect -y 1. Al estar haciendo estas pruebas con la versión 2 de la tarjeta RaspPi, hemos puesto un '1' de parámetro. En el caso de que fuera la primera versión, pondríamos un '0', es decir, la instrucción sería i2cdetect -y 0.
Para evitar tener que ejecutar i2cdetect en modo root, vamos a añadir los usuarios que tengan estas facultades al grupo i2c. En este caso el usuario es pi. Reiniciamos el sistema y podremos comprobar que si ejecutamos i2cdetect sin sudo y sin ser root, se ejecutará correctamente.
sudo adduser pi i2c
sudo shutdown -r now

Manejando el Reloj DS1307 (hwclock)

Ahora viene la prueba de fuego:
- poner en (fecha y) hora el DS1307
- leer la (fecha y) hora almacenados en el DS1307
Para tal fin, el sistema Linux posee una instrucción para gestionar el RTC siempre que el hardware del sistema disponga del mismo. Esta utilidad es hwclock. Si tecleamos en un terminal (en este caso, desde un terminal remoto, invocado con la instrucción ssh) las siguientes instrucciones:
sudo hwclock -V
sudo hwclock -h
nos aparecerá en la misma ventana los siguientes resultados:
La primera instrucción nos muestra su versión. Y la segunda, todas las instrucciones (con sus correspondientes parámetros) que están implementados en esta versión. Para comprobar el buen funcionamiento del montaje realizado, ejecutaremos dos instrucciones:
sudo hwclock -w
sudo hwclock -r
En la primera instrucción, pondremos en hora el RTC. Y con la segunda, obtendremos la fecha y hora que contiene. Manos a la obra:
¡Error,Horror! ¿Qué ha sucedido? La instrucción no se ha llegado a ejecutar correctamente, dándonos un mensaje de error, que para mi, ha sido algo críptico. No importa. Recurrimos de nuevo al 'Gran Hermano', que es Google, introduciendo como búsqueda en un navegador, la primera línea de error. Y entre los 6.000 resultados que proporciona la búsqueda, encontraremos la solución.
En un principio, se puede llegar a pensar que es un problema de hardware, de que el montaje no está bien realizado, o de que el circuito integrado no responde. Pero no parece que sea éste el problema, ya que la instrucción i2cdetect funciona a la perfección. Debe ser algún problema de configuración al arranque, que es por lo que nos decantamos. Tecleamos lo siguiente:
sudo -s
echo ds1307 0x68> /sys/class/i2c-adapter/i2c-1/new_device
exit
y comprobamos lo qué sucede.
El periférico DS1307 es reconocido, pero con una sutil diferencia. En vez de aparecer con un 68 aparece con el código UU. ¡Sorprendente! Recuerdo que en otro equipo, que también aparecía con este código, hwclock funcionaba a la perfección. Ahora, utilicemos la instrucción hwclock.
/etc/rc.local, e incluyendo esta línea al final del fichero.
¡Por fin!. Lo hemos conseguido. Ya nos funciona.
Pero ahora, lo que tenemos que hacer es automatizarlo para que esta sentencia se ejecute al arranque del sistema. ¿Cómo? editando el fichero
sudo -s
nano /etc/rc.local
en la siguiente imagen podemos observar el fichero /etc/rc.local, con la línea insertada.
Reiniciamos el sistema, y comprobamos de nuevo que tecleando
sudo hwclock -w
sudo hwclock -r
funciona a la perfección.

Cambiando de timezone

Si nos fijamos con atención, probablemente observaremos que la hora que aparece es la UTC. Para que aparezca la hora de nuestra zona horaria podemos ejecutar la siguiente instrucción y seguir los pasos que nos vaya indicando.
sudo dpkg-reconfigure tzdata 

Montaje físico

En la siguiente imagen se muestra un montaje real del RTC en una protoboard, conectado a la RaspPi a través de un cable plano.

Ficheros utilizados en Fritzing

En el siguiente apartado de Enlaces se incluyen los ficheros del montaje y de los componentes para ser utilizados en Fritzing, por si alguien los quiere utilizar.

Enlaces

- DS1307 datasheet
- Conectando Raspberri Pi a una protoboard (en este mismo blog)
- DS1307 Real Time Clock Breakout Board Kit (ejemplo para Arduino)
- Configuring i2c
- hwclock (man)
- DS1307 hwclock -r problem
- WiringPi - GPIO Interface library for the Raspberry Pi
- How to use GPIOs on raspberry pi (Simple I/O, PWM and UART)
- WiringPi - Download and install
- RaspPi examples
- Quick2Wire - I2C & SPI
- I2C Installation for Raspberry Pi
- Raspberry Pi - I2C Tutorial
- Cambiando tu timezone en Linux
y a continuación el montaje y los componentes utilizados en el programa Fritzing
- RTC_DS1307.fzz
- RaspPi2 Header 13x2.fzpz
- Battery Holder + CR2032.fzpz
- cristal_kHz.fzpz
- Fritzing
- Inkscape