SPI Speed

24 Nov 2010

I have installed a Graphics display with a SPI interface

SPI spi(p5, p6, p7); // mosi, miso, sclk

spi.format(8,3);

spi.frequency(4000000);

which uses the spi.write(xxxx) functions .

The same Display is running with an Arduino at a very high display speed. With the mbed its speed is very low when writing on the screen.

Can someone tell me how to speed up the SPI communications?

25 Nov 2010

Hi

From the NXP data sheet section 7.17.1, the SPI has a "maximum data bit rate of one eighth of the input clock rate".

The mbed schematic states 12MHz input, so this imples max SPI at 1.5 M bits/s.

 

Regards

Wayne

 

25 Nov 2010 . Edited: 25 Nov 2010

erm, that can't be correct. I have MAX7456 OSD chips running at 10MHz (verified with a scope) and flash chips running significantly higher.

edit: the schematic shows a 12MHz xtal, but internally the PLL ramps that up to 96MHz I believe.

25 Nov 2010

You are right Andy, the SPI clock is derived from the system clock, not the input clock.

25 Nov 2010

Thanks for correcting that guys, I was worried that would limit some other applications.

Any thoughts for setting it up for the Original Poster?

Cheers

W

25 Nov 2010

Well, we'ed need more information like, what type of display is it? Can he publish his code for review?

25 Nov 2010

No Problem. It is a Siemens S65 (LS020) Display. My fault that i did not mention it.

My h file

#ifndef S65LCD_H
#define S65LCD_H

 
//----- DEFINES -----
//declared in S65LCD.cpp
//#define LCD_MIRROR         //mirror the display
//#define LCD_ROTATE         //define to rotate the display

#define RGB(r,g,b)           (((r&0xF8)<<8)|((g&0xFC)<<3)|((b&0xF8)>>3)) //5 red | 6 green | 5 blue


//----- GLOBALS -----

extern void s65lcd_init(void);
extern void s65lcd_clear(unsigned int color);
extern  void s65lcd_cursor(unsigned int x, unsigned int y);
extern void s65lcd_area(unsigned int x0, unsigned int y0, unsigned int x1, unsigned int y1);
extern void s65lcd_drawPixel(uint8_t x0, uint8_t y0, uint16_t color);
extern void s65lcd_fillRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color);
extern void s65lcd_drawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color);
extern void s65lcd_drawRect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t color);
extern void s65lcd_drawCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color);
extern void s65lcd_fillCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color);
extern unsigned int s65lcd_puts(unsigned int x, unsigned int y, const char *s, unsigned int font, unsigned int size, unsigned int color, unsigned int bgcolor);
extern void s65lcd_putline(unsigned int x, unsigned int y, const char *s, unsigned int font, unsigned int size, unsigned int color, unsigned int bgcolor);

#endif //

My source file excerpt of the main init routines:

#include "mbed.h"
 

// ------------------------------
// * Siemens S65 Display  
// ------------------------------
#include "font_8x8.h"   // font1
#include "font_8x12.h"  // font2
#include "font_16x20.h" // font3


//-----S65 DISPLAY ROUTINES -----

SPI spi(p5, p6, p7); // mosi, miso, sclk
   
   
#define LCD_MIRROR          //mirror = encoder right else left
//#define LCD_ROTATE        //rotate = 132 x 176 default = 176 x 132
#if defined(LCD_ROTATE)
# define LCD_WIDTH           (132)
# define LCD_HEIGHT          (176)
#else
# define LCD_WIDTH           (176)
# define LCD_HEIGHT          (132)
#endif

DigitalOut LCD_RST(p20);
DigitalOut LCD_CS(p17);
DigitalOut LCD_RS(p30);

DigitalOut S65_CLK(p7);
DigitalOut S65_DAT(p5);

 

void s65lcd_cmd(unsigned int reg, unsigned int param)
{
  LCD_RS = 1; //cmd
  LCD_CS = 0;
  spi.write(reg);
  spi.write(param);
  wait_ms(1);
  LCD_CS = 1;

  return;
}

void s65lcd_data(unsigned int c)
{
  LCD_RS = 0; //data
  LCD_CS = 0;
  spi.write(c>>8);
  spi.write(c);
  wait_ms(1);
  LCD_CS = 1;

  return;
}

