Jim's Graphic LCD Problem

Here’s what I have so far:

The code I have can draw pixel, lines(Using bresenham line algorithm), and rectangles. Until i figure out this screen section problem i’m going to hold off on filled rectangles and circles
st7920.zip (1.88 KB)

I think you will need to take a different tactic to do your drawing stuff. That is holding a complete off screen bitmap of the display will eat up your entire RAM, which won’t work.

What I think you should do instead is make use of the display memory directly. That is when you wish to set a pixel, you first read in the appropriate byte or word from the display memory using the RW IO line to the display… Doing a quick look around, I think the library mentioned in: arduino.cc/playground/Code/GLCDks0108
Has all of the pieces for doing a lot (if not all of this). I did not check carefully enough to see if your display is supported or not, but it does show things like reading/writing and the like, plus has filled rectangles and the like…

Kurt

Wouldn’t doing a read for every pixel that needs changed require a lot of time? plus adding the RW ability uses another pin. I suppose though that if it’s the best way then Jim will have to make do with it :smiling_imp:

Timing wise, it depends. Yes if you are doing a lot of random bits at a time it can add up. But if you are drawing things like Horizontal lines, including such things like filled rectangles. You can do it pretty smartly. That is if for example if you are filling bits 4-40 on a line, you could have the code, figure out that the write did not start on an 8 bit boundary, which would require a read/update/write. (assuming 0 based). In this case we would read in to get the state of bits 0-7, then or in a 1 for bits 4-7 and do the write. We would then know we could simply output 0xff for bits 8-15, 16-23, 24-31, 32-39. Then we find we did not end on the end of a 8 bit boundary, so we would again have to read/update/write (Read in bits 40-47), Then set bit 40 and write the byte back out…

P.S - Also you can do some caching in the code to know which byte of data you last read in…

Kurt.

Well i’m reading 8 bits at a time now from the on screen RAM. Now to implement this method into my drawPixel() function and all of my code will be using the new method of drawing! 8)

Kurt,

Here’s the piece of code i’m using to read in bytes:

byte read8bits(byte x, byte y)
{
  byte ByteBuffer = 0;
  y |= 0x80;       //Set GDRAM Address
  x |= 0x80;       //
  command(y);   //
  command(x);   //
  digitalWrite(rw_pin, HIGH); //Get Ready for the DUMMY READ
  digitalWrite(rs_pin, HIGH); //
  pulseEnable();              //Do a DUMMY READ nibble 1
  pulseEnable();              //nibble 2 of DUMMY READ
  digitalWrite(enable_pin, HIGH); //Get ready to read the high nibble
  for(int i = 4; i < 8; i++)
  {
    pinMode(data_pins*, INPUT);
    Serial.println(digitalRead(data_pins*) << i, BIN);
    ByteBuffer |= digitalRead(data_pins*) << i;
  }
  Serial.println(ByteBuffer, BIN);
  digitalWrite(enable_pin, LOW); // done with the high nibble
  delayMicroseconds(110);        //don't know if this delay should be here or not
  digitalWrite(enable_pin, HIGH);//get ready to read the low nibble
  for(int i = 0; i < 4; i++)
  {
    Serial.println(digitalRead(data_pins*) << i, BIN);
    ByteBuffer |= digitalRead(data_pins*) << i;
  }
  Serial.println(ByteBuffer, BIN);
  digitalWrite(enable_pin, LOW); // Done Reading
  digitalWrite(rw_pin, LOW);      //
  digitalWrite(rs_pin, LOW);       //
  return ByteBuffer;
}

For some reason the code returns a flipped hex value every time the arduino resets.
For example:

I write 0x42 to the address (0x00, 0x00); read from address (0x00, 0x00) returns 0x42; reset; write 0x42; read returns 0x24; reset; write 0x42; read returns 0x42; etc...

this happens with any byte i write to the display so it’s doing something right because the right data is there, it’s just getting shifted around.
Any problems you see immediately that could be causing this? I’m at a loss here.*****

