News:

;) This forum is the property of Proton software developers

Main Menu

OLED Lite

Started by david, Apr 24, 2021, 10:37 PM

Previous topic - Next topic

david

The following code is offered as a demonstration of a 128x64, I2C controlled OLED display employing the SSD1315 chip.   Most of the existing demo code for the similar SSD1306 modules was bigger than any PICs I had and very difficult to follow because of various "includes" that were not always easy to locate.   I then started looking for a compromise solution that may allow their use in smaller projects.
The compromise I came to was that this demo only provides a single, small font with no graphics capability and can best be likened to a 21x8 character LCD even though it is pixel oriented.  The code is just under 1k total and doesn't require the usual 1k RAM.

The display is 128x64 pixels but for simplicity it is best to think of it as 128 columns wide by 8 lines down, indexed from the top left corner.    Each line is 8 pixels high. Characters are 7x5 pixels on an 8x6 printing grid, indexed at the lower left such that each character has the top row and the right side unprinted.   Rather than use a standard 6 column wide font with no data in the right (6th) column I elected to reduce the font table to 5 columns and simply print a blank, spacer column after every character thereby saving about 82 bytes.
It's convenient to adhere to the 8 lines when using horizontal mode addressing but the characters can be printed on any of the 128 8 bit columns on the line and not just at 6 column wide intervals allowing fractional character spacing if required.

The display needs to be initialized by setting up some of its operating parameters.  You will see in the code that this is all done in one long command that is broken down in to line by line registers and values to allow better commenting.  Most of the values are those recommended in the chip data sheet but you may want to play with the value of the contrast setting.   
Single value commands start with OLED address + Write bit + $80 followed by a register number. 
2 and even 3 byte commands can use OLED address + Write bit +$00 followed by the register then one or more values.  This is not well covered in the datasheet but appears to work as confirmed by a change in say the contrast value. 
HBusOut OLED_W,[$80,$AE]      Single register write
HBusOut OLED_W,[$00,$81,$7F]  Register write with value(s) (contrast) 

Writes to the display RAM start with $40 followed by as many bytes of screen data as required.
HBusOut OLED_W,[$40,0,0,0,0,0,0,0,0]  Print spacer column.

The next piece of code is used for clearing the random start up status of the Graphic Display Data RAM.  Screen memory values in RAM will be random resulting is a speckled display until cleared.
The code simply writes 8 bits of zeros to all 128 columns of the first line then repeats for all the other lines.  The lines are also referred to as pages in the data sheets.

Next is code for a sample print function and is arranged as follows-
HBusOut OLED_W,[$00,$21,13,127]   This is equivalent to Print X where X is column 13 across from the left margin.    127 defines the last column to print in and could be less.

HBusOut OLED_W,[$00,$22,3,7]    This is equivalent to Print Y where Y is line 3 down from the top (0).    7 defines the last line to print in and could be less.

mystring="Hello World 12345"  This is the text you want to appear on screen and it will be printed starting at the above location.

If you want to print a mix of text and numeric variables you could use something like this-
mystring= "1st " +Str$(Dec speed1) + "  km/h" where speed1 is a number.

The next task is to step through the printable text one character at a time and index that character's location in the font table at the end of the code.  This is a simple process of taking the character's ascii value, subtracting 32 (the ascii offset) and multiplying by 5 (5 bytes per character).  That will put us at the start byte of the character we want.  From there we just step through the remaining bytes of the character and then print a last column of zeros for the character spacer column.

If using this code in an application where various print commands were used you would make the indexing and printing code a subroutine or process and perhaps re-use the mystring variable to pass printable strings to it.   The values may be in a loop  and selected parts of the screen defined by the column and line values can be updated  (printed over) while other parts remain fixed.   

Note that the data sheet for the SSD1315 chip contains electrical specifications for the chip that may not reflect the module specifications as many modules have regulators built in and allow 5V operation.  What is less clear is the situation for the I2C lines.  With pull-up resistors to +5V how does the display chip running on Vdd =2.8V feel about this?  I could find no mention of the voltage compliance for the data and clock lines but have not experienced any problems .  Currents involved would be <1mA and probable well inside gate protection diode capability.
I should also mention that my experience with these devices is only measured in hours so there is still a lot to learn about them and hopefully other more experienced persons can add to this.
I think you will find this should run nicely on your smallest PIC but I have used a device with a MSSP module and others may want to try with a bit bashed I2C interface in which case you may want to reduce the bus speed down to 100kHz rather than the 1000kHz shown.

