Problem with Atmega32 interfacing Multiple Slave SPI

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

I'm trying to implement an SPI protocol with multiple slaves. I'm currently working with only two slaves and a master. Each slave has their own button which the user can press. What I want to do is this: When the user presses a button, the respective slave will send an acknowledgement to the master and master will blink an LED indicating it has receives acknowledgement from that particular slave. 

 

Here's my code so far:

 

Code for master:

#define F_CPU 1e6

#include <avr/io.h>
#include <util/delay.h>

#define ACK_Slave1 0x7D
#define ACK_Slave2 0x7E

#define MOSI_PIN DDB5
#define SCK_PIN DDB7
#define SLAVE_SELECT1 DDB4
#define SLAVE_SELECT2 DDB3 

/**
*	set SPI enable (SPE), set MC as master (MSTR)
*	set serial clock freqeuncy (prescalar) = f_osc / 16 ; (SPR1 and SPI2X being 0 , f_osc --> internal clock/crystal frequency)
*   MOSI, SCK & Slave Select as output
*   We have to set SS as output for master
*/

void SPI_Master_Init(void){
	DDRB |= (1 << MOSI_PIN) | (1 << SCK_PIN) | (1 << SLAVE_SELECT1) | (1 << SLAVE_SELECT2);
	PORTB &= ~(1 << SLAVE_SELECT1);
	PORTB &= ~(1 << SLAVE_SELECT2);
	SPCR = (1 << SPE)  | (1 << MSTR) | (1 << SPR0);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Master_Init();

	DDRD  |= (1 << DDD0) | (1 << DDD1);
	PORTD &= 0x00; // clear output

	unsigned char data;

	while (1) {
		data = 0x00;
		data = SPI_Transceiver('1');
		if(data == ACK_Slave1){
			PORTD |= (1 << DDD0);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD0);
			_delay_ms(1000);
		}
		if(data == ACK_Slave2){
			PORTD |= (1 << DDD1);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD1);
			_delay_ms(1000);
		}
	}
	_delay_ms(500);
}

 

Code for slaves:

 

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>

#define ACK_Slave1 0x7D
#define ACK_Slave2 0x7E

#define MISO_PIN DDB6
#define SLAVE_SELECT DDB4

/**
*	MISO as output
*	enable SPI enable
*
*/

void SPI_Slave_init(void){
	DDRB |= (1 << MISO_PIN);
	SPCR = (1 << SPE);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Slave_init();

	DDRA &= ~(1 << DDA0);
	PINA &= 0x00;

	unsigned char data;

    while (1) {
                data = 0x00;
		if(PINA & (1 << DDA0)){
			data = SPI_Transceiver(ACK_Slave1); // will be changed to ACK_Slave2 for another slave
		}
    }
}

 

The problem is the LED connected at PD0 doesn't blink at all and when I press the button , the LED at PD1 blinks an extra time i.e , if I press it one time, it blinks twice. I've attached a pin diagram of my configuration. Please point out any error in the code or in the diagram. Any help would be appreciated. 

Attachment(s): 

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

<EDIT> - Missed your master code - following is not correct for the code above </EDIT>

 

You need a separate chip select for each slave. I only see one, which you appear to call SLAVE_SELECT. You need two, one for each. 

 

There may be other problems - that is just the first thing I see.

 

Jim

 

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

Last Edited: Mon. Jun 4, 2018 - 11:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

    Ok, I think you do not really understand how SPI works. First, you can't talk to two slaves in the same time. Your code correctly defines pins for the master to select slave 1 and 2, but in the schematic you tie together these two lines.

 

    You need to continuously talk to slave1 and then to slave2 and again and again. When you talk to slave1, you select it and then write to the SPI data register. When done, deselect slave1 , see if the button was pressed and select slave2 with its own nSS line and write data to the SPI register. When done, deselect it and see if the button has been pressed. Repeat again and again.

 

    Edit: Continuation. For the slave, it does not know when the master will talk to it. Use interrupts. When the master talks to the slave, the byte that is in the data buffer will go out down the wire. When is actually out, you get an interrupt. When you service it, read the button pin and place this data on the SPI buffer for the next time. When ? Whenever the master will talk again. This data needs to be there before the master will talk.

Last Edited: Mon. Jun 4, 2018 - 11:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

A common way for a slave to be read at a particular time is to use an "alert" line from each slave to a separate master pin. Make them interrupts, if that helps. Then the process works this way:

 