Quick guess is you are reading nibbles in the reverse order. That is you are reading most than least,but looks like least than most.

Also I doubt you need any delay here as that is the delays are to allow previous commands to complete. Now that you have a read line you can potentially change your code to get rid of long delays and instead read the busy flag…

Also once you have this working the way you like, you have lots of options to improve the performance. Things like, right now you set the pins to digital every time you output a nibble. You could instead remember which state you were in and only set to input or output when you need to… Your Pulse enable sets to low, then high then low. You can get rid of the first low. You would need to set it low in the init function… But again, I would not worry much about speeding things up, until you get things working the way you like. You may not even need to as I know that a lot of this came from a standard library (LiquidCrystal).

If you don’t mind becoming hardware dependent and fix the connections to the LCD to fixed pin numbers, you can also gain performance. This is what several of the shields and the library that I posted a link to. Example you are using pins D8-11 as your 4 data lines. Probably because some of the others did? Why could this be interesting? Because they map to the underlying ATMega328 pins PB0-3. Which is the 4 lower bits of an IO port. (arduino.cc/en/Hacking/PinMapping168) . So in theory you could instead simply read in the port, and it with 0xf0 and or it with your nibble and write it out… Likewise for reads, you could simply read the port and and it with 0xf and return it… I can give you more details if you like, but the very big downside is that it makes the code to be dependent on the exact hardware. In some other libraries, I have gone to a middle ground, where I map the Arduino pin to the port/bit inside the init function and then set/clear them with real simple inline functions… About 4 times faster…

Kurt

The problem is that the nibbles reverse order on every reset of the arduino. That’s what is confusing me here. Timing wise there is a lot that i can do to speed things up. I probably will make this hardware specific when i’m done but we’ll have to wait until i’ve got everything running the way i want

I think the problem is the display is incrementing the AC everytime i do a read. I think i need to read in 16 bits at a time to fix this so that i can not worry about incrementing the AC for the second 8 bits. What would be the best way to return two individual bytes from a function? using a struct or an array?

I figured out that the reversing problem is with the display. If I tie the display’s reset line to the arduino’s then it reads correctly every time the arduino resets.

Good work!

Kurt

I’m back to drawing things however I’m am now using the onscreen RAM!! 8)
I’m currently getting a horrible full screen refresh rate so i think it’s time to start checking the busy flag and start working on port manipulation to get the delays as small as possible.

Here’s what i have so far.

My code can draw Little text both positive and negative. Circles, lines, and rectangles.

Currently the only thing i’m unhappy with is that to draw little text the program must draw the entire line thereby erasing everything in the way. I wish to make it read in the pixels at the beginning and end of the string and then only draw the area the text takes up.


st7920_3_2.zip (4.47 KB)

Sounds like good progress here.

Hi Guys,

Yesterday I played a bit with this display. I’m still figuring out how to connect it. The manual says that the display supports 3 interfaces. 8 bits parallel, 4 bits parallel and clock synchronized serial. I’m aiming for the last one since it takes up less I/O.

In the paragraph “serial interface” (page 24) it says that the pins used for serial are:

  • PSB (needs to be down for serial)
  • SCLK (clock)
  • SID (Data)
  • CS (needs to be high when receiving data)

When looking at the “Interface description” (page 7), non of those pins are mentioned??
Only the pins needed for the parallel interfaces are in there.

In the “serial interface” paragraph they mention a MPU. looking at the “Block Diagram” I see the MPU drawn as a separate module. If it is, the serial interface is a separate module and the display does not support this. So it shouldn’t be in the manual. But the needed pins are not mentioned elsewhere in the manual.

Can one of you guys clarify this for me??

Thanks!

Xan

Sorry, I dont have one…

Kurt

The display does support clocked serial via a solder jumper but i’ve never used it in that way before. I do see what you mean by the lack of information in the manual. You might have to contact Crystalfontz to get the information you need.

