Sobre SPI en Arduino y multiples dispositivos

Buenas, haber si me podeis hechar una mano por favor, estoy intentando
usar el protocolo SPI en el arduino:

Este protocolo usa 4 puertos, uno el reloj, dos para comunicacion de y
hacia el arduino y un cuarto para la seleccion del dispositivo, por
que puede haber varios

bien, estos puertos suelen ser del 10 al 13, el problema me surge
cuando quiero usar por ejemplo dos dispositivos SPI,

segun creo el SPI comparte 3 de estos 4 cables, osea puedes usar los
mismos 3 cables para el reloj y la comunicacion, pero el "slaveselect"
o cuarto cable, tiene que ser unico por cada dispositivo,

el problema es que cuando intento cambiar este puerto, (que es el
numero 10), poniendo por ejemplo numero 9 u 8, no me deja, no me
funciona el mismo programa

esto me pasa desde leyendo una targeta sd, con la ethernet shield, y
demas, pero en algunos post en arduino.cc veo como hablan de cambiar
este puerto 10 para cada SPI por que tiene que ser unico

y bla bla, pero luego miras en el datasheet del propio chip del
arduino da igual la version, y te aparecen los 4 puertos del spi bien
claritos, y parece ser que no movibles

¿como puedo conectar a la vez mas de un dispositivo SPI en Arduino?

Muchas gracias

Hola,

La verdad, que nunca lo he probado. Sólo he manejado 1 sólo dispostivos SPI, pero en principio es el usuario, quien pone a ALTO ó BAJO el pin de chip selection. Por lo que puede ser cualquier pin digital (en el Master).

Las lineas de MISO,MOSI y SCK son comunes.

La transmisión comienza cuando pones un dato en el registro SPDR.

Por ejemplo, aqui pego dos funciones que tengo creadas para escribir sobre un transceiver de CAN Bus:

byte SPI_ReadWrite( byte data )
{
SPDR = data;

// Esperar hasta final de transmisión
while( !( SPSR & (1<<SPIF) ) );

return SPDR;
}

void mcp2515_write_register(uint8_t address,uint8_t data)
{
digitalWrite(P_CS,LOW);
SPI_ReadWrite(0x02); //Instrucción de WRITE
SPI_ReadWrite(address);
SPI_ReadWrite(data);
digitalWrite(P_CS,HIGH);
}

mi pin P_CS, puede ser cualquiera. Primero, seleciono el dispositivo al cual me quiero comunicar, poniendo su pin de Chip Select a bajo, y luego pongo mi dato a transmitir en el registo SPDR.
Cuando el ATMega funciona como master, no tiene control del pin SS, es el usuario el que lo controla.

Copiado del datasheet:
When configured as a Master, the SPI interface has no automatic control of the SS line. This
must be handled by user software before communication can start. When this is done, writing a
byte to the SPI Data Register starts the SPI clock generator, and the hardware shifts the eight
bits into the Slave. After shifting one byte, the SPI clock generator stops, setting the end of
Transmission Flag (SPIF). If the SPI Interrupt Enable bit (SPIE) in the SPCR Register is set, an
interrupt is requested. The Master may continue to shift the next byte by writing it into SPDR, or
signal the end of packet by pulling high the Slave Select, SS line. The last incoming byte will be
kept in the Buffer Register for later use.

Ya te digo que nunca he probado una red de SPI, pero por lo que entiendo del datasheet, lo que te hace empezar la transmisión en el maestro es escribir sobre el registro SPDR.

Lo único que tienes que hacer, es poner a bajo el pin de tu Arduino, el cual esta conectado al CS del esclavo al cual quieres enviarle datos.
Repito, que nunca lo he probado, si me equivoco, por favor decirlo... :wink:

Saludos

Igor R.

Link interesante: Using Serial Peripheral Interface (SPI) Master and Slave with Atmel AVR Microcontroller | ermicroblog

Igor R muchas gracias, podrias probar en tu proyecto a cambiar el pin que usas para el SS del 10 a otro el que tu quieras y ejecutar, haber si te funciona?

