Thursday, November 29, 2018

How to Define Special Characters on LCD


Hi there. This post is somehow a continuation of previous LCD post however not related with hardware but only software. I will address the problems, mentioned in the previous post and mention how to define special characters on LCD. Although, this is really simple to do in high level platforms such as Arduino using libraries, unfortunately there are only few resources on the Internet about that. 

I will try to follow the sequence of events in the previous post.


Problem with the Pins
I could not write any character to the display initially. It came to my mind that the characters were actually written on the display but I couldn't see them. I had experienced this a long time ago. It's simple enough to connect the LCD contrast pin (3) to the ground over a resistor with 4.7K or with 2.2K value. I was going to do like that. I was still thinking like "it is working without any problem but I could not see it", therefore I changed the resistor with a potentiometer in order to adjust the contrast. Normally, backlight is also not needed in green LCDs. Therefore, I chose a green one. Anyway, I connected pin 15 of LCD to Vcc and pin 16 of LCD to GND.

The problem was still not solved, although I connected everything without any shortcuts. I have changed the line outb(0, BASE) at the end of the code to outb(255, BASE). I checked the voltage on the data pins but everything was fine with them. I increased the delay parameter to 3 seconds in order to read signals with multimeter and checked E and RS pins. E was flipping between high and low as expected but there was nothing on RS except plain high signal. Pin connections I used, are as follows:

PP Signal
DB25 Pin
Centronics Pin
IC In
IC Out
LCD Signal (Pin)
nStrobe(C0)
1
1
IC2_17
IC2_3
E (6)
nSelect (C3)
17
36
IC2_15
IC2_5
RS (4)
Data0 (D0)
2
2
IC1_2
IC1_18
D0 (7)
Data1 (D1)
3
3
IC1_4
IC1_16
D1 (8)
Data2 (D2)
4
4
IC1_6
IC1_14
D2 (9)
Data3 (D3)
5
5
IC1_8
IC1_12
D3 (10)
Data4 (D4)
6
6
IC1_17
IC1_3
D4 (11)
Data5 (D5)
7
7
IC1_15
IC1_5
D5 (12)
Data6 (D6)
8
8
IC1_13
IC1_7
D6 (13)
Data7 (D7)
9
9
IC1_11
IC1_9
D7 (14)

