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 CCS Technical Support

Question re uses of synchronous Master / Slave SPI?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
RKnapp



Joined: 23 Feb 2004
Posts: 51

View user's profile Send private message

Question re uses of synchronous Master / Slave SPI?
PostPosted: Tue Aug 29, 2006 5:44 pm     Reply with quote

Friends,

CCS v3.249; PCWH, dsPIC -- but I think this applies to all previous SPI modules as well.

I am about to start a new board layout which will have several PICs on it. In the past, I made a multi-PIC layout in which all the PICs communicated via UARTs, and have also successfully used an SPI bus to hang peripherals off a PIC; peripherals such as an A/D converter and a programmable filtering chip for the A/Ds.

But now, in order to free up all my UARTs, I'm considering trying to communicate between the PICs (actually, dsPIC30F6014 -- though I don't think this makes a difference?) not via UARTs but via SPI, and wonder if anyone has thought about this, and would be willing to share their experience / expertise:

- Is SPI better or worse than using UARTs to communicate between PICs?
- Say there are two PICs; *MUST* one set up one PIC's SPI as a master, with the other PIC's SPI bus set up as a slave? Or can both be Masters?
- Say there are four PICs, in which one is considered the Top Dog and the other three would feed him information in a star configuration. Would it make sense to set up TopDog as an SPI Master and star out his SS1-bar line to the other three lesser dogs, with their SPIs set up as slaves?
- Or, should TopDog use up some of his general DIO pins to act as individual SS1-bar pins for each slave; these would act as individual chip-selects?
- Or, ?

Any thoughts on inter-PIC communication via SPI would be appreciated. Have a nice day,

Smile Robert
Ttelmah
Guest







PostPosted: Wed Aug 30, 2006 2:23 am     Reply with quote

Do you need communications in both directions at once?. If not, then consider I2C, rather than SPI. SPI, is a 'single master' bus. One chip generates the clock, and a simultaneous transfer of data takes place in both directions at once. Since the driver is a full 'push-pull' output, if you tried to implement multi-masters, and two attempted to communicate at the same time, there would be significant current drawn, with a lot of noise, and the potential to damage the chips. With I2C, the drivers are 'open collector' (pull down only), so no damage will occur if two try to control the bus at the same time. Multi-master I2C implementations have been published here in the past. With any 'multi-master' system, the chips are programmed as _slaves_, at all times, except when trying to initiate a transaction. The device wanting to send, checks if the bus is idle, and then starts it's transaction. If the transaction fails (which could be caused by a bus clash, or another problem), you then have a 'recovery' algorithm, which re-tries after an interval. Normally it is critical to choose the timing of the retry to be either biased so that the more important chips will retry first, or using a random time delay, to make the probability of a second clash low.
Beware of 'star' wiring configurations. If you use SPI, at high speed, there is the potential for significant ringing on the unterminated wire ends. On a fast PIC, you can easily operate SPI, at over 5Mbps, and at these sorts of speeds, a single 'line' structure, with termination, will be far more reliable.

Best Wishes
RKnapp



Joined: 23 Feb 2004
Posts: 51

View user's profile Send private message

PostPosted: Wed Aug 30, 2006 4:14 pm     Reply with quote

Ttelmah,

Thanks very much for your comments; they've helped me clarify my thinking.

I do really want bidirectional communication, and simultaneity is a plus. Thus, I2C seems less desirable to me than SPI. In carefully reading the manual on SPI -- which hopefully reflects reality -- I find that if I do want to build a star:

