[jallib] graphic lcd interface standardization

29 views
Skip to first unread message

Joep Suijs

unread,
Mar 5, 2010, 7:56:27 AM3/5/10
to jal...@googlegroups.com
Hi Guys,

I've been playing with my 128x64 glcd (created a 'game of life'
program as a demo), salvaged a 101x80 graphic color lcd from a Siemens
telephone and also Richard and Mike are using graphic libraries.So I
think it is a good time to consider standardization of the graphic
interface. A few things to consider:

- We now use glcd as a file prefix, but the function to draw a line is
called lcd_line. Is this as we want it? You could argue line is
obvious graphic, so you don't need to add the G. But out of
consistency, you could argue it should have a glcd_ prefix.
- Glcd also has an lcd'put procedure. This enables it replace a
character display without change of the main code of the application.
Is this what we want?
- What about the name lcd_write_pixel()?

An other topic is about read back from the display and more efficient
write. The memory of the display I use consists of bytes that
represent a column. The underlying architecture is a bit difficult
(multiple chips are used), but a transparent way to access is by
function ks0108_read_byte(byte in x, byte in y) and procedure
ks0108_write_byte(byte in x, byte in y, byte in veri) is (where y is,
like x, in pixels and, so y is divided by 8 before used). Is this
interface usable (and efficient) for all black & white displays? If
so, we could implement this for each b&w display and create generic
versions of lcd_write_pixel and lcd_write_char.

The third topic is about generic graphic applications. I created a
game of life app that is fixed to the full screen my 128x64 display. I
want to change it in such a way that it can run on any sized field
(with the limitation that Y must be a multiple of 8 pixels) and also
add an offset to put it on the desired place on the screen. Mike, what
are your plans with your clock application and what would it take to
make it scalable and movable?

The last topic to explore is color displays. Anyone experience with those?


Joep

Mike@watty

unread,
Mar 5, 2010, 10:29:48 AM3/5/10
to jallib

Yes... I have experience of palette and True Colour and also Alpha
channel and Z buffer.

I have most of these and using most with PIC 18F4550 / 16F877 and
KS0108