Best regards to all,
David Swarbrick
25th April 2021

'OLED drive with hardwarwe I2C  Needs 4.7k pull-up resistors on clk, data lines
'128x64 display using SSD1315 chip.   949 bytes with fonts ascii 32 to 122 
'Chip connections
'
'                  Vdd <1 U 8> Gnd   
'    Spare I/O     RA5 <2   7> RA0  Spare I/O
'    Spare I/O     RA4 <3   6> RA1  SCL
'   Spare input    RA3 <4   5> RA2  SDA           


Device = 12F1840
Config1 FCMEN_OFF, IESO_OFF, CLKOUTEN_OFF, BOREN_OFF, CPD_OFF, CP_OFF, MCLRE_OFF, PWRTE_ON, WDTE_OFF, FOSC_INTOSC
Config2 LVP_OFF, BORV_19, STVREN_OFF, PLLEN_OFF, WRT_OFF

Declare Xtal = 16 'Internal OSC
OSCCON = %01111010    '16MHz=01111010, 4MHz=01101010, 8MHz =01110010
TRISA = %00000110     '
Declare Hbus_Bitrate 1000    '100kHz, 400kHz, 1000kHz
SSPCON1=%00111000       'enable port, 7 bit address, master mode

Symbol OLED_W= %1111000  'OLED address and write
Symbol OLED_R= %1111001  'OLED address and read  - not needed.

'**********    variables   ******************
Dim Col As Byte  'columns - applies to Cdata, characters or absolute no.
Dim Lin As Byte  'effectively lines 0 to 7 down display
Dim num As Byte  'absolute index number in Cdata array
Dim Chr As Byte 'Character in Cdata array
Dim length As Byte
Dim mystring As String *20
Dim index As Byte

'initialize display
        DelayMS 200
        HBusOut OLED_W,[$80,$AE,_      'display OFF
                        $00,$20,$00,_  'Mem mode  Horiz
                        $00,$81,$7F,_  'contrast control reg/value
                        $80,$A1,_      'set segment remap
                        $80,$A4,_      'graphic RAM displayed
                        $80,$A6,_      'display norm/reverse
                        $00,$A8,$3F,_  'multiplex ratio/value
                        $80,$C8,_      'com scan direction
                        $00,$D5,$90,_  'set osc division/value
                        $00,$D9,$22,_  'set precharge period/value
                        $00,$DA,$12,_  'set Com pins/value
                        $00,$DB,$30,_  'set vcomh/value
                        $00,$8D,$14,_  'set charge pump enable/value
                        $80,$AF]       'display ON
       DelayMS 1000
       
'clearing random display in RAM       
Wipe:     
       For Lin=0 To 7
        HBusOut OLED_W,[$00,$22,Lin,7]  'Set page start/end
         For Col=0 To 127
           HBusOut OLED_W,[$40,0,0,0,0,0,0,0,0]  'write zeros 
         Next Col                       'wipe vertical columns
      Next Lin
      DelayMS 1000

'printing a sample string on the screen 
     HBusOut OLED_W,[$00,$21,13,127]  'Set column range, pointer x=13 (from left)
     HBusOut OLED_W,[$00,$22,3,7]     'Set Line range, pointer y=3 (from top)
     mystring="Hello World 12345"     'print input

'indexing the look up table     
     For Chr=0 To Len (mystring)-1     
     index=mystring[Chr]-32            'index to character in font table
       For Col=0 To 4                  '5 bytes per character
       num= CRead8 Fonts [index*5+Col]
        HBusOut OLED_W,[$40,num]       'print 5 values into columns 0 to 4 for each character
       Next Col                   
       HBusOut OLED_W,[$40,0]        'print blank spacer column in to 6th column
      Next Chr
       
      DelayMS 5000                    'delay
      GoTo Wipe                       'do it again
     