The source article, I used during the assembly of the circuit, shows pin 13 for nSelect signal. I misunderstood this part, because pin 13 is actually an input pin. In another source [ https://www.lammertbies.nl/comm/cable/parallel.html ], which I usually used, port directions were also drawn. I was trying to get an output from pin 13 not pin 36 and since pin 13 is an input pin it was always set. BTW, the width of the plastic part on the both ends of jumper cables (colored ones) is bigger than the distance of the pins in Centronics port. Therefore, I used wires in even numbered ports and jumper cables in odd numbered ports (example). First, I suspected a contact problem but if this was the case, the code would produce different results on each execution. I will also mention the relationship of signals and ports in further chapters.

By the way, there is a video on LCDs, that there is no upper limit for DELAY parameter:


The Problem with the Function lcdKomut()
This function was initially written as follows: 

void lcdKomut(unsigned char veri)    {
    outb(veri, BASE);
    outb(8   , CTRL);    // RS = 0; E = 1
    usleep(DELAY);
    outb(9   , CTRL);    // RS = 0; E = 0
    usleep(DELAY);
}

For some reason, each time after I sent a command with this function, following data was printed twice. For example, as I tried to print 'Testing' in first line and '123' in the second, it was actually printed 'TTesting' and '1123'. I thought, this caused because the parallel port controller cannot reset the pin fast enough. Even E pin is still not zero, the CPU was too fast compared to the controller and sends the data to the bus immediately. But I have observed the same behavior even with bigger values of DELAY parameter. I changed the value 9 to 1 in the code and problem was fixed. There is an image, I like about these situations:


Since the problem was solved, I didn't want to investigate further. Maybe I should examine incoming signals with an oscilloscope but as I said, I didn't want to deal with it.


Status and Control Signals of Parallel Port
Speaking of signals, I need to briefly mention status and control signals. Parallel port has three groups of signals: data, status and control. These signals are controlled by the BASE, BASE+1 and BASE+2 I/O ports, respectively. Data signals are simple: The parallel port pins between 2 and 9 are set/reset according to the byte written to the BASE port and they remain. Status pins can be used for input because they are designed to read the printers status, i.e. printer generates an interrupt request, runs out of paper or has a paper jam etc.

nStrobe and nSelect pins are in control signal group. These control signals exist to control the printer and they are "active low" signals. Therefore, the name of the pin is prefixed by "n" or "~". nStrobe is used as a clock signal when computer is transmitting data to printer. The computer has to set this signal each time the data pins are changed. nSelect is set when the printer is selected (to print). nStrobe and nSelect pins were controlled using 0. and 3. bits of the control register, which is mapped to 0x378 + 2 = 0x37A I/O port. nStrobe is reset by writing 1 to the control port and nSelect is reset by writing 8 to the control port.

LCD Commands and Defining Special Characters
I used some of the LCD commands without mentioning all of them. 3-4 commands are really enough while working on LCDs. I usually use this image working on LCDs: https://goo.gl/images/QHtKee. Many similar results can be found in Google images by searching "lcd commands". The most proper way, is always relying on the datasheet of LCDs however reading an 60 pages document to build some device quickly, is impossible. I uploaded a generic datasheet to my Google drive and will use it to program CGRAM and create my own character set in LCD.

LCD fonts are stored CGRAM and CGROM (character generator RAM). There is a DDRAM, which stores the codes of the characters shown in the LCD cells. When a data is written to DDRAM, CGRAM/CGROM is used as a look-up table to demonstrate the characters. Since CGRAM is writable, it allows the users to create their own character set. There are 6 bits reserved for addressing CGRAM according to the datasheet but I am not sure that all of these bits are used in a standard LCD. CGRAM address starts with the zero.
On the page 24 of datasheet, table of the LCD commands can be found on Table 6. I first need to specify with a command, which character I will write. To address CGRAM, I need to issue 0b01XX XXXX command. Those Xs are the address bits of the character. Therefore the command is 0x40 for the zeroth address. According to page 31, the data can be send with lcdVeri() function. The character to be defined, must be sent as 5-bit-wide bitmap data. This information is on the previous pages in datasheet. One important thing is, LCD has to be disabled while writing CGRAM.

I slightly changed my old code to define characters. Definitions, lcdVeri() and lcdKomut() functions are same. I have pasted main() below:

int main(int argc, char* argv[])    {
    int i;

    if(ioperm(BASE, 3, 1))    {
        fprintf(stderr, "Access denied to %x\n", BASE);
        return 1;
    }

    lcdKomut(0x38);    // 8 bit, 2 lines, 5x7 px
    lcdKomut(0x08);    // disable lcd

    const unsigned char specialchars[] = {
        // something like smiley
        0B01110, 0B10001, 0B11011, 0B10001,
        0B11011, 0B10101, 0B10001, 0B01110,
        // inverse of smiley
        0B10001, 0B01110, 0B00100, 0B01110,
        0B00100, 0B01010, 0B01110, 0B10001,
        // spades
        0B00100, 0B01110, 0B11111, 0B11111,
        0B10101, 0B00100, 0B01110, 0B00000,
        // clubs
        0B00000, 0B01110, 0B10101, 0B11111,
        0B10101, 0B00100, 0B01110, 0B00000,
        // heart
        0B00000, 0B00000, 0B01010, 0B11111,
        0B11111, 0B01110, 0B00100, 0B00000,
        // tile (diamond)
        0B00000, 0B00100, 0B01110, 0B11111,
        0B11111, 0B01110, 0B00100, 0B00000
    };



    lcdKomut(0x40);   // 0. CGRAM address
    for (i = 0; i <= 47 ; i++)
      lcdVeri(specialchars[i]);

    lcdKomut(0x01);    // clear the screen
    //lcdKomut(0x80);    // linefeed
    lcdKomut(0x0F);    // enable screen, cursor blink

    lcdVeri('D'); lcdVeri('e'); lcdVeri('n');
    lcdVeri('e'); lcdVeri('m'); lcdVeri('e');
    lcdKomut(0xC0);    // second line
    lcdVeri('1'); lcdVeri('2'); lcdVeri('3');
    lcdVeri(' '); lcdVeri(' '); lcdVeri(' ');

    // special characters
    lcdVeri(0x00); lcdVeri(0x01); lcdVeri(0x02);
    lcdVeri(0x03); lcdVeri(0x04); lcdVeri(0x05);
 
    outb(0, BASE);
    return 0;
}

With this code above, special characters are defined and printed on the display:

Thursday, November 8, 2018

Calculator the Game and Its Solution


Hi there. After a long break, this post is again about a game. I will talk about the game and use Matlab.


I had downloaded "Calculator: The Game" in the beginning of summer. The aim of the game is, to start with a given number and to reach to the "goal" number in a limited number of operations. Here is a video of that game:  https://www.youtube.com/watch?v=w5yyY341-4A. This game was downloaded 5M+ times at that time, so I can assume that it is a famous game. The screenshot, left, is from the first level. This level starts with zero. The allowed operation is +1 and the aim is obtaining 2 in two moves. Since there is only one operation, it is obvious that the solution is pressing +1 two times.

Level 30
In advanced levels, more complicated operations are available. For example, '<<' operation gives 432 from 4321. Violet buttons with numbers on them like in the screenshot right, append numbers to the actual number. Pressing violet 5 on 432, implies 4325. Orange conversion buttons, seen on the same screenshot right again, replaces 1s to 2 ( 1 => 2 ) and 2s to 3
( 2 => 3 ).  The solution of level 30, in the rightmost screenshot, is  pressing: 1, 2, 2=>3, 1=>2, 2, 1. SUM button gives the sum of the digits of the number. Inv10 subtracts each digit from 10. [+]1 works on the calculator buttons and adds 1 to the values on the buttons. Store, stores the number in memory, in order to use the same more than once. Shift, corresponds rotation operation in assembly. Mirror, appends the reversed digits of a number to its left. 

Examples:
4325 (SUM) -> 14 (SUM) -> 5
4325 (Inv10) -> 6785
4325 (Shift>) -> 5432 (<Shift) -> 4325
25 (Mirror) -> 2552 -> (Mirror) 25522552

There are also portals in the game which are not buttons. For example, if there is a portal from hundreds place to one's place and if the result of an operation is greater than 100, the portal adds the digit on the hundreds place to one's place and removes the digit from hundreds place.

Bölüm 60
I played this game for a long time and noticed that a "trial and error" approach on all combinations is more practical than thinking, in specific levels. For example, let's consider level 30 (the screenshot above). The solution is quite easy. There are 46 = 4096 button combinations in total, since there are 4 buttons and six moves. For this example, thinking is more practical. On the other hand, let's consider 60th level, in the screenshot on the right. This level looks like harder than 30th level however pressing on two keys in five moves makes 25 = 32 different combinations. In this level, brute force technique is much more simpler than thinking.

Not using a computer is unthinkable, when brute force approach is considered. So that, even though 4096 may seem like huge, this can be tried in a computer in a few seconds. The most important is to approach the problem correctly.

If the operations would be written in a single function, they could not be called in different sequences, in a linearly running code. The button operations should be defined as functions and there must be as many functions as the number of keys. Or in other words, each key should be written as a function.

How can the keys be pressed? For example, even though there are five different keys in a level, pressing only one of them consequtively can be a solution. Or pressing first key and then second key and then first again etc. Let's assume the keys are numbered and pressing sequence does not matter. Since there are five button, five digits will be used for numbering. Let's also assume that number of moves are three for this theoretical level. Pressing the first key consequtively corresponds to 111, pressing first three keys in a sequence corresponds to 123. If generalized, it's used as many numerals as the number of keys and the number corresponding to a key sequence consists from as many digits as the number of moves. These are some examples to the valid combinations: 125, 134, 225, 334, 415, 531, 555. Since there are 53 = 125 combinations in total, there is no need and space to count them all. In the meantime, if 0 is used instead of 5 when numbering the keys, the relation to the 5-based numbering system can be noticed easily.

125 means to press 1st, 2nd and 5th keys or calling first then second and then fifth function respectively. So, how should the functions be called in a certain order according to the value of the number? The easiest way to do this is to work with function pointers, not the functions itself. This might sound a bit complicated. Speaking of complicated, this is done in C as follows:
#include<stdio.h>

void fonk1(int i)    {
  fprintf(stdout, "Fonk1: %d\n", i);
}

void fonk2(int i)    {
  fprintf(stdout, "Fonk2: %d\n", i);
}

void fonk3(int i)    {
  fprintf(stdout, "Fonk3: %d\n", i);
}


int main(int argc, char* argv[])    {
  void (*fparray[3])(int i);
  int i;
 
  fparray[0] = fonk1;
  fparray[1] = fonk2;
  fparray[2] = fonk3;
 
  for(i = 0; i < 3; i++)    {
    (*fparray[i])(i);
  }
 
  return 0;
}

In the example above, three simple functions were defined. A void function pointer array with three elements is created in the main() function and pointers of fonk1, fonk2 and fonk3 are assigned to this array. Considering that, the name of a function in C is the pointer to itself at the same time, no operator (*, &) is required for assignments. In other words, the name of the function contains the address of the first command of function. In for loop, elements of the array is called one-by-one with the argument 'i'.
Level 192
Function pointers in C, are hard to understand (at least for me). It is confusing which parentheses should be where. Instead of C, I used Matlab for the solution. It is quite easier to code this in Matlab. Similar to the & operator in C, there is @ operator in Matlab for function pointers. To store the function pointers, I used cell arrays instead of matrices and feval function to evaluate the button function with given argument. Instead of dealing with number systems in the code, I used nested for loops as many as the number of functions.

For example, 192nd level was hard. I had to code for this level. There are five buttons and six moves, which makes so many combinations. There is a portal from thousands position to one's position. First, I started to write functions to the buttons. Please note that, the functions in Matlab must be saved in files with the same name of the function. First function is in the file tus1.m, second function is in the file tus2.m etc.

function deger = tus1(deger)
  % +8
  deger = deger + 8;
endfunction

function deger = tus2(deger)
  % *4
  deger = deger * 4;
endfunction

function deger = tus3(deger)
  % Inv10
  s_deger = int2str(deger); % convert number to string
  for k1 = 1:length(s_deger)
    if (s_deger(k1) != '0')
      s_deger(k1) = int2str(10 - str2num(s_deger(k1))); % subtract the characters from 10
    endif
  endfor

  deger = str2num(s_deger); % convert the string back to number

endfunction

function deger = tus4(deger)
  % append 9
  deger = deger * 10 + 9;
endfunction

function deger = tus5(deger)
  % 7 => 0
  if( floor(deger / 100) == 7 )
    deger = deger - 700;
  endif
 
  if( mod(floor(deger / 10), 10) == 7 )
    deger = deger - 70;
  endif
 
  if(mod(deger, 10) == 7)
    deger = deger - 7;
  endif
 
endfunction

I considered the portal as a separate function, accepting the value, returned from any button function, as an argument. The result of a function, enters to the portal function and  exits  arranged. I named the portal function as "girdicikti":

function deger = girdicikti(deger)
  if(deger > 999)
    binler = floor(deger / 1000);
    deger = mod(deger, 1000) + binler;
    if(deger > 999)
      girdicikti(deger)
    endif
  endif
endfunction

Main function is as follows:

ilkdeger = 189; % ilkdeger means initial value

% Function array
f_a = { @tus1, @tus2, @tus3, @tus4, @tus5 };

for k1 = 1:5
  for k2 = 1:5
    for k3 = 1:5
      for k4 = 1:5
        for k5 = 1:5
          %for k6 = 1:5
           
            step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
            step2 = girdicikti( feval (f_a{k2}, step1) );
            step3 = girdicikti( feval (f_a{k3}, step2) );
            step4 = girdicikti( feval (f_a{k4}, step3) );
            step5 = girdicikti( feval (f_a{k5}, step4) );

            if(step5 == 500)
              printf("%d %d %d %d %d\n", k1, k2, k3, k4, k5);
              break
            endif
          %endfor
        endfor
      endfor
    endfor
  endfor
endfor

The 'ilkdeger' variable enters to a function. As a result of a key press (function), ilkdeger becomes step1. Another key press results in step1 being step2... Interestingly, this level is solved in five steps instead of six. The solution took about 15.96 seconds in my computer. This program produces two different outputs:

Level 199
2 5 4 1 5: 189 (x4) -> 756 (7 => 0) -> 056 (9) -> 569 (+8) -> 577 (7 => 0) -> 500
4 2 1 4 2: 189 (9) -> 900 (x4) -> 603 (+8) -> 611 (9) -> 125 (x4) -> 500

I wrote another code for the level 199. There are 46 = 4096 button combinations in this level. Since the third button is them same button as the previous example, I skipped it below:

function deger = tus1(deger)
  % append 7
  deger = deger * 10 + 7;
endfunction

function deger = tus2(deger)
  % 3 => 5
  deger = str2num(strrep(num2str(deger), '3', '5'));
endfunction

function deger = tus4(deger)
  % shift >          3002 => 2300
  if(deger > 999)
    deger = mod(deger, 10) * 1000  +  floor(deger / 10);
  elseif(deger > 99)
    deger = mod(deger, 10) * 100  +  floor(deger / 10);
  elseif(deger > 9)
    deger = mod(deger, 10) * 10  +  floor(deger / 10);
  endif
endfunction

The portal from ten thousands place to one's place: 

function deger = girdicikti(deger)
  if(deger > 9999)
    onbinler = floor(deger / 10000);
    % strip ten thousands place
    deger = mod(deger, 1000) + onbinler;
    % add to ones place
    if(deger > 9999)
      girdicikti(deger)
    endif
  endif
endfunction

In the main function, unlike the previous example, I assigned the number of functions to lfa variable and ran the for loops up to this variable:
clc
clear

ilkdeger = 3002; % ilkdeger means initial value

f_a = { @tus1, @tus2, @tus3, @tus4 };
lfa = length(f_a);

for k1 = 1:lfa
  for k2 = 1:lfa
    for k3 = 1:lfa
      for k4 = 1:lfa
        for k5 = 1:lfa
          for k6 = 1:lfa
            step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
            step2 = girdicikti( feval (f_a{k2}, step1) );
            step3 = girdicikti( feval (f_a{k3}, step2) );
            step4 = girdicikti( feval (f_a{k4}, step3) );
            step5 = girdicikti( feval (f_a{k5}, step4) );
            step6 = girdicikti( feval (f_a{k6}, step5) );
            if(step6 == 3507)
              printf("%d %d %d %d %d %d\n", k1, k2, k3, k4, k5, k6);
              return
            endif
          endfor
        endfor
      endfor
    endfor
  endfor
endfor

This level is solved in six moves. The solution is "1 1 2 3 4 1" and it took approximately 0.68 seconds:
3002 (7) -> 30 (7) -> 307 (3 => 5) -> 507 (Inv10) -> 503 (Shift>) -> 350 (7) -> 3507

This level finishes the game and ending video starts. This approach, described in the post, can be applied to many levels of this game. But it is difficult to apply the keys like Store and more importantly keys like [+]2. For the latter, it should be possible to define a global increment value and modify the button functions according to this value. Since I had no difficulty with the levels containing such keys, I didn't have to write any code for these.