EmbeddedRelated.com
Forums

SPI slave on ATmega162: transferring data

Started by Roman Mashak December 9, 2004
"Roman Mashak" <mrv@tusur.ru> wrote in message
news:cp9mce$bj5$1@mpeks.tomsk.su...
> char *t_data = "1"; > ... > > SIGNAL(SIG_SPI) > { > SPDR = *t_data; > LED0_blink(); // debugging feature > } > > void SPI_SlaveInit(void) > { > DDRB = (1 << PB6); > SPCR = (1 << SPIE) | (1 << SPE); // select slave and enable SPI > > PORTB |= (1 << PB6); > } >
Almost. You do not detect whether you are at the end of the array or ready sending data. Meindert
In article <cp98r7$2ocg$1@mpeks.tomsk.su>, mrv@tusur.ru says...
> Hello, All! > > I keep fighting with atmega162 and its SPI :) > > So now I configured slave mode. The purpose is to send 8 bytes one after > another. I tested and debugged all code in simulator hundreds of times, I > watched MCU registers, SPI registers and etc., everything seems to be fine, > but after burning in chip - some weird problem.
What is the frequency of the SCK signal from the master? Sometimes simulators will respond to clock signals too fast for the actual hardware.
> > After receiving data from me, master is logging them onto the screen, so I > can watch what's going on. Indeed it happenes, data got by master are > strange and not what I sent. >
Most of the SPI systems I've worked with use a separate signal as a chip select. An SPI slave device will generally require a low-going chip select from the master device to inform it that a transfer is pending. In your case, you could use that incoming low-going CS signal to start the transfers. However, you will need to ensure that there is enough time between the CS signal and the start of the transfer. As noted in another post, you may have to 'pre load' the SPI data register so that the hardware can send the byte as soon as the master starts SCK. The CS interrupt service routine then simply loads the NEXT byte when the first transfer is done and polls the SPIF bit to determine when to load subsequent bytes. If you rely on an SPIF interrupt, you need VERY fast interrupt service to get the next byte into the output register before clocking starts, if the master is requesting bytes one after the other in continuous fashion.
> My chip is ATmega162, frequency 8MHz. Here is code: > > char *data = "123456780"; > ... > > /* > SPI init > Mode: slave > MISO: output > MOSI: input > SS: input > SCK: input > */ > void SPI_SlaveInit(void) > { > DDRB = (1 << PB6); > SPCR = (1 << SPIE) | (1 << SPE); // slave and enable SPI > > PORTB |= (1 << PB6); > } > > void SPI_SendByte(char *data) > { > SPDR = *data; > while ( !(SPSR & (1 << SPIF)) ) > ; > } > > SIGNAL(SIG_SPI) > { > char *t; > > t = data; > while ( *data != 0 ) { > SPI_SendByte((char *)data); > data++; > } > > data = t; > > LED0_blink(); // for debug: flush LED > } > > > int main(void) > { > sei(); > SPI_SlaveInit(); > ........ > return 1; > } > > And now I don't know, where is my problem has hidden. >
Mark Borgerson
In article <10rgo4fm7tdtfa4@corp.supernews.com>, 
mhsprang@NOcustomSPAMware.nl says...
> "Roman Mashak" <mrv@tusur.ru> wrote in message > news:cp9mce$bj5$1@mpeks.tomsk.su... > > char *t_data = "1"; > > ... > > > > SIGNAL(SIG_SPI) > > { > > SPDR = *t_data; > > LED0_blink(); // debugging feature > > } > > > > void SPI_SlaveInit(void) > > { > > DDRB = (1 << PB6); > > SPCR = (1 << SPIE) | (1 << SPE); // select slave and enable SPI > > > > PORTB |= (1 << PB6); > > } > > > > Almost. You do not detect whether you are at the end of the array or ready > sending data. >
And if the LED0_blink() takes longer than 8 SCK cycles to execute, you're going to have problems with continuous data. If LED0_Blink() simply sets a flag so that the main routine can blink the LED, you may be OK. You haven't said what SCK rate is being used by the master. If the slave is being implemented on an 8MHz machine, I suspect it may not like SCK signals in excess of 2MHz. If the SCK is 2Mhz, You don't have a lot of machine cycles to respond to the interrupts. I would suggest starting with a clock rate in the 100KHz region, with perhaps a millisecond between transfers at the host end. When that works, you can start increasing the SCK rate. One of the nice things about being an SPI slave is that you don't really have to worry about slow clock rates. Mark Borgerson
Roman Mashak wrote:
>
... snip ...
> > void SPI_SendByte(char data) > { > SPDR = data; > while ( !(SPSR & (1 << SPIF)) ) > ; > }
It is more efficient to do other things while the transmitter becomes ready, i.e. use: while (!(SPSR % (1 << SPIF))) continue; SPDR = data; -- Chuck F (cbfalconer@yahoo.com) (cbfalconer@worldnet.att.net) Available for consulting/temporary embedded and systems. <http://cbfalconer.home.att.net> USE worldnet address!
Hello, Meindert!
You wrote  on Thu, 9 Dec 2004 15:27:20 +0100:

 ??>>
 MS> Almost. You do not detect whether you are at the end of the array or
 MS> ready sending data.
I don't have any array, I'm sending just 1 byte.

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru 


Hello, Mark!
You wrote  on Thu, 09 Dec 2004 15:35:51 GMT:

 MB> And if the LED0_blink() takes longer than 8 SCK cycles to execute,
 MB> you're going to have problems with continuous data.  If LED0_Blink()
 MB> simply sets a flag so that the main routine can blink the LED,
 MB> you may be OK.
    Yeah,, may be that's the main issue. My LED0_blink() function is pretty 
dumb and I'm not sure it's fast enought to jump out of ISR:

void LED0_blink(void)
{
 uint8_t i=0;
 DDRC = 0x01;

  // flash LED (LED is inverse)
  PORTC &= ~(1 << PC0);
  for (i = 0; i < 50; i++) {
   _delay_loop_2(100);
  }

  // down LED
  PORTC |= (1 << PC0);

  for (i = 0; i < 50; i++) {
   _delay_loop_2(100);
  }

}

 MB> You haven't said what SCK rate is being used by the master.  If
 MB> the slave is being implemented on an 8MHz machine, I suspect it
 MB> may not like SCK signals in excess of 2MHz.   If the SCK is
 MB> 2Mhz,    You  don't have a lot of machine cycles to respond
 MB> to the interrupts.
    SCK rate of master is 500KHz
 MB> I would suggest starting with a clock rate in the 100KHz region,
 MB> with perhaps a millisecond between transfers at the host end.
 MB> When that works, you can start increasing the SCK rate.
 MB> One of the nice things about being an SPI slave is that you
 MB> don't really have to worry about slow clock rates.

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru 


"Roman Mashak" <mrv@tusur.ru> wrote in message
news:cpas34$1u4i$1@mpeks.tomsk.su...
> Hello, Meindert! > You wrote on Thu, 9 Dec 2004 15:27:20 +0100: > > ??>> > MS> Almost. You do not detect whether you are at the end of the array or > MS> ready sending data. > I don't have any array, I'm sending just 1 byte.
Yes, but you're sending it over and over again until you hit the reset button. Meindert
Hello, Meindert!
You wrote  on Fri, 10 Dec 2004 07:02:42 +0100:

 MS>>> Almost. You do not detect whether you are at the end of the array or
 MS>>> ready sending data.
 ??>> I don't have any array, I'm sending just 1 byte.

 MS> Yes, but you're sending it over and over again until you hit the reset
 MS> button.
Do you mean, some flag indicating the status of process should be included 
in code?

With best regards, Roman Mashak.  E-mail: mrv@tusur.ru 


"Roman Mashak" <mrv@tusur.ru> wrote in message
news:cpbeu5$2mtm$1@mpeks.tomsk.su...
> Hello, Meindert! > You wrote on Fri, 10 Dec 2004 07:02:42 +0100: > > MS>>> Almost. You do not detect whether you are at the end of the array
or
> MS>>> ready sending data. > ??>> I don't have any array, I'm sending just 1 byte. > > MS> Yes, but you're sending it over and over again until you hit the
reset
> MS> button. > Do you mean, some flag indicating the status of process should be included > in code?
Well, it depends on what you want to achieve. Your original code sent out a string, there you have to test for the end of the string. Later, you changed your code to send only one byte, to see what went wrong. But that code keeps sending indefinately because of the interrupt routine that gets called after you send the first and only byte 'manually'. Oh, and as other already pointed out: in an interrupt routine that runs very frequently (do you actually know how often it is executed? You should!), you cannot blink a LED and then wait in a nested loop. During that loop, the interrupt routine might get called another few 10-100 thousand times but not executed because the processor inhibits interrupts unless you enable them explicitly within the interrupt handler. If all this sounds like chinese to you, with all respect try something more easy to achive until you thoroughly understand what the processor is doing during interrupts. Meindert