'character font table             
Dim Fonts As Code=As Byte  $00, $00, $00, $00, $00,_      ' char space  0 Start +4chr ascii 32
                           $00, $00, $BE, $00, $00,_      ' char !      1  *5   +4chr
                           $00, $00, $03, $00, $03,_      ' char "
                           $50, $F8, $50, $F8, $50,_      ' char #
                           $48, $54, $FE, $54, $24,_      ' char $
                           $98, $58, $20, $D0, $C8,_      ' char %
                           $60, $9C, $AA, $44, $80,_      ' char &
                           $00, $00, $00, $03, $00,_      ' char '
                           $00, $38, $44, $82, $00,_      ' char (
                           $00, $82, $44, $38, $00,_      ' char )
                           $02, $06, $03, $06, $02,_      ' char *
                           $10, $10, $7C, $10, $10,_      ' char +
                           $A0, $60, $00, $00, $00,_      ' char ,
                           $10, $10, $10, $10, $10,_      ' char -
                           $C0, $C0, $00, $00, $00,_      ' char . 
                           $80, $40, $20, $10, $08,_      ' char / 
                           $7C, $A2, $92, $8A, $7C,_      ' char 0 
                           $00, $84, $FE, $80, $00,_      ' char 1 
                           $C4, $A2, $92, $92, $8C,_      ' char 2 
                           $44, $82, $92, $92, $6C,_      ' char 3 
                           $18, $14, $12, $FE, $10,_      ' char 4 
                           $9E, $92, $92, $92, $62,_      ' char 5 
                           $7C, $92, $92, $92, $64,_      ' char 6 
                           $06, $02, $E2, $12, $0E,_      ' char 7 
                           $6C, $92, $92, $92, $6C,_      ' char 8 
                           $4C, $92, $92, $92, $7C,_      ' char 9 
                           $CC, $CC, $00, $00, $00,_      ' char : 
                           $AC, $6C, $00, $00, $00,_      ' char ; 
                           $00, $10, $28, $44, $82,_      ' char < 
                           $48, $48, $48, $48, $48,_      ' char = 
                           $00, $82, $44, $28, $10,_      ' char > 
                           $04, $02, $B2, $12, $0C,_      ' char ? 
                           $7C, $82, $BA, $AA, $BC,_      ' char @ 
                           $F8, $14, $12, $14, $F8,_      ' char A 
                           $FE, $92, $92, $92, $6C,_      ' char B 
                           $7C, $82, $82, $82, $44,_      ' char C 
                           $FE, $82, $82, $44, $38,_      ' char D 
                           $FE, $92, $92, $82, $82,_      ' char E 
                           $FE, $12, $12, $02, $02,_      ' char F 
                           $7C, $82, $92, $92, $F4,_      ' char G 
                           $FE, $10, $10, $10, $FE,_      ' char H 
                           $00, $82, $FE, $82, $00,_      ' char I 
                           $60, $80, $80, $80, $7E,_      ' char J 
                           $FE, $10, $18, $24, $C2,_      ' char K 
                           $FE, $80, $80, $80, $80,_      ' char L 
                           $FE, $04, $38, $04, $FE,_      ' char M 
                           $FE, $04, $08, $10, $FE,_      ' char N 
                           $7C, $82, $82, $82, $7C,_      ' char O 
                           $FE, $12, $12, $12, $0C,_      ' char P 
                           $7C, $82, $A2, $C2, $FC,_      ' char Q 
                           $FE, $12, $12, $12, $EC,_      ' char R 
                           $4C, $92, $92, $92, $64,_      ' char S 
                           $02, $02, $FE, $02, $02,_      ' char T 
                           $7E, $80, $80, $80, $7E,_      ' char U 
                           $3E, $40, $80, $40, $3E,_      ' char V 
                           $FE, $80, $70, $80, $FE,_      ' char W 
                           $C6, $28, $10, $28, $C6,_      ' char X     
                           $06, $08, $F0, $08, $06,_      ' char Y 
                           $C2, $A2, $92, $8A, $86,_      ' char Z 
                           $00, $FE, $82, $82, $00,_      ' char [ 
                           $08, $10, $20, $40, $80,_      ' char \
                           $00, $82, $82, $FE, $00,_      ' char ] 
                           $08, $04, $02, $04, $08,_      ' char ^ 
                           $80, $80, $80, $80, $80,_      ' char _ 
                           $00, $00, $02, $04, $00,_      ' char ` 
                           $40, $A8, $A8, $A8, $F0,_      ' char a 
                           $FE, $88, $88, $88, $70,_      ' char b 
                           $70, $88, $88, $88, $10,_      ' char c 
                           $70, $88, $88, $88, $FE,_      ' char d 
                           $70, $A8, $A8, $A8, $30,_      ' char e 
                           $10, $FC, $12, $12, $04,_      ' char f 
                           $90, $A8, $A8, $A8, $70,_      ' char g 
                           $FE, $10, $10, $10, $E0,_      ' char h 
                           $00, $90, $F4, $80, $00,_      ' char i 
                           $40, $80, $80, $90, $74,_      ' char j 
                           $FE, $20, $50, $88, $00,_      ' char k 
                           $7E, $80, $80, $00, $00,_      ' char l 
                           $F8, $08, $70, $08, $F0,_      ' char m 
                           $F8, $08, $08, $08, $F0,_      ' char n 
                           $70, $88, $88, $88, $70,_      ' char o 
                           $F8, $28, $28, $28, $10,_      ' char p 
                           $10, $28, $28, $F8, $80,_      ' char q 
                           $F8, $08, $08, $08, $10,_      ' char r 
                           $90, $A8, $A8, $A8, $48,_      ' char s 
                           $08, $08, $FE, $88, $88,_      ' char t 
                           $78, $80, $80, $80, $F8,_      ' char u 
                           $38, $40, $80, $40, $38,_      ' char v 
                           $F8, $80, $70, $80, $F8,_      ' char w 
                           $88, $50, $20, $50, $88,_      ' char x 
                           $18, $A0, $A0, $A0, $78,_      ' char y 
                           $88, $C8, $A8, $98, $88        ' char z     ascii 122
 End               