1. A slave alerts

 

2. The master asserts (pulls low) the select for that slave

 

3. Master sends a message to the slave. 

 

4. The master keeps clocking while the slave returns its message.

 

5. Master de-asserts the select line.

 

6. Master waits for next slave request.

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

If I press the two buttons within a short time span (<1s) will the master be able to tell which one was pressed first? Is there a time threshold for consecutive communication? How can I implement this? The situation is sort of like quiz buzzer system.

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

I understand Master initializes the communication. Does that mean sending something first from the master to the slaves ? And then the slaves can send their data to the master ? 

 

In my communication, the master doesn't have to do anything except blink a LED responding to the slave's data. Now any of the button can be pressed at any time. All I simply got to do is that when a slave presses it's button , master will blink it's LED. Now that means master will ignore the other slave. So it has to pull high the other slave's SS' line. Now how can the master know which slave pressed it's button ? If the master somehow knew, then it could take action (Making the slave select line of that slave low and other's high ). But how can it be known at runtime ? 

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

Referring to the previous reply, I'm not making the SS' lines distinct. Because I don't know how to get indication from the master side that particular slave pressed it's button. If I make the SS' all short and low, thereby allowing all the slaves to communicate at any time, this also causes a problem of overlapping data. In this case, one the LED blink n + 1 times ( if pressed n times ) and other doesn't blink at all. How can I efficiently solve this problem ? 

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

The master has to "poll" the slaves in turn. So it asserts the slave select of the first unit (and makes sure all others are deselected) then it sends a byte to trigger the slave to send his status back. Having done that it can deselect that slave and move on to the next.

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

Is there a time threshold of this poll checking ? I mean, if I press one slave button, and then immediately press another one ( < 1s ) , will the master be able to distinguish between the two ? Or do I have to wait some time period to poll the next button press ? 

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

Each slave will "latch" the button press (I assume) so the "delay" is simply how long it takes you to get round all slaves and read their states. As it presumably only involves the transfer of one byte per slave (and the time to enable/disable select lines) then unless you run SPI at a stupidly low speed it should be possible to check them all within microseconds, in other words check all the buttons 100,000's or even 1,000,000's of times per second. (well OK, perhaps not millions - but so fast/so many times that you won't miss the slow human response times!)

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

clawson wrote:

Each slave will "latch" the button press (I assume) so the "delay" is simply how long it takes you to get round all slaves and read their states. As it presumably only involves the transfer of one byte per slave (and the time to enable/disable select lines) then unless you run SPI at a stupidly low speed it should be possible to check them all within microseconds, in other words check all the buttons 100,000's or even 1,000,000's of times per second. (well OK, perhaps not millions - but so fast/so many times that you won't miss the slow human response times!)

 

I have used the continuous polling approach but that is not working also.My code so far:

 

Master Code:

 

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>
#define ACK_Slave1 0x01
#define ACK_Slave2 0x02
#define ACK_Master 0x03

#define MOSI_PIN DDB5
#define SCK_PIN DDB7
#define SLAVE_SELECT1 DDB4
#define SLAVE_SELECT2 DDB3
#define RESET 0xFF

/**
*	set SPI enable (SPE), set MC as master (MSTR)
*	set serial clock freqeuncy (prescalar) = f_osc / 16 ; (SPR1 and SPI2X being 0 , f_osc --> internal clock/crystal frequency)
*   MOSI, SCK & Slave Select as output
*   We have to set SS as output for master
*/

void SPI_Master_Init(void){
	DDRB |= (1 << MOSI_PIN) | (1 << SCK_PIN) | (1 << SLAVE_SELECT1) | (1 << SLAVE_SELECT2);
	PORTB |= (1 << SLAVE_SELECT1) | (1 << SLAVE_SELECT2);
	SPCR = (1 << SPE)  | (1 << MSTR) | (1 << SPR0);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Master_Init();

	DDRD  |= (1 << DDD0) | (1 << DDD1);
	PORTD &= 0x00; // clear output

	unsigned char data;

	while (1) {
		data = 0x00;
		PORTB &= ~(1 << SLAVE_SELECT1);
		data = SPI_Transceiver(ACK_Master);
		if(data == ACK_Slave1){
			PORTD |= (1 << DDD0);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD0);
			_delay_ms(1000);
			continue;
		} else{
			PORTB |= (1 << SLAVE_SELECT1);
		}

		data = 0x00;

		PORTB &= ~(1 << SLAVE_SELECT2);
		data = SPI_Transceiver(ACK_Master);
		if(data == ACK_Slave2){
			PORTD |= (1 << DDD1);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD1);
			_delay_ms(1000);
			} else{
			PORTB |= (1 << SLAVE_SELECT2);
		}
	}
	//_delay_ms(500);
}