- I can make my TopDog a master, and have multiple slaves. Making them all masters would be possible but foolish, and it would require extra chips.
- To pull this off, I'd ignore the SPI Master's SSx line but route general purpose DIO into each slave's SSx line so that I could talk only to the one I want to talk to at each point in time. According to the documentation, if that line is driven high, all kinds of good things will happen including the key thing, that the DOx line will tristate -- sweet -- so that all the DOx of the slaves can be directly connected together (no intermediary AND gate needed) and wired into the master's DI line.
- To make it really work without collisions, I know I'd need additional "I'm ready" control lines on each side, but that's okay, I'm going to use an 80-pin chip and have those lines. (I've just figured out that three semaphore lines are needed between each slave and the master to be fully deterministic, as well as the synchronous slave mode selector SSx -- plus lines DO/DI/CLK.)
- I might face a bus-ringing problem at high speed (my max speed would be 30Mbps if I were to use 1:1 prescaling -- though I'd probably run slower) so thanks for reminding me of this; there may be a way to terminate fairly simply -- a few hundred ohms or trace thickness adjustment?

Anyway, thanks for your reminders and I really appreciate all your help in the past, too. If anyone has ever tried to use synchronous slave mode and got burned, please let me know as I'm depending blithely on the manuals to actually be correct.

Smile Robert
ckielstra



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

View user's profile Send private message

PostPosted: Thu Aug 31, 2006 1:12 am     Reply with quote

Quote:
my max speed would be 30Mbps if I were to use 1:1 prescaling
Your speed will be lower, at 1:1 prescaling your SPI frequency is Fosc/4. With a PIC running at the max 40MHz this would give you a maximum SPI speed of 10Mbps.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Aug 31, 2006 3:16 am     Reply with quote

Read this thread for a discussion of the maximum SPI clock speed
for a PIC used as an SPI slave:
http://www.ccsinfo.com/forum/viewtopic.php?t=27914&start=4
RKnapp



Joined: 23 Feb 2004
Posts: 51

View user's profile Send private message

Somehow I am getting up to 30Mbaud on dsPIC30F4013's SPI
PostPosted: Fri Dec 01, 2006 2:18 pm     Reply with quote

Friends,

I thank you very much, PCM and others, for so kindly sharing your expertise on so many topics. I just wished to report something interesting, that the SPI bus can reach speeds of up to 30MBaud.

I am testing a simple board my colleague laid out which sports a dsPIC30F4013 TQFP-44 pin chip running with a ~7MHz clock that we're PLL'ing up 16x so that when you divide Fosc by 4, you get about 29MHz. On the chip's single SPI bus we have hung an 8-bit serial-to-parallel buffer and a DAC which I feed 4 control bits and 12 bits of resolution -- 16 bits -- and these are both output devices.

Because the two peripherals on this bus are not at all compatible (in CKE/CKP, chip select polarity, or even in data width, 8 vs. 16 bits) I have to rewrite the SPI control word each time I want to address one of these. Each peripheral has its own chip select so that the peripheral I'm not talking to won't go nuts. But the interesting thing is that it runs very fast. I plan to back down to 14Mbaud for normal operations, but it will run without glitches using a 1:1 clock input; a speed of about 29Mbaud.

I have introduced some "delays" into the system to make sure that the data is fully shifted out by the time I latch my peripherals, and I admit that I haven't fully tuned these delays with my ANT-16, but the following code will run (alas, no CCS compiler yet for any dsPIC) under MPLABS.

I just thought you guys might like to know this.

Smile Robert

Code:

      if(Dout ==0)
         Dout = 0x0080;
      else
         Dout = (Dout/2)&0x00ff;
         
      SPI_TxByte   = Dout;

      #define DOUT_DELAY_1   2
      #define DOUT_DELAY_2   20
      #define DOUT_DELAY_3   2   

      // SPI bus 8-bit operation:
      SPI1CON          = 0x013b;                // SPI CONFIG  8 bit 14 MBaud CKE/CKP=1/0
      SPI1STAT       = 0x0000;               // disable the SPI bus and clear SPIROV
      SPI1STAT       = 0x8000;               // CLEAR SPI ERRORS and ENABLE SPI bus

      DOUT_CS          = 1;                     // set strobe to "pass input data through"
      for             ( i=0; i<DOUT_DELAY_1; i++ );
      // SPI bus 8-bit Rx:
      if ( ( SPI1STAT & 0x0001 ) )            // IF the SPI port thinks it got a byte,
         SPI_RxByte    = SPI1BUF;               // read the input buffer (which takes time)
      // SPI bus 8-bit Tx:
      SPI1BUF         = SPI_TxByte;
      while ( ( SPI1STAT & 0x0002 ) );         // wait until I COULD Tx another byte if desired
      for             ( i=0; i<DOUT_DELAY_2; i++ );
      DOUT_CS          = 0;                     // set strobe to "ignore input data"
      for             ( i=0; i<DOUT_DELAY_3> 4095 )
         DacOutBits = 0;       
      SPI_TxWord  =  ( DacOutBits & 0x0FFF );

      #define DACOUT_DELAY_1   2
      #define DACOUT_DELAY_2   20
      #define DACOUT_DELAY_3   2
   
   // SPI bus 16-bit operation:
   
   SPI1CON          = 0x043b;                // SPI CONFIG  16 bit 14 MBaud CKE/CKP=0/0
   SPI1STAT       = 0x0000;               // disable the SPI bus
   SPI1STAT       = 0x8000;               // CLEAR SPI ERRORS and ENABLE SPI bus
   
   DAC_CS          = 0;                     // set to "use input data"            
   for             ( i=0; i<DACOUT_DELAY_1; i++ );
   // SPI bus 16-bit Rx:
   if ( ( SPI1STAT & 0x0001 ) )            // IF the SPI port thinks it got a byte,
      SPI_RxWord    = SPI1BUF;               // read the input buffer (which takes time)
   // SPI bus 16-bit Tx:
   SPI1BUF         = SPI_TxWord;
   while          ( ( SPI1STAT & 0x0002 ) );         // wait until I COULD Tx another byte if desired
   for             ( i=0; i<DACOUT_DELAY_2; i++ );
   DAC_CS          = 1;                     // ignore further input            
   for             ( i=0; i<DACOUT_DELAY_3; i++ );
   




ps. I bet I am introducing many, many wait states every time I set up a FOR loop and haven't investigated this. The chip is running so fast (AND so HOT -- 40 degrees over ambient!) that I am not worried about wasting time here because its computing power is already overkill for us.

If I wanted to really eke out performance in this section, I could pull out the ANT and finely tune my delays, possibly eliminating one or more of those FOR loops. Also, I admit that the code above isn't too lovely; my excuse is that it's test code.
RKnapp



Joined: 23 Feb 2004
Posts: 51

View user's profile Send private message

PostPosted: Fri Dec 01, 2006 2:54 pm     Reply with quote

Friends,

It was pointed out to me (thank you!) that the code fragment I just posted is garbled. I am therefore disabling HTML and merely re-posting the same code just in case anyone else wishes to try it with their MPLABS C30 compiler (I am hoping CCS gets a wiggle on with their own dsPIC support.)

Communicating inter-chip at this speed (>50x the speed of CAN) is good stuff... I'm hoping it works without ringing when I try to set up a star with master / slave relationships.

Thanks very much for everyone's helpful input,

Smile Robert

Code:


 char SPI_RxByte,
       SPI_TxByte;
 unsigned int DacOutBits,
       SPI_RxWord,
       SPI_TxWord;



DOUT_CS          = 0;      // de-select, HIGH-notch activates it
DAC_CS          = 1;       // de-select, LOW-notch activates it

Dout             = 0;
DacOutBits      = 0;


            
      if(Dout ==0)
         Dout = 0x0080;
      else
         Dout = (Dout/2)&0x00ff;
         
      SPI_TxByte   = Dout;

      #define DOUT_DELAY_1   2
      #define DOUT_DELAY_2   20
      #define DOUT_DELAY_3   2   

      // SPI bus 8-bit operation:
      SPI1CON          = 0x013b;                // SPI CONFIG  8 bit 14 MBaud CKE/CKP=1/0
      SPI1STAT       = 0x0000;               // disable the SPI bus and clear SPIROV
      SPI1STAT       = 0x8000;               // CLEAR SPI ERRORS and ENABLE SPI bus

      DOUT_CS          = 1;                     // set strobe to "pass input data through"
      for             ( i=0; i<DOUT_DELAY_1; i++ );
      // SPI bus 8-bit Rx:
      if ( ( SPI1STAT & 0x0001 ) )            // IF the SPI port thinks it got a byte,
         SPI_RxByte    = SPI1BUF;               // read the input buffer (which takes time)
      // SPI bus 8-bit Tx:
      SPI1BUF         = SPI_TxByte;
      while ( ( SPI1STAT & 0x0002 ) );         // wait until I COULD Tx another byte if desired
      for             ( i=0; i<DOUT_DELAY_2; i++ );
      DOUT_CS          = 0;                     // set strobe to "ignore input data"
      for             ( i=0; i<DOUT_DELAY_3; i++ );
   



   
      DacOutBits   += 409;
      if ( DacOutBits > 4095 )
         DacOutBits = 0;       
      SPI_TxWord  =  ( DacOutBits & 0x0FFF );

      #define DACOUT_DELAY_1   2
      #define DACOUT_DELAY_2   20
      #define DACOUT_DELAY_3   2
   
      // SPI bus 16-bit operation:
   
      SPI1CON          = 0x043b;                // SPI CONFIG  16 bit 14 MBaud CKE/CKP=0/0
      SPI1STAT       = 0x0000;               // disable the SPI bus
      SPI1STAT       = 0x8000;               // CLEAR SPI ERRORS and ENABLE SPI bus
   
      DAC_CS          = 0;                     // set to "use input data"            
      for             ( i=0; i<DACOUT_DELAY_1; i++ );
      // SPI bus 16-bit Rx:
      if ( ( SPI1STAT & 0x0001 ) )            // IF the SPI port thinks it got a byte,
         SPI_RxWord    = SPI1BUF;               // read the input buffer (which takes time)
      // SPI bus 16-bit Tx:
      SPI1BUF         = SPI_TxWord;
      while          ( ( SPI1STAT & 0x0002 ) );         // wait until I COULD Tx another byte if desired
      for             ( i=0; i<DACOUT_DELAY_2; i++ );
      DAC_CS          = 1;                     // ignore further input            
      for             ( i=0; i<DACOUT_DELAY_3; i++ );
   
    



ps. I happen to have this code in a loop so that some LEDs I have connected to the DIO output buffers ("DOUTs") are lit in turn; I am likewise measuring my DAC output with a voltmeter to find that it is acting as expected. In my case, for the DAC, it's the case that:


Code:

//SPI_TxWord   = 0x0FFF;   // 11v
//SPI_TxWord   = 0x0000;   // -11v
//SPI_TxWord   = 0x03FF;   // -5.5v
//SPI_TxWord   = 0x0C00;   // 5.5v
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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