Controlling a PG320240H-P9 with a dsPIC33FJ128GP802

Sunday, 21st March 2010

In a previous entry I mentioned that I had purchased a PG320240H-P9 graphical LCD. This is a 320×240 white-on-blue pixel display, and it does not have an on-board controller or RAM. To display something on it you need to constantly refresh it with picture data; in this instance, sending four pixels at a time, starting from the top left and working from left to right, top to bottom — a bit like the scanning pattern of a CRT monitor.

FFC adaptor.

Connecting a circuit to the LCD is made slightly more tricky by its use of a 16-pin 1mm flexible flat cable. To get around this I soldered together an adaptor using a suitable FCC connector, pin strip, piece of stripboard and a fairly excessive quantity of hot melt adhesive. Even more tricky was the lack of a suitable datasheet for the LCD. After some digging I located this one for the PG320240WRM-HNNIS1 — it's slightly different, but contains timing diagrams and specifications that seem to work with the LCD I bought. One thing I still haven't worked out is the contrast adjustment; a 5K variable resistor between 0V and the relevant pin seems to have had the best results thus far. A helpful webpage, Graphical LCD controller for ST8024+ST8016 based displays, has a plain English description of how to drive the LCD, though as far as I'm aware the M pin should have its logic level toggled every frame, giving you a "glass" frequency of half of the refresh rate, not 200Hz-400Hz. The lack of a proper datasheet makes these things a little complicated!

LCD driven by an ATmega644P, showing a picture of a cat.

My first attempt to drive the LCD involved an ATmega644P, a microcontroller with 64KB of flash ROM and 4KB of RAM. The above photo shows it displaying a picture of a cat, which was stored in ROM and output using the following code:

#include <stdint.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define LCD_FLM   (6)
#define LCD_M     (5)
#define LCD_C1    (4)
#define LCD_C2    (3)
#define LCD_D_OFF (2)

#define LCD_CONTROL_PORT (PORTC)
#define LCD_CONTROL_PIN  (PINC)
#define LCD_CONTROL_DDR  (DDRC)

#define LCD_DATA_PORT    (PORTA)
#define LCD_DATA_PIN     (PINA)
#define LCD_DATA_DDR     (DDRA)

#include "cat.h"

int main(void) {

    // Make control pins outputs.
    LCD_CONTROL_DDR |= _BV(LCD_FLM) | _BV(LCD_M) | _BV(LCD_C1) | _BV(LCD_C2) | _BV(LCD_D_OFF);
    
    // Make data pins outputs.
    LCD_DATA_DDR |= 0b1111;
    
    // Enable the LCD.
    LCD_CONTROL_PORT |= _BV(LCD_D_OFF);
    
    for(;;) {
    
        // Toggle the M pin to provide the LCD AC voltage.
        LCD_CONTROL_PIN |= _BV(LCD_M);
        
        const uint8_t* picture_ptr = cat_picture;
    
        // Scan 240 rows in the image.
        for (uint8_t row = 0; row < 240; ++row) {
        
            // Begin the line.
            LCD_CONTROL_PIN |= _BV(LCD_C1);
            LCD_CONTROL_PIN |= _BV(LCD_C1);

            if (row < 2) LCD_CONTROL_PIN |= _BV(LCD_FLM);
            
            // Send 40 eight-bit words.
            for (uint8_t column = 0; column < 40; ++column) {
                LCD_DATA_PORT = pgm_read_byte(picture_ptr) >> 4;
                LCD_CONTROL_PIN |= _BV(LCD_C2);
                LCD_CONTROL_PIN |= _BV(LCD_C2);
                LCD_DATA_PORT = pgm_read_byte(picture_ptr);
                LCD_CONTROL_PIN |= _BV(LCD_C2);
                LCD_CONTROL_PIN |= _BV(LCD_C2);
                ++picture_ptr;
            }
        }
    }

}

A 320×240 display has 76,800 pixels, and if you store each pixel as a single bit (so eight pixels per byte) you need 9600 bytes to store a complete frame, which clearly won't fit in the 4KB offered by the ATmega644P. Rather than upgrade to an AVR with more memory, I jumped to the dsPIC33FJ128GP802, a 16-bit microcontroller with 16KB of RAM. As well as quadrupling the RAM from the ATmega644P it also doubles the program memory (128KB from 64KB) and speed (40 MIPS from 20 MIPS). When working with AVRs I'd been using a slow home-made serial programmer, and rather than continue with this sorry state of affairs (lack of debugging capabilities is never fun, especially when it takes over a minute to program the microcontroller) I treated myself to a PICkit 3 Debug Express.

dsPIC33FJ128GP802 controlling the PG320240H-P9

The above photo shows the LCD connected to the microcontroller as well as the PICkit 3. The dsPIC33FJ128GP802 requires a voltage supply from 3.0V to 3.6V, not the 5V I am used to, so to power it I have put two IN4001 rectifier diodes in series with the 5V regulator output. Each diode incurs a voltage drop of 0.7V, producing 3.6V for the rest of the circuit. The LCD is powered from the main 5V supply, but it seems happy with the 3.6V logic "high" from the dsPIC.

The LCD is connected to the dsPIC as follows:

  • FLM to RB15
  • M to RB14
  • C1 to RB13
  • C2 to RB12
  • /D_OFF to RB11
  • D0~D3 to RA0~RA3