Mono Library:
I would call the items
(all draw one pixel wide in on or off ink, to allow erase/animation)
(I'd not bother with XOR mode drawing as it looks terrible)
PlotPixel
DrawOrthLine
DrawLine -- any angle
DrawBox -- only orthogonal uses DrawOrthLine
DrawRect -- uses DrawLine, so can draw rectangle any angle
DrawPoly -- less useful
DrawCircle -- radius and x.y of centre
DrawButton -- location, width, height. DrawBox with a drop shadow.
Show a physical Keypad map or be a touch key
DrawStyledLine -- width, dash/dot style also

Versions where a parameter is line width of border and Fill ink is
specified.

DrawFillBox -- only orthogonal uses DrawOrthLine
DrawFillRect -- uses DrawLine, so can draw rectangle any angle
DrawFillPoly -- less useful
DrawFillCircle -- radius and x.y of centre

Higher level objects have multiple procedures:
Clock
vertical bar with optional graticules -- use for meters, progress
bars, VU, signal level etc.
Horizontal bar with optional graticules
X,Y Plot Graph. Can plot in real time (repeated calls in loop/
interuppt) or an array. Line, points or Bar style


I also use by default 6 x 8 grid with 5x7 font but have control
characters and command:
Commands:
goto XY -- not Row, Col! on current character spacing/line spacing
grid!
line spacing (to fit text in buttons)
character spacing
Control Characters: Double Size (2x2 pixels for each font dot, i.e.
10x16), Bold, Underline, Normal

For efficiency, the basic library "ink" is a on/off
a palette based display uses byte ink and a separate Palette
procedure
A true colour (RGB) or high colour (16bit) uses either R, G and B ink
as byte, or if you want to be neat, use an array of 5 bytes, R, G, B,
Alpha and Z
Alpha is transparency, and Z is one of 256 layers. from foreground to
background.

So really on/off mono displays need different library to colour for
efficency. A grey scale display is same as palette based (single byte
ink) except there is no palette procedure.

I've also simulated grey scale on the on/off display by dither pattern
(hercules display on PC) and 256 colour on a 16 colour EGA. There is
not a lot you can do with the slug death CGA (four colour or maybe
four other colour, it's better in higher res mono!).

Clock:
Changing the X & Y location by constant is no Code/CPU overhead.
Changing X & Y at run time is about 24 adds I think, every second.
Scale at run time is needing a lookup table of 15 sin values (you can
use it for 0 to 360 and Cos ) and suitably accurate arithmetic to
calculate the
60 ends of second hand
60 ends of minute hand
12 to 48 ends of hour hand
12 hour markers
60 minute/second markers.
The co-ordinates are calculated for a given radius on spreadsheet
right now, and the spread sheet can have the whole statement with
numbers filled in so
you just copy / paste the entire MinuteHand etc...
It's R* cos(theta) and R * sin (theta) . But of course you only need a
multiply and 15 sin values in a table to do all 60 positions.

I suppose at Init time you would calculate all the positions. That
would be a lot of RAM. Or write them to EEPROM and read that to plot
hand.
Or do 8 adds and two multiplies for each hand every second...


mattschinkel

unread,
Mar 5, 2010, 3:30:12 PM3/5/10
to jallib
> - We now use glcd as a file prefix, but the function to draw a line is
> called lcd_line. Is this as we want it? You could argue line is
> obvious graphic, so you don't need to add the G. But out of
> consistency, you could argue it should have a glcd_ prefix.
> - Glcd also has an lcd'put procedure. This enables it replace a
> character display without change of the main code of the application.
> Is this what we want?
> - What about the name lcd_write_pixel()?

I would go with GLDC_ for graphics LCD to distinguish it from other
types of LCD's and GCLCD_ could be used for "Graphical Color LCD"?

I have two feature suggestions as well, I would like to be able to
load a BMP or JPG into the LDC screen, and I would like to be able to
"FILL" an area that is surrounded by other lines, shapes, etc.

> I want to change it in such a way that it can run on any sized field

A resize or zoom feature would be nice to have.

Matt.

Joep Suijs

unread,
Mar 5, 2010, 4:05:26 PM3/5/10
to jal...@googlegroups.com
Hi Mike,

It looks like we can expect a extensive graphics library ;)

But it will probably take some itterations before we have a stable,
generic interface...

2010/3/5 Mike@watty <watt...@gmail.com>:


> Clock:
> Changing the X & Y location by constant is no Code/CPU overhead.
> Changing X & Y at run time is about 24 adds I think, every second.

The good thing is we don't have to choose.
In most cases, constants will be good and that's what I'd use in
samples. But if you define a var in stead of a const, you get the
appropriate code.

Joep

Mike@watty

unread,
Mar 5, 2010, 5:42:48 PM3/5/10
to jallib

Loading an Image or a Sprite and animating it is trivial.

You can load using XModem/YModem or whatever via USB / Serial

You can store an image or sprite "as is" and use PlotColumn (x, y,
column8pixels) for mono screen from EEPROM.

You can use TIF encoding to save space (simple and works well on
boolean ink mono).

Existing Linux/Windows tools can make the raw byte array or Tiff
encoded file. TIFF is what faxes use to compress transmission, it's
line based run length encoding.

Colour is hugely more costly in storage (8x for palette based and 24x
for raw RGB and 48x if you have RGBAZ!)

Animating an 8x8 sprite (and "actors" and "maps" made of tiled sprites
is easy too). You don't use XOR, which is slow.


I think the best way to have a run time scale-able clock, panel meter
arcs / VU meters and such is a procedure that generates XY coordinate
for Radius and angle. This uses a lookup table to avoid sin and cos.
you only need store one 1/4 of a circle. 15 words for 6 degree
resolution. 30, = 3, 45 = 2 and 90 words ROM for 1 degree.
procedure PolarToCartesian(byte in radius, byte in angle, byte out
xPos, byte out yPos).

this only works for up to a 256x256 display. For larger displays you
need word. Infact my existing routines may be limited to 128x128
graphic. Just change bytes or sbytes to words or sword for up to 32768
x 32768.

For example if a clock is 29 radius for dial, 27 for second hand, 10
long for hour hand and 16 long for minute hand

the minute hand is (3 o'clock/15 minutes is zero degrees, 6pm/30mins
= 90 degrees)
--code to update scaled minute hand
-- erase at old position, using global xhPos yhPos, xmPos etc
DrawLine (clockXcentre, clockYcentre,clockXcentre+xhPos, clockYcentre
+yhPos, false)
DrawLine (clockXcentre, clockYcentre,clockXcentre+xmPos, clockYcentre
+ymPos, false)
DrawLine (clockXcentre, clockYcentre,clockXcentre+xsPos, clockYcentre
+ysPos, false)
-- update hrs, mins, sec...

--- recaluculate with new time...
PolarToCartesian(hrsHandLength, hrs*5-15, xhPos, yhPos)
PolarToCartesian(minHandLength, minutes-15, xmPos, ymPos)
PolarToCartesian(sec HandLength, seconds-15, xsPos, ysPos)
DrawLine (clockXcentre, clockYcentre,clockXcentre+xhPos, clockYcentre
+yhPos, true)
DrawLine (clockXcentre, clockYcentre,clockXcentre+xmPos, clockYcentre
+ymPos, true)
DrawLine (clockXcentre, clockYcentre,clockXcentre+xsPos, clockYcentre
+ysPos, true)

The PolarToCartesian is a lookup table and cos/sin are 90 degrees out
of phase. You only need 90 degrees of table of "sin"
it then does two lookups, one for cos and one for sin (for the one
angle but 90 degrees offset) and two multiplications.. we then take
only MSB of the radius * sin and radius * cos for X and Y..

It might even be LESS code than my static 60 element case statement
for each hand!

The dots and spots calculated the same way at in DrawClockFace

Mike@watty

unread,
Mar 5, 2010, 7:02:02 PM3/5/10
to jallib

Just tested my theory in VB on my simulator, and indeed you only need
sin (or cos) lookup table for 1/4 of a circle and the PolarToCartesian
does then allow you to scale clock face and hands.

I multiplied the sin values by 4096 (maybe 256 is enough on smaller
displays) to have an Integer lookup to do integer math with Radius.
then divide result (power of 2 so a shift).

Mike@watty

unread,
Mar 6, 2010, 5:20:41 AM3/6/10
to jallib
Here is JAL PolarToCartesian with 1 degree accuracy and byte based
lookup table

const byte SINLOOKUP[] = {0, 3, 8, 12, 17, 21, 26, 30, 35, 39, 43, 48,
52, 57,
61, 65, 70, 74, 78, 82, 87, 91, 95, 99, 103, 107, 111, 115, 119,
123, 127,
131, 135, 138, 142, 146, 149, 153, 157, 160, 164, 167, 170, 174,
177, 180,
183, 186, 189, 192, 195, 198, 201, 203, 206, 209, 211, 214, 216,
218, 221,
223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244,
245, 246,
247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255,
255, 255 }
-- 0 to 90 degrees in 1 degree steps
-- WARNING
-- Don't forget to to add 1 to lookup, apart from value zero !
-- use the SINLOOKUP cast to an sword +1, then divide expression by
256 when done.
-- fixed point Integer math

procedure PolarToCartesian(sword in radius, sword in angle, sword out
xPos, sword out yPos) is
--make sure works for ANY angle ...
While angle < -90 loop
angle = angle + 360
end Loop
While angle > 270 loop
angle = angle - 360
end Loop
If angle > -90 And angle < 0 Then
angle = angle + 90
xPos = sword(SINLOOKUP[angle]) + 1
yPos = -sword(SINLOOKUP[90 - angle]) - 1
ElsIf angle > 0 And angle < 90 Then
yPos = sword(SINLOOKUP[angle]) + 1
xPos = sword(SINLOOKUP[90 - angle]) + 1
ElsIf angle > 90 And angle < 180 Then
angle = angle - 90
xPos = -sword(SINLOOKUP[angle]) - 1
yPos = sword(SINLOOKUP[90 - angle]) + 1
ElsIf angle > 180 And angle < 270 Then
angle = angle - 180
xPos = -sword(SINLOOKUP[90 - angle]) - 1
yPos = -sword(SINLOOKUP[angle]) - 1
End If
Case angle of
0, 360:
xPos = radius
yPos = 0
90:
xPos = 0
yPos = radius
180:
xPos = -radius
yPos = 0
-90, 270:
xPos = 0
yPos = -radius
otherwise
xPos = xPos * radius / 256
yPos = yPos * radius / 256
End case
End procedure

Above is not tested!


The VB6 version below is working
Private Sub PolarToCartesian(ByVal radius As Integer, ByVal angle As
Integer, ByRef xPos As Integer, ByRef yPos As Integer)
Dim sinLookup As Variant
'apart from zero, all values are 1 less than actual to allow
storage in 1 byte each
sinLookup = Array(0, 3, 8, 12, 17, 21, 26, 30, 35, 39, 43, 48, 52,
57, 61, 65, 70, 74, 78, 82, 87, 91, 95, 99, 103, 107, 111, 115, 119,
123, 127, 131, 135, 138, 142, 146, _
149, 153, 157, 160, 164, 167, 170, 174, 177, 180, 183, 186, 189,
192, 195, 198, 201, 203, 206, 209, 211, 214, 216, 218, 221, 223, 225,
227, 229, _
231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 247, 248,
249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255)
'make sure works for ANY angle ...
Do While angle <= -90
angle = angle + 360
Loop
Do While angle >= 270
angle = angle - 360
Loop
If angle > -90 And angle < 0 Then
angle = angle + 90
xPos = sinLookup(angle) + 1
yPos = -sinLookup((90 - angle)) - 1
ElseIf angle > 0 And angle < 90 Then
yPos = sinLookup(angle) + 1
xPos = sinLookup((90 - angle)) + 1
ElseIf angle > 90 And angle < 180 Then
angle = angle - 90
xPos = -sinLookup(angle) - 1
yPos = sinLookup((90 - angle)) + 1
ElseIf angle > 180 And angle < 270 Then
angle = angle - 180
xPos = -sinLookup((90 - angle)) - 1
yPos = -sinLookup(angle) - 1
End If
Select Case angle
Case -90:
xPos = 0
yPos = -radius
Case 0:
xPos = radius
yPos = 0
Case 90:
xPos = 0
yPos = radius
Case 180:
xPos = -radius
yPos = 0
Case Else
xPos = xPos * radius \ 256
yPos = yPos * radius \ 256
End Select
End Sub

dim xOrg = 62
dim yOrg = 31
dim radius =31

Private Sub DrawClockFace(radius as Integer , xOrg as Integer, yOrg as
Integer)

Dim faceDots As Integer
Dim xPos As Integer
Dim yPos As Integer
LCD_Init
LCD_DrawRectangle xOrg, yOrg, 2, 2, True 'centre
'draw minutes dots
For faceDots = 0 To 59
PolarToCartesian radius, faceDots * 6, xPos, yPos
LCD_Plot xOrg + xPos, yOrg + yPos, True
Next
'draw hour squares
For faceDots = 0 To 11
PolarToCartesian radius, faceDots * 30, xPos, yPos
LCD_DrawRectangle xOrg + xPos, yOrg + yPos, 2, 2, True
Next
End Sub

Rob Hamerling

unread,
Mar 6, 2010, 5:50:31 AM3/6/10
to jal...@googlegroups.com

Hi Mike,

Mike@watty wrote:
> Here is JAL PolarToCartesian with 1 degree accuracy and byte based
> lookup table

Since you seem to have experience with trigonometric functions.....
'sin' and 'cos' (and maybe more) would be nice to have in the 'math'
library. May I invite you for this task?

Regards, Rob.

--
Rob Hamerling, Vianen, NL (http://www.robh.nl/)

Mike@watty

unread,
Mar 6, 2010, 7:52:20 AM3/6/10
to jallib

On Mar 6, 10:50 am, Rob Hamerling <robhamerl...@gmail.com> wrote:

> Since you seem to have experience with trigonometric functions.....
> 'sin' and 'cos' (and maybe more) would be nice to have in the 'math'
> library. May I invite you for this task?
>
> Regards, Rob.


No problem. I first did 16bit/32 bit math library for 78HC11 in
assembler in 1983. It only has 8 bit add and complement built in :(
Then debugged some 8051 asm math.

Back then I was doing PID, thermocouple compensation/linearise, low
pass filtering all on Z80, 78HC11, 8051 in Forth, ASM and Blockware
for Westinghouse.

You have now sin/ cos.
For more accurate use a table of 180 values of sin 0 to sin 90 at 0.5
degree intervals scaled by 65536 -1, do lookup and add one. Use
degrees x 2 as the fixed point integer. i.e. 75.5 = 151

For Powers and Roots, use a table of Logs (scaled to fixed point
integer) and then use kyle's builtin multiple & divide.
Then for antilog to save space do a split binary search on the log
table array. 1000 entries only takes 10 lookups worst case to find
antilog.

see also http://en.wikipedia.org/wiki/Cordic

We can have DSP library that can do ANYTHING a DSP chip or FPGA can
do... The only limitation is speed and RAM!
Many applications exist that are < 100Hz speed or even < 0.1Hz.
(Heating control PID etc)

If you use the Sin lookup and PWM, you can generate sine wave where
sample rate is PWM frequency. If you add Sin lookups at different
phases and speeds (sum of Fourier series) you can use PWM or I2C DAC
or resistors on a port to make a DAC to synthesis arbitrary waveform
and frequency up to maybe 100kHz. By mix of samples (add different
angles + sample rates of SinLookup Table) you can have flute, piano,
violin sound. You then use an envelope lookup table to scale the
amplitude at start and end of note.

see http://en.wikipedia.org/wiki/Category:Signal_processing

What do people need?


Mike@watty

unread,
Mar 6, 2010, 12:23:28 PM3/6/10
to jallib

As promised :-)

fully scale-able clock, any position, can change during runtime!
Animated movement of clock!

http://www.techtir.ie/forums/showthread.php?p=4084#post4084

tested on 18F4550

Change the DrawClockFace to use constants instead of variables to save
RAM.

second hand is automatically 2 pixels shorter than clockface radius
hour hand is automatically 1/2 size
Minute hand is automatically average of second hand and hour hand.
two of the hour squares lose a pixel, so maybe make second hand 3
pixel shorter.
You can make a x3 wide hour hand and x2 wide minute hand with some
thought.
Though it's more RAM, I think it's less code.
Hour hand now is nearest 1/4 hour rather than just on the hour as
before.

Rob Hamerling

unread,
Mar 9, 2010, 3:17:52 AM3/9/10
to jal...@googlegroups.com

Hi Mike,

On 06/03/10 01:52 pm, Mike@watty wrote:
>
> On Mar 6, 10:50 am, Rob Hamerling<robhamerl...@gmail.com> wrote:
>
>> Since you seem to have experience with trigonometric functions.....
>> 'sin' and 'cos' (and maybe more) would be nice to have in the 'math'
>> library. May I invite you for this task?
>>
>> Regards, Rob.
>
>
> No problem.
>

> Back then I was doing PID, thermocouple compensation/linearise, low
> pass filtering all on Z80, 78HC11, 8051 in Forth, ASM and Blockware
> for Westinghouse.
>
> You have now sin/ cos.

I'm not sure we understand each other correctly! I asked you to add sin
and cos functions to our math lib. But from your answer (and because I
didn't see an update of the math lib yet) I seem to understand that you
expect me to do it. Please clarify.


> For more accurate use a table of 180 values of sin 0 to sin 90 at 0.5
> degree intervals scaled by 65536 -1, do lookup and add one. Use
> degrees x 2 as the fixed point integer. i.e. 75.5 = 151
>
> For Powers and Roots, use a table of Logs (scaled to fixed point

> integer) and then use kyle's builtin multiple& divide.


> Then for antilog to save space do a split binary search on the log
> table array. 1000 entries only takes 10 lookups worst case to find
> antilog.
>
> see also http://en.wikipedia.org/wiki/Cordic
>
> We can have DSP library that can do ANYTHING a DSP chip or FPGA can
> do... The only limitation is speed and RAM!
> Many applications exist that are< 100Hz speed or even< 0.1Hz.
> (Heating control PID etc)
>
> If you use the Sin lookup and PWM, you can generate sine wave where
> sample rate is PWM frequency. If you add Sin lookups at different
> phases and speeds (sum of Fourier series) you can use PWM or I2C DAC
> or resistors on a port to make a DAC to synthesis arbitrary waveform
> and frequency up to maybe 100kHz. By mix of samples (add different
> angles + sample rates of SinLookup Table) you can have flute, piano,
> violin sound. You then use an envelope lookup table to scale the
> amplitude at start and end of note.
>
> see http://en.wikipedia.org/wiki/Category:Signal_processing
>
> What do people need?

Good question (meaning I don't know the answer)!
It could also be a checken and egg problem. The more functionality
Jallib offers (on request or not) the more popular it may become.

Mike@watty

unread,
Mar 9, 2010, 10:59:37 AM3/9/10
to jallib

On Mar 9, 8:17 am, Rob Hamerling <robhamerl...@gmail.com> wrote:
> Hi Mike,

> I'm not sure we understand each other correctly! I asked you to add sin
> and cos functions to our math lib. But from your answer (and because I
> didn't see an update of the math lib yet) I seem to understand that you
> expect me to do it.  Please clarify.

> Rob Hamerling, Vianen, NL (http://www.robh.nl/)

If you want it quick, do it. If you can wait a while, I'll do it. I
want to get the CatPad more functional.

I havn't had time to figure the SVN yet.

So... I'm happy to do it, but maybe not this week :-)

Also on CRC, it's best done with a table.

We need to also decide which fixed point integer formats are desired.

Rob Hamerling

unread,
Mar 9, 2010, 1:21:05 PM3/9/10
to jal...@googlegroups.com

On 03/09/10 04:59 pm, Mike@watty wrote:

> On Mar 9, 8:17 am, Rob Hamerling<robhamerl...@gmail.com> wrote:

>> I'm not sure we understand each other correctly! I asked you to add sin
>> and cos functions to our math lib. But from your answer (and because I
>> didn't see an update of the math lib yet) I seem to understand that you
>> expect me to do it. Please clarify.

> If you want it quick, do it. If you can wait a while, I'll do it.

No hurry, just to be sure we're not waiting for each other..

Regards, Rob.

--

Reply all
Reply to author
Forward
0 new messages