CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

MASTER SLAVE SPI PIC TO PIC PROBLEM
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

MASTER SLAVE SPI PIC TO PIC PROBLEM
PostPosted: Fri Apr 01, 2005 3:43 am     Reply with quote

Hello,

I use 2 PIC 18LF458 for an SPI communication.

I am just using this for th SLAVE :

Code:

void main(void)
{
int8 data;

// SLAVE, Front négatif de CLK

setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_64);

//enable_interrupts(GLOBAL);
output_high(PIN_A5);
   while(1)
   {
   data = spi_read(0xFF);
   printf("data = %X", data);
   delay_ms(1000);
   }

}



And this for th MASTER :


Code:

void main(void)
{
int8 data;

// MASTER, Front négatif de CLK

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

//enable_interrupts(GLOBAL);
   while(1)
   {
   spi_write(0x01);
   delay_ms(1000);
   }

}




I have signals on the scope but i can't read on the SLAVE :

it seems that this is not working :



Quote:
data = spi_read(0xFF);



Could you help me ? Thanks ! =)
Ttelmah
Guest







PostPosted: Fri Apr 01, 2005 4:57 am     Reply with quote

First comment, you don't need a clock rate on the slave settings. The slave is clocked by the master.
Now understand that SPI, sends a byte in both directions at once. When you 'SPI_WRITE' on the master, a byte is sent by the master, and anything waiting on the slave, is clocked back at the same time, and can then be read. The SPI_READ, with data, clocks out a byte, and reads the return. A _slave_ device, cannot generate a clock.
So something like this should work:
Code:

void main(void)
{
int8 data;

// SLAVE, Front négatif de CLK

setup_spi(SPI_SLAVE | SPI_L_TO_H);

   output_high(PIN_A5);
   spi_write(0xFF);
   //This puts a byte into the output buffer, for the master to receive
   while(1)
   {
   if (SPI_DATA_IS_IN() {
       data = spi_read();
       spi_write(0);
       //This will be received by the master on it's next transmission
       printf("data = %X", data);
       //No delay is wanted/needed. The transaction is synchronised
       //by the master
       //delay_ms(1000);
       }
   }
}

void main(void)
{
int8 data;

// MASTER, Front négatif de CLK

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
   while(1)
   {
   spi_write(0x01);
   if (SPI_READ()==0) {
       //The master now knows that the slave has seen the byte
       //and can do something here...
       }
   delay_ms(1000);
   }
}

I slightly "don't like", the way the standard SPI functions behave, and in the past have posted a set of macros, which seperate the behaviour into (to my mind) a 'better' logic for SPI communication.

Best Wishes
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Tue Apr 05, 2005 3:19 am     Reply with quote

I use this for the SPI which works very well, but now i want to write 2 or 3 times, and so read the 2 or 3 values.
For example, i want to write 0x01; 0x02 ; 0x03 and then read the values on the slave.

How can i synchronise the delay for the data (i know it is with the clock but how )?

Could someone help me ?

Code:
 

void main(void)
{
int8 data;

// MASTER

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

   while(1)
   {
   output_high(PIN_A5);
   spi_write(0x01);
   output_low(PIN_A5);
   delay_ms(20);


//if (SPI_READ()==0) {
       //The master now knows that the slave has seen the byte
       //and can do something here...
       //}

   }

}
 



Code:


void main(void)
{
int8 data;

// SLAVE

setup_spi(SPI_SLAVE|SPI_SS_DISABLED);

while(1)
   {
   if (SPI_DATA_IS_IN())
   {
   output_high(PIN_A5);
   data = spi_read(0xFF);
   printf("\nDATA = %X", data);
   delay_ms(1000);
   }
     
}
}
 
Ttelmah
Guest







PostPosted: Tue Apr 05, 2005 6:59 am     Reply with quote

global wrote:
I use this for the SPI which works very well, but now i want to write 2 or 3 times, and so read the 2 or 3 values.
For example, i want to write 0x01; 0x02 ; 0x03 and then read the values on the slave.

How can i synchronise the delay for the data (i know it is with the clock but how )?

Could someone help me ?

Code:
 

void main(void) {
   int8 count;
   // MASTER

   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

   while(1)  {
      output_high(PIN_A5);
      spi_write(0xAA);
      //allow enough time for slave to respond
      delay_us(10);
      if (spi_read(0x55)==0) {
          //Here the slave has acknowledged the first marker byte
          for (count=0;count<5;count++) {
              delay_u(10);
              spi_write(count);
          }
      }
      output_low(PIN_A5);
      //Here you have sent five bytes, that are now in the data array in the
      //slave. Pause now, for the slave to do it's thing, and when this is
      //finished, the slave will wait for another header.
      delay_ms(2000);

   }
}

void main(void) {
   int8 data[5];
   int8 count;
   int8 state=0;
   spi_write(0xff);
   // SLAVE
   setup_spi(SPI_SLAVE|SPI_SS_DISABLED);

   while(1) {
      if (SPI_DATA_IS_IN()) {
         switch (state) {
         case 0:
              if (spi_read(0)==0xAA) state=1;
              break;
         case 1:
              if (spi_read(0)==0x55) {
                  state=2;
                  count=0;
                  //Show the header has been seen
                  output_high(PIN_A5);
              }
              break;
         case 3:
              data[count++]=spi_read();
              if (count==5) {
                  spi_write(0xFF);
                  state=0;
                  output_low(PIN_A5);
                  //Signal you have received a block
                  //Here do what you want with the five bytes of data
               

              }
              else spi_write(0);
              break;
          }
          //Same comment as before. You _must_ get rid of the delay
          //in the slave. The transaction is synchronised by the master
          //and if the slave waits longer than the gap between bytes
          //from the master, data will be lost
          //delay_ms(1000);
     }
   }
}
 


This is showing doing a five byte block, with a marker header (not needed if you are sure the bus is synchronised).

Best Wishes
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Tue Apr 05, 2005 7:10 am     Reply with quote

Thank you very much ! =)