From what i’ve read the serial interface is terribly slow. I would recommend using the display in combination with a 74HC595 and a 74HC166. By using the two shift registers you can control the display in 8-bit mode while only using five dedicated pins. You would actually be using eight pins however three of the display pins may be reused when ever your controller isn’t writing to the display.

I’ve uploaded the header files from my remote code that control the display. All the information you need to set up the circuit is in the main ST7920.h file. These are Arduino files by the way.

By now i pretty much know this display all around so feel free to ask any questions… Keeping in mind that all the code i’ve written for it is in C++, not basic.
Symbols.h (7.46 KB)
ST7920.h (10.6 KB)

Devon,

Thanks for the head’s up. I still think it’s pretty strange the manual isn’t clear about the serial solution. I like your idea about adding the shiftregister’s. I think I’ll go with the same solution. :slight_smile:

Thanks, Xan

Hi Devon,

After some fiddling I’m able to get some text on the display. But the only thing I get is the Big Text…
I also have no idea what the array’s in the symbols.h file represent.
Could you give me some heads up on that?

Thanks, Xan

Hi Devon,

I’ve got your code to work. I think I’m using a different chip (Arduino Mege 2560) so I had to reroute the used PortE to some separate pins.

I had the same horrible refresh rate as you mentioned before. When reading trough the datasheet I noticed that the GRAM, used to print the small font, also has and internal address counter. The address will inclement after writing the data bits. The address will only increment on the X direction. I changed your code that the position will only be send once a row. This strongly increases the refresh rate.

Here is the code.

[code]// Writes a group of 1x16 pixels on the given x, y position
// LCD will automatically increase the X address counter.
// At the end of the line X = 0x0F the position needs to be written again
void drawPixelGroup(byte x, byte y, byte value1, byte value2)
{
x |= 0x80;
y |= 0x80;
command(y);
command(x);
data(value1);
data(value2);
}

// Writes a group of 1x16 pixels on the current address counter.
// LCD will automatically increase the X address counter.
// At the end of the line X = 0x0F the position needs to be written again
void drawPixelGroup(byte value1, byte value2)
{
data(value1);
data(value2);
}

// Writes small text 8x8 bits using GDRAM
void writeLittleText(int x, int y, String string, boolean invert)
{
int xpos;
int ypos;
char carray[string.length() + 1];
string.toCharArray(carray, string.length() + 1);

//prep line buffer
for(int i = 0; i < 128; i++)
{
LineBuffer* = 0;
}

for(int i = 0; i < string.length(); i++)
lcdPlaceCharacter(0, i + x, carray*);

command(0x26); // turn on extended instructions
for(int x = 0; x < 64; x++)
{
xpos = x%8;

if (xpos == 0) // include position
{
  // Recalculate position
  ypos = x/8 + y*8;
  if(ypos > 31)
  {
    ypos -= 32;
    xpos += 8;
  }
  if (invert)
    drawPixelGroup(xpos, ypos, ~LineBuffer[x*2], ~LineBuffer[x*2+1]);
  else
    drawPixelGroup(xpos, ypos, LineBuffer[x*2], LineBuffer[x*2+1]);
}
else
{
  if (invert)
    drawPixelGroup(~LineBuffer[x*2], ~LineBuffer[x*2+1]);
  else
    drawPixelGroup(LineBuffer[x*2], LineBuffer[x*2+1]);
}

}
}[/code]

The current code always writes a whole row of chars.
Each row of chars is 8 pixels high. To send one pixel row, 16 bits for the address and 265 bits for the pixels needs to be send.

There are some options to further increase speed.

  1. We could only send the chars needed. Now the whole line is send. But since the font is dived in blocks of 6 pixels wide and the display needs blocks of 16 bits we will get a strange overlap.

  2. We could cache the current status of the pixels in the microchip. Then compare the pixelgroup (1x16 bits) and only send them when needed. But then the pixelgroup also needs an address. This is good for small updates. Not for a whole line.

Currently the speed is very good. So I will keep it like this. This is more of a note for myself :slight_smile:**