SPI comunication between two avr

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys, I need to implement a comunication between two avr in different period of time.

The first avr send data to other avr, that after elaborate resend to the first.

I would to implement the comunication with interrupt.

First i think assign at the first avr the role of MASTER and when the second avr need to send its data, wake the master using an external interrupt.

I am mandatory to use external interrupt.

But if i use the SS port as input and connect another port of the second avr, and use all of avr as master?

When a master recieve a low level on SS input port, it became slave.

 

CONNECTION HARDWARE:

SCK - SCK

MISO - MISO

MOSI - MOSI

SS -  PORTB1

PORTB1 -  SS

Can this work? Can i wake up the other avr when i need to send data?

In the future i post the code.

 

thanks a lot

 

 

This topic has a solution.
Last Edited: Mon. Apr 23, 2018 - 03:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is not common to do multi master with SPI.
Please fix the master and poll it.
Or use UART for communication method.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kabasan wrote:
Or use UART for communication method.

We've already been through all that in the previous thread:

 

https://www.avrfreaks.net/forum/twi-comunication-between-two-arduino

 

@radamirez: this is exactly why you should include links between your threads!

 

You should also mark that thread as solved - see Tip #5

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try and find...

 

"DN_035 Using the SPI as High Speed, Bi-directional Data Bus with Automatic MasterSlave Switch.pdf"

 

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

kabasan wrote:
Or use UART for communication method.

We've already been through all that in the previous thread:

 

https://www.avrfreaks.net/forum/twi-comunication-between-two-arduino

 

@radamirez: this is exactly why you should include links between your threads!

 

You should also mark that thread as solved - see Tip #5

I can't use UART .

 

kabasan wrote:

It is not common to do multi master with SPI.
Please fix the master and poll it.
Or use UART for communication method.

 

I must avoid poll.

Why i can't use multi master?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

SPI is a master/slave arrangement so just pick a master. Either the master can just regularly poll in case the slave needs attention or if you really need fast response add another wire and use that to interrupt the master to say "exchange now". You might even be able to make use of the SPI wires them selves for this, disable the SPI when it's noot being used then use a pin change on MISO so the slave can use thus to ask for service. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your circuit diagram is very non informative.

I can't even read the numbers on the "arduino" boards you have drawn the fancy colored wires between.

And Even If I could I'd have to look up the "arduino" board schematics to see to which pins of the uC's those colored wires are attached.

And because of the many clones available I don't even now which AVR's you are using.

 

However:

According to what I read from the datasheet of several AVR's it should be possible to even use multiple (>10 or so) AVR's in a multi master SPI setup.

MISO can not be used in that context (or need extra logic) and all SS pins can be connected together.

Each node should be configured as master. When a Node wants to send anything, it pulls it's own SS low and all other nodes drop into slave mode.

This functionality is described in the datasheet, there may even be an AN for this.

I was mildly intersted in the DN_035 Brian mentioned, but gave up after a few minutes.

 

I once wanted to use this feature, but never got beyond the planning stage for that project.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

SPI is a master/slave arrangement so just pick a master. Either the master can just regularly poll in case the slave needs attention or if you really need fast response add another wire and use that to interrupt the master to say "exchange now". You might even be able to make use of the SPI wires them selves for this, disable the SPI when it's noot being used then use a pin change on MISO so the slave can use thus to ask for service. 

 

 

Paulvdh wrote:
Your circuit diagram is very non informative.

Sorry, these are the connection:

SCK (output) - SCK (output)   RED

MISO (input) - MISO (input)    YELLOW

MOSI (output)- MOSI (output)    GREEN

 

SS (input) -  PORTx (output)    BLUE 

PORTx (output) -  SS (input)    CYAN

 

 

PORTx is used to simulate SS connection, is used as output to change the role of avr master.

At the start i have 2 master.

When one of it need to send data, first give low PORTx, so other master recieve in SS a low level and became Slave (sck and mosi  became input).

 

 

I try to write the code but for now not work

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <string.h>


#define SPI_PORT PORTB
#define SPI_DDR  DDRB

#define SCK PORTB5
#define MISO PORTB4
#define MOSI PORTB3
#define SS PORTB2

#define CONTROL_SS PORTB1

#define SPI_CS   PB2



int indice = 0;
char dataString[100] = "start\0";
char status = 'B';

void SPI_setMasterPort(void)
{
	SPI_DDR |= (1 << MOSI);
	SPI_DDR |= (1 << SCK);
	//SPCR |= (1 << SPE);
	SPCR |= (1 << MSTR);
	SPCR |= (1 << SPR1);
	SPCR |= (1 << SPR0);
}

void SPI_TrasmitMaster(char data)
{
	SPI_PORT &= ~(1 << CONTROL_SS);
	SPDR = data;
		SPI_setMasterPort();
	SPCR |= (1<<SPIE);
	SPCR |= (1 << SPE);
	status = 'M';
}


void init_UART()
{
	UBRR0L = 0x67;
	UCSR0C = (1<<UCSZ00) | (1<<UCSZ01) ;//8 bit
	UCSR0B = (1<<RXEN0) | (1<<TXEN0); // abilita ricezione e trasmissione senza interrupt
}


int main()
{
	//CLKPR = (1<<CLKPS3);
	init_UART();

	SPI_setMasterPort();
	
	SPI_DDR |= (1 << CONTROL_SS); //init control ss
	
	char *s = "start \r\n\0";
	strcpy(dataString,s);
	UCSR0B |= 1UL << UDRIE0;


	sei();

	set_sleep_mode(SLEEP_MODE_IDLE);

	while(1)
	{
		sleep_enable();
		sleep_mode();
		sleep_disable();
	}
	
	return 0;
}




ISR (SPI_STC_vect)
{
	if(status == 'M')
	{
		SPI_PORT |= (1 << CONTROL_SS);
//		SPCR &= ~(1 << SPIE);
//		SPCR &= ~(1 << SPE);
		status = 'B';
	}
	else if(status == 'R')
	{
		char data = 'X';
		strcpy(dataString,data);
		UCSR0B |= 1UL << UDRIE0;
	}
	else
	{
		SPI_PORT |= (1 << CONTROL_SS);
		status = 'R';
	}
	
	strcpy(dataString,"SPI\r\n");
	UCSR0B |= 1UL << UDRIE0;
}

ISR (USART_RX_vect) // interrupt recieve
{
	char input = UDR0;

	strcpy(dataString,"KEYBOARD\r\n");
	UCSR0B |= 1UL << UDRIE0;
	
	SPI_TrasmitMaster(input);
}

ISR (USART_UDRE_vect) // interrupt transmit
{
	if(dataString[indice]!='\0')
	{
		UDR0 = dataString[indice];
		indice++;
	}
	else
	{
		UCSR0B &= ~(1UL << UDRIE0);	//disable 
		UCSR0B |= (1UL << RXCIE0);	//enable
		indice = 0;
	}
}

 

Last Edited: Sat. Apr 21, 2018 - 12:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could always simply create 2 "spi" connections between A & B.  

From A to B set up a MOSI pin, SCK....IRQ detection of the sck pulses reads MOSI values into B (nice and fast)

From B to A set up a MOSI pin, SCK....IRQ detection of the sck pulses reads MOSI values into A (nice and fast)

4 wires total , (you have plenty of room).  A very simple simple routine generates the MOSI values & SCK pulses

Now either can send to the other whenever desired, even at the same time.

When in the dark remember-the future looks brighter than ever.

Last Edited: Sat. Apr 21, 2018 - 03:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

You could always simply create 2 "spi" connections between A & B.  

From A to B set up a MOSI pin, SCK....IRQ detection of the sck pulses reads MOSI values into B (nice and fast)

From B to A set up a MOSI pin, SCK....IRQ detection of the sck pulses reads MOSI values into A (nice and fast)

4 wires total , (you have plenty of room).  A very simple simple routine generates the MOSI values & SCK pulses

Now either can send to the other whenever desired, even at the same time.

 

But i have only one SPI on Atmel328p , if i set MOSI as output in A to B , then i can't set MOSI as input in B to A, it's right?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But i have only one SPI on Atmel328p , if i set MOSI as output in A to B , then i can't set MOSI as input in B to A, it's right?

who cares?

 

Set two lines (your choice) as outputs:

Take the data byte you want to send & match the so-called "MOSI" pin high or low to your data's MSB

Generate a high/low pulse on your sck pin (maybe 10us wide)

shift your data left (mult by 2)

Repeat in a loop 8 times...now your data has been sent out!!  [Could actually send 9, 13, 16 bits or whatever you predefine]

 

Irq:

If SCK pin irq occurs, read data pin.

Shift rcv data value left (mult by 2) and add 0 or 1 as incoming data pin reads

When this has occurred 8 times (keep a count), the data byte is completely received & ready to use.

Move data to a buffer, or process the data (command?) as desired.

If an irq has not occurred for 1ms, reset the count to zero (to set initial sync or resync) 

 

Both A & B have the same set of identical routines.  Now you can immediately send data from A to B & B to A

Doesn't get too much simpler! 

 

 

 

 

When in the dark remember-the future looks brighter than ever.

Last Edited: Sat. Apr 21, 2018 - 05:12 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The task OP is talking about is the way almost all SPI devices actually work (but with only one master). Consider this example that I use in a commercial product:

 

1) Mega328P is SPI master

 

2) Accelerometer is SPI slave

 

3) There is an "interrupt" or "alert" connection between the two.

 

4) Master writes configuration data to the slave. Among other things, it defines the slave pin that is used for the alert function and defines when it is active.

 

5) Master waits for an alert signal from the slave

 

6) When the slave has data available, it signals with an alert.

 

7) The master then reads the data from the slave

 

8) Go back to (5)

 

That is all that it takes. No multimaster madness. It is the way SPI is designed to work. There is no reason why one Arduino cannot be the permanent master and the other be the permanent slave.

 

The connections would include MOSI,  MISO, SCK, SS, Alert. No more wires than shown in the original diagram.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Sat. Apr 21, 2018 - 05:33 PM