david

Further reading.

david

Some screen shots during development.

david

#3
Attached is code for a practical application of the OLED Lite routine above.
It's a simple GPS based sensor for measuring RC planes speed, distance covered and time elapsed. Altitude could be added but GPS derived altitude is not very accurate and barometric sensors are preferred. 
The code checks for a valid fix and activates a flashing bezel on the display.  The speed uses integers but checks the first decimal point and rounds up or down accordingly and this should provide a more accurate distance indication rather than simply truncating down to the nearest integer.
A speed limit is used so that readings are ignored if under 5km/h so that a plane can land and be idle for any length of time without the average speed or run time changing.
Please note the flexibility of the OLED Page addressing mode.  A single line or a piece of a line can be updated easily and they really are nice little displays to work with.

Cheers,
David

'GPS speed sensor

'                  Vdd <1 U 8> Gnd 
'    From GPS  Rx  RA5 <2  7> RA0    Out
'                  RA4 <3  6> RA1    SCL
'        in/gnd  RA3 <4  5> RA2    SDA


Device = 12F1840
Config1 FCMEN_OFF, IESO_OFF, CLKOUTEN_OFF, BOREN_OFF, CPD_OFF, CP_OFF, MCLRE_OFF, PWRTE_ON, WDTE_OFF, FOSC_INTOSC
Config2 LVP_OFF, BORV_19, STVREN_OFF, PLLEN_OFF, WRT_OFF


Declare Xtal = 16 'Internal OSC
OSCCON = %01111010    '16MHz=01111010, 4MHz=01101010, 8MHz =01110010
APFCON = %10000100    'Rx=RA.5
TRISA = %00101110    '
ANSELA=0              '
PORTA=0
All_Digital=true
Declare Hserial_Baud=9600
Declare Hserial_SPBRG=25
RCSTA=%10010000
BAUDCON=%01000000 
Declare Hserial_Clear=On
Declare Hbus_Bitrate 1000    '100kHz, 400kHz, 1000kHz
SSPCON1=%00111000      'enable port, 7 bit address, master mode
Symbol OLED_W= %1111000  'OLED address and write

'OLED variables
Dim comma As Byte    'For counting commas
Dim col As Byte  'columns - applies to Cdata, characters or absolute no.
Dim lin As Byte  'effectively lines 0 to 7 down display
Dim num As Byte  'absolute index number in Cdata array
Dim Chr As Byte 'Character in Cdata array
Dim length As Byte
Dim index As Byte
Dim mystring As String *20

