[SOLVED] Replacing shiftOut with hard SPI

Hello,
I'm tweaking the nokia 5110 LCD's library from adafruit for more performance. To do so, I want to replace the shiftOut with hardware SPI.
The original working code is :

inline void Adafruit_PCD8544::fastSPIwrite(uint8_t d) {
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
    *clkport &= ~clkpinmask;
    if(d & bit) *mosiport |=  mosipinmask;
    else        *mosiport &= ~mosipinmask;
    *clkport |=  clkpinmask;
  }
}
//a slower alternative :
inline void Adafruit_PCD8544::slowSPIwrite(uint8_t c) {
  shiftOut(_din, _sclk, MSBFIRST, c);
}

(line 192 Adafruit-PCD8544-Nokia-5110-LCD-library/Adafruit_PCD8544.cpp at master · adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library · GitHub, shiftOut alternative line 202)

So I replace it by (I renamed the library Gamebuino_screen, but don't care about that)

void Gamebuino_screen::begin(uint8_t contrast) {
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV64); //to have the same clock speed than the "software" SPI
  SPI.setDataMode(SPI_MODE3);
[...]
}

inline void Gamebuino_screen::fastSPIwrite(uint8_t d) {
  SPI.transfer((char)d);
}

And the screen acts weirdly... Here is a video :

The image moves to the right at each frame.
Something strange : if I bridge the pins DC & DIN (MOSI) with my finger, the image stops moving, but the menu's text is not vertically aligned as it should.

So what's the difference between the software SPI above and the hardware SPI ? Please help me :frowning:

  SPI.setDataMode(SPI_MODE3);

As a quick test, try different modes (eg. 0, 1, or 2).

I already tried it, only mode 0 & 3 display something (but with the same weird horizontal scrolling).
Mode 3 is for data on rising clock and clock at high level when idle. It makes sense that only this mode works, if you look at the working code : the data is set, and then the clock is raised. And once the transmission is done, it remains high. Arh, it's strange...
I found that library that uses the hardware SPI, and I tried the same settings... it still doesn't work.
https://github.com/energia/Energia/tree/master/examples/7.Display/LCD_5110_SPI

Try taking chip select low at the start of each byte, and high again after it. That might help synchronize the bytes. (In other words, on each side of the SPI.transfer).

Hem... the CS is always low :roll_eyes:... but it works with the soft SPI library :frowning:
I give it a try, thank you for your feedback ! But the hardware SPI should do exactly the same thing than shiftOut, isn't it ?
I just saw that adafruit and the hard SPI library doesn't init with the same bytes... I'm dipping in the datasheet to see what's behind that.

By the way, the datasheet says 4Mbit/s max, so I won't be able to communicate at full speed (8Mhz on a 16Mhz atmega). Bad news, as I'm designing a portable console, and I need the more free processing time I can get.

Rodot:
I give it a try, thank you for your feedback ! But the hardware SPI should do exactly the same thing than shiftOut, isn't it ?

Exactly the same thing, except the speed. And the speed might be what is causing it. That is, timing errors are more likely to manifest themselves if you are shoving out data quickly.

Rodot:
Something strange : if I bridge the pins DC & DIN (MOSI) with my finger, the image stops moving, but the menu's text is not vertically aligned as it should.

Sounds like a floating input somewhere.

I totally agree with you, but the SPI port uses internal pull up, isn't it ?

That's why I've set the clock divider to have the same clock frequency than with software SPI (measured with a oscilloscope).

I'll look further tonight, 'cause I've to go to school for a Test :sweat_smile:

PROBLEM SOLVED !!!
The DC (select between Data / Command) pin of the screen was connected to the pin 12 of the arduino. What wrong with that ? That's the MISO pin ! So the SPI library was setting it as an input, while the LCD library was setting it as an output. Input = high z = floating, that's why the screen was behaving differently when I touched the DC pin. Sorry for annoying you Nick Gammon :blush:

Edit : even with clock divider set to 4 (default), the communication with the screen is 16 time faster than before ! It represents 30% more of free cpu for my console running @ 20FPS. Greaaat ! :smiley: I've done some other tweaks, and added new functions (rotated sprites for example, very useful for games). I'll post the library soon

Rodot:
I totally agree with you, but the SPI port uses internal pull up, isn't it ?

Not that I am aware of.

the communication with the screen is 16 time faster than before !

Great. Glad you worked it out. :slight_smile: