![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
SPI on timer2 |
Posted: Mon Apr 22, 2019 2:18 pm |
|
|
Needing SPI to be faster than the fosc/4
I am running a 20MHz crystal on a 18F87K22 Not really wanting to run higher clock speeds.
Shouldn't I be able to set the SPI up to run on timer2?
this line:
Code: | #USE SPI(MASTER, MODE=0, SPI1, STREAM=SPI,FORCE_HW) |
sets my SPI up but having problems finding how to syntax the timer2 clock option with USE SPI.
Also, pitfalls on going this route? If I cannot get SPI to run faster will have to ditch SPI SRAM and go to parallel RAM.
I have done tests and running Fosc at 20MHz my SPI takes 2E-5 sec to transmit one 16bit word in the sequential mode of the 23LC1024 SRAM chip. I am afraid that the write will not happen fast enough before another write is needed.
I am taking 8000 16 bit words in 0.1S of time. Based off of my test code it will require 0.08S to do the writes. not much time to do everything else.
I am calling the following function once to do 250 byte writes in sequential mode of the 23LC1024 SRAM chip.
Code: | void SRAM_write_block(unsigned int32 address, byte *block, int16 number)
{
// send a block of data stored at 'block'
// number is how many items to send.
int8 dummy;
if(number<1) return; // do nothing if zero items requested to send.
output_low(SRAM_CS1); // test with chip 1
spi_xfer(SPI, WRITE_CMD, 8); // send write command
spi_xfer(SPI, address, 24); // send address
// Now, loop through the data
while(--number) // do except for the last byte
{
spi_xfer(SPI, *(block++), 8); // send each byte
} // end while loop for data send
dummy=spi_xfer(SPI,*(block++),8); // send last byte
output_high(SRAM_CS1);
} // end SRAM_write_block()
|
The math of the SPI running at fosc/4 with a 20MHz clock would show there should be time to do all this but the scope data shows otherwise.
overhead? CCS options to speed up the SPI without going huge on Fosc? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: SPI on timer2 |
Posted: Mon Apr 22, 2019 2:46 pm |
|
|
beaker404 wrote: |
sets my SPI up but having problems finding how to syntax the timer2 clock option with USE SPI.
|
If you did want to use Timer2, the following code looks like it would work
to change the SPI clock source, while still allowing you to use spi_xfer():
Code: |
#include <18F87K22.h>
#FUSES NOWDT
#use delay(internal=64M)
#USE SPI(MASTER, MODE=0, SPI1, STREAM=SPI,FORCE_HW)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
//==================================
void main()
{
setup_spi(SPI_MASTER | SPI_CLK_T2 | SPI_MODE_0); // Use T2 as clock
// Also add code to setup Timer2.
while (TRUE);
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Mon Apr 22, 2019 2:56 pm |
|
|
Thanks PCM.
Not sure Timer2 will get me there either, T2 runs at fosc/4 itself, so anything it does will slow SPI down more. If I am reading it correctly.
Really hate to keep going up in CPU speed. My experience has been boards and crystals get flakey the faster you go.
There must be some overhead I am not accounting for because it looks like a 20MHz crystal letting the SPI run at 5MHz and sending 8000 16bit words should be faster than what I am seeing.
In a perfect world, 8000 16 bit words clocked at 5MHz is 25mS. not 160mS. Is there really that much overhead? |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1329
|
|
Posted: Mon Apr 22, 2019 3:21 pm |
|
|
beaker404 wrote: | Thanks PCM.
Not sure Timer2 will get me there either, T2 runs at fosc/4 itself, so anything it does will slow SPI down more. If I am reading it correctly.
Really hate to keep going up in CPU speed. my experience has been boards and crystals get flakey the faster you go.
There must be some overhead I am not accounting for becuase it looks like a 20MHz crystal letting the SPI run at 5MHz and sending 8000 16bit words should be faster than what I am seeing.
In perfect world, 8000 16 bit words clocked at 5MHz is 25mS. not 160mS. Is there really that much overhead? |
Well if you are gonna have to spend some time looping through your data and writing it to the SPI functions, and even those might require some under the hood assembly to ensure the byte can be written to the register, etc. None of that is free. When you put it on an oscope, is the actual SPI clock running slow? I would expect it to be right at 5MHz (with it stopping inbetween bytes) but you would probably have some overhead inbetween bytes slowing the overall payload transfer time. You can always try and reduce that per byte overhead, but you will still have to have some mostly likely. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Mon Apr 22, 2019 4:53 pm |
|
|
Writing to SPI isn't a continuous thing - the processor must fetch the next word/byte, put that into the proper register(s), transmit, repeat.
To increase speed, practically you'd need to use a processor with DMA. Not aware of any 8 bit PICs with DMA, but the 16 bit dsPICs et al definitely have it.
Edit: there now seems to be 8 bit PICs with DMA. PIC18F26K83 is an example. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19375
|
|
Posted: Tue Apr 23, 2019 3:19 am |
|
|
Yes. It is an issue with SPI, that the transmit is not buffered. So you always
have to wait for a byte to complete, before you can load the next.
One issue in the code posted, is that it has to do the array access,
_after_ it has waited for the transfer. You can speed it
a little by doing this 'while' (pointer accessed are slow):
Code: |
void SRAM_write_block2(unsigned int32 address, byte *block, int16 number)
{
// send a block of data stored at 'block'
// number is how many items to send.
int8 dummy;
if(number<1) return; // do nothing if zero items requested to send.
output_low(SRAM_CS1); // test with chip 1
spi_xfer(SPI, WRITE_CMD, 8); // send write command
spi_xfer(SPI, address, 24); // send address
// Now, loop through the data
while(--number) // do except for the last byte
{
dummy=*(block++); //preload the byte
spi_xfer(SPI, dummy, 8); // now do the wait/transfer
} // end while loop for data send
dummy=spi_xfer(SPI,*(block++),8); // send last byte
output_high(SRAM_CS1);
} // end SRAM_write_block()
|
This actually saves about 2 machine cycles per transfer. Not huge,
but possibly worthwhile. However the biggest saving here is to use
spi_write, rather than spi_xfer. Unfortunately, the ability of spi_xfer
to perform multiple byte transfers comes at the cost of having a loop
counter in the routine. Result it is several instructions less efficient
when performing single byte transfers. :(
So, though I don't actually 'like' mixing the two ways of operating,
for ultimate speed, use:
Code: |
void SRAM_write_block2(unsigned int32 address, byte *block, int16 number)
{
// send a block of data stored at 'block'
// number is how many items to send.
int8 dummy;
if(number<1) return; // do nothing if zero items requested to send.
output_low(SRAM_CS1); // test with chip 1
spi_xfer(SPI, WRITE_CMD, 8); // send write command
spi_xfer(SPI, address, 24); // send address
// Now, loop through the data
while(--number) // do except for the last byte
{
dummy=*(block++);
//spi_xfer(SPI, dummy, 8); // send each byte
spi_write(dummy);
} // end while loop for data send
dummy=spi_xfer(SPI,*(block++),8); // send last byte
output_high(SRAM_CS1);
} // end SRAM_write_block()
|
This is about 20 instructions faster per byte, than the original code!.... |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9176 Location: Greensville,Ontario
|
|
Posted: Tue Apr 23, 2019 5:02 am |
|
|
re:
Quote: | Really hate to keep going up in CPU speed. My experience has been boards and crystals get flakey the faster you go. |
This is usually down to improper design (PCB layout) and materials (thin CU, no bypass caps, etc.). When you consider the modern PC is running a LOT faster, tain't no excuse to not run the PIC at 64 Megs. |
|
![](templates/subSilver/images/spacer.gif) |
beaker404
Joined: 24 Jul 2012 Posts: 163
|
|
Posted: Tue Apr 23, 2019 10:24 am |
|
|
Thanks guys for all the input on this topic. I will be running at 60MHz once I get my 15MHz crystal in.
Side note: running at 40 MHz right now, making the speed changes to the code yielded a 930uS write time for 250 bytes down from the original 1.13mS time! savings of 200uS
For the data block I will be writing that is a time savings of 12.8mS!!!
nice tip. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9176 Location: Greensville,Ontario
|
|
Posted: Wed Apr 24, 2019 5:19 am |
|
|
hmm, for test purposes, why not use the internal osc + PLL to run the PIC at 64MHz ? While not as stable or accurate as a real xtal/2 caps, it should run fine.
Jay |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|