Slave code:

 

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>
#define ACK_Slave1 0x01
#define ACK_Slave2 0x02
#define ACK_Master 0x03
#define RESET 0xFF

#define MISO_PIN DDB6
#define SLAVE_SELECT DDB4

/**
*	MISO as output
*	enable SPI enable
*
*/

void SPI_Slave_init(void){
	DDRB |= (1 << MISO_PIN);
	SPCR = (1 << SPE);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Slave_init();

	DDRA &= ~(1 << DDA0);
	PINA &= 0x00;

	unsigned char data;
	while (1) {
		if(PINA & (1 << DDA0)){
			data = SPI_Transceiver(ACK_Slave1); // will be changed to ACK_Slave2 for another slave
		}
		/*else if(~(PINA & (1 << DDA0)))
		{
			data = SPI_Transceiver(none);
		}*/
	}
}

Here is my pin diagram:

Last Edited: Tue. Jun 12, 2018 - 09:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the other thread, I wrote:

Define, "not working".

 

  1. What, exactly, were you expecting to happen?
  2. What, exactly, is actually happening?
  3. What testing/debugging/investigation have you done to find the problem(s) ?

 

For a start, how have you proved that your Master and Slave code works properly in isolation?

 

Don't try to debug both at once!

 

Instrument you code to see what's happening.

 

 

General debugging tips: https://www.avrfreaks.net/commen...

 

and dbrion0606 wrote:
Does the configuration :

one master <-> one slave work as you want?

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

Robur_131 wrote:
 

data = SPI_Transceiver(ACK_Slave1); // will be changed to ACK_Slave2 for another slave

How will it be changed?

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

Robur_131 wrote:

data = SPI_Transceiver(none);

What is "none" ?

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

awneil wrote:

Robur_131 wrote:

data = SPI_Transceiver(none);

What is "none" ?

 

Basically if the button is not pressed, then the slave would send "none" to master. I forgot to define it. That's why I commented it out.

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

awneil wrote:

Robur_131 wrote:
 

data = SPI_Transceiver(ACK_Slave1); // will be changed to ACK_Slave2 for another slave

How will it be changed?

 

The code for both the slaves are same. When burning the code, the argument to SPI_Transceiver will be ACK_Slave1 for one slave and ACK_Slave2 for the other.

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

and how are you sure that you've got that right?!

 

it's a maintenance nightmare!

 

why not just have a pin which tells the slave whether it is Slave-0 or Slave-1 ?

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

why not just have a pin which tells the slave whether it is Slave-0 or Slave-1 ?

 

    To try to avoid maintenance nightmare, one might notice avrs do have lots of pins , which could be used on the slaves :

one pin should be connected to a jumper, giving slave adress (0 or 1) -your idea-

other pins might drive LEDs (+¨resistors) , indicating whether slave has been polled, whether slave acknoledged.... (each interesting state of a slave)

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

dbrion0606 wrote:
other pins might drive LEDs (+¨resistors) , indicating whether slave has been polled, whether slave acknoledged.... (each interesting state of a slave)

Indeed.

 

And useful diagnostic output could be sent to the UART.

 

This is the kind of stuff I was thinking of with:

I wrote:
Instrument you (sic) code to see what's happening

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

"And useful diagnostic output could be sent to the UART."

Which UART:

Master UART is used ... to blink LEDs (made mey eyes weep)

Remain **two ** slaves.When arriving into a PC (needs two UART-USB adapters), there is a risk one does not know which slave a traterm session refers to.

LEDs might be more easy to understand.... even if they do not keep track of what happened.

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

dbrion0606 wrote:
Master UART is used ... to blink LEDs (made mey eyes weep)

Yes - that's a very poor decision!

 

 (needs two UART-USB adapters)

Indeed,  but that's really no problem: it's easy to connect many single USB-to-UART adaptors to a PC, and USB-to-multiple-UART adaptors are readily available.

 

there is a risk one does not know which slave a traterm session refers to.

