Go Down

Topic: Sobre SPI en Arduino y multiples dispositivos (Read 23213 times) previous topic - next topic

joaquinrl

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

igorreal

#1
Nov 30, 2009, 12:32 pm Last Edit: Nov 30, 2009, 12:36 pm by igorreal Reason: 1
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... ;)


Saludos



Igor R.


joaquinrl

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?????

igorreal

¿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.

igorreal

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

igorreal

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)

joaquinrl

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:(

joaquinrl

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:(

joaquinrl

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

Code: [Select]


// 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


  • TEMP F [32]

    PRESSURE


  • 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)

joaquinrl

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:

Code: [Select]


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?

igorreal

#11
Dec 03, 2009, 10:44 am Last Edit: Dec 03, 2009, 10:46 am by igorreal Reason: 1
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.... ;)
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  ;) )
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.... :D

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... ;)


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

3) 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%27n%20Tricks,%2041285A.pdf
EN ÉSTE DOCUMENTO TIENES TODO EXPLICADO (Tip 10 es lo que he intentado explicarte)




joaquinrl

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

igorreal

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

joaquinrl

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

Go Up