'GPS variables
Dim speed As Byte=0    'numerical speed value
Dim speedmax As Byte=0  'top speed
Dim totalsecs As Word=0      'accumulated seconds 
Dim dot As Byte=0
Dim secs As Byte=0
Dim mins As Byte=0      'accumulated mins
Dim kph As string*5  'captured string
Dim tempstr As String
Dim range As Long=0
Dim totalspd As Dword=0    'accumulated speed readings
Dim avgspeed As Byte=0


        DelayMS 500
'initialize display
        HBusOut OLED_W,[$80,$AE,_      'display OFF
                        $00,$20,$00,_  'Mem mode  Horiz
                        $00,$81,$7F,_  'contrast control reg/value
                        $80,$A1,_      'set segment remap
                        $80,$A4,_      'graphic RAM displayed
                        $80,$A6,_      'display norm/reverse
                        $00,$A8,$3F,_  'multiplex ratio/value
                        $80,$C8,_      'com scan direction
                        $00,$D5,$90,_  'set osc division/value
                        $00,$D9,$22,_  'set precharge period/value
                        $00,$DA,$12,_  'set Com pins/value
                        $00,$DB,$30,_  'set vcomh/value
                        $00,$8D,$14]  'set charge pump enable/value
                        '$80,$AF]      'display ON

                        DelayMS 1000
'clearing random display in RAM     
Wipe:     
      For lin=$B0 To $B7
        HBusOut OLED_W,[$00,$22,lin,$B7]  'Set page start/end
        For col=0 To 127
          HBusOut OLED_W,[$40,$00,$00,$00,$00,$00,$00,$00,$00]   
        Next col      'wipe vertical columns
      Next lin
      DelayMS 200
      HBusOut OLED_W,[$80,$AF]  'display on
     

    HBusOut OLED_W,[$00,$21,0,110]  'Reset column range, pointer to 0
    HBusOut OLED_W,[$00,$22,0,0]  'Reset Page range, pointer to zero
    mystring="GPS SPEED METER"      'print input
GoSub printing     

'*****  check for valid signal  ******
start:  HRSIn Wait ("RMC,")
        While HRSIn<>",": Wend
        If HRSIn <>65 Then GoTo start  'check for "A"
        DelayMS 1000

'Flashing bezel for GPS fix       
begin:  DelayMS 200              'Loop delay time
        HBusOut OLED_W,[$00,$21,114,127]  'Reset column range, pointer to 114
        HBusOut OLED_W,[$00,$22,0,0]  'Reset Page range, pointer to zero
        If dot=1 Then mystring="*" :GoSub printing      'print input
        If dot=0 Then mystring=" " :GoSub printing 
        dot=dot+1
        If dot=2 Then dot=0
       
       
        HRSIn Wait ("VTG,")      'Wait for VTG sentence
        For comma=1 To 6          'Step out 6 fields
          While HRSIn<>",": Wend
        Next comma
        HRSIn kph    'take next 5 char as kph string

'****** locate decimal point - take nearest integer  ************       
        If kph[1]="." Then          'n.4=n.  n.5=n+1
          tempstr=kph[0]
          speed=Val(tempstr,Dec)
          If kph[2]>52 Then speed=speed+1
        EndIf 
               
        If kph[2]="." Then          'nn.4=nn.  nn.5=nn+1
          tempstr=kph[0] +kph[1]
          speed=Val(tempstr,Dec)
          If kph[3]>52 Then speed=speed+1
        EndIf
       
        If kph[3]="." Then          'nnn.4=nnn.  nnn.5=nnn+1
          tempstr=kph[0] +kph[1] +kph[2]
          speed=Val(tempstr,Dec)
          If kph[3]>52 Then speed=speed+1
        EndIf

'**********  Cut off speed  ****************       
        If speed>5 Then
          totalspd=totalspd+speed
          totalsecs=totalsecs+1
          avgspeed=totalspd/totalsecs
          If speed>speedmax Then speedmax=speed
        EndIf
       
'**********  Time  *************
      mins=totalsecs/60
      secs=totalsecs//60 
     