Hardly.

 

I often have 4 or more TeraTerms running at once - TeraTerm can put the COM port number in the window Title bar

 

An advantage of TeraTerm is that it can record timestamped logs - so you can use the timestamps to merge all the activities from the 3 "nodes".

 

 

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

"

Hardly.

 

I often have 4 or more TeraTerms running at once - TeraTerm can put the COM port number in the window Title bar"

I ageree you can.

I bet OP wonot (perhaps -s-he will be able once distracting bugs have disappeared : introducing new softs -even if they are useful on the long term-  while debugging can make things worse).

 

I agree LEDs cannot time stamp states/useful information. But maybe they are enough (and cheaper, easier to find than UART<->USB adapters)

 

Edited again :I looked at the schema (should have rembered it) ... and , as I saw NO Xal, using UART as a -not that- poor man debugging tool seems a very bad idea!

Last Edited: Tue. Jun 12, 2018 - 02:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just getting here...

1)Now, has OP told us how many "multiple slaves" is?  Cliff talks of how many polls per second and mentions millions.  I'd like to think about that for a second.  Even with e.g. an 8MHz bit rate that is one microsecond per byte transfer.  Add on chip select/deselect/wait for completion/take action and it is more.  And the entire AVR is dedicated to the task.

 

2)  Unfortunately OP has chosen the ancient model.  If "multiple" is more than "a few" then the external interrupt sources are much more limited than with a model with pin-change.

 

3)  OP is apparently planning to run the SPI bus to all the slaves, plus a separate chip-select line.  If the only thing each slave is doing is to monitor a single button and the app is to see which came first (didn't we just have a thread on this with wireless buzzers?) then why not just bring an "alert" line from each slave, and react in the master?

 

3a)  If as described, why is a remote Mega32 needed for each button?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

1) multiple == 2 -> makes polling rather fast.

 

2+3 ) if OP  has a OR circuit,  slaves can interrupt on one line their master ... and master has to poll to know which slave interrupted.

Maybe OP is just trying to test the polling part before putting interrupts (SLAVE1 alert line OR slave2 alert line -> master interrupt).

 

3a) As an exercise? Advantages of mega is ... they have lots of pins (can show, via LEDs, lots of states) smaller avrs do not. Maybe OP forgot this advantage...

Because they are the only avalaible in OP town/village?

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

Why not just daisy-chain the slaves into one continuous loop?

 

The master polls the slaves by sending out two bytes to clock both slaves in. Slave one set the upper 4 bits to 0001_xxxx, where xxxx is the response and slave 2 sets it's reply to 0010_xxxx. This scheme could be expanded to 15 slaves easily.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "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."

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

Brian Fairchild wrote:
Why not just daisy-chain the slaves

Indeed - something like this:

 

https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Daisy_chain_configuration

 

Still needs some means for the Slaves to know whether they are "Slave one" or "slave 2" ...

 

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

Excuse me, but I cannot see how slave1 ... slave x can manage not to send a message at the same time (4094/74hc595  have an overflow line, making daisy chaining easy to see).

Or slaves should be different  : slave1 responding "immediately", slave2 responding later (OPs slaves are the same)

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

It is a standard configuration for SPI.

 

The whole system just forms one big shift register - just like a JTAG chain.

 

The 2nd slave won't see the Master's request until it has been shifted through the first slave.

 

EDIT

 

Possibly it's a bit clearer in this image:

 

Image result for spi daisy chain animation

https://electronics.stackexchange.com/questions/359974/feedback-on-daisy-chained-spi-sensors

 

 

EDIT 2

 

link for above image.

 

Another view - maybe makes the "chain" easier to see:

 

Fig.2

https://www.mct.net/faq/spi.html

 

 

EDIT 3

 

A Maxim App Note on the subject:

APPLICATION NOTE 3947  

Daisy-Chaining SPI Devices

 https://www.maximintegrated.com/en/app-notes/index.mvp/id/3947

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...
Last Edited: Tue. Jun 12, 2018 - 03:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbrion0606 wrote:
slave x can manage not to send a message at the same time
So you send a 3 byte package each time - only change bits in bytes that need to change on this occasion. Maintain copies of everything else and after the complete 3 byte/24 bit transfer perhaps only one of the 3 devices really sees any change.

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

Your schematics makes me begin to understand

 

If master sends always the same byte,

 

