Send a number of characters to SPI and stop

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

Hi Guys,

I am trying to send four bytes across the SPI on a Atmega328 configured as a master. Here is the code I am using:

#include              
#include  
#include 
#define ddr_spi    DDRB     
#define port_spi   PORTB     
#define pin_ss     PORTB2       
#define pin_mosi   PORTB3       
#define pin_miso   PORTB4       
#define pin_sck    PORTB5       

unsigned char Data;

//---------------------------------------------------------------------------
void SPI_MasterInit(void)
{
   ddr_spi   = ((1<<pin_mosi)|(1<<pin_sck))|((1<<pin_ss));    // MOSI, SCK = 1
   PORTB = 0xFF; //This is very important; need to toggle Slave select line from high to low
    SPCR      = (1<<SPE) | (1<<MSTR) | ( 0 << SPI2X) | (0 << SPR1) | (0 << SPR0) ;  // Enable SPI, master, prescaler 128

   PORTB &= ~(1 << pin_ss); //toggle slave select line from high to low
   Data = SPSR;
   Data = SPDR;

}


//---------------------------------------------------------------------------
void SPI_MasterTransmit(char Spi_Data)
{
      SPDR =   Spi_Data;               // Load byte to output register
      while(!(SPSR&(1<<SPIF)));     // Wait for byte to be sent
}


//---------------------------------------------------------------------------
int main (void)
{   
  
   SPI_MasterInit();               

   while(1)                         
   {
      
           SPI_MasterTransmit(0x01); //want to transmit 0x01, 100 times and then stop, maybe a for loop would work here? 
    }

}



I want to transmit a 0x01 a 100 times and stop. How can I get this working? As it is in a while(1) loop is there no way I can make this work so that it transmits only once and stops.

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

Quote:

How can I get this working?

int main (void) 
{    
  
   SPI_MasterInit();                

   for (int i=0; i<100; i++) {
     SPI_MasterTransmit(0x01); //want to transmit 0x01, 100 times and then stop, maybe a for loop would work here? 
   }

   while(1)                          
   { 
   } 

}

or maybe:

int main (void) 
{    
  int i = 0;
  SPI_MasterInit();                

   while(1)                          
   { 
      if (i<100) {
           SPI_MasterTransmit(0x01); //want to transmit 0x01, 100 times and then stop, maybe a for loop would work here? 
           i++;
      }
    } 

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  char count = 100;
  while(1) {
     if (count) {
       count--;
       SPI_MasterTransmit(0x01);
     }
   }

Beat to the punch by the Brit. Must be that tasty ash in the air.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Just to note that while my second suggestion and Chuck's are very similar his is the better solution as it's often more efficient to count down rather than up so the compiler can simply check for Z being set after the decrement. (but I might move Chuck's decrement to the other side of the function call to give the compiler more chance - but, having said that, this is exactly the kind of code re-ordering that people bemoan the optimiser for, hopefully it would re-order things if it helped it)

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

Ok I tried Chuck's idea and I am getting a continuous running display on the scope of 8 clock cycles with 0x01 and this pattern repeats (with the reset gap between the consecutive 8 clocks).

Here is a stupid question: if thetransmission is supposed to stop after sending the 100, 0x01 bytes, should I not see a display showing 100, 8 clock cycles?

I even tried it using a count of 2 instead of 100 and I still see a continuous display of clock pulses and data instead of seeing just 2 groups of 8 clock pulses with data.

How do I know that the AVR is sending only 16 bits (using 2 groups of 8 clocks each) and not repeatedly sending 16 bits?

Do I need a logic analyzer for this?

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

Maybe post your actual code that is behaving this way first.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Did you try the for() loop outside of the while(1) ? How did that work out for you?

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

Ok I confirmed the output and both of them worked. Must have not flashed the chip right the first time.

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

And then there is this:

char count = 100;
  
  do {
     SPI_MasterTransmit(0x01);
  }while(--count != 0);

EDIT TO ADD:

 

I know this thread is a bit outdated.  But I was researching threads on using SPI with the Mega328P for use with some NRF24L01 based RF modules that are due for delivery this week.  These RF modules use SPI in slave mode.  I haven't used SPI since my MC68HC11 days and thought I would get some ideas, beyond what the Mega328P datasheet discusses.

 

Anyway, I ran across this thread and though I would add my two-bits worth, even though it is pretty old.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

Last Edited: Mon. Feb 23, 2015 - 05:15 PM