es que es lo que yo ago y no me funciona, va bien si usas del 10 al 13, como coja el 10 y le diga que ese no, que el 9 ya no me sale nada por serial.

ya se que en muchos sitios te dice que se puede, pero yo sigo sin conseguirlo, tengo un duemilanove con el atmega168 y estoy desesperado, por que quiero ponerle la ethernet shield, un sensor de presion barometrica y el lector de targetas sd del ethernet shield y no consigo meterlo todo en el spi.

las pruebas las ago solo con el sensor barometrico spc1000 pero ya te digo que no hay forma, si lo dejas del 13-10 muy bien, tocas el 10 y a la mierda

haces algo para poner el arduino en modo master?????

¿Puedes poner el código? Porque a lo mejor estas usando un código que no tienes parametrizado con una variable el pin SS, y por eso no puedes cambiarlo....¿lo has revisado? ¿Has cambiado el pin en tu código, a parte de físicamente?

El registro SPCR y SPSR son los de configuración del SPI. Te recomiendo leas el datasheet del ATMega168,ya que encontrarás toda la info que necesitas.

Por cierto, si usas el duemilanove, tienes niveles de 5V y el SPC1000 es 3v3.
¿Como lo conectas? ¿Dicho sensor es tolerante a niveles ttl?

Te recomiendo leer esto => http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65

Aqui tienes todo explicado a la perfección.
Es una nota de aplicación de Atmel=> http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf

(ten cuidado de poner, aunque no lo uses, el pin SS del micro como Output cuando uses varios esclavos => ver tabla de verdad 2.2 del documento)

MADRE MIA, vamos a ver, yo conecto los cables y ya esta, nada de poner resistencias en ningun sitio, por lo que veo MINIMO tengo que engancharle resistencias para que no se queme?

Y luego dice: Caution is needed with this approach as it is not guaranteed that your 3.3V device will contain clamping diodes.

Mi sensor es justo el que dice en ese tutorial y yo lo conectaba todo directamente sus 3.3 voltios al sensor y ya esta, y mas o menos me iva pero malamente.

Me podrias indicar que es un clamping diode?, o si lo tiene mi sensor como viene el plaquita no es solo el sensor en si.

Alomejor por eso estoy teniendo los problemas.

Y otra cosa, estoy conectando tambien una targeta SD directamente al arduino usando el ethernet shield, sin poner resistencias ni nada tampoco, deberia ponerselas? o no seria suficiente y deberia comprar diodo?

