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

Difference between <#USE SPI> and setup_spi()

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



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

Difference between <#USE SPI> and setup_spi()
PostPosted: Thu Mar 09, 2017 8:48 am     Reply with quote

Compiler: 5.026
Device: PIC24EP512GP806

Yet another question that needs clarification where manuals and help files are not always ideal (in my case anyhow!).

My MCU is tied to two external SPI devices on SPI3 (pins RE7, RE3 and RE2):

Device 1 uses RE4 for /CS (EEPROM 24LC1024)
Device 2 uses RF0 for /CS (ACCELEROMETER ADXL0345)


Of course, ideally, I want to take advantage of the maximum speed when accessing either device.

Initially at MCU startup, I am using the following to configure SPI3 because that's how the SPI bus needs to be configured for the EEPROM:

setup_spi3( SPI_MASTER | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16 );

Then later in the code, I have functions that use spi_write3() for accessing both devices. So far so good, all works fine, no issues here, its been like this forever.

But as I learn more and more while working on this project, I am wondering if I am really taking advantage of the full SPI bus capabilities.

When I need to read or write to either device, the only differece is with the accelerometer's SPI configuration when I need to access it:

1) I must first call setup_spi3( SPI_MASTER | SPI_XMIT_L_TO_H | SPI_H_TO_L | SPI_CLK_DIV_16 );
2) Then I can read or write to the device;
3) Lastly I must call setup_spi3( SPI_MASTER | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16 ); to put the SPI bus back to 'EEPROM' mode since it is accessed much more often.

The accelerometer is rarely accessed after it is initially configured, the EEPROM is more accessed therefore I set the SPI back to the 'EEPROM' mode.

All this being said, hoping I didn't give too much irrelevant information, what is the difference between setting-up the SPI port with setup_spi vs #USE SPI?

Is there a difference in speed when the device is accessed? I haven't tried using the #USE SPI because I am not sure what else is required when using that fuse.


Thanks,

Ben
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Mar 09, 2017 12:07 pm     Reply with quote

benoitstjean wrote:

Device 1 uses RE4 for /CS (EEPROM 24LC1024)

This eeprom part number doesn't exist, or no longer exists. You almost
certainly are really using 25LC1024.

benoitstjean wrote:

I must first call setup_spi3( SPI_MASTER | SPI_XMIT_L_TO_H | SPI_H_TO_L | SPI_CLK_DIV_16 );
2) Then I can read or write to the device;
3) Lastly I must call setup_spi3( SPI_MASTER | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16 );
to put the SPI bus back to 'EEPROM' mode since it is accessed much more often.

The data sheet for 25LC1024 says it can use SPI modes 0 or 3.
This is stated in the following diagram in the data sheet:
Quote:
FIGURE 1-2: SERIAL INPUT TIMING


The ADXL345 also uses SPI mode 3. This is stated in the SPI section
of the data sheet:
Quote:

The maximum SPI clock speed is 5 MHz with 100 pF maximum loading,
and the timing scheme follows clock polarity (CPOL) = 1 and clock
phase (CPHA) = 1.

Since both chips can use Mode 3, you don't need to change modes.
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Mar 09, 2017 12:18 pm     Reply with quote

Hi PCM Programmer, correct, typo from my end, it is a 25LC1024.

Ok for the modes... thanks.

But the general question is still valid:

What is the difference between setting-up the SPI port with setup_spi vs #USE SPI?

And which SPI 'model' will take advantage of the max speed of the SPI bus?

Thanks again,

Benoit
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Fri Mar 10, 2017 4:00 am     Reply with quote

setup_spi, is the older way of using the SPI.

Only works with hardware ports.
Uses spi_write and spi_read for transfers.
Only supports 8bit transfers.
Does not offer any control of handshake lines.
Requires direct control of the configuration bits (directions, levels etc.). Simpler defines for these though are easy.

#USE_SPI is the more powerful 'modern' way of controlling SPI.
Supports software and hardware ports.
Requires spi_xfer for the actual transfers.
spi_xfer is coded slightly differently. For a transmit transfer, on the hardware port, it'll check if the peripheral is 'free' before transferring a byte, then transfer _and immediately return_. This means you code can be preparing the next byte while this transfer is occurring.
Supports automatic multi byte transfers (up to 4 bytes).
Can control latch and enable pins.
Supports 'mode' names for configuring the port.
Also allows you to specify bit order and byte order for the transfers.

SPI_XFER for sequential writes is faster, because of the ordering of the 'device ready' test.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Fri Mar 10, 2017 5:39 am     Reply with quote

