Using the USI for SPI in tiny2313

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

I've got a bunch of tiny2313 chips that I'd like to use in SPI mode. For testing, I'm using one as a master and one as a slave. I want the master to send the slave a byte and have the slave show the byte using the lights on the stk500. I don't need interrupts in the master since it decides when it wants to send and isn't receiving anything. The slave should have interrupts to detect when the byte is received from the master.

I'm having a little bit of trouble as the lights don't change.

I initialize the slave like this:

void initialize(void)
{
// Setting up ports
	
	DDRD = 0xff; //Port D is all outputs (leds)
	
	// Configure USI to 3-wire slave mode with overflow interrupt.
	USICR = (1<<USIOIE) | (1<<USIWM0) | (1<<USICS1) | (0<<USICS0);
	
	USISR |= (1 << USIOIF); //Enable interrupt when byte has been transferred
	
	DDRB |= (1 << PB6);  //DO is an output
	
	DDRB &= ~(1 << PB7) | (1 << PB5);  //USCK and DI are inputs
	PORTD |= (1 << PB7) | (1 << PB5);  //pullups on them inputs
	
	
	sei();  					//Activate all enabled interrupt
}

I then have a simple interrupt routine to read a byte from the spi buffer and put it on portd which is just the leds on the STK500:

ISR(USART_RX_vect){
	PORTD = USIDR;
}

As for the master, it's initialized like this:

void initialize(void)
{
// Setting up ports
	
		
	// Configure USI to 3-wire master mode with overflow interrupt.
	USICR = (1<<USIOIE) | (1<<USIWM0) |
	        (1<<USICS1) | (0<<USICS0) |
	        (1<<USICLK);
	
	DDRB |= (1 << PB6);  //DO
	DDRB &= ~(1 << PB7) | (1 << PB5);  //USCK and DI
	PORTD |= (1 << PB7) | (1 << PB5);  //pullups
	
}

and I just send a byte out the SPI every second:

unsigned char matt=0;
//Start Main Repeating Loop
for (;;) 					// loop forever
{   
	_delay_ms(1000);
	USIDR = matt;
	matt++;
}

I've read the application note regarding the use of the USI as an SPI interface. I've looked at the C code that Atmel supplies and have borrowed the control register settings from it. I can't use the code directly as it wasn't written for the winavr compiler.

If anyone has any ideas or knows of an SPI from USI library for winavr that I can use I'd appreciate it.

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

Quote:

ISR(USART_RX_vect){
   PORTD = USIDR;
}

Shouldn't the vector be USI_OVERFLOW_vect?

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

Could be. I'll try that when I get home tonight. Can you tell me how you found that? I found the list of vectors in the io2313.h include file and it doesn't show that in the list.

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

You should be looking in iotn2313.h for the ATTiny2313, not io2313.h.

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

Guess I need to learn more about these include files. Don't know the difference between those two files but I can't wait to see if that makes the difference!

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

The difference is that the io2313.h file is for the 90s2313 and the iotn2313.h file is for the tiny2313. While similar devices (the tiny2313 is the 90s2313 replacement) there are significant differences.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

io2313.h is for the older AT90S2313. iotn2313.h is for the newer ATtiny2313.h. The AT90S2313 does not have a USI interface which is why you cannot find USI related interrupt vectors in the io2313.h file.

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

Bummer. Still not working. Will keep screwing around. Interesting thing is that all leds are lit except 2 : led5 and led7.

Led7 is no surprise since portb in the 2313 is only 7 bits but I have no explanation for led5.

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

Your transmit routine is only setting the data register. Unlike the full SPI interfaces in the larger AVRs, with the USI you need to manually generate the clock.

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

You're definitely right that I'm not generating clock pulses. I don't know how. I think I'm over my head here.

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

Just did it with two mega644's in 10minutes. My god was that easier....

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

If you are still interested in getting the USI to work on the tiny2313, having the working mega644 implementation could help you debug it. For example, you could use one mega644 as the master and the tiny2313 as a slave. That way you can test the master and slave implementations separately.

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

Just an update to this.
Your code was almost there witht the 2313.
All you needed was a clock as was said above.

So you might need to have another look at the datasheet page 144-148
Esp the values you've written to USICR

Eg - My code for sending a byte.
(Not fully tested as i havent soldered up the rx board yet, but it will be soon... I've just probed the data signals on the scope and they look good)


unsigned char matt=0xA5;
  //Start Main Repeating Loop
  for (;;){                // loop forever
    //delay1(1000);
    USIDR = matt;
    send_spi();
    matt++;
  } 

void send_spi(void){
  for(int i=0;i<8;i++){
    USICR = (1<<USIOIE) | // Enable counter overflow interrupt
            (1<<USIWM0) | // Set spi mode
            (0<<USICS1) | (0<<USICS0) | // Set clock source for both shift reg and counter as software strobe (USICLK)
	    (1<<USICLK) |
	    (1<<USITC);  // Toggle external clock
	     asm("nop"); // required for some strange reason?
  }
}

You can also use timer1/counter1 as the clock which i'll give a go later or tomorrow.
Its not really needed for my application as im only sending spi bytes once in a blue moon
I reckon just strobing the spi clk in software is enough for most applications...