unit Nokia_3310_Lcd;
//****************************************************************************//
// Written by ANTON RIECKERT
// anton.rieckert@gmail.com
// http://www.riecktron.za.net
//****************************************************************************//
Procedure NOK_Write (databit, mode : byte);
Procedure NOK_Chr(symlcd : Byte);
Procedure NOK_GotoXY(x,y : byte);
Procedure NOK_Invert;
Procedure NOK_Clear;
Procedure NOK_Out(x, y : byte; var sentance : array[14] of char);
Procedure NOK_Out_CP(var sentance : array[14] of char);
Procedure NOK_Init(var port: byte; SCLK_pin, SDA_pin, DC_pin, CS_pin, RES_pin : byte);


implementation
//****************************************************************************//
{Const
     ___NCS   : byte = 3;    // INDF,3   -  CS   - Chip Enable
     ___NRES  : byte = 5;    // INDF,5   -  RES  - Reset Input
     ___NSCLK : byte = 0;    // INDF,0   -  SCLK - Serial Clock Input
     ___NDC   : byte = 2;    // INDF,2   -  DC   - databit / Command
     ___NSDA  : byte = 1;    // INDF,1   -  SDA  - Serial Data Input}
     
var portaddress : byte;
     ___NCS   : byte; //   CS   - Chip Enable
     ___NRES  : byte; //   RES  - Reset Input
     ___NSCLK : byte; //   SCLK - Serial Clock Input
     ___NDC   : byte; //   DC   - data / Command
     ___NSDA  : byte; //   SDA  - Serial data Input}

//****************************************************************************//
const font5x7_1 : array[230] of byte =
   (0x00, 0x00, 0x00, 0x00, 0x00 ,  // sp
    0x00, 0x00, 0x2f, 0x00, 0x00 ,  // !
    0x00, 0x07, 0x00, 0x07, 0x00 ,  // "
    0x14, 0x7f, 0x14, 0x7f, 0x14 ,  // #
    0x24, 0x2a, 0x7f, 0x2a, 0x12 ,  // $
    0xc4, 0xc8, 0x10, 0x26, 0x46 ,  // %
    0x36, 0x49, 0x55, 0x22, 0x50 ,  // &
    0x00, 0x05, 0x03, 0x00, 0x00 ,  // '
    0x00, 0x1c, 0x22, 0x41, 0x00 ,  // (
    0x00, 0x41, 0x22, 0x1c, 0x00 ,  // )
    0x14, 0x08, 0x3E, 0x08, 0x14 ,  // *
    0x08, 0x08, 0x3E, 0x08, 0x08 ,  // +
    0x00, 0x00, 0x50, 0x30, 0x00 ,  // ,
    0x10, 0x10, 0x10, 0x10, 0x10 ,  // -
    0x00, 0x60, 0x60, 0x00, 0x00 ,  // .
    0x20, 0x10, 0x08, 0x04, 0x02 ,  // /
    0x3E, 0x51, 0x49, 0x45, 0x3E ,  // 0
    0x00, 0x42, 0x7F, 0x40, 0x00 ,  // 1
    0x42, 0x61, 0x51, 0x49, 0x46 ,  // 2
    0x21, 0x41, 0x45, 0x4B, 0x31 ,  // 3
    0x18, 0x14, 0x12, 0x7F, 0x10 ,  // 4
    0x27, 0x45, 0x45, 0x45, 0x39 ,  // 5
    0x3C, 0x4A, 0x49, 0x49, 0x30 ,  // 6
    0x01, 0x71, 0x09, 0x05, 0x03 ,  // 7
    0x36, 0x49, 0x49, 0x49, 0x36 ,  // 8
    0x06, 0x49, 0x49, 0x29, 0x1E ,  // 9
    0x00, 0x36, 0x36, 0x00, 0x00 ,  // :
    0x00, 0x56, 0x36, 0x00, 0x00 ,  // ;
    0x08, 0x14, 0x22, 0x41, 0x00 ,  // <
    0x14, 0x14, 0x14, 0x14, 0x14 ,  // =
    0x00, 0x41, 0x22, 0x14, 0x08 ,  // >
    0x02, 0x01, 0x51, 0x09, 0x06 ,  // ?
    0x32, 0x49, 0x59, 0x51, 0x3E ,  // @
    0x7E, 0x11, 0x11, 0x11, 0x7E ,  // A
    0x7F, 0x49, 0x49, 0x49, 0x36 ,  // B
    0x3E, 0x41, 0x41, 0x41, 0x22 ,  // C
    0x7F, 0x41, 0x41, 0x22, 0x1C ,  // D
    0x7F, 0x49, 0x49, 0x49, 0x41 ,  // E
    0x7F, 0x09, 0x09, 0x09, 0x01 ,  // F
    0x3E, 0x41, 0x49, 0x49, 0x7A ,  // G
    0x7F, 0x08, 0x08, 0x08, 0x7F ,  // H
    0x00, 0x41, 0x7F, 0x41, 0x00 ,  // I
    0x20, 0x40, 0x41, 0x3F, 0x01 ,  // J
    0x7F, 0x08, 0x14, 0x22, 0x41 ,  // K
    0x7F, 0x40, 0x40, 0x40, 0x40 ,  // L
    0x7F, 0x02, 0x0C, 0x02, 0x7F);  // M

const font5x7_2 : array[225] of byte = (
    0x7F, 0x04, 0x08, 0x10, 0x7F ,  // N
    0x3E, 0x41, 0x41, 0x41, 0x3E ,  // O
    0x7F, 0x09, 0x09, 0x09, 0x06 ,  // P
    0x3E, 0x41, 0x51, 0x21, 0x5E ,  // Q
    0x7F, 0x09, 0x19, 0x29, 0x46 ,  // R
    0x46, 0x49, 0x49, 0x49, 0x31 ,  // S
    0x01, 0x01, 0x7F, 0x01, 0x01 ,  // T
    0x3F, 0x40, 0x40, 0x40, 0x3F ,  // U
    0x1F, 0x20, 0x40, 0x20, 0x1F ,  // V
    0x3F, 0x40, 0x38, 0x40, 0x3F ,  // W
    0x63, 0x14, 0x08, 0x14, 0x63 ,  // X
    0x07, 0x08, 0x70, 0x08, 0x07 ,  // Y
    0x61, 0x51, 0x49, 0x45, 0x43 ,  // Z
    0x00, 0x7F, 0x41, 0x41, 0x00 ,  // [
    0x55, 0x2A, 0x55, 0x2A, 0x55 ,  // 55
    0x00, 0x41, 0x41, 0x7F, 0x00 ,  // ]
    0x04, 0x02, 0x01, 0x02, 0x04 ,  // ^
    0x40, 0x40, 0x40, 0x40, 0x40 ,  // _
    0x00, 0x01, 0x02, 0x04, 0x00 ,  // '
    0x20, 0x54, 0x54, 0x54, 0x78 ,  // a
    0x7F, 0x48, 0x44, 0x44, 0x38 ,  // b
    0x38, 0x44, 0x44, 0x44, 0x20 ,  // c
    0x38, 0x44, 0x44, 0x48, 0x7F ,  // d
    0x38, 0x54, 0x54, 0x54, 0x18 ,  // e
    0x08, 0x7E, 0x09, 0x01, 0x02 ,  // f
    0x0C, 0x52, 0x52, 0x52, 0x3E ,  // g
    0x7F, 0x08, 0x04, 0x04, 0x78 ,  // h
    0x00, 0x44, 0x7D, 0x40, 0x00 ,  // i
    0x20, 0x40, 0x44, 0x3D, 0x00 ,  // j
    0x7F, 0x10, 0x28, 0x44, 0x00 ,  // k
    0x00, 0x41, 0x7F, 0x40, 0x00 ,  // l
    0x7C, 0x04, 0x18, 0x04, 0x78 ,  // m
    0x7C, 0x08, 0x04, 0x04, 0x78 ,  // n
    0x38, 0x44, 0x44, 0x44, 0x38 ,  // o
    0x7C, 0x14, 0x14, 0x14, 0x08 ,  // p
    0x08, 0x14, 0x14, 0x18, 0x7C ,  // q
    0x7C, 0x08, 0x04, 0x04, 0x08 ,  // r
    0x48, 0x54, 0x54, 0x54, 0x20 ,  // s
    0x04, 0x3F, 0x44, 0x40, 0x20 ,  // t
    0x3C, 0x40, 0x40, 0x20, 0x7C ,  // u
    0x1C, 0x20, 0x40, 0x20, 0x1C ,  // v
    0x3C, 0x40, 0x30, 0x40, 0x3C ,  // w
    0x44, 0x28, 0x10, 0x28, 0x44 ,  // x
    0x0C, 0x50, 0x50, 0x50, 0x3C ,  // y
    0x44, 0x64, 0x54, 0x4C, 0x44);  // z
//****************************************************************************//

Procedure NOK_Write (databit, mode : byte);
Var i : byte;
Begin
     FSRPtr := portaddress;
     // Pull DC high for DATA or low for COMMAND
     If TestBit(mode,0) = 1 then SetBit(INDF,___NDC);
     If TestBit(mode,0) = 0 then ClearBit(INDF,___NDC);

     ClearBit(INDF,___NCS);   //       CS = low

     // Clock in 8 bits of data - Highst bit first
     For i := 8 downto 1 do
     Begin
          ClearBit(INDF,___NSCLK);                             // SCLK = low
          If TestBit(databit, i - 1) = 0 then ClearBit(INDF,___NSDA)  // SDA = low
                                 else SetBit(INDF,___NSDA);   // SDA = high
          SetBit(INDF,___NSCLK);                               // SCLK = high
    End;
    SetBit(INDF,___NCS);     //        CS = high
End;
//****************************************************************************//
// Draws a character on screen at current possition
Procedure NOK_Chr(symlcd : Byte);
Var l : Byte;
    m : Byte;
Begin
      NOK_Write(0x00,1);          // Space between characters
      
      If (symlcd < 78) then
      Begin
           For l := 1 to 5 do
           Begin
                m := (symlcd - 32);
                m := m * 5;
                m := m + l;
                m := m - 1;
                NOK_Write(Font5x7_1[m],1);
           End;
      End;
      
      If (symlcd > 77) then
      Begin
           symlcd := symlcd - 46;
           For l := 1 to 5 do
           Begin
                m := (symlcd - 32);
                m := m * 5;
                m := m + l;
                m := m - 1;
                NOK_Write(Font5x7_2[m],1);
           End;
      End;
End;
//****************************************************************************//
// Set the current position for data (0<= x <= 84,  0<= y <= 5)
Procedure NOK_GotoXY(x,y : byte);
Begin
     SetBit(x,7);
     SetBit(y,6);
     NOK_Write (y,0);
     NOK_Write (x,0);
End;
//****************************************************************************//
// Inverts Display - Here is still a bug. It only inverst once and doesn't
// want to invert back again
Procedure NOK_Invert;
Begin
     NOK_Write(0x0D,0);
End;
//****************************************************************************//
// Clear the LCD Data memory
Procedure NOK_Clear;
Var p, q, r : Byte;
Begin
     FSRPtr := portaddress;
     ClearBit(INDF,___NSDA);   // SDA = low - Data bit is low
     SetBit(INDF,___NDC);     // DC = high - Data mode
     ClearBit(INDF,___NCS);   // CS = low  - Chip Enable

     For p := 1 to 6 do //  for 6 rows
     Begin
          For q := 1 to 84 do   //    for 84 colums
          Begin
               For r := 1 to 8 do   //   for 8 loop (8 bits)
               Begin
                    ClearBit(INDF,___NSCLK);   //  SCLK = low  - Serial Clock Input
                    SetBit(INDF,___NSCLK);     //  SCLK = high - Serial Clock Input
               End;
          End;
     End;
     SetBit(INDF,___NCS);   // CS = high  - Chip Enable
     NOK_GotoXY(0,0);
End;
//****************************************************************************//
// Writes a string at x, y position (maks 14 char per row)  (0 <= x <= 84 , 0 <= y <= 5)
Procedure NOK_Out(x, y : byte; var sentance : array[14] of char);
Var v : byte;
Begin
     NOK_GotoXY(x,y);
     For v := 0 to length(sentance) - 1 do
     Begin
          NOK_Chr(sentance[v]);
     End;
End;
//****************************************************************************//
// Writes a string at current position
Procedure NOK_Out_CP(var sentance : array[14] of char);
Var v : byte;
Begin
     For v := 0 to length(sentance) - 1 do
     Begin
          NOK_Chr(sentance[v]);
     End;
End;
//****************************************************************************//
// LCD Initialization
Procedure NOK_Init(var port: byte; SCLK_pin, SDA_pin, DC_pin, CS_pin, RES_pin : byte);
Begin
     // Automatic assing pins to correct port. This is done by using the FSR and INDF registers
     portaddress := @port;
     
     ___NCS      := CS_pin;
     ___NSCLK    := SCLK_pin;
     ___NSDA     := SDA_pin;
     ___NDC      := DC_pin;
     ___NRES     := RES_pin;
     
     // Now we must take care of the TRIS register
     FSRPtr := portaddress + $80;
     ClearBit(INDF,___NSCLK);          //    SCLK = low
     ClearBit(INDF,___NSDA);           //    SDA  = low
     ClearBit(INDF,___NDC);            //    DC   = low
     ClearBit(INDF,___NCS);            //    CS   = low
     ClearBit(INDF,___NRES);           //    RES  = low


     FSRPtr := portaddress;
     // Now the correct port is in the FSR register and we can use the INDF register
     // to change the status of the pins
     
     ClearBit(INDF,___NSCLK);          //    SCLK = low
     ClearBit(INDF,___NSDA);           //    SDA  = low
     ClearBit(INDF,___NDC);            //    DC   = low
     ClearBit(INDF,___NCS);            //    CS   = low
     ClearBit(INDF,___NRES);           //    RES  = low

     // Toggle LCD reset
     Delay_ms(200);
     ClearBit(INDF,___NRES);       //     RES = low
     Delay_ms(500);
     SetBit(INDF,___NRES);         //     RES = high

     FSRPtr := portaddress;
     SetBit(INDF,___NCS);         //     CS  = high
     NOK_Write(0x21,0);       //     Extended commands
     NOK_Write(0xc5,0);       //     LCD Vop
     NOK_Write(0x06,0);       //     Temp coef
     NOK_Write(0x13,0);       //     LCD Bias 1:48
     NOK_Write(0x20,0);       //     Standard commands
     NOK_Write(0x0c,0);       //     Normal Mode

     // Clear and position at top of LCD
     NOK_Clear;
     NOK_GotoXY(0,0);
End;
end.