'*********  Range  **********     
    range=(totalspd*5)/18    'divide by 3.6 for meters
   
'Cur speed
    'HBusOut OLED_W,[$00,$21,0,127]  'Reset column range, pointer to zero
    'HBusOut OLED_W,[$00,$22,1,1]  'Reset Page range, pointer to 1
    'mystring= "Cur spd " + kph + " km/h  "      'print input
    'GoSub printing         
               
'max speed
    HBusOut OLED_W,[$00,$21,0,127]  'Reset column range, pointer to zero
    HBusOut OLED_W,[$00,$22,2,2]  'Reset Page range, pointer to 2
    mystring= "Max spd " +Str$ (Dec speedmax) + " km/h  "      'print input
    GoSub printing 
 
'avg speed   
    HBusOut OLED_W,[$00,$21,0,127]  'Reset column range, pointer to zero
    HBusOut OLED_W,[$00,$22,3,3]  'Reset Page range, pointer to 3
    mystring= "Avg spd "+Str$(Dec avgspeed) +" km/h  "      'print input
    GoSub printing 

'dist
    HBusOut OLED_W,[$00,$21,0,127]  'Reset column range, pointer to zero
    HBusOut OLED_W,[$00,$22,4,4]  'Reset Page range, pointer to 4
    mystring= "Dist "+Str$(Dec range) +" m"      'print input
    GoSub printing

'time     
    HBusOut OLED_W,[$00,$21,0,127]  'Reset column range, pointer to zero
    HBusOut OLED_W,[$00,$22,5,5]  'Reset Page range, pointer to 5
    mystring= "Time "+Str$(Dec mins)+" m "+Str$(Dec secs) +" s "      'print input
    GoSub printing 
   
GoTo begin   
     
'subroutines       
printing:    'indexing the look up table     
    For Chr=0 To Len (mystring)-1   
    index=mystring[Chr]-32
      For col=0 To 4                  '5 bytes per character
      num= CRead8 Fonts [index*5+Col]
        HBusOut OLED_W,[$40,num]      'print 5 values into columns 0 to 4 for each character
      Next col                   
      HBusOut OLED_W,[$40,0]        'print blank spacer column in to 6th column
      Next Chr
      Return
 
