lunes, 29 de abril de 2013

Analizador lógico (digital) | Logic analyzer (digital)

Una buena herramienta para trabajar con la lógica digital es el analizador lógico. Como necesito uno y ahora no es un buen momento para gastar dinero he decidido construir uno casero con Arduino.

Lo primero que necesito es saber cuántas lecturas puedo llegar a hacer en un determinado tiempo. Lo más fácil sería leer el estado de un pin de entrada y enviarlo por el puerto serie y luego controlar el tiempo de lectura desde un software de PC, pero esto sería demasiado lento y podríamos perder muchos datos. Lo óptimo sería leer un determinado número de veces, guardarlo en la memoria SRAM de Arduino y luego volcarlo todo al puerto serie. Sabiendo el tiempo empleado para leer una vez, podemos calcular la gráfica a pintar en pantalla. La forma más precisa es trabajar con instrucciones de ensamblador. Para ello hay que echar un vistazo al set de instrucciones de los chips ATmega y determinar que instrucciones usar y los ciclos de reloj que consume cada una de estas instrucciones. Además, si queremos leer varios pines a la vez, debemos acceder a ellos mediante los puertos internos del microcontrolador. Si utilizamos un Arduino UNO o un Arduino Nano (como en mi caso) tendremos el siguiente mapeado de puertos:
A good tool for working with digital logic is the logic analyzer. As I need one and now is not a good time to spend money I decided to build a homemade one using Arduino.

The first thing I need to know is how many readings I can get in a determinate time. The easiest way would be to read the state of an input pin and send it via the serial port and then control the reading time from a PC software, but this would be too slow and I could lose a lot of data. The optimum would be to read a certain number of times, save it in Arduino SRAM and then bounce everything to the serial port. Knowing the time used to read one time, we can calculate the graph displayed on the screen. The most accurate way is to work with assember instructions. This requires taking a look at the instruction set of the ATmega chip and determining which instructions to use and how many clock cycles consume each of these instructions. Furthermore, if we read several pins at once, we have to access to the internal ports of the microcontroller. If we use an Arduino UNO or Arduino Nano (as in my case) we have the following port mapping:



BIT 7 6 5 4 3 2 1 0
PORTB XTAL XTAL 13 12 11 10 9 8
PORTC NC RST A5 A4 A3 A2 A1 A0
PORTD 7 6 5 4 3 2 TX 1 RX 0



Si utilizamos el puerto B para leer las entradas, debemos utilizar los bits 0..5 ya que los bits 6 y 7 están conectados al cristal. Si utilizamos el puerto C, usaremos los bits 0..5 ya que en el bit 6 está conectado el reset y el bit 7 no está conectado. Y si usamos el puerto D, usaremos los bits 2..7 porque los bits 0 y 1 se utilizan para la comunicación por el puerto serie.

Yo, concretamente, he decidido utilizar el puerto B para hacer las lecturas de lógica, así que podré leer 6 canales.

Para leer los 8 bits de un puerto con Arduino utilizamos la siguiente instrucción:
    byte b = PINB;

Para leerlos con instrucciones a bajo nivel (ASM) lo leemos de la siguiente forma:
    IN Rd, A

Dónde Rd es el registro de memoria de destino y A es el puerto de entrada. Esta instrucción consume un ciclo de reloj (Pag 13).

Para guardar la lectura en memoria y pasar a la siguiente posición de memoria usaremos la siguiente instrucción:
    ST z+, Rr

Dónde z es la posición de memoria donde vamos a guardar el dato y Rr es el registro donde previamente hemos leído el puerto de entrada. ST consume un ciclo de reloj y el incremento de posición de memoria otro ciclo más.
Así, tenemos el siguiente bloque de código ensamblador:
    in r0, A
    st z+,r0

A parte de esto tenemos que saber de cuanta memoria SRAM disponemos para almacenar lecturas. ATmega 328 dispone de 2Kb (2048 bytes), de los cuales una cantidad la consume el bootloader de Arduino. Haciendo unas pruebas he visto que puedo utilizar un buffer de 1800 bytes. Si sabemos que estamos consumiendo 3 ciclos por cada lectura podemos deducir lo siguiente:

If we use the port B to read inputs, we use the bits 0..5 as bits 6 and 7 are connected to the xtal. If we use the port C, we will use the bits 0..5 as in the bit 6 is connected to the reset and bit 7 isn't connected. And if we use the port D, we use bits 2..7 because bits 0 and 1 are used for serial port communication.

I, specifically, I decided to use port B to make logical readings, so I can read 6 channels.

To read the 8 bits of a port with Arduino we use the following statement:
    byte b = PINB;

To read with low-level instructions (ASM) we read as follows:
    IN Rd, A

Where Rd is the destination memory register and A is the input port. This instruction consumes one clock cycle (Pag 13).
To save the reading in memory and move to the next memory location we will use the following instruction:
    ST z+, Rr