each slave (through wiring, becomes the next slave's ..master) has to send

 

a) its own message (only once, through ~SS : else each slave would duplicate number of messages)

 

b) "master"s  messages (should distinguish master messages and other leading slaves messages from garbage)

a slave does not need to know  which number it is

purple slave will send its message, then blue slaves one, then greens one

 

-> I begin to understand : it might be difficult to troubleshout but it is brilliant.

 

Master has to know how many slaves there are (to stop listening) , but slaves do not have to know their color/number.... edited to have the chain working (master can deduce the slave number from the incoming bytes order, and its state from the content of the xth byte)

 

Edited : read maxims note :

a) and b) order are changed in the standard daisychain (first in, first out : I saw a last in, first out, thus master "knows" when each of the slaves has "answered" -get its own message- , if slaves have very simple answers to send, maybe this error is a minor one).

 

Last Edited: Tue. Jun 12, 2018 - 04:12 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have not yet made any progress with this. But I have managed to pinpoint the offending cause (I hope so).

 

Initially my setting included two buttons in the slave end. But one of the button press worked and the other didn't. And also, when I simulated the code in Proteus 8, it showed data overrun. What I think it means that, master was continually sending data to the slaves. But as I didn't press any button, buffer overflow happened. So, just to check if the master was able to handle two slaves simultaneously, I decided to get rid of the buttons and test without them anyway. It improved one thing. I managed to get rid of data overrun. But I expected both the slaves would work i.e, would send their corresponding acknowledgement to the master and master would in return turn on LEDs respective of them. But only one of the LED turned on and the other didn't. 

 

Following is my master code:

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>
#define ACK_Slave1 0x01
#define ACK_Slave2 0x02
#define ACK_Master 0x03

#define MOSI_PIN DDB5
#define SCK_PIN DDB7
#define SLAVE_SELECT1 DDB4
#define SLAVE_SELECT2 DDB3
#define RESET 0xFF

/**
*	set SPI enable (SPE), set MC as master (MSTR)
*	set serial clock freqeuncy (prescalar) = f_osc / 16 ; (SPR1 and SPI2X being 0 , f_osc --> internal clock/crystal frequency)
*   MOSI, SCK & Slave Select as output
*   We have to set SS as output for master
*/

void SPI_Master_Init(void){
	DDRB |= (1 << MOSI_PIN) | (1 << SCK_PIN) | (1 << SLAVE_SELECT1) | (1 << SLAVE_SELECT2);
	PORTB |= (1 << SLAVE_SELECT1) | (1 << SLAVE_SELECT2);
	SPCR = (1 << SPE)  | (1 << MSTR) | (1 << SPR0);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Master_Init();

	DDRD  |= (1 << DDD0) | (1 << DDD2);
	PORTD &= 0x00; // clear output

	unsigned char data;

	while (1) {
		/*

		data = 0x00;

		PORTB &= ~(1 << SLAVE_SELECT1);
		data = SPI_Transceiver(ACK_Master);

		if(data == ACK_Slave1){
			PORTD |= (1 << DDD0);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD0);
			_delay_ms(1000);
		} 

		PORTB |= (1 << SLAVE_SELECT1);
		_delay_ms(1000);

		*/

		data = 0x00;

		PORTB &= ~(1 << SLAVE_SELECT2);

		data = SPI_Transceiver(ACK_Master);
		if(data == ACK_Slave2){
			PORTD |= (1 << DDD2);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD2);
			_delay_ms(1000);
		}
		PORTB |= (1 << SLAVE_SELECT2);
		_delay_ms(1000);	

	}
}

The commented part in the while(1) loop works as expected. That is for slave 1. But the following part, which is for slave 2 doesn't work. The slave select line of slave 2 don't get pulled to low so it is unable to send data to master. But miraculously, if I comment the following line,

 

PORTB |= (1 << SLAVE_SELECT2);

That is I let slave select 2 always pull low, then it works. Otherwise it doesn't. My slave code is:

 

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>
#define ACK_Slave1 0x01
#define ACK_Slave2 0x02
#define ACK_Master 0x03
#define RESET 0xFF

#define MISO_PIN DDB6
#define SLAVE_SELECT DDB4

/**
*	MISO as output
*	enable SPI enable
*
*/