'character font table           
Dim Fonts As Code=As Byte  $00, $00, $00, $00, $00,_      ' char space  0 Start +4chr ascii 32
                          $00, $00, $BE, $00, $00,_      ' char !      1  *5  +4chr
                          $00, $00, $03, $00, $03,_      ' char "
                          $50, $F8, $50, $F8, $50,_      ' char #
                          $48, $54, $FE, $54, $24,_      ' char $
                          $98, $58, $20, $D0, $C8,_      ' char %
                          $60, $9C, $AA, $44, $80,_      ' char &
                          $00, $00, $00, $03, $00,_      ' char '
                          $00, $38, $44, $82, $00,_      ' char (
                          $00, $82, $44, $38, $00,_      ' char )
                          $02, $06, $03, $06, $02,_      ' char *
                          $10, $10, $7C, $10, $10,_      ' char +
                          $A0, $60, $00, $00, $00,_      ' char ,
                          $10, $10, $10, $10, $10,_      ' char -
                          $C0, $C0, $00, $00, $00,_      ' char . 
                          $80, $40, $20, $10, $08,_      ' char / 
                          $7C, $A2, $92, $8A, $7C,_      ' char 0 
                          $00, $84, $FE, $80, $00,_      ' char 1 
                          $C4, $A2, $92, $92, $8C,_      ' char 2 
                          $44, $82, $92, $92, $6C,_      ' char 3 
                          $18, $14, $12, $FE, $10,_      ' char 4 
                          $9E, $92, $92, $92, $62,_      ' char 5 
                          $7C, $92, $92, $92, $64,_      ' char 6 
                          $06, $02, $E2, $12, $0E,_      ' char 7 
                          $6C, $92, $92, $92, $6C,_      ' char 8 
                          $4C, $92, $92, $92, $7C,_      ' char 9 
                          $CC, $CC, $00, $00, $00,_      ' char : 
                          $AC, $6C, $00, $00, $00,_      ' char ; 
                          $00, $10, $28, $44, $82,_      ' char < 
                          $48, $48, $48, $48, $48,_      ' char = 
                          $00, $82, $44, $28, $10,_      ' char > 
                          $04, $02, $B2, $12, $0C,_      ' char ? 
                          $7C, $82, $BA, $AA, $BC,_      ' char @ 
                          $F8, $14, $12, $14, $F8,_      ' char A 
                          $FE, $92, $92, $92, $6C,_      ' char B 
                          $7C, $82, $82, $82, $44,_      ' char C 
                          $FE, $82, $82, $44, $38,_      ' char D 
                          $FE, $92, $92, $82, $82,_      ' char E 
                          $FE, $12, $12, $02, $02,_      ' char F 
                          $7C, $82, $92, $92, $F4,_      ' char G 
                          $FE, $10, $10, $10, $FE,_      ' char H 
                          $00, $82, $FE, $82, $00,_      ' char I 
                          $60, $80, $80, $80, $7E,_      ' char J 
                          $FE, $10, $18, $24, $C2,_      ' char K 
                          $FE, $80, $80, $80, $80,_      ' char L 
                          $FE, $04, $38, $04, $FE,_      ' char M 
                          $FE, $04, $08, $10, $FE,_      ' char N 
                          $7C, $82, $82, $82, $7C,_      ' char O 
                          $FE, $12, $12, $12, $0C,_      ' char P 
                          $7C, $82, $A2, $C2, $FC,_      ' char Q 
                          $FE, $12, $12, $12, $EC,_      ' char R 
                          $4C, $92, $92, $92, $64,_      ' char S 
                          $02, $02, $FE, $02, $02,_      ' char T 
                          $7E, $80, $80, $80, $7E,_      ' char U 
                          $3E, $40, $80, $40, $3E,_      ' char V 
                          $FE, $80, $70, $80, $FE,_      ' char W 
                          $C6, $28, $10, $28, $C6,_      ' char X     
                          $06, $08, $F0, $08, $06,_      ' char Y 
                          $C2, $A2, $92, $8A, $86,_      ' char Z 
                          $00, $FE, $82, $82, $00,_      ' char [ 
                          $08, $10, $20, $40, $80,_      ' char \
                          $00, $82, $82, $FE, $00,_      ' char ] 
                          $08, $04, $02, $04, $08,_      ' char ^ 
                          $80, $80, $80, $80, $80,_      ' char _ 
                          $00, $00, $02, $04, $00,_      ' char ` 
                          $40, $A8, $A8, $A8, $F0,_      ' char a 
                          $FE, $88, $88, $88, $70,_      ' char b 
                          $70, $88, $88, $88, $10,_      ' char c 
                          $70, $88, $88, $88, $FE,_      ' char d 
                          $70, $A8, $A8, $A8, $30,_      ' char e 
                          $10, $FC, $12, $12, $04,_      ' char f 
                          $90, $A8, $A8, $A8, $70,_      ' char g 
                          $FE, $10, $10, $10, $E0,_      ' char h 
                          $00, $90, $F4, $80, $00,_      ' char i 
                          $40, $80, $80, $90, $74,_      ' char j 
                          $FE, $20, $50, $88, $00,_      ' char k 
                          $7E, $80, $80, $00, $00,_      ' char l 
                          $F8, $08, $70, $08, $F0,_      ' char m 
                          $F8, $08, $08, $08, $F0,_      ' char n 
                          $70, $88, $88, $88, $70,_      ' char o 
                          $F8, $28, $28, $28, $10,_      ' char p 
                          $10, $28, $28, $F8, $80,_      ' char q 
                          $F8, $08, $08, $08, $10,_      ' char r 
                          $90, $A8, $A8, $A8, $48,_      ' char s 
                          $08, $08, $FE, $88, $88,_      ' char t 
                          $78, $80, $80, $80, $F8,_      ' char u 
                          $38, $40, $80, $40, $38,_      ' char v 
                          $F8, $80, $70, $80, $F8,_      ' char w 
                          $88, $50, $20, $50, $88,_      ' char x 
                          $18, $A0, $A0, $A0, $78,_      ' char y 
                          $88, $C8, $A8, $98, $88        ' char z    ascii 122
 End