NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » How to keep slave working if SS is pulled high?

October 23, 2010
by kle8309
kle8309's Avatar

Ok, so I have a SPI setup for a master and a slave. I having trouble keeping the slave mcu working (like counting) while the master pull the ss line high. I just need help with the code. Here is my code for the slave:

// slave.c
// serial peripheral interface
// Kelvin Le
// 10-22-2010

#define F_CPU 14745600

#include <stdio.h>
#include <string.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

//#define MISO PB4

/*---------------------------------------------------*/
void SPI_SlaveInit(void){

  // Set Mosi, all others input
  DDRB = (1<<PB4);
  // Enable SPI
  SPCR = (1<<SPE);  
}
void SPI_SlaveOff(void){

  // all input
  DDRB = 0x00;
  // disable SPI
  SPCR = 0x00;  
}

char SPI_SlaveReceive(void){
  DDRC |= (1<<PC5)|(1<<PC4);
  // wait for reception complete
  while(!(SPSR&(1<<SPIF))){
  // do nothing
  PORTC|=(1<<PC5);
  delay_ms(100);

  }
  PORTC&=~(1<<PC5);
  delay_ms(100);

  // Return Data Register aka this also reads it
  // this will clear the SPIF
  return SPDR;
}

void SPI_SlaveTransmit(uint8_t cData){
  DDRC |= (1<<PC4);
  // Start transmission
  SPDR = cData;
  // wait for transmission complete
  // note: when transmission is done, SPIF is set to 1
  while(!(SPSR&(1<<SPIF))) {

    PORTC|=(1<<PC4);
    delay_ms(100);
  }
  PORTC&=~(1<<PC4);
  delay_ms(100);

}

//////////////////////////////MAIN//////////////////////////////////////

int main(void) {

 DDRC |= (1<<PC4);
 // start lcd

 lcd_init();
 FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
 lcd_clear_and_home(); 
 // init counters
 int32_t n=0;
 uint8_t i;

 uint8_t sr[9];
 //char st[8] = {'H','e','l','l','o','_'};

 // init slave

while(1){

// collect data

//  if high then turn off spi
if((PORTB&(1<<PB2))!=0){

  SPI_SlaveOff();

}
// else if low then init spi
else{

  SPI_SlaveInit();
  for(i=0;i<8;i++){

  sr[i] = SPI_SlaveReceive();
  lcd_line_one();
  fprintf_P(&lcd_stream, PSTR("Let Rec: %u"),sr[i]);
  }

}

    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("n: %u"),n);

  n++;

}

  return 0;

}
October 25, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi kle8309,

I'm not sure what you mean when you say the chip doesn't keep counting when the SS pin is pulled high. I can't think of a good reason why your chip would just stop working. I can see some possible timing issues in your code, and I can't quite follow what you are trying to do in some places. I would move the call to Salve_Init() to the beginning of the main loop outside the while(1) loop. It's possible your slave is just inside the init method whenever you are trying do send data from the master.

Perhaps the best thing for you to try is to strip down your code and start smaller. Try to get one byte across from the master to the slave and display it, and then architect your code around that functionality. Let us know how your project comes along.

Humberto

October 25, 2010
by kle8309
kle8309's Avatar

So I have traced the run time execution to line 41 above, where the slave gets stuck in the while loop (waiting for master transmission to be completed aka SPIF==1). The one thing I noticed is that while the SS is pulled high, I can't change the SPIF to one.

Any code inside the while loop from line 41 will work. The only way that the slave can turn off spi is when SS is low (when the master gives permission to the slave then it can go off on its own?)

ps. What i meant by counting is like just incrementing a number like n++

October 26, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi Kelvin,

I don't think you actually need to have your code explicitly turning SPI on and off following SS -- just have it setup as a SPI slave, and stay as an SPI slave.

Also, you shouldn't turn on PC5 as an output, because as a slave, the clocking is still done by the master. (This is ignored by the microcontroller anyway -- see table 18-1 on page 164 of the ATmega168 datasheet.)

I think you could achieve what you intend by checking for SPIF from your main loop as an indication that a new character has been received, or using the SPI interrupt instead. Does that make sense for what you're trying to do?

Mike

Post a Reply

Please log in to post a reply.

Did you know that reading a double floating point variable with scanf requires "%lf" for "long float"? Learn more...