Slow SPI

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Slow SPI

2,234 Views
kapsel
Contributor I
Hi
I'm curently using MC9S12NE64 (25Mhz oscilator + PLL configured by OpenTcp, SS pin not used from oryginal interface but connectec to one of PORTH's pins) with OpenTcp additional I wrote MMC suport based on SPI interface. Everything work's fine but it's slow... Acording to Datasheet my bound rate schould be 12Mhz but i'm geting about 245 kHz. I hope someone can help me becouse I have no ideas what could be wrong.

My SPI code:
#pragma CODE_SEG __NEAR_SEG NON_BANKED

void Init_spi(void)
{
DDRS_DDRS6=1;
DDRS_DDRS5=1;
CS_DIR=1;
PIEH=0x00;
SPICR1=0b01010000;
SPICR2=0x00;
//SPIBR=0b00010101;
SPIBR=0x00;

}

#pragma MESSAGE DISABLE C4000
tU08 send_byte(tU08 bajt)
{
while (SPISR_SPTEF==0);
SPIDR=bajt;
do
{
if (SPISR_SPIF==1)
return SPIDR;
} while (1);
}

#pragma MESSAGE DEFAULT C4000

#pragma CODE_SEG DEFAULT

Test procedure ( run_count is incremanted Every 1ms by internal timmer) :

extern unsigned long run_count;

volatile unsigned long start,stop,count;
start=run_count;
for (count=0;count1048576;count++)
send_byte(0xAA);
stop=run_count-start;

PLL config:
RTICTL = 44;
CLKSEL_PLLSEL = 0; /* Select clock source from XTAL */
SYNR = 0; /* Set the multiplier register */
REFDV = 0; /* Set the divider register */
PLLCTL |= 112; /* PLLCTL: PLLON=1,AUTO=1,ACQ=1 */
while(!CRGFLG_LOCK); /* Wait */
CLKSEL_PLLSEL = 1; /* Select clock source from PLL */


Thx for any help
Regards Kapsel

Message Edited by kapsel on 2006-11-2601:17 PM

Message Edited by kapsel on 2006-11-2601:17 PM

Labels (1)
0 Kudos
4 Replies

471 Views
bigmac
Specialist III
Hello Kapsel,
 
If my understanding is correct, your measurement of 245 kHz may refer to the data throughput rate and not the SPI clock rate.  The SPI clock signal will only occur as each byte is transferred, and will cease between bytes.  With the code you are using, the period between bytes may well exceed the period of the actual transfer.
 
You can speed throughput up a little bit by modifying your code as shown below.  This might also eliminate the need for the MESSAGE DISABLE pragma.
 
tU08 send_byte(tU08 bajt)
{
  while (SPISR_SPTEF == 0);
  SPIDR = bajt;
  while (SPISR_SPIF == 0);
  return SPIDR;
}
 
Your test loop is also likely to require significant additional overhead that will reduce the overall throughput.
 
Regards,
Mac
 
0 Kudos

471 Views
kapsel
Contributor I
Hello bigmac,

You are right that the overhead added by my test procedure is quite large. I wrote a new one :

void TestSPI()
{
// call's 16*65535 send byte
_asm
{
LDY #16
LDX #65535
loop: LDAB #170
JSR send_byte
DEX
CPX #0
BNE loop
DEY
CPY #0
BNE loop
RTC
}
}

Using this one I got data throughput 520kHz. So the main idea is to optimize my code using assembler to maximize throughput.
But when I think about it's still quite a big difrence betwen expected throughput and the one I got. SPI uses bus clock (25Mhz) my core clock schoud be 50Mhz from the pll. When i look at the assembly of my code there are just few instructions betwen each byte send so they shouldnt put such a big deley between bytes. Acutaly the delay schuld be minimal or am I missing something?

PS sory for the poor english...
PS2 Thx for bigmac for the quick response

Regards Kapsel
0 Kudos

471 Views
bigmac
Specialist III
Hello Kapsel,
 
With a 25 MHz bus frequency, the maximum SPI clock frequency setting will be 12.5 MHz.  However, the transfer of each byte will require 8 clock cycles - I wonder if this fact has been overlooked.  If my rough calculation is correct, your 520 kHz throughput rate suggests a total overhead of about 32 bus cycles for each SPI byte sent (the actual data transfer requires an additional 16 bus cycles).  Any improvement on this is likely to be marginal.
 
What throughput rate (bytes per second) do you actually need to achieve?
 
The send_byte function might be further simplified, with the assumption that the transmit buffer will be empty whenever the function is entered, and its state would not need testing - this assumption would apply to your present test code.
 
tU08 send_byte(tU08 bajt)
{
  SPIDR = bajt;
  while (SPISR_SPIF == 0);
  return SPIDR;
}
 
For any further improvement, you would need to consider use of assembly code for this function.  Have you examined the disassembled code that the C function produces?
 
Regards,
Mac
 
0 Kudos

471 Views
kapsel
Contributor I
Hi
My goal is to reach maximum transfer rate for openTCP stack(acording to my test's about 200kb/s) from mmc.
The problem is that excepy SPI code i have my own MMC and FAT32 code wich puts quite a delay( i'v could wrote it better but i'm a little lazy.. :smileywink:). On top of that is a ftp and http serwer. My oryginal asumption was that I would get at least 1Mhz throughput rate from SPI and the delay from the rest of the code would give mi a throughput of about 300 kb/s while reading a file using my fat system. It looks i was wrong...

Further optimization of send_byte acording to me is not posible. Curently asembly of send_byte consists of 3 assembler instructions (BRCLR,STAB,LDAB). Optimization you sugestested in your previous post works after adding "while (SPISR_SPTEF == 0);" to Init_spi.

I already have about 110kb/s from my ftp serwer. Additional optimization to my mmc and fat code is posible so I hope I can squeeze 200kb/s from it... :smileyhappy:

Thx for help and I hope I can manage on my own now...

Regards,
Kapsel
0 Kudos