SPI sending a byte from master to slave

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

Hi all , I have a program written in c (Code Vision) and in this program the content of 3 port from master is sent to slave (both atmega 32) and seen on LCD(2x16).

This works ok,but now I want to change the program to send a bit or a byte to slave and turn on an LED .Don;t know how to do that. will any body help please?

this is my current code for master part.

#include <mega32a.h>
#include <delay.h>
// SPI functions
#include <spi.h>
#include <stdio.h>

//Write a character to the spi buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
 {
 spi(c);
 }    
 #pragma used-
// Declare your global variables here
 int i;
void main(void)
{
// Declare your local variables here
char str[40];
/*...........*/
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P 
PORTA=0xFF;
DDRA=0x00;

// Port B initialization
// Func7=Out Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=In 
// State7=0 State6=P State5=0 State4=0 State3=P State2=P State1=P State0=P 
PORTB=0x40;
DDRB=0xBF;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P 
PORTC=0xFF;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P 
PORTD=0xFF;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;

// USART initialization
// USART disabled
UCSRB=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 500/000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x55;
SPSR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;
i=0;
    for(i=0;i<=3;i++) //Startup Led
    {
     PORTB.0=~PORTB.0;
      delay_ms(200);
    }

while (1)
      {
      // Place your code here
       delay_ms(100);
       if(PINA.1==0)
       {
        
       sprintf(str,"PORTA=%03u PORTC=%03u PORTD=%03u\r",PINA,PINC,PIND);
       puts(str);
       }
      }
}

 

This topic has a solution.
Last Edited: Thu. Jan 3, 2019 - 03:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you can already get whole bytes across the link isn't this just a question of protocol/interpretation? You could say that if 0x01 is sent the LED turns on and if 0x02 is sent it turns off. You could maybe use 0x03 followed by 0xnn to send the port value etc etc

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

Yes thats the problem. How to say that? I want to omit the lcd display and only write the code to do what you said.Sorry I am a bit not sure  in writing these code will you guide me pls.?

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

