SPI anomaly :(

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

Hi everyone,
i want to ask questions about SPI communication using ATMega8 and ATMega16. Here's a brief info about my system.
I'm connecting two AVRs using SPI communication. The master side is Mega8 and the slave side is Mega16. I programmed the master side to send 2 datas (1 byte each) to the slave countinuously. On the slave side, i programmed to send the received SPI data using USART (the usart was connected to my computer's serial port).
I started a terminal to look at the serial, the result was so surprising. It's just receiving the second byte. That means the slave just receive the second byte.
That's kinda odd for me... where does the first byte goes?
here's the code on the master side:

#include 
#include 
#include 
#include 

void SPI_MasterInit(void)
{
	/* Set MOSI and SCK output, all others input */
	DDRB = (1<<DDB0)|(1<<DDB1)|(1<<DDB2)|(1<<DDB3)|(1<<DDB5)|(1<<DDB6)|(1<<DDB7);
	/* Enable SPI, Master, set clock rate fck/16 */
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}

void SPI_MasterTransmit(uint8_t SPIdata)
{
	/* Start transmission */
	SPDR = SPIdata;

	/* Wait for transmission complete */
	while(!(SPSR & (1<<SPIF)))
		;
}

void move(uint8_t speed, uint8_t dir)
{
	SPI_MasterTransmit(speed); //the first data
	timerPause(10); //wait a little while
	SPI_MasterTransmit(dir); //the second data
	timerPause(10); //wait a little while again
}
int main()
{
	DDRB = 0xFF;
	DDRC = 0xFF;
	DDRD = 0xFF;
	
	PORTB = 0xFF;
	PORTC = 0xFF;
	PORTD = 0xFF;

	SPI_MasterInit();
	timerInit();
	timerPause(2000);  //wait for 2 secs
	while(1)
	{
		move(4,0);
		timerPause(3000); //wait for 3 secs
	}
}

and the slave section code:

#include
#include
#include

void USART_Init(unsigned int ubrr)
{
	/* Set baud rate */
	UBRRH = (unsigned char)(ubrr>>8);
	UBRRL = (unsigned char)ubrr;
	/* Enable receiver and transmitter */
	UCSRB = (1<<RXEN)|(1<<TXEN);
	/* Set frame format: 8data, 2stop bit */
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

void USART_Transmit( unsigned char data)
{
	/* Wait for empty transmit buffer */
	while ( !( UCSRA & (1<<UDRE)) )
		;
	/* Put data into buffer, sends the data */
	UDR = data;
}

void SPI_SlaveInit(void)
{
	/* Set MISO output, all others input */
	DDRB = (1<<DDB0)|(1<<DDB1)|(1<<DDB2)|(1<<DDB3)|(1<<DDB6);
	/* Enable SPI */
	SPCR = (1<<SPIE)|(1<<SPE);
}

ISR(SPI_STC_vect)
{
	uint8_t bufferSPI;
	/* Wait for reception complete */

	while(!(SPSR & (1<<SPIF)))
		;
	/* Return data register */

	bufferSPI = SPDR;
	USART_Transmit(bufferSPI);
}

int main()
{
	DDRA = 0xFF;
	DDRB = 0xFF;
	DDRC = 0xFF;
	DDRD = 0xFF;
	PORTB = 0xFF;
	PORTD = 0xFF;
	USART_Init(51); //baudrate 9600bps @ 8Mhz
	SPI_SlaveInit();
	while(1)
	{
	}
}

The initialization part was copy-pasted from datasheet with a little editing for adjustment to fit my need.
See the code above, i tried to send 2 bytes using SPI consists of 4 and 0. But when i looked a the terminal, i only see zeros, when i change the code from move(4,0); to move(0xF,0xF0); i only see 0xF0's
got what i mean?
at present i tricked this by modifying move procedure using like this:

void move(uint8_t speed, uint8_t dir)
{
	SPI_MasterTransmit(0); //send dummy byte
	timerPause(10);
	SPI_MasterTransmit(speed); //send first data
	timerPause(10);
	SPI_MasterTransmit(0); //send dummy again
	timerPause(10);
	SPI_MasterTransmit(dir); //send second data
	timerPause(10);
}

Boom! then i see 4 0, 4 0, 4 0... that's exactly what i want. But, anybody can explain why i should add dummy byte like above?

I've looked at another posting about SPI in this forum but i'm still don't understand :(
Thanks for all of your help :)

KISS - Keep It Simple Stupid!

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

Did you ever calculate how many clock cycles it takes you to jump into the
ISR, and start executing code there?

Also, inside the ISR, you'll *never* have to wait for the interrupt flag,
because entering the ISR has just cleared the flag...

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Great!
you are right!
i changed the ISR to this:

ISR(SPI_STC_vect)
{
	uint8_t bufferSPI;
	/* Return data register */

	bufferSPI = SPDR;
	USART_Transmit(bufferSPI);
}

i've deleted the 'waiting' part and that just work correctly as i expect. Then i conclude that when using ISR i dont need to 'wait' the flag again.
Thanks.
You cool, man! too cool!
Thanks again :D

KISS - Keep It Simple Stupid!