Vinculum + Mega

Hola,

He estado experimentando un poco con el chip Vinculum de FTDI. En concreto con el módulo de prototipos VDIP1.
http://www.vinculum.com/prd_vdip1.html
Te permite manejar un dispositivo USB y maneja archivos FAT de forma transparente, por lo que es ideal para aplicaciones donde se desea guardar datos sin muchas complicaciones. El precio es de 22 euros desde la web del fabricante.
He realizado un pequeño ejemplo basandome en la información que hay en el Playground de Arduino y a un ejemplo de la web del fabricante con un PIC.
http://www.arduino.cc/playground/Main/UsbMemory
http://www.vinculum.com/downloads.html#vutilities

He usado el Mega con el Serial 3, y sin "flow control". Lo suyo sería utilizar las lineas CTS y RTS para saber si el dispositivo esta preparado para recibir información.
La conexión del VDIP1:
Pin 1.- 5 voltios
Pin 6.- TXD
Pin 7.- GND
Pin 8.-RXD
Pin 10.- GND

En el ejemplo, cada vez que se pulsa un pulsador conectado al pin 9, se abre un archivo como escritura llamado igor.txt y se guarda una linea de texto en la que pone IGOR y el tiempo millis() en una linea. Es un poco tonto, pero para empezar esta bien... Voy sacando la info del programa por el Serial (el USB de programar).

//---------------------------------------
//By Igor Real
//VDIP1 without flow control
//11-07-09
//---------------------------------------
byte dato_recibido;
byte VNC1_State=0;
int noOfChars=1;
long int x;
long int val;

void setup() {

  pinMode(9,INPUT);
  
  Serial.begin(9600);
  Serial3.begin(9600);
  Serial3.flush();
  Serial3.print("IPA"); 
  Serial3.print(13,BYTE);  //RETURN
  //CONTESTA UN D:\> + CR
  if (VNC1_Confirmation()){
    Serial.println("CONFIGURADO LONG COMMAND");
  }else{
    Serial.println("ALGO FALLO");
  }


}

void loop() 
{

  if (digitalRead(9)==1){
  delay(300);
  //VNC1_State=0   => Sync
  //VNC1_State=1   => FindDisk
  switch(VNC1_State){
    case 0:
      if (VNC1_Sync()==1){
        if (VNC1_FindDisk()==1){  
          VNC1_State=1;  
        }else{
          Serial.println("No hay disco");
        }  
      }else{
        Serial.println("Imposible Sync");
      }
      break;
    case 1:
      Serial.println("Hay disco");
      
      Serial3.flush();
      //Abro fichero para escritura
      Serial3.print("OPW igor.txt");
      Serial3.print(13,BYTE);  //RETURN
      //CONTESTA UN D:\> + CR
      while (VNC1_Confirmation()==0);
      //Meto datos
      val=millis();  
      x=val;
      noOfChars=1;      
      while (x>= 10){                 
        noOfChars++;                
        x/=10;     
      }
      noOfChars +=7;
      
      Serial3.print("WRF ");
      Serial3.print(noOfChars);
      Serial3.print(13,BYTE);  //RETURN
      Serial3.print(73,BYTE);  //I
      Serial3.print(71,BYTE);  //G
      Serial3.print(79,BYTE);  //O
      Serial3.print(82,BYTE);  //R
      Serial3.print(32,BYTE);  //<SPACE>
      Serial3.print(val);  
      Serial3.print(13,BYTE);  //RETURN 
      Serial3.print(10,BYTE);  //NEW LINE 
      Serial3.print(13,BYTE);  //RETURN   
      //CONTESTA UN D:\> + CR
      while (VNC1_Confirmation()==0);
      Serial3.print("CLF igor.txt");
      Serial3.print(13,BYTE); 
      //CONTESTA UN D:\> + CR
      while (VNC1_Confirmation()==0);      
      VNC1_Sync();
      Serial.println("Sacar el disco");
      
      VNC1_State=0;
      break;
    default:
      VNC1_State=0;
    
  }
  
  }

}

//----------------------------------------------------------------
// FUNCION: MIRAR SI HAY PENDRIVE
//----------------------------------------------------------------
byte VNC1_FindDisk(){

  byte FindDisk=0;

  Serial3.flush();
  Serial3.print(13,BYTE);  //RETURN
  //CONTESTA UN D:\> + CR
  if (VNC1_Confirmation()){
    FindDisk=1;
  }else{
    FindDisk=0;
  }
    
  //Serial.print("FindDisk= ");
  //Serial.println(FindDisk,DEC);
  Serial3.flush();
  return FindDisk;  
}