Are you familiar with the OSI 7 layer model? Most comms links can be characterized in this model. It basically says that you have increasingly complex "layers" in any link. At the liwest level you have things like the wiring and voltages, what constitutes a '0' and what is a '1' then above that is the shape of the pulse trains that convey "bytes" (or some other format of data values) then above that you start to add an interpretation to the bytes. You might decide to call 0x02 "start of text = STX" and will be the byte you send at the start of some byte sequence of significance. You might call 0x03 "end of text = ETX" and so on as a marker for the end of a byte sequence. So then you might decide to send "packets" that consist of STX, cmd_byte, data1_byte, data2_byte, ETX. The receiver now ignores anything until it sees STX, it then interprets the next byte as a command then, if needed, the next two bytes as data, then it expects ETX.
.
As you can this is defining the communications in increasing levels of complexity.
.
So it is with your situation. I'm not saying you have to implement the "protocol" I just defined, in fact there are as many different possible protocols as I've had hot dinners throughout a long life and all engineers have an idea for a protocol that will be "even better" than all that have gone before them ;-)
.
But you need to define one of your own (if you can't simply reuse one of many that alrwady exist) to transfer the knowledge from one end of your link to the other.
.
BTW when you get beyond a simple protocol such as I've just described then the protocols can start to be "layered" themselves. So you might have a base level data exchange protocol that for arguments sake let's call "Internet Protocol" which just gets a packet of bytes from one place to another. Then you might put a protocol on top if this called Transmission Control Protocol that adds the ability for the delivery of multiple packets to be sequenced, checked and resent if necessary. Then you might choose to implement yet another protocol called Hyper Text Transfer Protocol that uses TCP port 80 on top of the TCP which os on top pf the IP and suddenly you've invented the internet as we know it.
.
These are all examples of the OSI 7 layer model. I'm not saying your SPI needs to be this complex but I think it helps to think of the increasing complexity of any data you may want to transfer in this layered way and more generally to undetstand the OSI concept.

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

Thanks a lot . You opened my eye on a new era which din;t know before.I had to read some pages on the net to get some idea.

But my case is not that complex .my case is this: I have a port in master part ,say PORTA, and it is configured as input .I want when if any bit of this port is Grounded , one led on the slave port be lighted. Thats all.

So I wanted a few lines of code to give me this. Sorry for the the trouble.

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

If one micro just needs to be able to contiually read PORTA on the other then why don't you simply have one repeatedly transmit PINA over SPI then? What am I missing? When the second micro reads the inbound SPDR it's just as if it's directly reading the other PINA.

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

Sorry didn't get your point.I am too dumb to understand I am new to this spi and do't see what you say .I think I should send the Slave code for you see and please tell me what changes I should make.

#include <mega32a.h>
#include <delay.h>
// SPI functions
#include <spi.h>
#include <stdio.h>

//Alphanumeric LCD Module function 
#asm
     .equ __lcd_port=0x15 //Please make sure there is a gap between .equ and __
#endasm
#include <lcd.h>
bit senddata=0;
//standard input/output function
//spi intrrupt sevice routin
char buffer[32],wr_index=0;
interrupt [SPI_STC]void spi_isr(void)
 {
  unsigned char data;
  data=SPDR;      
  #asm("sei")
 if(data=='#')
   {
    buffer[0]=data;
    wr_index=1;
    }
    else if(wr_index>=1 &&data!='\r')
    {
     buffer[wr_index]=data;
     wr_index++;
     }
     else if(data=='\r')  //if Enter is pressed 
     {
      senddata=1;
      }
      else
      wr_index=0;
  }
 int i;unsigned char data;
void main(void)
{
// Declare your local variables here
char str[32];
/*...........*/
#asm("sei")

PORTA=0x00;
DDRA=0x00;

PORTB=0x40;
DDRB=01001111;

PORTC=0xFF;
DDRC=0xff;

PORTD=0xFF;
DDRD=0xff;

TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;

UCSRB=0x00;

ACSR=0x80;
SFIOR=0x00;

ADCSRA=0x00;

// SPI initialization
// SPI Type: Slave
// SPI Clock Rate: 500/000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0xC5;
SPSR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;
#asm
    in    r30,spsr
    in    r30,spdr
#endasm
#asm("sei")    
i=0;
    for(i=0;i<=3;i++) //Startup Led
    {
     PORTB.0=~PORTB.0;
      delay_ms(200);
    }

while (1)
      {
      // Place your code here
       if(senddata)
       {
         
        lcd_clear();
        lcd_gotoxy(0,0);
        sprintf(str,"%s",buffer);
        lcd_puts(str);
        senddata=0;
        }
        }
       
      
}

 

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

Heres a real simple 'protocol'.  YOu are already sending three bytes over already right?  Send a fourth byte for 'LED Control'.  then in your Receive routine you load the bytes into your buffer and pick and choose as you see fit.  If you are doing SPI with the /CS or /SS line then you are sending synchronously so no need to do anything fancy.

 

YOur receive code can act on the three port bytes and display on the LCD, and the fourth byte can drive your LED(s).

 

Simple.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Thank you . You took me one step forward.

Now on the Slave side the separation of the bytes received is a bit confusing ,would you please put some light to that part ? How do I get the content of each port from str. or buffer? 

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

Post your receive code. Much simpler to work with what you have rather than guess.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Hi Sir,

The receive code is already there(post no. 7), the first codes are for Master , and the second one is for Slave.Sorry for taking your time.

 

Last Edited: Wed. Jan 2, 2019 - 09:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

azizollah wrote:
This works ok,but now I want to change the program to send a bit or a byte to slave and turn on an LED .Don;t know how to do that.

 

In master code try

 

 

while (1)
      {
       if(PINA.1==0)
       {
        delay_ms(50);
        spi(1);       // send byte 1 - Led on
       }
       else
        spi(0);       // send byte 0 - Led off

       }
      }

In slave

 

interrupt [SPI_STC]void spi_isr(void)
{
  unsigned char data;

  data = SPDR;      

  if(data == 1)
     PORTC.0 = 1;   // switch Led on PORTC.0 ON

  else
     PORTC.0 = 0;   // Led OFF   (Led from port to GND)
}

