Weird SPI behavior w/ATMega32

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

I'm learning how to use SPI and seeing some behavior that I cannot explain. For now, all I'm trying to do is to configure the ATMega32 as a SPI master and trigger the serial transfer complete interrupt. In my configuration, I'm setting the SS (PB4) pin as an output. Excerpt from the datasheet: "If SS is configured as an output, the pin is a general output pin which does not affect the SPI system." My code contains a loop that toggles an LED once a second. But when I run the code below, it seems to get stuck on the while loop in the transmit function (confirmed via simulation in avr studio) and my LED doesn't blink:

int main() {

	DDRC |= (1<<PINC0)+(1<<PINC1);
	PORTC |= (1<<PINC0)+(1<<PINC1);
	DDRB |= (1<<PINB4);

	// enable global interrupts
	sei();
	SPI_MasterInit();
	while (1) {
                // Toggle an LED connected to PINC1
		PORTC ^= (1<<PINC1);
		SPI_MasterTransmit('a');
		_delay_ms(1000);
	}
}

void SPI_MasterTransmit(char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
}

In my attempts to figure out why this happens, I noticed that in simulation by the time I get to SPI_MasterTransmit, the MSTR bit gets cleared. The datasheet say this can happen if the SS pin gets pulled low when configured as an input, but that's not the case here. Nonetheless, I tried setting SS and if I add PORTB |= (1<<PINB4) after DDRB |= (1<<PINB4) in the code above, my LED starts blinking. I thought the SS pin shouldn't matter when it's an output? Help greatly appreciated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 PORTC ^= (1<<PINC1); 

You need to use PB1 not PINC1 for output. Doesn't really matter in this case as they both have the same value, just confusing.

Don't trust the simulator.

You are enabling interrupts, do you have an ISR? What's happening in SPI_MasterInit();?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

I do have an ISR, here's the rest of my code:

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

// SPI serial transfer complete interrupt
ISR(SPI_STC_vect)
{
	// toggle an LED
	PORTC ^= (1<<PINC0);
}

The thing is, the behavior between the simulator and the hw is similar - the code that causes the simulator to get stuck also results in the LED's not blinking when I program my ATMega32 on the STK500.

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

It would not have killed you to post the whole code to start with. :)

Try putting sei after master init, see if it makes any difference.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

John, thanks for your input. The problem was in my code - in my SPI_MasterInit, I was inadvertently making the SS pin an input by using DDRB =, instead of DDRB |=. After making this change, everything works.

Quote:
You need to use PB1 not PINC1 for output. Doesn't really matter in this case as they both have the same value, just confusing.

Why should I use PB1 if my output port is PORTC and I'm toggling PINC1?

Quote:
It would not have killed you to post the whole code to start with.

I know, I just feel bad making people read through my code. In this case, it was worth doing.

Also, I found this app note really helpful:
http://www.google.com/url?sa=t&source=web&ct=res&cd=3&ved=0CBMQFjAC&url=http%3A%2F%2Fwww.atmel.com%2Fdyn%2Fresources%2Fprod_documents%2Fdoc2585.pdf&ei=r_ppS7P7BMOYlAeepoijCA&usg=AFQjCNG4MfGQD8LDotttZbHI158T73ILYQ&sig2=mnc0KcMs21FZke1lpg62tA

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

Sorry I should have said PC1.

Quote:
Why should I use PB1
To avoid confusion and possible errros in the future. The pins are defined as a bit number so in THIS case it makes no difference.

However if you look in the definition headers for the M32 you find:

#define PINC    _SFR_IO8(0x13)  //Can you see the confusing bit?

/* PORTC */
#define PC1     1  //Usually used for output

/* DDRC */
#define DDC1    1  //Usually used for data direction setting

/* PINC */
#define PINC1   1  //Usually used for input

As you can see they are all defined as 1 so it doesn't really matter but it is nice to stick to convention. You could just use 1<<1 but it makes it clearer to use conventional bit numbers. Just my 2c. :)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Gotcha, thanks for the tip!