A 10K resistor is included between /D_OFF and ground. This is very important, as it holds the /D_OFF line low when RB11 is floating (e.g. during reset), forcing the display off — if the display is powered, but is not being actively refreshed, the LCD panel can become overloaded and damaged.

I have knocked together a simple demo that shows a few different graphics on the LCD. The LCD is constantly refreshed by an interrupt service routine that runs in the background, leaving some CPU time to the user program. As there is only enough RAM for a single frame buffer, animation has to be quite simple to avoid flickering, but I've still managed to include my favourite spinning cube.

The project can be downloaded here. I'm still getting to grips with the dsPIC series; the code is likely to be pretty awful, and I still have a problem where the dsPIC resets itself every couple of minutes (I'm not really sure if this is a software or hardware issue). Still, it's a start, and I hope that I can use this LCD as the display for my Z80 computer project.

Update: Having seen this post, the chap who originally suggested that I investigate the dsPIC33FJ128GP802 sent me an email with some advice, chiefly about my poor power supply, missing decoupling capacitors and use of an electrolytic capacitor on the VCAP pin. I have since replaced the two rectifier diode affair with a proper 3.3V regulator for the power supply, added a decoupling capacitor across AVDD/AVSS and moved the decoupling capacitor between VDD/VSS closer to the microcontroller. I have also ordered some tantalum capacitors to replace the electrolytic one. A bit of debugging found that the watchdog timer is responsible for the spurious resets; I have disabled it in the code for the time being, which has stopped the resets.

Adding more stereoscopic modes to Quake II's OpenGL renderer

Thursday, 11th March 2010

Quake II's OpenGL renderer supports stereoscopic rendering providing you own a video card that has the requisite hardware and driver support ("quad-buffered" OpenGL – rather than a single front and back buffer you have two front buffers and two back buffers, one for each eye). Not owning such a video card I decided to have a go at adding some other stereoscopic rendering modes that worked with regular hardware.

The four new stereoscopic rendering modes
The four new stereoscopic rendering modes

The ability to enable or disable drawing with a particular colour component in OpenGL makes implementing an anaglyph mode very simple – temporarily switch off red when drawing the view from one eye and temporarily switch off blue and green when drawing the view from the other to produce a final image that can be used with red/cyan 3D glasses. A new string console variable cl_stereo_anaglyph_colors can be amended to set the colour of your particular glasses, e.g. mg for magenta/green.

By drawing a mask to the stencil buffer before rendering one can easily add "interleaved" modes; there's the standard row interleaved format, but I've also added column and pixel interleaved formats.

It looks like the stereoscopic OpenGL code was started but not finished in Quake II; there were a number of odd bugs, such as the viewport position being changed instead of the camera position when drawing the left and right eye views (producing two views that were offset in 2D, not 3D). A snippet of code hints towards why this may be:

#if 0 // commented out until H3D pays us the money they owe us
    GL_DrawStereoPattern();
#endif

H3D manufactured a VGA adaptor for 3D glasses which relied on a special pattern being displayed on the screen to enable it and switch it to the correct mode rather than let the user do so. H3D went bust toward the end of 1998, so I guess id software never got their money and that function has been commented out ever since.

Anaglyph rendering example

The new binaries can be downloaded from the Stereo Quake page, and the source can be found on Google Code.

ATmega644P CHIP-8/SCHIP interpreter

Sunday, 7th March 2010

In an attempt to solve the screen resolution problem issue I've bought a very cheap 320×240 pixel graphical LCD – a PG320240H-P9 on eBay for $24. Part of the reason for its cheapness may be down to its the lack of a controller; you need to constantly refresh the LCD with pixel data yourself (easier to use modules have integrated controllers that refresh the display for you from some on-board RAM). If I manage to get it working I'll have a 128×64 pixel graphical LCD going spare – finding a use for it could make an interesting project.

I have a bit of a soft spot for the CHIP-8 programming language, having previously written an few implementations. The CHIP-8 environment requires just under 3.5KB of RAM, and my recent investment in an ATmega644P boasting 4KB of RAM provided me with a microcontroller that was up to the task.

Complete CHIP-8/SCHIP system

Beyond the ATmega644P and LCD the hardware is pretty simple; a potentiometer is provided to adjust the speed of the interpreter when it's running, from 1/8th speed up to 8× speed. Sound is output using a piezo transducer, which I've taped to the hard plastic lid from a tube of chocolates to amplify it. Games rely on a 4×4 hex keypad for input, and as I do not have a 4×4 keypad – hex or otherwise – I assembled my own on another breadboard. I don't even have sixteen switches of the same type, hence the mixture in the above photo. A schematic of the hardware can be downloaded in PDF format.

Game menu

When you reset the circuit a list of all of the programs stored on the microcontroller is shown on the LCD. The 64KB of flash memory on the ATmega644P is enough to store the code for the interpreter and all of the CHIP-8 and SCHIP games available on the Internet. For a change I've decided to have a go at designing a variable width font rather than use one of my existing fixed-width fonts; I don't think it looks too shabby.

'Joust' summary

When a game has been selected a (gramatically incorrect) summary of the game is shown. To the right of the screen is a 4×4 grid informing the player which key does what; arrows for directional controls, a diamond for "fire" or confirmation actions and a tick/cross for yes/no input. There doesn't seem to be any particular convention for keypad input in CHIP-8/SCHIP games, which makes this feature invaluable!

Ant

Click here to download the source code.

FirstFebruary 2010April 2010Last RSSSearchBrowse by dateIndexTags