Where z is the memory location where we will store the data and Rr is the register where we have already read the input port. ST consumes one clock cycle and increasing memory location another cycle.
Thus, we have the following assembler code block:
    in r0, A
    st z+,r0

Apart from this we have to know how much SRAM have to store readings. ATmega328 has 2K (2048 bytes), of which consumes an amount Arduino Bootloader. After doing some tests I have seen that I can use a buffer of 1800 bytes. If we know that we are consuming 3 cycles for each reading we can deduce the following:

    16 MHz / 3 Cycles = 5.33 MHz
    3 Cycles * 1800 Times = 5400 Cycles
    16 MHz = 62.5 ns per cycle
    5400 Cycles * 62.5 ns = 337.5 us

Tenemos una frecuencia de lectura de 5.33 Mhz. El tiempo total de lectura es de 337.5 us.

Para hacer las 1800 lecturas he decidido no utilizar un bucle porque perdería tiempo incrementando variables y saltando al inicio del bucle en cada vuelta.

We have a 5.33 MHz reading frequency. The total reading time is 337.5 us.

To make 1800 readings I decided not to use a loop, because it can make lose time increasing the index and looping back.



#define DATA 1800

byte _data[DATA];

void ReadDigital()
{
  __asm__ __volatile(
    "in r0,%[port]\n\t"
    "st z+,r0\n\t"            // 1
    "in r0,%[port]\n\t"
    "st z+,r0\n\t"            // 2
.
.
.
    "in r0,%[port]\n\t"
    "st z+,r0\n\t"            // 1800
    :
    : [port] "i" (_SFR_IO_ADDR(PINB)), "z" (_data)
    :
  );
}






PRUEBAS:
TESTS:


He programado también una aplicación en VB.Net 4 para simular por pantalla los datos recogidos por el analizador. Más adelante, cuando esté perfeccionado, subiré el código, por ahora he subido el ejecutable.

Para probar el funcionamiento del analizador, he programado otra placa Arduino como un generador de señales PWM, de forma que cada una de las salidas genera una señal PWM del 50% a su máxima frecuencia. Pins 3, 9, 10 y 11 a 31250 Hz y pins 5 y 6 a 62500 Hz. He conectado estas salidas a los pins de entrada del analizador y este ha sido el resultado:
I have also programmed an application in VB.Net 4 to simulate on screen the data collected by the analyzer. Later, when it is perfected, I'll upload the code, now I uploaded the executable.

To test the performance of the analyzer, I have programmed another Arduino board as a PWM signal generator, so that each of the outputs generates a PWM signal of 50% at maximum frequency. Pins 3, 9, 10 and 11 are 31250 Hz and pins 5 and 6 are 62500 Hz. I connected these to the analyzer input pins and this is the result:


Ejemplo de conexiones
Example of connections

Esquema
Schematic

6 Señales PWM
6 PWM signals



#include "PwmFrequency.h"

int pins[] = {3, 5, 6, 9, 10, 11};

void setup()
{
  
  for(int i=0; i<6; i++)
  {
    setPwmFrequency(pins[i], 1);
    pinMode(pins[i], OUTPUT);
    analogWrite(pins[i], 127);
  }

}

void loop()
{}







Descargas:
Downloads:


LogicAnalyzer.zip




Enlaces:
Links:


Analizador lógico (ES): http://es.wikipedia.org/wiki/Analizador_lógico
Logic analyzer (EN): http://en.wikipedia.org/wiki/Logic_analyzer
8-bit AVR® Instruction Set (EN): http://www.atmel.com/Images/doc0856.pdf
Arduino registro PORT (ES): http://arduino.cc/es/Reference/PortManipulation
Arduino port registers (EN): http://arduino.cc/en/Reference/PortManipulation
ATmega port manipulation (EN): http://playground.arduino.cc/Learning/PortManipulation



viernes, 26 de abril de 2013

Velocidad y sentido | Speed and direction:

Además de controlar la velocidad también nos interesa controlar el sentido de la marcha. Para lograr esto sin necesidad de utilizar componentes electromecánicos como los relés existen varias soluciones, una de ellas es el puente H.

Un puente H consta de 4 interruptores que dejan pasar la electricidad en un sentido o en otro. Veamos el siguiente esquema:
In addition to controlling the speed we also want to control the direction of travel. To accomplish this without the use of electromechanical elements as relays as there are several solutions, one of which is the H bridge.

An H bridge consists of 4 switches that let electricity in one direction or another. Consider the following diagram:


Puente H.
H Bridge.