WHere should i put the printf to see if it is read ?
Could you explain me a little bit more what you are doing here ?
Could you help me one last time ? =)
Ttelmah
Guest







PostPosted: Tue Apr 05, 2005 7:28 am     Reply with quote

Where I say 'do what you want with the five bytes of data'. At this point, you can print it, dance a jig, do anything you want...
There is a lot of data about the SPI hardware, in the MicroChip application notes. At the end of the day, you need to read about, and understand the interface first.
The code is pretty basic, if you understand that 'SPI_DATA_IS_IN', will only go true, when a byte has arrived, and not been read. You can therefore just wait in the slave for each byte, and read it in turn. The code was made more complex, by deliberately looking for a 'header', which allows the slave to know that it is receiving 'legitimate' data, and not just noise.
For what you are describing/asking so far, I have to ask 'why SPI'?. SPI is only really worthwhile, where large amounts of data need to transfer in both directions. For a simple 'master slave' data transfer, possibly with an answer, I2C is easier. Unfortunately, the high latency in the PIC interrupts, together with the lack of hardware byte searching, make the response time for an SPI slave very poor, restricting the utility of this interface as a slave...

Best Wishes
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Tue Apr 05, 2005 9:46 am     Reply with quote

Why can't i work it out whit this ? I should have 0x01 0x02 0x03 when i read on the slave...

Code:
void main(void)
   {
   //spi_master_write();
   spi_slave_read();
   }