void SPI_Slave_init(void){
	DDRB |= (1 << MISO_PIN);
	SPCR = (1 << SPE);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Slave_init();

	//DDRA &= ~(1 << DDA0);
	//PINA &= 0x00;

	unsigned char data = 0x00;
	while (1) {
		//if(PINA & (1 << DDA0)){
			data=SPI_Transceiver(ACK_Slave1); // just change argument to "ACK_Slave2" for another slave, both are defined above
		//}
		/*else if(~(PINA & (1 << DDA0)))
		{
			data = SPI_Transceiver(none);
		}*/
	}
}

This is my pin diagram.

I don't know what I'm doing wrong. As I can't attach video files here, I've share two links, the first one is for my working slave 1 and the other one is for non working slave2. 

 

Working Slave 1: https://drive.google.com/file/d/...

Not working slave 2: https://drive.google.com/file/d/...

Commenting out the suspected line: https://drive.google.com/file/d/...

 

[Blue squares indicate reset or 0 and Red square indicate set or 1 in the proteus simulation]

 

Sorry for the long reply. But I have working on this for about three weeks now and I still don't know what's going wrong. I want both the slaves to correctly communicate with the master. And if I can implement it without the buttons, I would proceed to implement that with slave pushing buttons without facing data overrun. 

Last Edited: Tue. Jun 26, 2018 - 12:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

You’re using Proteus and it comes with a swag of virtual instruments like oscilloscopes and logic analysers, but you don’t seem to use them. I’d suggest you get intimate with these devices and use them to visualise what is actually happening. Once you can see it, then you’re more likely to understand the problem and solve it.

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

Kartman wrote:
You’re using Proteus and it comes with a swag of virtual instruments...

It also allows you to step your code & view internals

 

Quote:
 I’d suggest you get intimate with these devices and use them to visualise what is actually happening.

Absolutely!!

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

Can proteus simulate 2-3 avr-s- at the same time?

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

Robur_131 wrote:
it showed data overrun
Hold on a minute - SPI is SYNCHRONOUS - how can there be "data overrun" ? It goes exactly as fast as the master pulses SCK. Or is the suggestion here that the master is pulsing SCK so fast that the slave cannot detect the edges ??

 

BTW SPI is by nature a "short connection" so presumably these three mega32 are on the same board or at least very close? Why not use one big 128K or 256K chip with 100 pins and you would not have any of these comms issues that have occupied your last 3 weeks.

Last Edited: Tue. Jun 26, 2018 - 01:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Why not use one big 128K or 256K chip 

Actually, in the schematic shown, just the ATMega32 has more than enough pins to do the whole thing in one small chip!

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

Maybe OP wants to self learn... or cannot understand why simulated things with proteus do not work, once wired (which is very puzzling)...

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

Robur_131 wrote:
I have working on this for about three weeks now and I still don't know what's going wrong

See #12: you are making the classic mistake of doing far too much all at once - so that, when it doesn't work, you have no idea where to start looking.

 

It's not even clear that you have the basic switch debouncing working reliably.

 

I suggest that you start again, and take things one small step at a time.

 

For a start, review the decision to use 3 separate processors.

This makes the whole thing more than 3 times as complicated as just using a single processor.

 

Think carefully about the design before you go anywhere near a code editor.

 

Remember to include debug facilities in your design.

 

Be sure that you thoroughly understand how SPI works - do preliminary experiments with standard chips to gain understanding, if necessary.

 

https://www.avrfreaks.net/commen...

 

 

EDIT

 

See the diagram & animation in this post illustrating how SPI works: https://www.avrfreaks.net/commen...

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...
Last Edited: Wed. Jun 27, 2018 - 11:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried with only one atmega32 slave this time. I disconnected the other one from the master. So this is the current pin diagram:

 

 

U3 is my master. Previously, U1 and U2 were both connected to U3. Now I decided to proceed only with U2.

 

Now my slave code looks like this:

#define F_CPU 1e6

#include <avr/io.h>
#include <util/delay.h>

#define MISO_PIN DDB6

/**
*	MISO as output
*	enable SPI enable
*
*/

void SPI_Slave_init(void){
	DDRB |= (1 << MISO_PIN);
	SPCR = (1 << SPE) | (1 << SPR0);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Slave_init();

	unsigned char data;

	while (1) {
		data=SPI_Transceiver(0x02);
		_delay_ms(1000);
	}
}

I'm sending 0x02 to master.

 

My master code:

 

#define F_CPU 1e6
#include <avr/io.h>
#include <util/delay.h>

