UDGBUF, Part 1.5 : Adventures with the HD44780

posted 2009-06-16 19:57:31, link to this article

Yesterday (and today when I confirmed this), I noticed that it can be helpful to actually understand what you're doing. :) What I didn't knew when I was POKEing bytes in my Psion Organiser's address space at first, is that when you access addresses 0x180 and 0x181, you're actually addressing the HD44780 LCD controller in the Organiser.

The address 0x180 is the instruction register of the HD44780 LCD controller, the address 0x181 is its data register. I should have wondered already why it was possible to write subsequent rows in a UDG to the same address 0x181 to define a character.
If we look at the code of defining a user defined character again:

udg:(udgnum%, b0%, b1%, b2%, b3%, b4%, b5%, b6%, b7%)
        pokeb $180, 64 + udgnum%*8
        pokeb $181, b0%; pokeb $181, b1%
        pokeb $181, b2%; pokeb $181, b3%
        pokeb $181, b4%; pokeb $181, b5%
        pokeb $181, b6%; pokeb $181, b7%

You see that first the argument 64 + udgnum%*8 is written to the address 0x180. The term 64 (or 0x40) is the instruction to the HD44780 LCD controller to set the CG (character generator) RAM address. The least significant 6-bits of the instruction contain the address itself, this is the udgnum% * 8 term. udgnum% In this case, is the character to define. A character contains 8 rows of pixels, so to reach the next character you multiply this by 8.
Poking to 0x181 writes the bit pattern poked to this address in the CG RAM, the magic part is that after writing this pattern, the CG RAM address is automatically incremented by the controller!

Knowing this, I realized that it must be possible to use this to read from the CG RAM as well as writing, but it's not possible to use the autoincrement magic then. This morning, in the train to work I wrote a small OPL program to test this assumption:

        rlcdreg:
                local char%, row%, byte%
                rem dump UDGs from HD44780 CG RAM
                char% = 0
                while char% <= 7
                        row% = 0
                        while row% <= 7
                                rem hd44780 instr reg is at 180h
                                rem instr 40h addresses CG RAM
                                pokeb $180, $40 + char%*8 + row%

                                rem data reg is at 181h
                                byte% = peekb($181)
                                print "chr"; char%,
                                print "row"; row%,
                                print "val"; byte%

                                row% = row% + 1
                        endwh
                        char% = char% + 1
                endwh

And the character definitions came scrolling down my Psion's little screen!
Pretty useless, maybe. But it means that it is possible to manipulate the UDG definitions in the LCD controller directly, without using some shadow copy in the Psion's RAM. I think that I will experiment with this in OPL first and when succesful port it to machine code instead for speed, would be a nice opportunity to learn the instruction set of an ancient processor. ;)

To be continued.

UDGBUF: a poor man's framebuffer on Psion Organiser II, Part 1

posted 2009-06-13 21:57:15, link to this article

Today I had some more fun with my rediscovered Psion Organiser II. It's about time to get my hands on a model LZ or LZ64 to enjoy twice the amount of screen real estate. ;)

This time I toyed with UDG (user defined characters) again. As the Psion reference manual states you can use these to make small animations as updating these changes them on screen immediately. That gave me the idea to implement some minimalistic framebuffer using all eight UDGs. I print four static UDGs in screen row 1, the other four in screen row 2, this way you get a whopping 40x16 pixel space for graphics!

It would be nice to read/write to the display controller directly and provide some convenience functions to do basic drawing, but I don't feel like learning to write HD6303 machine code just yet, so for now I plan to pass a pointer to some shadow memory (which I plan to allocate by creating a large global array or string) around where you do your graphics stuff, this will be then copied to the UDGs.

As a first test, I wrote a small program that walks through the memory of the Psion and displays it in the UDGs, with this result:

Tomorrow, I'll try to write some functions to provide a few basic graphics operations to set and get a pixel value. And maybe even some Bressenham line/circle drawing after that.

Psion Organiser II bargraphs

posted 2009-06-07 16:48:12, link to this article

Today, when searching for some other stuff, I came across some OPL (Organiser Programming Language, some sort of Pascal-ish bastard child of BASIC) code that I must have written around 2000, or so.

One of the programs was a set of functions to display bargraphs using user-defined characters on the two line text LCD of the Psion Organiser II. So I dug out my trusty old Psion Organiser II XP and cleaned up the code a bit.

Psion LCD bargraph

This might be of use to someone, therefore I publish it here.

udg:(x%, b0%, b1%, b2%, b3%, b4%, b5%, b6%, b7%)
	pokeb $180, 64 + x%*8
	pokeb $181, b0%; pokeb $181, b1%
	pokeb $181, b2%; pokeb $181, b3%
	pokeb $181, b4%; pokeb $181, b5%
	pokeb $181, b6%; pokeb $181, b7%

bargudg:
	udg:(0, 0, 0, 0, 0, 0, 0, 0,31)
	udg:(1, 0, 0, 0, 0, 0, 0,31,31)
	udg:(2, 0, 0, 0, 0, 0,31,31,31)
	udg:(3, 0, 0, 0, 0,31,31,31,31)
	udg:(4, 0, 0, 0,31,31,31,31,31)
	udg:(5, 0, 0,31,31,31,31,31,31)
	udg:(6, 0,31,31,31,31,31,31,31)
	udg:(7,31,31,31,31,31,31,31,31)

barchr$:(n%)
	if n% > 8
		n% = 8
	endif
	if n% = 0
		return " "
	endif
	return chr$(n% - 1) 

When you add these functions to your Organiser, after calling bargudg: you can call barchr$:() just like chr$() to print bargraph characters to the screen or to concatenate them to a string. barchr$:() accepts integers in the range 0..8, 0 being actually a space, not an UDG.

Cobalt status LCD, NetBSD version

posted 2008-11-09 00:18:41, link to this article

Here is a NetBSD/Cobalt version of my Cobalt Qube/Raq LCD status screen updater.
The Debian linux version is described in an earlier post on this page, here: Cobalt Qube status LCD system monitor.

This script works fine on NetBSD/Cobalt 3.0, I haven't tested it on other versions yet.

You can download the new NetBSD version at http://isquared.nl/src/lcdbanner-netbsd.sh

Cobalt Qube status LCD system monitor

posted 2008-11-01 21:58:29, link to this article
Read full article

This is a handy framework to monitor several system parameters on Cobalt hardware running Debian GNU/Linux.