SparkFun Forums 

Where electronics enthusiasts find answers.

Discussions on the software and hardware for Atmel's STK standard.
By firstoption
#175500
Good day to all,


Please I need help on how to write the Clock Code for my Slave device. I understand that only the Master device can generate the clock signal while slave device will listen to the incoming signal however I do not know how to implement this concept in the slave program such that the slave can equally send data to the master. I would be very glad if somebody can help me out. Below are my lines of code for both the Master device and the Slave device.





MASTER DEVICE ATTINY4313

Code: Select all
#include <avr/io.h>
#include <util/delay.h>


/* SPI port and pin definitions.*/
 
#define _BV(bit)            (1 << (bit)) 
#define  OUT_REG         PORTB //!<  port output register.
#define  IN_REG             PINB //!<  port input register.
#define  DIR_REG         DDRB //!<  port direction register.
#define  CLOCK_PIN         PINB2 //!<  clock I/O pin.
#define  DATAIN_PIN         PINB1 //!<  data input pin.
#define  DATAOUT_PIN     PINB0 //!<  data output pin.

unsigned char   Transmitt_Receive_Master(unsigned char  data);

void SetClock()
{
 PORTB |= (1 << PINB2);   
}

void ClearClock()
{
 PORTB &= ~(1 << PINB2);  
}

void SetData()
{
 PORTB |= (1 << PINB0);   
}

void ClearData()
{
 PORTB &= ~(1 << PINB0);  
}

void Spi_Master_Init()
{
 // set up SCK/MOSI as output Pins
 
 DIR_REG |= (1<<DATAOUT_PIN) | (1<<CLOCK_PIN);

 DIR_REG &= ~(1<<DATAIN_PIN);  // Data-In (MISO) AS input

}

int main(void)
{
   Spi_Master_Init();
   
    while(1)
    {
        Transmitt_Receive_Master(20);
    }
}

unsigned char   Transmitt_Receive_Master(unsigned char  data)
{
 unsigned char i;
 unsigned char ReceivedValue=0;
 
 
 for (i=0;i<8;i++)

 {
  
  if (data & _BV(i))
  {
   SetData();
   
  }
  else
  {
   ClearData();
  }
  
  data <<= 1;
  // set clock high
  _delay_ms(100);
  
  SetClock();
  
  ReceivedValue <<= 1; //shift left one bit
  
   if (IN_REG & DATAIN_PIN )
   {
    ReceivedValue |= _BV(i);
   }
   else
   {
     ReceivedValue &= ~_BV(i);    
   }
  
         ClearClock();
   
 }

 return   ReceivedValue;
}



SLAVE DEVICE ATTINY 2313

Code: Select all

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


/* SPI port and pin definitions.*/

#define _BV(bit)            (1 << (bit))
#define  OUT_REG         PORTB //!<  port output register.
#define  IN_REG             PINB //!<  port input register.
#define  DIR_REG         DDRB //!<  port direction register.
#define  CLOCK_PIN         PINB2 //!<  clock I/O pin.
#define  DATAIN_PIN         PINB0 //!<  data input pin.
#define  DATAOUT_PIN     PINB1 //!<  data output pin.

unsigned char  Spi_Slave_Init()

{
 
 DIR_REG |= (1<<DATAOUT_PIN); // Set up MISO as output Pins
    DIR_REG &= ~(1<<CLOCK_PIN);  // Clock-Pin  aS input
 DIR_REG &= ~(1<<DATAIN_PIN);  // Data-In (MOSI) AS input


}

void SetData()
{
 PORTB |= (1 << PINB0);
}

void ClearData()
{
 PORTB &= ~(1 << PINB0);
}


unsigned char   Transmitt_Receive_Slave(unsigned char  data)
{
 unsigned char i;
 unsigned char ReceivedValue=0;
 
 
 for (i=0;i<8;i++)

 {
  
  if (data & _BV(i))
  {
   SetData();
   
  }
  else
  {
   ClearData();
  }
  
  data <<= 1;
  // set clock high
  _delay_ms(100);
  
  ReceivedValue <<= 1; //shift left one bit
  
  if (IN_REG & DATAIN_PIN )
  {
   ReceivedValue |= _BV(i);
  }
  else
  {
   ReceivedValue &= ~_BV(i);
  }
  
 }

 return   ReceivedValue;
}

int main(void)
{
     DDRD =0xFF;
  Spi_Slave_Init();
  
    while(1)
    {
       PORTD = Transmitt_Receive_Slave(40); 
    }
}
Thank you all for the support.Best regards.
By stevech
#175579
Do a bit of googling on software SPI.
I see lots of implementations. One in the Arduino libraries - open source. And others.

Master asserts chip select (a GPIO output pin connected to the slave device's chip select). Assert usually means a 0 is output.
On most devices, the master then sends a command byte (rarely, two bytes), placing each data bit 1 or 0 on the GPIO data line, then toggling the clock GPIO with a square wave with a period of, say, 1 microsecond.
After the command is sent, and a brief delay (device specific), the master changes the GPIO data to an input with pullup. Then the master issues 8 clocks as above, and for each clock, reads the GPIO pin. The data will be asserted by the slave.

There are more details to this, but sounds like you're needing to use what's out there, not reinvent.
By monkeyxpress
#179898
In the slave everything has to happen on the clock edge from the master (either rising or falling depending on the polarity mode). So in your while loop you just want to block until you see a clock edge, then you go do your processing (read the MOSI pin and put your data onto the MISO pin). Once that is done you return to your blocking loop until you see the next clock edge, and repeat until all the bits have been processed:
Code: Select all
void WaitForRisingEdge(void) 
{
	// Wait for clock pin to go low
	while(IN_REG & (1 << CLOCK_PIN)) {
		continue;
	}

	// Wait for clock pin to go high
	while(!(IN_REG & (1 << CLOCK_PIN)) {
		continue;
	}	
}

uint8_t SendReceiveByte(uint8_t data) {
	
	uint8_t i = 0;

	while(i < 8) {
	
		WaitForRisingEdge();

		// Send bit to master (MSB first)
		if(data & 0x80) {
			OUT_REG |= (1 << DATAOUT_PIN);
		}
		else {
			OUT_REG &= ~(1 << DATAOUT_PIN);
		}

		// Shuffle data along
		data <<= 1;

		// Read bit from master (MSB first)
		if(IN_REG & (1 << DATAIN_PIN)) {
			data |= 0x01;
		}

		// Next bit
		i++;
	}
	
	return data;
}

void main() {

	// Setup ports...
	
	// Main loop
	while(1) {
		PORTD = SendReceiveByte(40);
	}
}