don't quite understand function

Thread Starter

Bear_2759

Joined May 23, 2008
120
hi guys, so I'm still a noob to C++ and having trouble with some basics. have a rough idea about some pointers but still havent fully grasped the idea yet.
I have a nokia 6100 LCD and Arduino, it works great, but what I want to do is alter the default font table and instead of it being a 8x16 font I want a 16x32 font. modifying the font table is easy enough. would be helpfull if anyone can tell me a good font to binary converter though so I dont have to do it manually.
the part I'm having trouble with, is understanding where in the following code it is defined/limited to 8x16.

Rich (BB code):
void setChar(char c, int x, int y, int fColor, int bColor)
{
    //y    =    (COL_HEIGHT - 1) - y; // make display "right" side up
    //x    =    (ROW_LENGTH - 2) - x;

    int             i,j; //integer up to -32K -> +32Kish
    unsigned int    nCols; //unsigned 0 -> 65Kish
    unsigned int    nRows;
    unsigned int    nBytes;
    unsigned char   PixelRow;
    unsigned char   Mask;
    unsigned int    Word0;
    unsigned int    Word1;
    unsigned char   *pFont;
    unsigned char   *pChar;
                                    
    // get pointer to the beginning of the selected font table
    pFont = (unsigned char *)FONT8x16;
    // get the nColumns, nRows and nBytes
    nCols = *pFont;
    nRows = *(pFont + 1);
    nBytes = *(pFont + 2);
    // get pointer to the last byte of the desired character
    pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
    // Row address set (command 0x2B)
    LCDCommand(PASETP);
    LCDData(x);
    LCDData(x + nRows - 1);
    // Column address set (command 0x2A)
    LCDCommand(CASETP);
    LCDData(y);
    LCDData(y + nCols - 1);
    // WRITE MEMORY
    LCDCommand(P_RAMWR);
    // loop on each row, working backwards from the bottom to the top
    for (i = nRows - 1; i >= 0; i--) {
        // copy pixel row from font table and then decrement row
        PixelRow = *pChar++;
        // loop on each pixel in the row (left to right)
        // Note: we do two pixels each loop
        Mask = 0x80;
        for (j = 0; j < nCols; j += 2) 
        {
            // if pixel bit set, use foreground color; else use the background color
            // now get the pixel color for two successive pixels
            if ((PixelRow & Mask) == 0)
                Word0 = bColor;
            else
                Word0 = fColor;
            Mask = Mask >> 1;
            if ((PixelRow & Mask) == 0)
                Word1 = bColor;
            else
                Word1 = fColor;
            Mask = Mask >> 1;
            // use this information to output three data bytes
            LCDData((Word0 >> 4) & 0xFF);
            LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
            LCDData(Word1 & 0xFF);
        }
    }
}
I assume it may also have something to do with the following
Rich (BB code):
const unsigned char FONT8x16[97][16] = {
0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00,
}
97 is pretty close to the length of the font table (I didnt count, that's an assumption), and I'm assuming 16 is the number of bytes per character. the hex values in the code above are for the character "$". I thought it best to leave out the rest of the font table and just have one as an example:rolleyes:

I've spent hours looking up code sites for any clues/hints that help me understand this better, and it has helped a bit. but pointers are still a bit confusing. mainly * and it's used allot in this.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
first 3 lines as follows

Rich (BB code):
0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
good point, but it would be hard for me to do this without understanding exactly how the function and font table works.

there are other binary format images stored in a similar way in some of the example programs that would be much bigger than the font table so with my limited knowledge I doubt it. but can't be sure without fully understanding how it works.
 

MrChips

Joined Oct 2, 2009
30,805
Ok, thanks for providing the info. It is just as I thought.

Those first three lines you show contain no character font. The programmer is using the first three bytes (8, 16, 16) to store the size of the font.

The * operator serves two separate purposes, somewhat related.
The first purpose is to identify a variable of type pointer, for example:

unsigned char *pChar

What is a pointer? A pointer is a memory location (usually of size equal to the native word length, in this case, maybe 16 bits) that can hold a memory address. Hence pChar holds an address. The part "unsigned char" is only important to the compiler for type checking. All pointers will be one memory location regardless of the variable type.

So treat pChar as a variable containing an address.

The second purpose of the * operator is, it is called the indirection operator.

If ch is a char variable defined as

unsigned char ch;

I can do:

ch = *pChar;

That is, get the address in pChar and fetch the character at this address.
Why are pointers important? Here are two examples.

1) If you have a character string or a large array that you wish to pass to a subroutine, you do not want to pass all the values of the array to the routine. All you need to pass is the address of the start of the string or array.