Si cerramos SW3 y SW2 dejamos pasar la corriente desde el polo positivo del motor al negativo, por lo tanto el tren se mueve hacia adelante. Si por el contrario, cerramos SW1 y SW4 dejamos pasar la corriente al revés y el tren se moverá hacia atrás. Este circuito se puede construir con cualquier tipo de interruptor, ya sea manual o electromecánico, pero lo óptimo es hacerlo con transistores. De hecho existen en el mercado circuitos integrados que contienen el puente H. Uno de estos circuitos es el L293 (36V 1A).

Para controlar este circuito con Arduino necesitamos una salida PWM y dos salidas digitales para controlar el sentido de giro del motor.Una de estas salidas controla SW1 y SW4, y la otra controla SW2 y SW3.
If we close SW3 and SW2 then the current pass from the positive pole to the negative pole of motor, so the train moves forward. If, however, we close SW1 and SW4 the current pass backwards and the train will move back. This circuit can be built with any type of switch, either manual or electromechanical, but it is optimal to do with transistors. In fact exist on the market integrated circuits containing the H bridge. One of these circuits is the L293 (36V 1A).

To control this circuit with Arduino we need a PWM output and two digital outputs for controlling the rotational direction of the motor. One of these outputs controls SW1 and SW4, and the other one controls SW2 and SW3.


Ejemplo de conexiones.
Example of connections.

Esquema.
Schematic.


El siguiente bloque de código muestra la forma de cambiar de sentido, simplemente activando y desactivando los pins asignados al L293:
The following piece of code shows how to change direction by simply activating and deactivating the assigned pins to the L293:



 
...
void SetDirection()
{
  switch(_dir)
  {

    case Left:
      digitalWrite(dirPin0, LOW);
      digitalWrite(dirPin1, HIGH);
      break;

    case Right:
      digitalWrite(dirPin0, HIGH);
      digitalWrite(dirPin1, LOW);
      break;
      
    default:
      digitalWrite(dirPin0, LOW);
      digitalWrite(dirPin1, LOW);
      break;

  }

}
...
 


Como en el artículo anterior, he hecho un pequeño ejecutable en VB.Net 4.0 para controlar tanto la velocidad como el sentido del tren.
As in the previous post, I made a small executable in VB.Net 4.0 to control both the speed and the direction of the train.


Ejecutale VB.
VB Executable.




Descargas:
Downloads:


ArduinoL293.zip



Enlaces:
Links:


L293 (EN): http://www.ti.com/lit/ds/symlink/l293d.pdf
Puente H (ES): http://es.wikipedia.org/wiki/Puente_H_(electrónica)
H Bridge (EN): http://en.wikipedia.org/wiki/H_bridge




lunes, 22 de abril de 2013

Mover un tren con Arduino | Move a train with Arduino

Uno de mis hobbies es el modelismo ferroviario. Un día, buscando algún tipo de placa que me proporcionase entradas y salidas mediante una conexión USB a un PC, di con Arduino. Pronto descubrí que podía utilizarse para cualquier cosa que pudiese imaginar, así que decidí comprar un Arduino Mega para probar. Hoy en día tengo varios tipos diferentes de Arduino que uso para diferentes proyectos.

Hoy voy a explicar la forma más sencilla de controlar el movimiento de un tren de escala Z (1/220) mediante Arduino UNO.

Velocidad:

Esta forma de control consiste en utilizar una salida PWM (Modulación por Ancho de Pulso) para controlar la velocidad del motor. El PWM es un tipo de señal digital de una duración determinada que se repite indefinidamente. Cada uno de estos ciclos consta de un estado a nivel alto (Tensión máxima) y uno a nivel bajo (Tensión mínima). La suma del tiempo que dura el estado alto y el bajo es la duración total del ciclo. En Arduino UNO concretamente la tensión de los estados es de 5V y 0V respectivamente. Al utilizar una señal PWM estamos utilizando señales del voltaje máximo aceptado por el motor, así aprovechamos toda su potencia.
One of my hobbies is model railroading. One day, looking for some kind of pc board that can provide inputs and outputs through an USB connection to a PC, I found Arduino. I soon discovered that it could be used for anything I could imagine, so I decided to buy an Arduino Mega to try. Today I have several different types of Arduino to use for different projects.

Today I will explain the easiest way to control the movement of a Z scale (1/220) train using Arduino UNO.

Speed:

This way of control is to use a PWM (Pulse Width Modulation) to control motor speed. The PWM is a digital signal type of fixed duration that repeats indefinitely. Each of these cycles consists of a high-level state (high voltage) and one low (low voltage). The sum of the duration of the high and the low is the total cycle. In Arduino UNO specifically states voltage are 5V and 0V respectively. By using a PWM signal we are using maximum voltage accepted by motor and we get full power.
Diferentes ejemplos de pulsos PWM.
Different examples of PWM pulses.


En la imagen anterior vemos varios ejemplos de pulsos PWM (rojo) y su equivalente en tensión (verde). La diferencia entre usar pulsos de 9V y de usar tensiones de 0V a 9V es que usando PWM siempre alimentamos el motor con su máxima tensión.