#define MOSI_PIN DDB5
#define SCK_PIN DDB7
#define SLAVE_SELECT2 DDB3 

/**
*	set SPI enable (SPE), set MC as master (MSTR)
*	set serial clock freqeuncy (prescalar) = f_osc / 16 ; (SPR1 and SPI2X being 0 , f_osc --> internal clock/crystal frequency)
*   MOSI, SCK & Slave Select as output
*   We have to set SS as output for master
*/

void SPI_Master_Init(void){
	DDRB |= (1 << MOSI_PIN) | (1 << SCK_PIN) | (1 << SLAVE_SELECT2);
	SPCR = (1 << SPE)  | (1 << MSTR) | (1 << SPR0);
}

/**
*	Load data in the buffer (SPI data register / shift register)
*	Wait until data transmission is complete
*   return received data
*/

unsigned char SPI_Transceiver(unsigned char data){
	SPDR = data;
	while(!(SPSR & (1 << SPIF)));
	return SPDR;
}

int main(void){

	SPI_Master_Init();

	DDRD = (1 << DDD2);
	PORTD &= 0x00; // clear output

	unsigned char data;

	while (1) {
		/*

		PORTB &= ~(1 << SLAVE_SELECT1); 

		data = SPI_Transceiver(0x03);

		PORTB |= (1 << SLAVE_SELECT1);

		if(data == 0x01){
			PORTD |= (1 << DDD0);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD0);
			_delay_ms(1000);
		}

		*/

		PORTB &= ~(1 << SLAVE_SELECT2);

		data = SPI_Transceiver(0x03);

		PORTB |= (1 << SLAVE_SELECT2);	

		if(data == 0x02){
			PORTD |= (1 << DDD2);
			_delay_ms(1000);
			PORTD &= ~(1 << DDD2);
			_delay_ms(1000);
		}

		_delay_ms(1000);
	}
}

 

The commented part was for U1 when it was connected to master. So, I'm sending a data from master (0x03) and waiting for slave acknowledgement. 

 

Okay, so I ran it in the Proteus and it worked fine. The LED at the master end blinked indicating that master and slave were communicating.

 

But when I checked the simulation log file, I noticed something strange:

 

 

Even after disconnecting U1, the master is receiving 0x01 (which could only be send by U1 as U2 sends 0x02 to master). I don't know where master is getting is garbage data. This continues throughout the simulation. And for this reason the D2 LED at PD2 blinks after a long pause, although I have given only 1s as delay. How can I debug this?

Last Edited: Wed. Jun 27, 2018 - 09:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Robur_131 wrote:
could only be send by U1 as U2 sends 0x02 to master

See #17

 

How can I debug this?

Did you not read #32 and #33 ?

 

Proteus is a 3rd-party product totally unrelated to Microchip (or Atmel) - this is not the place to ask questions about how to use Proteus.

 

To learn to use Proteus, you will have to study the Proteus documentation, use their training materials, ask on their forum, etc.

 

https://www.labcenter.com/simulation/

 

https://www.labcenter.com/tutorials/

 

https://www.labcenter.com/support/

 

https://support.labcenter.com/forums/index.php

 

EDIT 3: more proteus links: https://www.avrfreaks.net/commen...

 

EDIT 4: they even have a YouTube channel, if you prefer watching videos:  https://www.youtube.com/channel/UCFNnl5S532GMtwXJUYRo_wQ

 

 

EDIT 1

 

For general debugging tips, see #19

 

See also: https://www.avrfreaks.net/commen...

 

 

EDIT 2

 

And, going back to #38, taking the "small steps" includes learning & practising how to use your tools as you go!

 

See: https://www.avrfreaks.net/commen...

 

 

#ProteusSupport

#ProteusRtfm

 

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...
Last Edited: Mon. Nov 11, 2019 - 11:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
while (1) {
		data=SPI_Transceiver(0x02);
		_delay_ms(1000);
	}

why the delay? What happens if the master is sending data, but your slave is sitting in a delay loop?    

The slave will only send data when the master clocks it out - it's not like the uart where transmit and receive are separate. With spi the master runs the show.

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

Again:

In #37, I wrote:
Be sure that you thoroughly understand how SPI works

 

EDIT

 

See the diagram & animation in this post: https://www.avrfreaks.net/commen...

 

 

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...
Last Edited: Wed. Jun 27, 2018 - 11:00 AM