2) If your subroutine needs to modify a parameter that has been passed to it, you need to know where that parameter is stored. Hence you pass a pointer, not the value. This is what is know as passing parameters by reference versus passing by value.

The other related and useful operator to be aware of is the address operator &.
I can set a pointer by using this operator:

pChar = &ch;

This gets the memory address of the variable ch and sets in into the pChar variable.

So in your program:

Rich (BB code):
nCols = *pFont;
nRows = *(pFont + 1 );
nBytes = *(pFont + 2);
is simply extracting information on the size of the font from the first three bytes of the font table. You could just have written:

Rich (BB code):
nCols = 8;
nRows = 16;
nBytes = 16;
If you are going to increase the font width to 16, you will have to plan seriously how you will manipulate 16-bit information. Your font table will have to be unsigned int or you can use a pair of bytes.

Secondly, most LCD graphics displays work with 8-bit data. You will have to transfer the 16 bits as a pair of bytes.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
thanks for all the info, it really helped. I worked it out now... please feel free to criticise, it's the only way I'll learn. but at this point I now have a 16x32 "!" on my screen.
here's what I did.

I tested using unsigned int instead of unsigned char like you said but the screen just went blank and I couldnt work out why, probably just because I'm still a noob. so instead of having 16-bit values in the font table, I left it as 8-bit values but had twice as many per character.
here's how the "!" appears in the font table

Rich (BB code):
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x0F,0xF0,0x1F,0xF8,0x1F,0xF8,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x3F,0xFC,0x1F,0xF8,0x1F,0xF8,0x1F,0xF8,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0,0x07,0xE0,0x07,0xE0,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x00,0x00,0x01,0x80,0x07,0xE0,0x0F,0xF0,0x0F,0xF0,0x07,0xE0,0x01,0x80,0x00,0x00,
now dont misinterpret this, every 2nd value corresponds to the 2nd half(right 8 bits) of the character. it alternates (left 8),(right 8),(left 8),(right 8), and so on.

now there were several things I tried repeatedly but the one that worked, was to add another variable to the function, and run the setchar function twice, once for each half of the character.