Arduino UNO puede proporcionar 5V y 40ma por pin, esto no es suficiente para mover un motor de 9V y aproximadamente 300mA. Para ello necesitamos usar un transistor. Yo he utilizado para hacer la prueba un transistor darlington que me permite trabajar hasta con 80V y 4A. Se trata del transistor BD679.

Cuando trabajamos con motores y PWM debemos tener en cuenta la frecuencia de ciclo de la fuente de PWM. Si utilizamos frecuencias bajas, de entre 20Hz y 20KHz, entraremos dentro del espectro audible del ser humano y el motor producirá un zumbido desagradable. Con Arduino UNO no hay problema ya que los pins que proporcionan PWM trabajan con el Timer 0 (62500Hz) o con los Timers 1 y 2 (31250Hz).
In the picture above we can see several examples of PWM pulses (red) and the equivalent voltage (green). The difference between using 9V pulses and using voltages from 0V to 9V is that we always feed the engine with maximum voltage.  


Arduino UNO can provide 5V and 40mA per pin, this is not enough to move a 9V and approximately 300mA motor. For this reason we need to use a transistor. I've used for the test a darlington transistor that allows me to work up to 80V and 4A. This transistor is a BD679.

When we are working with motors we must consider PWM cycle frequency. If we use low frequencies, from 20Hz to 20KHz, we are entering in human hearing range and it causes an unpleasant humming. With Arduino UNO there is no problem because the pins that can provide PWM are working with the Timer 0 (62500Hz) or with Timers 1 and 2 (31250Hz).



Ejemplo de conexiones.
Example of connections.


Esquema
Schematic.


En la imagen anterior podemos ver el esquema necesario para mover un tren por una vía usando el pin 6 de Arduino que nos proporciona 62.5KHz. He utilizado el transistor BD679 y un diodo 1N4007 (1000V 1A) para eliminar los picos de tensión provocados por la bobina del motor.

El siguiente bloque de código muestra la lectura de un byte del puerto serie y la asignación del byte a la salida PWM:
In the picture above we can see the schematic required to move a train by the track using the Arduino's pin 6 that gives us 62.5KHz. I used a BD679 (80V 4A) transistor and a 1N4007 diode (1000V 1A) to eliminate voltage spikes caused by the motor coil.

The next piece of code shows reading an incoming byte from the serial port and then output this byte to the PWM pin:


 
...
 
// Velocity
byte vel = Serial.read();
analogWrite(pwmPin, vel);
 
...
 

Para hacer la prueba he creado un pequeño ejecutable en Visual Basic (.NET 4.0) que se puede descargar junto con todo el material de este post.
To test I created a small executable in Visual Basic (. NET 4.0) which can be downloaded along with all the material in this post.

Ejecutale VB.
VB Executable.






Descargas:
Downloads:


ArduinoBD679.zip



Enlaces:
Links:


Arduino UNO (EN): http://arduino.cc/en/Main/arduinoBoardUno
PWM Wikipedia (ES): http://es.wikipedia.org/wiki/Modulación_por_ancho_de_pulsos
PWM Wikipedia (EN): http://en.wikipedia.org/wiki/Pulse-width_modulation
PWM Arduino (ES): http://arduino.cc/es/Tutorial/PWM
PWM Arduino(EN): http://arduino.cc/en/Tutorial/PWM
Espectro audible (ES): http://es.wikipedia.org/wiki/Espectro_audible
Hearing range (EN): http://en.wikipedia.org/wiki/Hearing_range
BD679 (EN): http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/CD00000939.pdf
1N4007 (EN): http://www.diodes.com/datasheets/ds28002.pdf




viernes, 19 de abril de 2013

Intro

Desde que empecé con mi antiguo blog, hace algo más de un año, siempre he estado desarrollando proyectos caseros con Arduino. Proyectos que nunca he publicado ya que nada tenían que ver con el contenido del blog, pero siempre me ha rondado por la cabeza la idea de que vieran la luz. Por eso hoy empiezo un nuevo blog con la idea de dar a conocer todo aquel material que anda disperso entre hojas de papel y discos duros. Así como todo el material que aún está por desarrollar.

¡Empezamos!
First of all, sorry for my bad english. I'll try to explain my projects in english too because I think it's important for the visitors to read some text that isn't translated by robots (Though I help myself with Google Translate). So if you find any kind of grammar or syntax error, please, feel free to let me know, I'll be happy to learn.

Since I started with my old blog, a little more than a year ago, I have always been developing some homespun projects with Arduino. Projects that I've never posted and that had nothing to do with the content of the blog, I've always been thinking about the idea that they should be released. So today I start a new blog with the idea to give out all the material that is scattered between paper and hard drives. Just as all the material that is yet to develop.

Let's go!