void spi_master_write(void)
   {
int8 data;

// MASTER

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

   while(1)
      {
   output_low(PIN_A5);
   spi_write(0x01);
   delay_cycles(20);
   output_high(PIN_A5);
   
   output_low(PIN_A5);
   spi_write(0x02);
   delay_cycles(20);
   output_high(PIN_A5);
   
   output_low(PIN_A5);
   spi_write(0x03);
   delay_cycles(20);
   output_high(PIN_A5);
   
   
 
//if (SPI_READ()==0) {
       //The master now knows that the slave has seen the byte
       //and can do something here...
       //}

      }
      delay_ms(1000);

    }
   


void spi_slave_read(void)

   {
   int8 data;


// SLAVE

setup_spi(SPI_SLAVE|SPI_SS_DISABLED);

while(1)
   {
   if (SPI_DATA_IS_IN())
      {
   output_low(PIN_A5);
   data = spi_read(0xFF);
   printf("\nDATA = %X", data);
   output_high(PIN_A5);
      }
      delay_ms(2000); 
   }
Ttelmah
Guest







PostPosted: Tue Apr 05, 2005 2:58 pm     Reply with quote

It won't work for two reasons:
1) The damn delay in the slave!...
While the processor is delayed, any data received (except the last byte), will be lost. Your master is stopping for 20 machine cycles between bytes, your slave is stopping receiving for over 1 second.
2) The printf. This takes _time_ just like the delay. This is adding (depending on the baud rate), several more mSec, while the slave is not receiving.
If you want to do it like this, change the master to pause for 1 second between the bytes, and change the slave, to simply print the byte, and then return to the while loop. Since the bytes are sent every second, the slave will receive a byte, and print the message once per second.

Best Wishes
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Thu Apr 07, 2005 6:47 am     Reply with quote

Hello again Ttelmah I think this works =) :

Code:

void main(void)
   {
   //spi_master_write();
   spi_slave_read();
   }


void spi_master_write(void)
   {

// MASTER

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);

   while(1)
      {
      spi_write(0x01);
      delay_ms(1000);   
      spi_write(0x02);
      delay_ms(1000);   
      spi_write(0x03);
      delay_ms(1000);   

//if (spi_read()==0) {
       //The master now knows that the slave has seen the byte
       //and can do something here...
       //}

      }
    }

void spi_slave_read(void)

{
   int8 data;


// SLAVE

setup_spi(SPI_SLAVE|SPI_SS_DISABLED);

while(1)
   {
   if (SPI_DATA_IS_IN())
      {
   output_low(PIN_A5);
   data = spi_read();  // Get the data
   delay_cycles(40); // Need a short delay to see pulse on scope
   printf("\nDATA = %X", data);
   output_high(PIN_A5); // Scope to see ints
     
      }
   }
}


Thansk for your help !

Could you explain me what are he 0x55 and 0xAA you add in your code ? Is it for Configurate the registers or to intialize the SPI mode ?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Apr 08, 2005 5:43 am     Reply with quote

Quote:
Could you explain me what are he 0x55 and 0xAA you add in your code ? Is it for Configurate the registers or to intialize the SPI mode ?

Try reading a bit more carefull......
Quote:
This is showing doing a five byte block, with a marker header (not needed if you are sure the bus is synchronised).
0x55 and 0xAA are just two random values used in the start of each message (header) so you can check the message is starting correctly.

Just for anyone interrested in using Ttelmah's code, there is a small bug in his example. In case of a corrupted message header he is not resetting the state machine. Current implementation will work, but is less save now.
change
Code:
         case 1:
              if (spi_read(0)==0x55) {
                  state=2;
                  count=0;
                  //Show the header has been seen
                  output_high(PIN_A5);
              }
              break;

to
Code:
         case 1:
              if (spi_read(0)==0x55) {
                  state=2;
                  count=0;
                  //Show the header has been seen
                  output_high(PIN_A5);
              }
              else  // Error in receiving header
                state = 0;  // wait for first character of header again
              break;
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Fri Apr 08, 2005 6:56 am     Reply with quote

Hello, thanks for youhelp everything is fine.

I need to write with data from the slave and read these data with the master.