Led shines while you hold the button down.

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

azizollah wrote:

Hi Sir,

The receive code is already there(post no. 7), the first codes are for Master , and the second one is for Slave.Sorry for taking your time.

 

 

Sorry about that.  Thats what I get for not reading things properly.

 

Why are you using sprintf? I am guessing its to make human readable data for your LCD.

 

I see in your receive routine you already have a 32 byte buffer.  Pretty large, but ok.  Again, you simply add one more read to your TX routine and add one more bit of processing in your RX routine and you should be good to go.  One thing I don't see is control of the /SS line.  HOw do you achieve data synchronisation?

 

Jim

 

EDIT:  I see you are using \r as a delimiter as opposed to the /SS line so that answers one question

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Thu. Jan 3, 2019 - 12:33 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so I went and made very crude SPI send and SPI receive applications for you to try out.  Now in your TX code you are doing some conversions into things you can read on your LCD in your RX code.

I did not bother with any of that for this example.  Its raw port reads, that are sent over the SPI to the other AVR that takes the SPI data and loads a buffer.  When the buffer has 4 bytes the main code writes those four bytes to the corresponding ports.

I do not have any Mega32's but I have Mega324's which are pretty close so you should be able to change what you need to.

 

In your case you could extrapolate the bytes from the buffer and convert them to something to display on the LCD.

 

I did this in Studio 7, but I use CV to do the INIT stuff as I am too lazy to lookup what is what in the AVR ;)

 

 

For the Transmitter:

Pretty simple. 

 

Here I set up the include files, CPU clock speed and declarations:

#define F_CPU 8000000ul
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <avr/pgmspace.h>

volatile uint8_t txc_flag;	//SPI TX Complete Flag

#define TRUE 1
#define FALSE 0
#define spi_ss_pin 0x10		//portb.4
#define spi_port PORTB		//SPI PORT

 

Next I set up the AVR ports and SPI engine:

