Reply by Meindert Sprang December 10, 20042004-12-10
"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
Reply by Roman Mashak December 10, 20042004-12-10
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 


Reply by Meindert Sprang December 10, 20042004-12-10
"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
Reply by Roman Mashak December 9, 20042004-12-09
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 


Reply by Roman Mashak December 9, 20042004-12-09
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 


Reply by CBFalconer December 9, 20042004-12-09
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!
Reply by Mark Borgerson December 9, 20042004-12-09
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
Reply by Mark Borgerson December 9, 20042004-12-09
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
Reply by Meindert Sprang December 9, 20042004-12-09
"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
Reply by Roman Mashak December 9, 20042004-12-09
Hello, Meindert!
You wrote  on Thu, 9 Dec 2004 14:40:44 +0100:

 MS> The problem with the code above (I assume it is the code for the
 MS> master) is that you call spi_sendbyte from within the interrupt
this is code for slave
 MS> handler. Spi_sendbyte waits for the SPIF flag. The moment this flag is
 MS> set, another interrupt is issued while you are still inside
 MS> spi_sendbyte. You can safely remove the while loop in spi_sendbyte
Alright, I understand you. Here is changed version, I hope is correct :)
 MS> because you only call it once at the start of the communication. After
 MS> that it is called from the interrupt handler only when the shifter is
 MS> empty. So, no need to wait for the SPIF flag. And when the while loop
 MS> is removed, you'll that the only line left in spi_sendbyte can be put
 MS> in the interrupt handler to save a pair of unnecessary call/return.

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);
}

int main(void)
{
    sei();
    SPI_SlaveInit();
    SPDR = *t_data;    //write byte to trigger interrupt

    while (1)
    {
    .....
    }

    return 1;
}

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