Madre mia, soy nuevo en esto de la electronica pensaba que estaba cerca de tenerlo funcionando y me veo con un monton de problemas:(

MADRE MIA, vamos a ver, yo conecto los cables y ya esta, nada de poner resistencias en ningun sitio, por lo que veo MINIMO tengo que engancharle resistencias para que no se queme?

Y luego dice: Caution is needed with this approach as it is not guaranteed that your 3.3V device will contain clamping diodes.

Mi sensor es justo el que dice en ese tutorial y yo lo conectaba todo directamente sus 3.3 voltios al sensor y ya esta, y mas o menos me iva pero malamente.

Me podrias indicar que es un clamping diode?, o si lo tiene mi sensor como viene el plaquita no es solo el sensor en si.

Alomejor por eso estoy teniendo los problemas.

Y otra cosa, estoy conectando tambien una targeta SD directamente al arduino usando el ethernet shield, sin poner resistencias ni nada tampoco, deberia ponerselas? o no seria suficiente y deberia comprar diodo?

Madre mia, soy nuevo en esto de la electronica pensaba que estaba cerca de tenerlo funcionando y me veo con un monton de problemas:(

Y sobre lo que me decias del codigo, este es el codigo que estoy usando:

// define spi bus pins
#define SLAVESELECT 10
#define SPICLOCK 13
#define DATAOUT 11      //MOSI
#define DATAIN 12       //MISO
#define UBLB(a,b)  ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )

//Addresses
#define REVID 0x00      //ASIC Revision Number
#define OPSTATUS 0x04   //Operation Status
#define STATUS 0x07     //ASIC Status
#define START 0x0A      //Constant Readings
#define PRESSURE 0x1F   //Pressure 3 MSB
#define PRESSURE_LSB 0x20 //Pressure 16 LSB
#define TEMP 0x21       //16 bit temp

char rev_in_byte;          
int temp_in;
unsigned long pressure_lsb;
unsigned long pressure_msb;
unsigned long temp_pressure;
unsigned long pressure;

void setup()
{
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //disable device  
  
  SPCR = B01010011; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (500kHz)
  clr=SPSR;
  clr=SPDR;
  delay(10);
  Serial.begin(9600);
  delay(500);

  Serial.println("Initialize High Speed Constant Reading Mode");
  write_register(0x03,0x09);
}

void loop()
{
  
  rev_in_byte = read_register(REVID);
  
  pressure_msb = read_register(PRESSURE);
  pressure_msb &= B00000111;
  pressure_lsb = read_register16(PRESSURE_LSB);
  pressure = UBLB19(pressure_msb, pressure_lsb);
  pressure /= 4;
  
  Serial.print("PRESSURE [");
  Serial.print(pressure, DEC);
  Serial.println("]");
  
  temp_in = read_register16(TEMP);
  temp_in = temp_in / 20;
  temp_in = ((1.8) *temp_in) + 32;
  Serial.print("TEMP F [");
  Serial.print(temp_in , DEC);
  Serial.println("]");

  delay(1500);
  
}

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Start the transmission
  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission
  {
  };
  return SPDR;                    // return the received byte
}


char read_register(char register_name)
{
    char in_byte;
    register_name <<= 2;
    register_name &= B11111100; //Read command
  
    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte = spi_transfer(0x00); //Send nothing, but we should get back the register value
    digitalWrite(SLAVESELECT,HIGH);
    delay(10);
    return(in_byte);
  
}

float read_register16(char register_name)
{
    byte in_byte1;
    byte in_byte2;
    float in_word;
    
    register_name <<= 2;
    register_name &= B11111100; //Read command

    digitalWrite(SLAVESELECT,LOW); //Select SPI Device
    spi_transfer(register_name); //Write byte to device
    in_byte1 = spi_transfer(0x00);    
    in_byte2 = spi_transfer(0x00);
    digitalWrite(SLAVESELECT,HIGH);
    in_word = UBLB(in_byte1,in_byte2);
    return(in_word);
}

void write_register(char register_name, char register_value)
{
    register_name <<= 2;
    register_name |= B00000010; //Write command

    digitalWrite(SLAVESELECT,LOW); //Select SPI device
    spi_transfer(register_name); //Send register location
    spi_transfer(register_value); //Send value to record into register
    digitalWrite(SLAVESELECT,HIGH);
}

y me da valores como estos, (usando el metodo de poner resistencias que me has indicado con la pagina de antes):

PRESSURE [1073737712]

TEMP F [32]

PRESSURE [1073737674]

TEMP F [32]

y si pongo en la primera linea un 9 para el cableselect y cambio el pin fisicamente al 9 me deja de responder el asunto solo me aparece una y otra vez esta frase:

Initialize High Speed Constant Reading Mode

y si cambio el pin al 10 de nuevo y reseteo sin cambiar el cable select me da esto

PRESSURE [0]

TEMP F [32]

PRESSURE [0]

TEMP F [32]

Aparte yo creo que me he debido de cargar el sensor de la temperatura por que siempre da el mismo valor aunque ponga el dedo o lo que sea.

Muchas gracias por ayudarme (ahora hasta que solucione esto lo de que funcione con otros dispostivos SPI lo dejo en segundo plano, no pensaba que esto fuera a complicarseme tanto)

MADRE MIA, leyendome el pdf que me has pasado y tus notas he visto lo de que aunque cambie el SlaveSElect de sitio tengo que seguir poniendo como input el pin 10 del arduino, total que he cambiado la primera parte del setup añadiendo una linea:

void setup()
{
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
    pinMode(10,OUTPUT);

la ultima, y ya puedo cambiar el slaveselect arriba Y FUNCIONA, MAAAAAAAAADRE MIA, muchas gracias por tu ayuda, ahora voy a intentar que funcione junto con el ethernet y la tarjeta SD, todo SPI.

Solo me queda la duda esa que me mandaste de conectar dispositivos de 3.3v al arduino que va a 5.

Crees que deberia comprarme diodos y montar el asunto de protección en la SD y en el sensor de presión, para mayor seguridad?

ja,ja,ja. Tranquilo, es normal... todo el mundo le hemos sacado humillo a lo que estabamos montando...ja,ja,ja

Ya me parecía a mi, que algo raro tenías que estar haciendo software para que no te funcionase el SS del SPI con otro pin.... :wink:
Como puedes ver, es por código cuando pones dicho pin a bajo ó alto.
(aunque repasando el datasheet cuando formulaste la pregunta, vi que hay una tabla de verdad a tener en cuenta... es lo que tiene responder a la gente, que uno mismo aprende un montón :wink: )
Ya que aunque tu micro éste como Master, puede usar el pin SS para saber si hay otro master en la red... resumiendo, configurar el pin 10 cómo salida, aunque no se use, para asegurarnos.... :smiley:

Voy a intentar explicarme (no soy muy bueno haciendolo):

  1. Diodos de clamp: Son diodos puestos entre la entrada del pin en cuestion a alimentación y a masa.

    Resulta, que buscando en google una imagen para ponerte aqui, he encontrado un documento dónde lo explican....ja,ja,ja

http://zone.ni.com/devzone/cda/tut/p/id/4264

La idea es pones una resistencia de gran valor, para que pase poca corriente, ya que dichos diodos no suelen aguantar mucho (en el caso de las entradas de Arduino es 1mA). Al poner una tensión en la entrada del pin de tu dispositivo a probar mayor de 3V3 en éste caso, veras que por un lado de la resistencia (lado dispositivo 3V3) la tensión se queda limitada, y por el otro lado tendrás, por ejemplo, tus 5V.

¿Por qué pasa? Porque el diodo entra en conducción, y tendrás en la entrada Vcc + Vdiodo (3'3 + Vdiodo).
¿Qué pasa si no pones resistencia? No hay nada que limite la corriente, y hoy en día los dispositivos sacan corriente suficiente como para quemar dichos diodos y el dispositivo.
Recuerda, la electrónica es humo, y las resistencias son aquellos dispostivos que sirven para recogerlo y que no salga... :wink:

  1. Hay dispostivos, que aunque sean de 3v3, son tolerantes a TTL. Eso debería ponerlo en el datasheet.

  2. En el tutorial de Sparkfun, tienes explicados diferentes métodos. El de hacer divisor de tensión es el más sencillo y menos complicaciones.

Como mínimo, siempre pon resistencia entre tu dispositivo TTL y 3V3 y haz la comprobación si en la entrada de tu dispositivo 3v3 hay algo del entorno a 3v3 ó 5V. Así sabras si tienes diodos de clamp ó no.

Saludos

Igor R.

Otro link buenísimo de Microchiop que me ha salido buscando diode clamp para ponerte una imagen en google...ja,ja,ja
http://www.siongboon.com/projects/2006-01-08_more_circuit_schematic/3V%20Tips%20'n%20Tricks,%2041285A.pdf
EN ÉSTE DOCUMENTO TIENES TODO EXPLICADO (Tip 10 es lo que he intentado explicarte)

haber lo tengo todo funcionando junto, AHORA MISMO ESTOY EXULTANTE jejejeje SUBIDONNNNNNNNNNNN

Y me estas solucionando otra duda que tenia que era:

para que se usan tantas resistencias?, que dices bueno las uso, pero lo que no entiendo es que unos te dicen, no ponle una de 10K, pero por ejemplo si le pones una de 12K tambien funciona, (esto es de otro montaje que estoy haciendo con un transistor), no entiendo bien el tema de por que 10K por que no 100K por que no 4,7K

voy a leerme bien tu post que lo he leido un par de veces pero todavia no lo entiendo bien jejejej

te dije que no era bueno explicandome.....je,je,je :smiley:

no no, si la culpa es mia, que no tengo ni idea de electronica y estoy montando una estacion metereologica con 7 sensores jejejej

pero por lo que veo, en lo de sparkfun usan el diodo de distinta manera de la que tu me comentas, lo ponen en el MOSI para que si el arduino intenta mandarle 5 voltios, los deseche, pero si el sensor trata de mandar informacion o lo que sea a 3.3v lo deje pasar sin problemas, o eso creo entender

Siiii!! Pero los diodos de clamp están dentro del dispositivo.
Lo de sparkfun es un montaje para convertir 5v a 3v3, externamente.

http://www.siongboon.com/projects/2006-01-08_more_circuit_schematic/3V%20Tips%20'n%20Tricks,%2041285A.pdf

El del diodo,personalmente, es el que menos me gusta.... Porque cuando hay un "0" logico en la salida del dispositivo 5v, le estas inyectando corriente a dicha salida...

Oye y una cosa en la web de sparkfun que me pasaste dice:

Standard silicon diodes have a forward voltage drop of around 0.6V. The lower the forward voltage drop the better for this application therefore you may want to consider using a Schottky diode. These diodes have forward voltage drops of around 0.2V.

Tu crees que deberia comprar Schottky diodes? tengo por aqui un catalogo de electronica de una tienda cercana a mi casa y no tienen de eso, tienen diodos normales 1N4001-1N4007 que por lo que veo son todos iguales solo que aguantan mas voltaje de tension inversa de cresta maxima, de 50V a 1000V segun vas subiendo, pero yo creo que con 50V me vale para el arduino no?, (me ire esta tarde a pillar diodos creo y montare el circuito con diodos y resistencias que me parece lo mejor entre facilidad y seguridad, lo de los mostfet me da cosa meterme)

Mira, un diodo normal, en conducción tiene una caida de 0'6 voltios.
Ésto significa, que en según el montaje realizado, 0'6 es demasiado.
Un shottky tiene menos.

En el caso de lo de Sparkfun, cuando hay un nivel LOW, si tienes un diodo normal, tendrás 0'6 voltios en la entrada de tu dispositivo 3v3. Se debe verificar, si estas dentro del margen de voltaje para que sepa que esa tensión equivale a un "0" lógico.
Si tuvieras un shottky, pues son 0'2 v, que seguro que los interpreta como un "0" lógico.

Me extraña que no vendan shottky....

Pero primero mira si tienen tus dispostivos diodos de clamp. Es una prueba rápida, y sólo necesitas una resistencia.....Si tienen (hoy en día casi todos tienen), no necesitas nada más que la resistencia.
V=R*I y quieres que I sea menor de 1 mA.... los cálculos te los dejo a ti... :wink:

Ya sé que todos queremos tener montado nuestro "juguete" ya!!!

Pero párate un momento, cuenta hasta 10, lee los links que te he pasado, haz pruebas y luego compras lo que necesites...ja,ja,ja

(a mi también me pasa.... :wink: )

haber

V=R*I

5 = X * 0,1

x = 5/0,1 = 50

el 5 es por los 5 voltios y el 0,1 por le limite que soporta el arduino

asique necesito una resistencia de 50 omhnios, o mas? o tiene que ser de 50 omhnios?

y luego vale, la pongo en el mosi solo, los demas estan bien como estan?

y donde pongo el polimetro pa comprobar? jejejej

siento hacerte tantas preguntas pero es que no se nada de electronica y estoy haciendo un proyecto de estudio, que es mas hcer la parte de programacion y me he metido en un berengenal bueno queriendo hacer yo la estacion metereologica a mano jejej