void avr_init(void)
{
	// Input/Output Ports initialization
	// Port A initialization
	// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
	DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
	// State: Bit7=P Bit6=P Bit5=P Bit4=P Bit3=P Bit2=P Bit1=P Bit0=P
	PORTA=(1<<PORTA7) | (1<<PORTA6) | (1<<PORTA5) | (1<<PORTA4) | (1<<PORTA3) | (1<<PORTA2) | (1<<PORTA1) | (1<<PORTA0);

	// Port B initialization
	// Function: Bit7=Out Bit6=In Bit5=Out Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In
	DDRB=(1<<DDB7) | (0<<DDB6) | (1<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
	// State: Bit7=0 Bit6=P Bit5=0 Bit4=0 Bit3=P Bit2=P Bit1=P Bit0=P
	PORTB=(0<<PORTB7) | (1<<PORTB6) | (0<<PORTB5) | (1<<PORTB4) | (1<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

	// Port C initialization
	// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
	DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
	// State: Bit7=P Bit6=P Bit5=P Bit4=P Bit3=P Bit2=P Bit1=P Bit0=P
	PORTC=(1<<PORTC7) | (1<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (1<<PORTC3) | (1<<PORTC2) | (1<<PORTC1) | (1<<PORTC0);

	// Port D initialization
	// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
	DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
	// State: Bit7=P Bit6=P Bit5=P Bit4=P Bit3=P Bit2=P Bit1=P Bit0=P
	PORTD=(1<<PORTD7) | (1<<PORTD6) | (1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3) | (1<<PORTD2) | (1<<PORTD1) | (1<<PORTD0);

	// SPI initialization
	// SPI Type: Master
	// SPI Clock Rate: 500.000 kHz
	// SPI Clock Phase: Cycle Start
	// SPI Clock Polarity: Low
	// SPI Data Order: MSB First
	SPCR0=(1<<SPIE0) | (1<<SPE0) | (0<<DORD0) | (1<<MSTR0) | (0<<CPOL0) | (0<<CPHA0) | (0<<SPR10) | (1<<SPR00);
	SPSR0=(0<<SPI2X0);

}

 

Then the interrupt Handler.  This can be placed above the avr_init function like CV does it.  I simply am setting the TX Complete flag to TRUE to indicate that the byte has fully left the AVR. 

//Interrupt from SPI
ISR(SPI_STC_vect)
{
	txc_flag = TRUE;	//SPI transmission complete flag set

}

 

Here is the SPI transmit function.  I first set the /SS pin low( I actually do this EVERY time the function launches even though there are better ways to manage the /SS pin, but for now its OK), then I send the data byte to SPDR register and clear the TXC_FLAG.  I then sit in a while loop until the flag clears when the interrupt fires, at which time I return to the MAIN program.

void spi_send(uint8_t data)
{
	spi_port = (spi_port & ~(spi_ss_pin));		//send /SS low
	SPDR0 = data;	//load SPI Data register with DATA
	txc_flag = FALSE;	//clear txc flag

		while(txc_flag == FALSE)
		{
			//do nothing until the txc_flag sets.  When it does go back
			//to MAIN
		}

}

 

Speaking of MAIN. 

In MAIN I call the initialisation function, and then set the global interrupt flag.  I also have a local variable called DATA.  In my WHILE(1) loop I read a PORT into DATA and then send DATA to the SPI_SEND function.  When SPI_SEND finishes, and returns I read the next port etc., etc., until after the last byte is sent.  I then set the /SS pin TRUE, and wait 500 milliseconds then repeat the whole process over.

int main(void)
{
	avr_init();
	sei();
	uint8_t data;	//simple variable to use

		/* Replace with your application code */
		while (1)
		{
			data = PINA;	//read PINA
			spi_send(data);

			data = PINB;	//read PINB
			spi_send(data);

			data = PINC;	//read PINC
			spi_send(data);

			data = PIND;	//read PIND
			spi_send(data);

			spi_port = spi_port | spi_ss_pin;		//set spi /SS pin high

			_delay_ms(500);	//wait 500 milliseconds and then repeat

		}
}

 

Thats it.  Nothing fancy.

 

 

 

 

For the receiver things are a little different.  The beginning of the programs includes are the same, but the declarations are a little different.  YOu will see a counter, and a 4 byte buffer.

#define F_CPU 8000000ul
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
#include <avr/pgmspace.h>

volatile uint8_t count;		//simple counter
volatile uint8_t rxc_flag;	//receive complete flag
volatile uint8_t buffer[4];	//simple receive buffer

#define TRUE 1
#define FALSE 0
#define spi_ss_pin 0x10		//portb.4

 

The AVR_INIT function is just like the TX side, but now all the pins are OUTPUTS, and teh SPI is set up as a slave.

void avr_init(void)
{
	// Input/Output Ports initialization
	// Port A initialization
	// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (1<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
	PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

	// Port B initialization
	// Function: Bit7=In Bit6=Out Bit5=In Bit4=In Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRB=(0<<DDB7) | (1<<DDB6) | (0<<DDB5) | (0<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
	// State: Bit7=P Bit6=1 Bit5=P Bit4=P Bit3=0 Bit2=0 Bit1=0 Bit0=0
	PORTB=(1<<PORTB7) | (1<<PORTB6) | (1<<PORTB5) | (1<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

	// Port C initialization
	// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRC=(1<<DDC7) | (1<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0);
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
	PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

	// Port D initialization
	// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRD=(1<<DDD7) | (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2) | (1<<DDD1) | (1<<DDD0);
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
	PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

	// SPI initialization
	// SPI Type: Slave
	// SPI Clock Rate: 500.000 kHz
	// SPI Clock Phase: Cycle Start
	// SPI Clock Polarity: Low
	// SPI Data Order: MSB First
	SPCR0=(1<<SPIE0) | (1<<SPE0) | (0<<DORD0) | (0<<MSTR0) | (0<<CPOL0) | (0<<CPHA0) | (0<<SPR10) | (1<<SPR00);
	SPSR0=(0<<SPI2X0);
}

 

Heres the Interrupt Service Routine.  I am doing most, if not all of the heavy lifting here which many may scorn me for doing, but for this simple application its not an issue.

Basically every time a byte comes into the AVR the interrupt fires.  the data in the SPDR is transferred to the first byte in the buffer and the counter that provides the location to write to in the buffer is incremented by one after each write.  Next I read the value of PORTB and mask off all the bits EXCEPT for the /SS pin and store it in the local variable SS_PIN_TEST.  I now check for two possible conditions.  Condition #1 is if the COUNT has exceeded 3 OR if the /SS pin has gone high.  If either case is TRUE then I execute the first line inside the braces which is to clear the counter.  I then check to see if the /SS pin is in fact LOW because if it is, then it means that all four bytes were received properly and I set the RXC_FLAG high to indicate that the buffer is full.

 

OK, I am guessing you are wondering why I check the /SS pin for both a high and a low.  Reason is that lets say that the Receiving, or Transmitting AVR for some reason resets, or power cycles in the middle of a stream of data coming in.  If I do not see what the state of the /SS pin is, then the buffer will be loaded with incorrect data that will be outputted to the PORTS(in your case LCD and PORT).  If the /SS pin is high, then I want to reset the counter and not set the RXC_FLAG to keep the erroneous data from being processed in MAIN.  If the COUNT goes higher than 3 and the /SS pin  is still LOW then the Transmitter is done sending new data.  I realised that the reason this works is because of the slight delay I have in my transmitter application.  For this simple demo this will work, but in a proper application, a simple state machine that monitors the /SS line on the receiver is a far better solution.

 

Either way here is the ISR:

/Interrupt from SPI
ISR(SPI_STC_vect)
{
	uint8_t ss_pin_test = 0;	//used when checking the SS pin

	buffer[count] = SPDR0;		//load a byte into the buffer
	count++;					//increment the counter

	ss_pin_test = (PINB & spi_ss_pin);	//store the state of the SS pin, clear the other bits

		if((count > 3) | (ss_pin_test != 0))
		{
			count = 0;		//clear the counter as all 4 bytes are in, or the SS pin went high

				if(ss_pin_test == 0)
				{
					rxc_flag = 1;		//set the flag as all four bytes are in the buffer
				}
		}
}

 

 

Lastly the MAIN loop.  It starts off like the TX MAIN, but in the WHILE(1) loop I am waiting for the RXC_FLAG to set and then I write the buffer contents to teh respective ports, and then clear teh RXC_FLAG.

int main(void)
{
	avr_init();
	sei();

	//clear counter and flag
	count = 0;
	rxc_flag = 0;	

    while (1)
    {
		//wait until you have a full buffer
		if(rxc_flag == 1)
		{
			PORTA = buffer[0];	//write to port a
			PORTB = buffer[1];	//write to port b
			PORTC = buffer[2];	//write to port c
			PORTD = buffer[3];	//write to port d

			rxc_flag = 0;	//clear the flag
		}
    }
}

 

 

Like I said, its pretty crude, and in spite of the /SS pin management in the RX APP it does work and illustrate what I was referring to.  I will work on a better sensing of the /SS pin in the RX app to reduce data corruption

 

Cheers,

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Thu. Jan 3, 2019 - 04:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Jim,& Dear Visovian,

You have been very kind to me  and I realy appreciate all your efforts,spending this lots of time on my question.You are realy kind  and lovely people.

My problem was solved and took all your advise and test it it worked ok and I got my answer.

Thank you all again.

Last Edited: Thu. Jan 3, 2019 - 09:03 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Visovian

Thank you my dear friend.

I must Thank you separately.

Your help was realy good and worked ok.

So Simple So Good.

Thanks again.

Last Edited: Thu. Jan 3, 2019 - 09:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please mark the solution. Good to read that things are now working.

Jim

Edit: I misread your intent. I thought you simply wanted to add the ability to light an led, not just create a simple application to turn an led on or off. Sorry about that

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Thu. Jan 3, 2019 - 11:43 AM