In fact, i need to do the same thing that i have done but before the slave wrote and the slave read, now the slave write and then the master read the data.

Can i keep the master as master and slave as slave ?
I know that when i change the master to slave and slave to master it is working (it was predictible you'll say).

Anyway could someone help me to do this ?

It is returning 0xFF :



Thanks !
Code:
void main(void)
   {
   spi_master_write();
   //spi_slave_read();
   }


void spi_master_write(void)
   {
int8 data;

// MASTER

//setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64 | SPI_XMIT_L_TO_H);

while(1)
   {
   //if (SPI_DATA_IS_IN())
      //{
   output_low(PIN_A5);
   data = spi_read(0xFF);
   printf("\nDATA = %X", data);
   output_high(PIN_A5);
      //}
      delay_ms(2000); 
   }
}

     
void spi_slave_read(void)

{
   int8 data;


// SLAVE

//setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
setup_spi (SPI_SLAVE | SPI_H_TO_L | SPI_XMIT_L_TO_H);

while(1)
      {
      spi_write(0x01);
      delay_ms(1000);   
      spi_write(0x02);
      delay_ms(1000);   
      spi_write(0x03);
      delay_ms(1000);   

//if (spi_read()==0) {
       //The master now knows that the slave has seen the byte
       //and can do something here...
       //}

      }
}
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Apr 10, 2005 6:54 am     Reply with quote

You have the master to slave communication working, great!

In SPI communication only one device can be the master, this is decided at design time and never changed afterwards. Although it is technicaly possible to change a master to slave this is not good practice and will give you a lot of headaches because synchronization is going to be difficult (how and when to decide to switch from master to slave?).


What kind of data do you have to transmit? Is the slave always responding to a command from the master? Or is it possible the slave wants to initiate a data transfer without a prior master command? If yes, what response times?
It might even turn out SPI is not the right bus for your application.
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Mon Apr 11, 2005 1:21 am     Reply with quote

Hello,

data that i have to transmit are only bytes for the moment but for example the slave should initiate the master with sending 0x02 to the master for the master to execute some commands.
I must be able to read and write on the slave as i must do it on the master. Commands could be from the master as well as from the slave.

The slave wants to initiate a data transfer without a prior master command, yes and it should be as fast as possible !

Some people already told me that SPI may be not the right bus for this application, but i want to know if there is any solution for that first before maybe change my point of view.

I need to know if my code could be writtable to only WRITE WITH THE SLAVE AND READ WITH THE MASTER !
Maybe you could give me some solutions or others ways to do what i want to do ...

Thanks a lot.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Apr 11, 2005 4:28 pm     Reply with quote

Quote:
The slave wants to initiate a data transfer without a prior master command, yes and it should be as fast as possible !
This won't be easy with SPI. I never had to implement something like that and am not sure what is the best solution.
One way to implement this with SPI is to add an extra signal line from slave to a master interrupt input. When the slave wants to initiate a data transfer it sends the interrupt signal to the master. Problem in this setup is the situation where both the master and slave want to start communications simultaneously, your protocol has to take care of this.

You didn't tell us enything about your application, maybe other solutions are possible. Why did you choose your current master to become the master? Maybe switching the master and slave role is a better solution?

I don't know enough of I2C, but this might be a better bus for your purpose as it allows for multiple masters. Maybe someone else can jump in here?
global



Joined: 01 Feb 2005
Posts: 21
Location: Paris

View user's profile Send private message

PostPosted: Tue Apr 12, 2005 2:07 am     Reply with quote

Hello,

could you help me with a code example using interrupts to do what i want to do ?
I may need a briefing on the interrupts i never used it before and i want to learn.

It is a project designed by other people, i just try to get where they want to go !
Anyway, it seems strange that i can write with the master and read with the slave and NOT write with the slave and read with the master ... It seems to be possible, but why can't we ?

Thanks again for your help. If someone could do something more ?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group