Direct port access / GLCD / Coding / Sanity check... (ST7565)

Hi.

I hope someone can help me, and thanks in advance for anything with this. I've just started using a ST7565 RGB LCD 128x64.

I've not really delved in to ports etc, its always something I was going to leave until I had everything else working first, and then strip the code back.

Now I'm faced with an ultra low refresh rate, which wont bode well in my design..

I'm currently working with this lib: https://github.com/adafruit/ST7565-LCD

This is the code I've identified to adjust in THIS FILE:

inline void ST7565::spiwrite(uint8_t c) {
shiftOut(sid, sclk, MSBFIRST, c);
}


}
void ST7565::st7565_command(uint8_t c) {
digitalWrite(a0, LOW);

spiwrite(c);
}

void ST7565::st7565_data(uint8_t c) {
digitalWrite(a0, HIGH);

To (something like) this:

inline void ST7565::spiwrite(uint8_t c) {
#if 0
shiftOut(sid, sclk, MSBFIRST, c);

#else 
for (byte mask = 0x80; mask != 0; mask >>= 1){
bitWrite(PORTC, 0, c & mask);
bitSet(PORTD, 4);
bitClear(PORTD, 4);
}

#endif


}
void ST7565::st7565_command(uint8_t c) {
#if 0
digitalWrite(a0, LOW);
#else
bitClear(PORTC, 3);
#endif
spiwrite(c);
}

void ST7565::st7565_data(uint8_t c) {
#if 0
digitalWrite(a0, HIGH);
#else
bitSet(PORTC, 3);
#endif
spiwrite(c);
}

I tried following this tutorial: http://jeelabs.org/2010/11/19/speedier-graphics/#comments

I uploaded as is, and get a blank display, so thought this was more than likely to do with the port assignment. (From THIS IMAGE).

For example:

bitSet(PORTD, 4);

I'm reading as digitalPin 4. (Is this correct?!)

So, I take that I need to change these assignments to the correct ones?

I haven't got any reference to what is contained in the link attached in the page, so working in the dark as to whether I'm on the right track or not.

As far as I can see, there are only 3 ports to change, which I believe to be:

PORTC, 0 PORTD, 4 PORTC, 3

From the ref HERE would be:

digitalPin 23 digitalPin 4 digitalPin 26

I have no idea what pins were used when they wrote the example. So can not be sure I'm even talking to the right ports etc.

With my set up, I'm using the following:

CS digitalPin 5 RST digitalPin 6 A0 digitalPin 7 SID digitalPin 9 SCLK digitalPin 11

Also getting confused as to what pins the functions are referring to (CS / A0 / SI).

eg.

void ST7565::st7565_data(uint8_t c) {
#if 0
digitalWrite(a0, HIGH);
#else
bitSet(PORTC, 3);
#endif
spiwrite(c);
}

I can see that they are using A0 after '#if', but unsure which 'PORTC, 3' is pointing at. I could be well off generally anyway, as it seems everyone else uses bitWrite etc in bin. Generally confused and unsure what to do, with the added fear that I'll short, brick or otherwise damage my Arduino.

Again, thanks in advance!

Sorry, TLDR!

And in particular, you are not using the convention for posting "code" sections which makes it sufficiently clear to examine that people might just delve into it.

Please RTFM and go back (yes, use that link!) and mark up each of the code sections in your post.

The "#IF 0" is basically a way to exclude the following code from compiling. With the code below:

inline void ST7565::spiwrite(uint8_t c) {
#if 0
shiftOut(sid, sclk, MSBFIRST, c);

#else 
for (byte mask = 0x80; mask != 0; mask >>= 1){
bitWrite(PORTC, 0, c & mask);
bitSet(PORTD, 4);
bitClear(PORTD, 4);
}

#endif

The compiler gets the following code:

inline void ST7565::spiwrite(uint8_t c) {
for (byte mask = 0x80; mask != 0; mask >>= 1){
bitWrite(PORTC, 0, c & mask);
bitSet(PORTD, 4);
bitClear(PORTD, 4);
}

That's about all I have because I'm having a hard time figuring out what else it is that you're asking.

Im trying to figure out the port numbers for each pin on the ST7565 so that I can change the .cpp file to directly write to the port.

Any ideas on how I can do this?

IE. in:

inline void ST7565::spiwrite(uint8_t c) {
for (byte mask = 0x80; mask != 0; mask >>= 1){
bitWrite(PORTC, 0, c & mask);
bitSet(PORTD, 4);
bitClear(PORTD, 4);
}

It states PORTC, 0 and PORTD, 4.

Does that mean pin analogPin 0, and digitalPin 4 on the UNO?

How do I tell which port belongs to:

CS digitalPin 5 RST digitalPin 6 A0 digitalPin 7 SID digitalPin 9 SCLK digitalPin 11

Take a look at this image. The PC(X) numbers in yellow indicate the PORTs.

Thank you, I think I'd seen this a while ago but had forgotten it over time.

So, at least I know I've got the right port/pin combination now! That's the sanity check out of the way..

I can see that PORTC 3 must be the A0 line for the screen. (Unless I'm well and truly lost).

Would that then mean that PORTC 0 is the Sid, PORTD 4 sclk?

I don’t know if it’s the best way but I use a set of defines to create macros for this.
Here’s an example. Mind you, these are for an Uno. They aren’t portable.

// Blink program

// Pin operation macros
#define INPUT_PORT(pin)       (pin < 8 ? PIND : (pin < 14 ? PINB : PINC))
#define OUTPUT_PORT(pin)      (pin < 8 ? PORTD : (pin < 14 ? PORTB : PORTC))
#define PIN_MASK(pin)         (pin < 8 ? 1<<pin : (pin < 14 ? 1<<pin-8 : 1<<pin-14))
#define SET_PIN(pin, level)   (level == LOW ? (OUTPUT_PORT(pin) &= ~PIN_MASK(pin)) : (OUTPUT_PORT(pin) |= PIN_MASK(pin)))


#define LED_PIN 13


void setup()
{
  pinMode(LED_PIN, OUTPUT);
}

void loop()
{
  SET_PIN(LED_PIN, LOW);
  delay(750);
  SET_PIN(LED_PIN, HIGH);
  delay(250);
}

By the way, while you can improve the speed of software SPI in various ways you'd see a much greater improvement if you used hardware SPI. Is that impossible for your setup?

If you mean MOSI/MISO/SCLK on the controller?

I'll be using these tied to other devices anyway when I've got everything else built.

I haven't tried it on those pins yet, as I was following the tutorial directly.

I'll swap over and rewrite the current code I have to see if it makes any difference..

I'm looking for the fastest way to transfer so I get a decent framerate. (I'm not concerned with other non graphic processes as I'll be using the LCD controller as a slave, and another controller to master everything else from).

Another option was for me to bit bang the data straight to the LCD from the standard MISO/SCLK pins. Would using "spi.write" be faster than using "digitalWrite"?

Yes, use SPI.transfer(). You'll still have to "bit bang" the CS line and A0 (command/data select?) but sending the byte will be faster. Also, if you're sending multiple bytes, which is pretty typical for a display, you would first set CS low, select A0 high or low, and then do multiple SPI.transfer() calls before setting CS high again. In my own display code the speed difference between software SPI and hardware SPI is about a factor of 10. Much quicker.

Awesome!

That's basically what I am trying to do, get a x10 faster refresh rate.

Still not 100% about port/code side in the .cpp, but this will be enough just to get things sped up.

It's a bit late here, so won't be able to double check everything tonight, but will tomorrow, then, once that's in the bag, I will give DPA another shot (at least that means I can get most of the other bits done, once I've got this method successful.

I'll keep you posted!

Best regards!