Rich (BB code):
void setChar(char c, int x, int y, int fColor, int bColor, int group)
{
    //y    =    (COL_HEIGHT - 1) - y; // make display "right" side up
    //x    =    (ROW_LENGTH - 2) - x;

    int             i,j;
    unsigned int    nCols;
    unsigned int    nRows;
    unsigned int    nBytes;
    unsigned char   PixelRow;
    unsigned char   Mask;
    unsigned int    Word0;
    unsigned int    Word1;
    unsigned char   *pFont;
    unsigned char   *pChar;
    unsigned int    First8;
    unsigned int    Seccond8;
    unsigned int    Block;
                                    
    // get pointer to the beginning of the selected font table
    pFont = (unsigned char *)FONT8x16;
    // get the nColumns, nRows and nBytes. first two rows of font table define these.
    nCols = *pFont;
    nRows = *(pFont + 1);
    nBytes = *(pFont + 2);
    // get pointer to the last byte of the desired character
    pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;
    // Row address set (command 0x2B)
    LCDCommand(PASETP);
    LCDData(x);
    LCDData(x + nRows - 1);
    // Column address set (command 0x2A)
    LCDCommand(CASETP);
    LCDData(y);
    LCDData(y + nCols - 1);
    // WRITE MEMORY
    LCDCommand(P_RAMWR);
    // loop on each row, working backwards from the bottom to the top
    for (i = nRows - 1; i >= 0; i--) {
        // copy pixel row from font table and then decrement row
                Seccond8 = *pChar++;
                First8 = *pChar++;
                if (group == 0)
                {
                  Block = Seccond8;
                }
                else if (group == 1)
                {
                  Block = First8;
                }
              // loop on each pixel in the row (left to right)
        // Note: we do two pixels each loop
        Mask = 0x80; 
        for (j = 0; j < nCols; j += 2) 
        {
            // if pixel bit set, use foreground color; else use the background color
            // now get the pixel color for two successive pixels
            if ((Block & Mask) == 0) 
                Word0 = bColor;
            else
                Word0 = fColor;
            Mask = Mask >> 1; 
            if ((Block & Mask) == 0)
                Word1 = bColor;
            else
                Word1 = fColor;
            Mask = Mask >> 1;
                        // use this information to output three data bytes
            LCDData((Word0 >> 4) & 0xFF);
            LCDData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
            LCDData(Word1 & 0xFF);

        }
}
}
and now the updated setStr function. runs the setchar function for the left side then the right side. for some reason, the right side was 1 pixel lower than the left side and it's now past midnight so too tired to work out why lol. so I just added the x = x - 1 before the right half of the character is printed and then after x = x + 1 otherwise the next character would be 1 pixel higher overall.

Rich (BB code):
void setStr(char *pString, int x, int y, int fColor, int bColor)
{
  x = x + 16;    //starting X position
  y = y + 8;    //starting Y postion
  // loop until null-terminator is seen
  while (*pString != 0x00) {    //*pString does not equal 0x00
    // draw the character
    char charselect;
    charselect = *pString++;
    setChar(charselect, x, y, fColor, bColor, 1);    //
    y = y + 8;
    x = x - 1;
    setChar(charselect, x, y, fColor, bColor, 0);  
    // advance the y position
    y = y + 8;
    x = x + 1;
    // bail out if y exceeds 131
    if (y > 131) break;
  }
}
please criticise and remember this is what a noob came up with ;):D
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
one last problem that i need assistance with, the length of each character in the font table is now 64 hex values, 32x2 because each one is split in two.
the first character works fine, but then the 2nd uses the 2nd half of the first and the first half of the 2nd. then the 3rd character uses the hex codes for the 2nd character. so...
1st character uses 1-32
2nd character uses 17-48
3rd character uses 33-64

where it should be
1st uses 1-32
2nd uses 33-64
3rd uses 65-96
 

MrChips

Joined Oct 2, 2009
30,805
Comments:

You do not have to use variables for nCols, nRows and nBytes.
You can declare these as constants:

#define NCOLS 16
#define NROWS 32
#define NBYTES 64

How did you declare the font table?
I would use

unsigned char Font16x32[96][32];

This would be my setStr function. I assume x is along the horizontal axis.

Rich (BB code):
void setStr(char *pString, int x, int y, int fColor, int bColor)
{
    char charselect;
  // loop until null-terminator is seen
  while (*pString != 0x00) {    //*pString does not equal 0x00
    // draw the character
    charselect = *pString++;
    setChar(charselect, x, y, fColor, bColor, 1); 
// advance the x position
    x = x + NCOLS;
  }
}

setChr( ) to come later.
 

MrChips

Joined Oct 2, 2009
30,805
The next question is how do you wish to define each character in the font table?
Do you want to go left-right 32 times or
left 32 times follow by right 32 times?
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
I'm pretty sure font table is delcared as [97][32]
I tried setting NBytes as 64 but screen just went blank.
left-right or left then right doesnt bother me, at the end of the day it wont make much difference.
I'll have to check half this stuff later when I get home though.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
actually font table was set as [97][16] but if I changed it to 32 nothing on the screen.
defining nbytes ncols and nrows worked a treat. the 4 characters I've created so far are displaying on the screen like they should.
 

MrChips