In terms of bus clock rate, they will both give the same maximum. Any difference in throughput will be due to firmware overheads, giving slighty larger gaps between transfers.

I am running a 25AA1024 on a PIC24HJ128GP504 on 3.3V. The bus lines are maybe 30mm long. I cannot reliably run at the maximum SPI clock rate that the 25AA1025 of 10MHz as even with the short, direct PCB traces, I am getting a lot of overshoot and ringing, making the waveforms a bit dodgy. So, I've had to slug the SPI to 5MHz (the clock rate divider only allows, obviously, integer sub-multiples of my Fcyc, 80MHz, so I can have 20MHz, 10MHz, 5MMhz, 2.5MHz, etc. but nothing in-between) to get reliable transfers in all my available hardware (granted not many: one prototype board worked fine, one didn't... sometimes). I could have probably fiddled wround with termination resistors to improve the waveforms, but there was no need, running at half-speed is just fine in my application (serving wepages on a LAN). So, I'd not recommend running at top speed for the sake of it, and it may not be easy to guarantee.
benoitstjean



Joined: 30 Oct 2007
Posts: 566
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Fri Mar 10, 2017 5:53 am     Reply with quote

Hi guys,

Thanks both for your replies, it's appreciated.

So maybe then when I get a bit of time, I will look at using the more "modern" version.

Thanks a lot!

Benoit
jeremiah



Joined: 20 Jul 2010
Posts: 1357

View user's profile Send private message

PostPosted: Fri Mar 10, 2017 8:09 am     Reply with quote

It's worth noting that at least for some chips for some compiler revisions, the #use spi generates slightly more code and takes a few instructions longer (for hardware mode).

Consider:
Code:

#include <24FJ64GA104.h>
#use delay(clock=8MHz)

#pin_select SDO1 = PIN_B7
#pin_select SDI1 = PIN_B6
#pin_select SCK1OUT = PIN_B8
#pin_select SDO2 = PIN_B9
#pin_select SDI2 = PIN_B10
#pin_select SCK2OUT = PIN_B11

#use spi(SPI2,FORCE_HW,master,bits=8,mode=0)

void main(){

   setup_spi(SPI_MASTER);
   
   spi_write(0x00);
   spi_xfer(0x00);
   
   while(TRUE){

   }
}


The spi_write() call generates:
Code:

....................    spi_write(0x00);
0292:  BCLR.B  240.6
0294:  BTSS.B  240.0
0296:  BRA     29C
0298:  MOV.B   248,W0L
029A:  BRA     294
029C:  CLR.B   248
029E:  BTSS.B  240.0
02A0:  BRA     29E


And the spi_xfer() call generates:
Code:

....................    spi_xfer(0x00);
02A2:  MOV     #8,W2
02A4:  MOV     #0,W0
02A6:  MOV     #0,W1
02A8:  CALL    200

which calls
Code:

.................... #use spi(SPI2,FORCE_HW,master,mode=0)
*
0200:  MOV     W5,[W15++]
0202:  MOV     W0,W4
0204:  MOV     W1,W5
0206:  MOV     #18,W3
0208:  CPSGT   W2,W3
020A:  BRA     210
020C:  MOV     #B,W3
020E:  BRA     222
0210:  MOV     #10,W3
0212:  CPSGT   W2,W3
0214:  BRA     21A
0216:  MOV     #A,W3
0218:  BRA     222
021A:  MOV     #8,W3
021C:  CPSGT   W2,W3
021E:  BRA     222
0220:  MOV     #9,W3
0222:  MOV.B   [W3+#0],W0L
0224:  MOV.B   W0L,268
0226:  BTSS.B  260.0
0228:  BRA     226
022A:  MOV.B   268,W0L
022C:  MOV.B   W0L,[W3--]
022E:  BCLR.B  260.6
0230:  SUB.B   #8,W2L
0232:  BRA     GTU,222
0234:  MOV     W4,W0
0236:  MOV     W5,W1
0238:  MOV     [--W15],W5
023A:  RETURN 


Not all of that code is run for the call, it is basically a selector for 8bits vs 16 bits vs 24 or 32 bits, so the extra overhead, is just doing the checks versus the bits size and the built in looping.

I wish CCS was a bit smarter on this and if you select a size equal to a hardware option, then forgo the extra stuff and replicate what spi_write() does. It is a compile time option, so it is certainly possible for them to do so.
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Fri Mar 10, 2017 9:46 am     Reply with quote

Interesting.

On the spi_write code. Note that it waits for the peripheral to be ready before sending, and then again afterwards.... :(

Now the multi byte code is silly. As you say it should not include this if you are fixing the transaction length. It doesn't on a PIC16/18.... Duh.
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