void s65lcd_init(void)
{
  // Setup the spi for 8 bit data, high steady state clock,
  // second edge capture, with a 4MHz clock rate
  spi.format(8,3);
  spi.frequency(4000000); 
 
  //reset
  LCD_CS = 1;
  LCD_RS = 1;
  LCD_RST= 0;
  wait_ms(50);
  LCD_RST = 1;
  wait_ms(50);
  LCD_CS = 0;

  s65lcd_cmd(0xFD, 0xFD);
  s65lcd_cmd(0xFD, 0xFD);

  wait_ms(50);

  //init 1
  s65lcd_cmd(0xEF, 0x00);
  s65lcd_cmd(0xEE, 0x04);
  s65lcd_cmd(0x1B, 0x04);
  s65lcd_cmd(0xFE, 0xFE);
  s65lcd_cmd(0xFE, 0xFE);
  s65lcd_cmd(0xEF, 0x90);
  s65lcd_cmd(0x4A, 0x04);
  s65lcd_cmd(0x7F, 0x3F);
  s65lcd_cmd(0xEE, 0x04);
  s65lcd_cmd(0x43, 0x06);

  wait_ms(7); //important: 7ms

  //init 2
  s65lcd_cmd(0xEF, 0x90);
  s65lcd_cmd(0x09, 0x83);
  s65lcd_cmd(0x08, 0x00);
  s65lcd_cmd(0x0B, 0xAF);
  s65lcd_cmd(0x0A, 0x00);
  s65lcd_cmd(0x05, 0x00);
  s65lcd_cmd(0x06, 0x00);
  s65lcd_cmd(0x07, 0x00);
  s65lcd_cmd(0xEF, 0x00);
  s65lcd_cmd(0xEE, 0x0C);
  s65lcd_cmd(0xEF, 0x90);
  s65lcd_cmd(0x00, 0x80);
  s65lcd_cmd(0xEF, 0xB0);
  s65lcd_cmd(0x49, 0x02);
  s65lcd_cmd(0xEF, 0x00);
  s65lcd_cmd(0x7F, 0x01);
  s65lcd_cmd(0xE1, 0x81);
  s65lcd_cmd(0xE2, 0x02);
  s65lcd_cmd(0xE2, 0x76);
  s65lcd_cmd(0xE1, 0x83);

  wait_ms(50);

  //display on
  s65lcd_cmd(0x80, 0x01);
  s65lcd_cmd(0xEF, 0x90);
  s65lcd_cmd(0x00, 0x00);

  //display options
  s65lcd_cmd(0xEF, 0x90);
#if defined(LCD_ROTATE)
# if defined(LCD_MIRROR)
  s65lcd_cmd(0x01, 0xC0); //x1->x0, y1->y0
  s65lcd_cmd(0x05, 0x00); //0x04=rotate, 0x00=normal
# else
  s65lcd_cmd(0x01, 0x00); //x0->x1, y0->y1
  s65lcd_cmd(0x05, 0x00); //0x04=rotate, 0x00=normal
# endif
#else
# if defined(LCD_MIRROR)
  s65lcd_cmd(0x01, 0x80); //x0->x1, y1->y0
  s65lcd_cmd(0x05, 0x04); //0x04=rotate, 0x00=normal
# else
  s65lcd_cmd(0x01, 0x40); //x1->x0, y0->y1
  s65lcd_cmd(0x05, 0x04); //0x04=rotate, 0x00=normal
# endif
#endif
  s65lcd_area(0, 0, (LCD_WIDTH-1), (LCD_HEIGHT-1));

  return;
}


void s65lcd_draw(unsigned int color)
{
  spi.write(color>>8);
  spi.write(color);
 
  return;
}

void s65lcd_drawstop(void)
{
  wait_ms(1);
  LCD_CS = 1;
 
  return;
}


void s65lcd_drawstart(void)
{
  LCD_RS = 0; //data
  LCD_CS = 0;
 
  return;
}

With this the Display is working alright, only the speed is very low.

 

25 Nov 2010

had the same problem with the embedded artist's OLED but after changing the spi speed from it's 1 MHz default to ( _spi.frequency(4000000); ) within Simons EAOLED driver the display text appears very fast now.

25 Nov 2010

Thanks Franz but as you can see in s65lcd_init routines i already have a spi.frequency of 4MHz. Still the display is very slow.

25 Nov 2010

void s65lcd_data(unsigned int c)
{
  LCD_RS = 0; //data
  LCD_CS = 0;
  spi.write(c>>8);
  spi.write(c);
  wait_ms(1); 
  LCD_CS = 1;

  return;
}

Hello voy,

do you need this "wait_ms(1)" ?

br

Franz

25 Nov 2010

Hi Franz,

fantastic idea. After removing all wait_ms(1) entries the display is now writing faster but still not reaching the speed of the Arduino. Altough the wait cycle is implemented in the Arduino source.

25 Nov 2010

maybe you have to do some more research work at your code. Optimizing it :-)

br

Franz

25 Nov 2010

I am just working on optimization.

Thanx

Voy

29 Nov 2010

Hi Voy ager,

Have you looked at the specs of the datasheet around the clock frequency of the of the screen? Or what frequency you are running it in your previous example?  

Perhaps try setting the frequency to e.g. 12MHz and see if that works?

Simon

29 Nov 2010

Simon

I have already increased the  spi.frequency from 4 to 8Mhz. The display is a bit faster now. I'll increase it once again to your suggestion and see if it is working better.  Datasheets from Siemens are not available. I have to do the reengineering myself. But i think i am on the right way.

Thanx

Voy