//----------------------------------------------------------------
// FUNCION: MIRAR SI HE RECIBIDO D:\>
//----------------------------------------------------------------      
byte VNC1_Confirmation(){  

  byte state=0;
  byte byte_received;
  byte confirm=0;  
  
  while (Serial3.available()<5) ;
  
  //Serial.print("Buffer= ");
  //Serial.println(Serial3.available(),DEC);
  
  while (Serial3.available()){
    byte_received=Serial3.read();
    //Serial.println(byte_received,DEC);
    
    if (byte_received==68 && state==0){
      //Received "D"
      state=1;
      //Serial.println ("Estado 1");
    }else if (byte_received==58 && state==1){
      //Received ":"  
      state=2;
      //Serial.println ("Estado 2");
    }else if (byte_received==92 && state==2){
      //Received "\"  
      state=3;
      //Serial.println ("Estado 3");
    }else if (byte_received==62 && state==3){
      //Received ">"
      state=4;
      //Serial.println ("Estado 4");
    }else if (byte_received==13 && state==4){
      //Received "CR"
      state=0;
      confirm=1;
      //Serial.println ("Estado 5");
      break;
    }else{
      confirm=0;
      break;
    }
  }  
  return confirm;
}  
//----------------------------------------------------------------
// FUNCION: SYNC
//----------------------------------------------------------------
byte VNC1_Sync(){
  
  byte cont_E=0;
  byte confirm_E=0;
  byte confirm_e=0;
  byte state=0;
  byte byte_received=0;
  
  
  Serial3.flush();
  while (confirm_E==0 && cont_E<255){
    Serial3.print(69,BYTE);  //E
    Serial3.print(13,BYTE);  //RETURN
    cont_E++;
    //Serial.print("Contador= ");
    //Serial.println(cont_E,DEC);
    
    while (Serial3.available()<2) ;
    
    while (Serial3.available()){
      byte_received=Serial3.read();
      //Serial.println(byte_received,DEC);
    
      if (byte_received==69 && state==0){
        //Received "E"
        state=1;
        //Serial.println ("Estado 1");
      }else if (byte_received==13 && state==1){
        //Received "CR"  
        state=2;
        confirm_E=1;
        //Serial.println ("Estado 2");
        break;
      }else{
        confirm_E=0;  
        delay(10);
      }
    }
    
  }
  if (confirm_E==1){
    //Serial.println("Vamos por e");
    Serial3.print(101,BYTE);  //e
    Serial3.print(13,BYTE);  //RETURN
    while (Serial3.available()<2) ;
    if (Serial3.read()==101){
      if (Serial3.read()==13){
        confirm_e=1;
      }
    }
  }
  return confirm_e;
  
}
//----------------------------------------------------------------

Saludos

Igor R.

Hola Igor!!!

Me gusta mucho esta idea. Estoy haciendo pruebas también con un GPS, y me gustaría ir guardando un log de los datos recibidos del GPS.

Por lo que he visto, entiendo que se podría utilizar también con un arduino Duemilanove no?

Como solo tengo un puerto serie en el duemilanove, estoy usando El pin Rx para recibir datos del GPS y el Tx para enviar información a un display. Supongo que podría sustituir el display por el Vinculum verdad?

Saludos, Pakoff.

Hola,

A parte de puerto serie, puedes controlarlo con SPI. Para aprender como funciona (http://www.arduino.cc/en/Tutorial/SPIEEPROM y Arduino Playground - Spi).

Por puerto serie,lo suyo es tener Rx y Tx para poder saber lo que te contesta el "dispositivo". Si no tienes que estar poniendo delays. También ampliar con CTS y RTS si necesitas enviar gran cantidad de datos...

Puedes utilizar la libreria Newsoftserial, para poder usar cualquier pin de Arduino como puerto serie (NewSoftSerial | Arduiniana).

Salu2

Igor R.

Hola Igor,

todo esto es muuuy interesante!

Por lo que entiendo este chip vinculum permite hacer que el arduino se convierta en un host usb. Por lo tanto, desde tu punto de vista, podría ser posible conectar un blackberry? Hay unas instrucciones en el BB para enviar y recibir datos low-level, pero lo que necesita es que antes se abra el canal USB, con todo el protocolo respetado etc etc. Piensas que este vinculum lo pueda hacer?

De esta manera se puede hacer algo que nos hace ahorrar mucha pasta (si tienes un BB, por supuesto;) ), y es decir puedes usar el teclado del BB para controlar el arduino, y usar también el display del BB. Esto, para aplicaciones donde el display enseña un estatus que cambia poco a menudo, y sobre todo se usa para configurar parametros, puede ser util...

Hola Sergio,

No tengo ni idea....
Pero el chip hace de USB host seguro. Lo que no sé que USB Class, subclass... no estoy muy puesto en el protocolo USB.

Yo sólo lo he utilizado como en el ejemplo que he publicado...

Puedes ojear: http://www.vinculum.com/documents/fwspecs/UM_VinculumFirmware_V205.pdf

Salu2

Igor R.

Gracias Igor,

espero entonces me sobren unos 25? para comprarme el vinculum y hacer la prueba...

ciao!

SN

Maxim ha sacado otro chip para hacer de usb host (Maxim MAX3421E).

Hay alguien trabajando para hacer un shield: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241065918

:wink:

muchas gracias! es un 3d muy interesante...ya veremos si se saca algo guapo:)

Hola Igor!!!