Joined Oct 2, 2009
30,805
Just changing the values of NCOLS, NROWS, NBYTES would not make it work. You still have to work through the code and change that also.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
sorry I was wrong, doesnt work for the full character table. only works if I comment out most of the character table. forgot about the 0-255 limit for unsigned char. I've changed it to unsigned int
Rich (BB code):
const unsigned int FONT16x32[95][32] = {
I've remved the first 2 lines where the original author had the values for nbytes, ncols etc. I've replaced most of the contents of the font table with
Rich (BB code):
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
there's only 2 characters defined at the moment and that's 1 and !.
 
Last edited:

Thread Starter

Bear_2759

Joined May 23, 2008
120
I've added this to the setchar function to split the 16-bit hex into two 8-bit blocks
Rich (BB code):
                PixelRow = *pChar++;
                First8 = ((PixelRow & 0xFF00) >> 8);
                Seccond8 = (PixelRow & 0x00FF);
I'm working through the rest of the setchar function now to see how I can change it to get it to work.

I added a second font table, the original 8x16 so I can print debug info to the screen and it's helped me get allot further now.
 

MrChips

Joined Oct 2, 2009
30,805
If you don't mind my asking, why do you want a 16 x 32 font? Those are large characters.
How much memory do you have on the processor?
 

MrChips

Joined Oct 2, 2009
30,805
sorry I was wrong, doesnt work for the full character table. only works if I comment out most of the character table. forgot about the 0-255 limit for unsigned char. I've changed it to unsigned int

I've removed the first 2 lines where the original author had the values for nbytes, ncols etc. I've replaced most of the contents of the font table with !.
You could have broken up the array into pieces.

unsigned int is ok too.

That is going to be a lot of typing to do but it is doable. I did it for my 8x12 character set which you will see soon.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
I want a font that large, partially for looks and partially so it can be viewed from a distance easier.

the typing is ok, I dont mind doing that. it'll take me about 15minutes per character to do but that's why I've only created 2 characters in the font table so far.

I've been working my way backwards through the setchar function to find where the issue is. I've been manually setting variables with values I know will work to see if it displays on the screen. at this point I've isolated it to the part that either reads the data from the font table, or the part that splits the 16bit string into two 8 bit.
 

Thread Starter

Bear_2759

Joined May 23, 2008
120
right, so the issue is with
Rich (BB code):
    pFont = (unsigned int *)FONT16x32;
    pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1; 
    for (i = nRows - 1; i >= 0; i--) {  
    PixelRow = *pChar++;
}
this works fine for a 8x16 font table, but when I changed it to unsigned int I dont know what went wrong. as far as the complier is concerned it's still fine...

if I specify an element in the array for PixelRow like this
Rich (BB code):
PixelRow = FONT16x32[2][6];
it works, I get that block printed to the screen. but if I do the following
Rich (BB code):
PixelRow = FONT16x32[2];

it does not work, as far as I know this SHOULD work, it's in the for loop, where i is constantly decrementing so I should actually be able to use this instead but for some reason my LCD doesnt like it.

I'm going to keep trying things but if you can suggest anything please do.
 

MrChips

Joined Oct 2, 2009
30,805
I will give this a shot sometime later when I have more time.
For now, this is how I would approach the problem

Rich (BB code):
// assuming
const unsigned int FONT16x32[95][32] = { 
// first char is SP
// second char is !
 };

#define NCOLS   16
#define NROWS   32
#define COFFSET 32  // offset of first character into ASCII table
   :
   :

void setChar(char c, int x, int y, int fColor, int bColor)
{
  
    int i, j; 
    unsigned int thisrow;
    unsigned char left8, right8;
    unsigned char *pFont;
    unsigned char *pChar;
      :
      :                                 
    pFont = &FONT16x32;
    pChar = pFont + (NROWS * (c - COFFSET));

    // loop for each row, we can fix up the order later
    i = NROWS;
    do
    {
       thisrow = *pChar++;
       left8 = thisrow >> 8;
       right8 = thisrow & 0x00FF;
         :
         :
    } while (i--);
}
I will check this for correct syntax later.
 
Last edited:
Top