Solamente darte las gracias por tu post, porque después de 4 días llenos de frustraciones, POR FIN HA FUNCIONADO!!!.

He estado a punto de pedirte ayuda, porque he invertido un montón de horas sin obtener resultados. El caso es que en lugar de hacer la prueba con el Vdip1 como tu, he comprado el Vdip2, el cual lleva 40 pines en lugar de los 24 del vdip1. Me he leído TODAS las webs que me devolvía google y nada. Mi intención es añadirle la posibilidad de grabar un .log a un proyecto que tengo con un GPS + arduino, y el problema era que nada más conectar el Vdip2 parpadeaban los dos leds de los puertos USB y no respondía al comando IPA. Por si le sirve a alguien, el problema se ha resuelto conectando el pin 11 de arduino al pin 18 del Vdip2 y poniendo el pin 11 de arduino en LOW. El pin 18 del Vdip2 cuando está configurado en modo UART es CTS.

Pero hoy por fin!!! :

Y la conexión de arduino con Vdip2 :

Saludos Felices!!!
Pakoff.

Hola Pakoff,

Me alegro que te sirva!!

Tienes que fijarte, en la documentación, que en el VDIP2 el pin 18 es el equivalente al pin 10 del VDIP1. Es el pin CTS.

Si vas a grabar datos de forma continua, para evitar problemas deberías conectar el pin CTS y RTS a tu arduino para hacer control de flujo. De esta forma te aseguras que el dispositivo no tiene el buffer de recepción lleno. Yo lo tengo en mi lista interminable de cosas por hacer.... :wink:

RTS => Request to send
CTS => Clear to send

Saludos


Igor R.

Por cierto, hay una cosa que no sé si se puede cambiar. Cada vez que conectas un pendrive, le cuesta mucho empezar la comunicación. Ésto debe ser porque busca si existe firmware en su interior para actualizarse.... ¿alguien sabe si se puede modificar ésto?

Por cierto, hay una cosa que no sé si se puede cambiar. Cada vez que conectas un pendrive, le cuesta mucho empezar la comunicación. Ésto debe ser porque busca si existe firmware en su interior para actualizarse.... ¿alguien sabe si se puede modificar ésto?

Si vas a grabar datos de forma continua, para evitar problemas deberías conectar el pin CTS y RTS a tu arduino para hacer control de flujo. De esta forma te aseguras que el dispositivo no tiene el buffer de recepción lleno. Yo lo tengo en mi lista interminable de cosas por hacer.... :wink:

RTS => Request to send
CTS => Clear to send

De momento lo veo algo complicado para mi.

He estado ojeando esto del control de flujo y he leido que el terminal que envía datos envía continuamente una señal al pin RTS y comprueba el Pin CTS, pero el pin CTS del vdip2 es de entrada (Input), es el pin que he tenido que conectar al arduino y enviar un LOW para que funcione?????

En fin, haré más pruebas intentando saturar de datos el vdip2 y consultando el pin 17 (RTS) a ver si cambia de estado...

Bye. Pakoff.

A mi me da la impresión de que no es firmware lo que busca, parece como si contara los sectores disponibles. He hecho la prueba con el vdip2 y un pen de 1 GB y ha tardado 20 seg. en estar listo, con uno de 8 GB ha tardado 124 Seg. No son 8 veces más, pero hay que tener en cuenta que el de 8GB es un OCZ mucho más rápido que el de 1 GB.

Bye. Pakoff.

Lo que esta haciendo tu Vinculum es monitorizar la linea CTS para saber si puede enviar datos. Es decir, si está a low, significa que el dispostivo receptor está preparado para recibir datos, y pondrá la linea a high cuando su buffer de recepción este lleno.

Como de momento, no implementamos dicha opción, lo cableamos a gnd (low) y asi siempre envia datos.

Ya, segun entiendo me quieres decir que el vinculum está revisando si él puede enviar datos al arduino. OK.
Cuando arduino esté leyendo el puerto serie que viene el vinculum, debe poner LOW la línea que va al CTS del vinculum.

Pero en el caso qeu nos ocupa, el control de flujo hay que hacerlo sobre el Vinculum no?

O sea, Arduino tendrá que revisar si el vinculum está listo para RECIBIR datos no?

Leche!! no me entero de nada...

Bye.

Exactamente!! es en ambos sentidos!! RTS y CTS van cruzados entre ambos dispositivos, de esta forma se sabe cuando alguno de ellos no puede procesar los datos porque tiene el buffer lleno.

Es decir:
RTS del dispositivo 1 al CTS del dispositivo 2.
CTS del dispositivo 1 al RTS del dispositivo 2.

Un ejemplo, si el Arduino puede recibir datos, pone su pin RTS(output) a nivel bajo. Dado que está conectado al CTS(input) del Vinculum, éste podrá transmitir datos.
Y lo mismo en sentido contrario....

¿Más claro ahora? :wink:

Igor R.

Je, je, je...

Como decían en no recuerdo qué película: CRISTALINO!!

Gracias de nuevo Igor.

Bye. Pakoff.