Jump to content

MIOS32 Voxel Space Graphics Demo on 256x64 Graphical OLED


Hawkeye
 Share

Recommended Posts

okay I figured out that I have to edit the display type in the makefile and set the environment variable back to universal. I haven't worked with custom displays before. I looked at the mios32 display types and I didn't see the ssd1322 on there. but if your demo works then it must be implemented somewhere. I will try it when I get home.

Link to comment
Share on other sites

  • Replies 60
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

Very slight screen flickering might be also due to the "improvised" display initialization - i experimented for hours with different init values - all completely different than the newhaven values :)

But putting a "buffering" cap to the 2.5V main display power supply is a good idea!

Regarding font output - it depends on your timeframe, i might get some code running next (not this) weekend, it should not be soo hard...

For my intended use, i´d like the screen to be divided into 64x16 pixel rectangle regions (each one corresponding to an encoder), each region filled with either two lines of 8 pixel high text (tiny) or one line with 16 pixel high text (well readable).

Bye!

Peter

Link to comment
Share on other sites

that's exactly the layout I'm looking for. let me know when you get something done. I'm just not experienced enough to write something from scratch.

edit: forget that... i'm gonna figure this out. after looking at your test screen code, it's a lot more clear. :)

another edit: using the test screen, i can see the flicker is really bad. hopefully only some capacitors will help. do you recommend a value?

Edited by ultra
Link to comment
Share on other sites

i'll try the caps later. for now i'm having a lot of fun with this. i got some nice single pixel wide horizontal meters written (i ditched the idea of having a meter behind text) with a light gray bar for the entire meter, and a brighter one showing the value. can be put anywhere on the display using parameters. i think i might go all out and make my own custom font and everything. that way i don't have to have fixed width characters and i can get more info from the screen. wheeeeee!

Link to comment
Share on other sites

I am usually working with variable-width fonts as well. Has lots of advantages, but makes aligning text a lot harder. A pretty nice workaround is (if you use smallish fonts and have all upper-case letters anyways) to use fixed-width upper-case and variable-width lower-case letters :)

Link to comment
Share on other sites

hawkeye:

is there some pattern to the shading?

i have a 2d array that stores information on individual pixels. this doesn't include what value i get when both pixels are on.

so if array[0] stores the value that gives me only the left pixel at a certain shade, and array[1] stores the value that gives me only the right pixel at a certain shade, is there an operation that can combine the two to give me two pixels at the same shade?

i hope i'm clear on this.

thanks

Link to comment
Share on other sites

Hi Ultra,

don´t know, if I completely understand the question, but will formulate a possible answer :)

as you have only 16 shades of grey/blue, you only need 4 bits for that information.

The memory is organized in bytes with 8 bits, so you can store 2 pixels in each byte.

If you want to set both pixels to color 15 (lightest shade/white), the byte would have to look like 1111-1111 in binary.

Example:

If the left one should be light grey (1000), the right one dark grey (0100), it would have to look like 1000-0100.

The C notation for entering binary numbers is to use the prefix "0b", you may not need this, just enter the values directly in decimal format (0-15) or copy them from your font bitmap source buffer.

The computation operation to combine these two values from 0-15 is first a "left shift" operation, which shifts your left pixel value so that it is on the left side:

unsigned char bothPixels = 0; // Yet unknown

unsigned char leftPixel = 0b1000; // Light grey

bothPixels = leftPixel << 4; // Shift bit pattern to the left, bothPixels now contains "1000-0000"

Then you just add the right pixel on top of that value
unsigned char rightPixel = 0b0100; // Dark grey

bothPixels += rightPixel; 

Now you can write this two-pixel byte to display memory (you usually write two bytes or four pixels at once). Regarding your question on how to calculate the "one byte" value with two pixels of the same color, it can be shortened to
unsigned char pixelColor = 5; // Decimal example

unsigned char bothPixels = (pixelColor << 4) + pixelColor;

Have lots of fun!

Greets,

Peter

Edited by Hawkeye
Link to comment
Share on other sites

I added one of those badboy OLEDs to my last Digi-key order, plus a white 16x2 OLED from Reichelt and some of those x4050 buffers. Guess there will be some experimentation with that and those Core LPCs laters :whistle:

FS1r programmer or this MB3396 look like the targets in line. Unless we get an MB-SIDv3 soon.

Link to comment
Share on other sites

hawkeye,

right now i don't have any code that would be useful to anybody else, unless they wanted to use my specific format. but i'm finding it limiting even for myself, so i'm going to work this afternoon to make it more universal.

my current method is to store an array[64][256] that simply contains 1's and 0's to tell whether or not a pixel should be on or off. this array is used for the entire region of the display. i'm going to change that to store 0-15 so the shade will be stored instead, which is why i asked my question earlier.

then i wrote a simple loop to read four slots out of the array at a time, and test them for on/off and write out the correct 2-byte codes to the display. it works great and i won't need to change it much for displaying the overall picture, except for changing the algorithm a little bit to account for shades. maybe this is the standard way of doing this, i don't know. i just started working out what makes sense to me as i don't have any previous experience in writing a display driver.

to draw my font, i wrote code specifically that would work with this font. i'd like to do it an entirely different way though, which i'll describe later. i have 3 functions to draw them: write_h_line and write_v_line will 'draw' horizontal and vertical lines into the main array based on starting x/y coordinates and length. a third function, write_pixel will write a single pixel based on x/y coordinates. calling them has to include whatever offsets i want (tall/short letter, etc). so when i feed in a string like "this", it loops each character, writes each to the main array, and puts an extra pixel for spacing. i just keep a running counter to show where the x-coordinate is for the start of a letter.

i'd like to just store fonts in different files. i like to have space available on both the top and the bottom to account for letters such as 'h' and 'g'. so for example, if i account for a font being 11 px tall (7 for a short letter like 'o', two px above that for a letter like 'h', and two below that for a letter like 'g') and want to write 'h', it'll be stored like this:

1000000

1000000

1000000

1111111

1000001

1000001

1000001

1000001

1000001

0000000

0000000

that's essentally an 'h' in the superpoint square font. but the same engine could easily read other fonts if the 1's and 0's (or actually, the value representing the shade) was stored for it.

my biggest setback is that i'm really not that great at C, and OOP makes more sense to me. i want to store data that contains the following information:

font name

overall font height

each character of the font, which has the following:

width (if even necessary)

left offset (i posted a pic below to show what that means)

an array storing the 1's and 0's (or shade values) that can be returned to the function calling it,a nd then inserted into the main array

i think i just need to learn more about defining types to store this data, and using pointers to make the array usable. i'll figure that out this afternoon maybe.

once this is done, and a small library of fonts are stored, the programmer or user could just select a font based on name, then size (i find that odd # sizes work best), and then write the letters where they want.

also i'm wondering how to handle words that are bigger than the space allowed (i want to code this to let the user define regions like you said), so if a word is too wide, it gets truncated. my thoughts were 'truncate' would turn into 'trunca.." if there wasn't enough space. if i go that route, i already have a good idea of how to do it. also, i'm going to incorporate left/center/right justification based on the user defined region.

anyway, i'm not really looking for you to answer anything unless you can tell me what's best for storing/retrieving the font data. i'm just throwing out what i've figured out so far and hoping for somebody to tell me if i'm going about it the wrong way.

the attached image shows what i mean by 'left offset'. the lowercase 'j' got it's own bit of code, which (if it's not the first char) backs up the counter to make the bottom part of the 'j' wrap around the previous letter. maybe switching from windows to a macbook has made me put too much emphasis on style. :P

post-4724-0-48779300-1333560503_thumb.jp

Edited by ultra
Link to comment
Share on other sites

J: great to hear! The moar 256x64 OLED users, the better :)

Ultra:

very nice! As far as i´ve understood, you are currently using the "lineTo" methods to draw the font, which makes sense for this linear font.

But to have a more universal font-drawing mechanism, i´d recommend to implement a packed bitmap font engine, that can handle characters with front leading ("j" in your example).

What you always have to keep in mind is the uC-limitations, you don´t have endless space, so "packing" data as well as possible is a necessity, or you will run out of memory for your main program...

So instead of using a full byte, if a pixel is lit or not, you could use a bit and extract it via bit operations (and/or/not bitwise operators -> wikipedia has some article on it).

To store a character with left offset, and flexible length you could

* put all characters in a 16x12 pixel bitmap (width x height), which will use only 192/8 = 24 bytes of space for each character.

* have a character "leading" and character "width" control parameter associated with each character, which you can also put into your packed font data structure (=26 bytes per character).

* do not output "blank pixels", so that the left offset of the "j" does not overwrite the right character pixels of the "a" in your demo.

Quick pseudo-algorithm to draw "j" with positive left-side leading

(Sorry don´t have more time to write the inner loop pixel checking and setting)


unsigned char x = 100; // Current x "cursor" coordinate

unsigned char y = 16; // Current y "cursor" coordinate


// Grab output buffer, that has enough room to store the to-be-rendered screen data

...


// Character output loop, example just writing character "j", assuming font with height 12 pixels, j has a left lead of 2 pixels, forces cursor to "go back"

unsigned char leftLead = packedCharacter['j'][24]; // Byte 25 contains the left leading

unsigned char width = packedCharacter['j'][25]; // Byte 26 contains the width


for (unsigned char yChar = y; yChar < y + 12; yChar++)

{

   for (unsigned char xChar = x - leftLead; xChar < x - leftLead + width; xChar++)

   {

  	// Code, that checks, if a pixel is lit in character buffer

  	// Only, if pixel is lit, modify output buffer

   }

}


// Write output buffer to screen

...

Edited by Hawkeye
Link to comment
Share on other sites

i understand what you mean with your algorithm and left lead and i'll implement that later. first, i need a method to store font information. i figured that 16x16 space is good for the maximum character size. this allows a u16 array[16] to be used to store the information. then i'll analyze the actual number to get the bits out of it. how does this look for a beginning to storing the actual fonts? this format might make it easy for others to add their own fonts:


// describes various fonts which can be up to 16 x 16 px wide.

// number of characters per font is 94.

// character index has a range of 0-94, which corresponds to chars 32-128 on the ascii table.  it's necessary to subtract 32 from the character code to get the correct character.


struct font_char {

    u16 bitmap[16];

    u8 left_lead;

    u8 width;

  };


struct font {

    u8 *name;

    u8 height;

    struct font_char chars[94];

  };


struct font fonts[] = {

    /* first font */

    {

        // superpoint square

        {

            // space

            {

                {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // bitmap

                0, // left lead

                2 // width

            },

            /* second character, and so on */

            /* ... */

        },

    },

    /* second font, and so on */

    /* ... */

};

keep in mind i'm just learning about how to use structs now, so maybe this is the wrong approach or the code is simply wrong.

Edited by ultra
Link to comment
Share on other sites

Hi there,

nice!

Instant initialization of complex pointered structures is not available in C - when dealing with "pointer" types, you need to store an address to a memory location, so initialization would be a 2-stage process, first storing the data, then getting and storing the address of it.

But, data serialization to the rescue. You can write a small "font data serializer" on your real computer, in your favourite language (script language is also fine), that creates a "C readable" seralized font description, that can be directly accessed.

Also, I´d put the different serialized fonts into different header or c files, so the user can include anything that is necessary (and thus reduce code size).

The font_char struct looks quite fine. It has a sizeof 16*2 + 1 + 1 bytes, which would be 34 bytes. Nao, some architectures/compilers do a structure aligning to int-size boundaries (here: 4bytes), i´d therefore make left_lead and width also 16 bits wide (u16), just to be on the safe side (sizeof / 4 = not a fraction), maybe structure aligning is turned off on MIOS32, but me iz not sure, also unsure about the future :).

Ok, long talk, here is some code, you need to strip away the typedefs, the main, and the printf(), i just tried it on a big computer, so that i do not tell you complete nonsense :)


typedef unsigned short u16;

typedef unsigned char u8;


/* One font char contains 18 16-bit words, or 36 bytes */

struct font_char

{

   u16 bitmap[16];

   u16 left_lead; 

   u16 width;	

};


struct font

{

   struct font_char character[96];  /* Starting at ascii character 32, which is a space, 

               						includes numbers, symbols, upper and lowercase letters */

};



/* Generated by off-line generator, made by big computer :) */

/* Put this in a header file and let the user choose which fonts he needs, to save space */

struct font serialized_square_font = { 0x0000, 0x1001, 0xFEED, 0xBEEF /* ,... and 1724 16-bit words more */};



int main()

{


   /* Let the user choose which font he wants, be obtaining a pointer to his preferred font */

   struct font* myFont = &serialized_square_font;


   /* Lets output the second and third bitmap "line" of the first character in the user-selected font */

   printf("%x\n", myFont->character[0].bitmap[2]);

   printf("%x\n", myFont->character[0].bitmap[3]);


   /* Note, you have to subtract "32" from every printed character value, as your

  	font "starts" at character 32, which is the "space". */

}


Have lots of fun!

Bye, Peter

Edit:

having switched to C++ 10 years or so ago, i was unaware of the following method of struct "by name" initialization - I´d *highly* recommend to go this route:

http://linuxprograms...ation-advanced/

It has the advantage, that the correct element order is not necessary and that less errors can occur - just write a "c font generator" that creates initializations in that format.

Edited by Hawkeye
Link to comment
Share on other sites

in my program to output the serialization, do i have to define each character like this?

for instance, here's a lowercase 'a' in superpoint square:

0000000000000000

0000000000000000

0000000000000000

1111111000000000

0000001000000000

0000001000000000

1111111000000000

1000001000000000

1000001000000000

1111111000000000

0000000000000000

0000000000000000

0000000000000000

0000000000000000

0000000000000000

0000000000000000

i left 3 px above it for uppercase letters extending upward, 3 px below for lowercase letters extending downward, and the unused 0's underneath. ignore what i said before about 11px fonts. this is 13 overall. this one is designed assuming the 0,0 coordinate is at the top-left, but it could be changed to the bottom-left. anyway, those specifics don't matter as much right now.

what i'm wondering is how i feed this into a serialization program? do i 'draw' each character like this, then write the program to loop through the lines and output a hex value for each set of 16 bits? if that's the case, i get how this works. just loop through the data, making a string with the hex value and concatenating a ', ' to the end. copy, paste into my C program, and repeat. or write in all the chars and have it output the information once.

also, does the serialized data contain left_lead and width information? 96*18=1728, so i'm assuming the two extra 16 bit words include the information. therefore, to retrieve the character's width, does it look like this?

width = myFont->character[0].bitmap[17]);

thanks for helping, i'm learning a lot about programming that i didn't know. i'm going to try to start working on a python program to output the serialized data.

Link to comment
Share on other sites

Hi there,

Yes, now convert every binary line into a 16bit hex value, separate by commas and you are good to go.

Your serializer also needs to write width and left_lead -> see the last link in my "edit" note below for how the serializer output format should look, ignore my long posting above, the proposed advanced structure initialization is much better. You should read the bitmap font first (on your big computer) and then write out the serialized "c struct initialization string", which you put into a separate header file for each font.

For each font, make your serializer iterate all 96 characters starting with character 32 (which is space).

Write a serializer loop that writes a long string for the whole font struct, that is a "C struct initialization" just as described in the link.

To access the width of a "space", just:

width = myFont->character[0].width;

Bye,

Peter

Edited by Hawkeye
Link to comment
Share on other sites

well that was easy


user_input = "0000100110001110"

total = 0


for bit in range(0, len(user_input)):

    total += int(user_input[bit]) << (15 - bit)


total = hex(total)

print(total)

0x98e

now i just need a bunch of instructions and loops and formatting and whatnot. :)

Edited by ultra
Link to comment
Share on other sites

i've written most the font generating program and it's working very well. it's pretty user friendly.

but i'm stuck trying to combine the information at the page you linked with how it should be in this context. should i end up with a .h file for the structs and a .c file for initialization?

so far, this is my output. i only put in two characters b/c i could spend all day testing this with 96. the series of hexadecimal numbers include the left_lead (now called left_shift) and width. but i'm assuming i don't have to do that since i'll be generating the initialization code.

anyway, here is what it looks like so far:


struct character {

	u16 bitmap[16];

	u16 left_shift;

	u16 width;

};


struct font {

	struct character characters[96];

};


struct serialized_superpoint_square = {0x0, 0x0, 0x0, 0xfe00, 0x200, 0x200, 0xfe00, 0x8200, 0x8200, 0xfe00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x8000, 0x8000, 0x8000, 0xfe00, 0x8200, 0x8200, 0xfe00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7};


this is of course not in the output. it's what you see as you build a character. 0/. is used for input to make it easier to see, and it's later translated into 1/0 for the hex output.

................

................

................

0000000.........

......0.........

......0.........

0000000.........

0.....0.........

0.....0.........

0000000.........

................

................

................

................

................

................


0...............

0...............

0...............

0000000.........

0.....0.........

0.....0.........

0000000.........

................

................

................

................

................

................

................

................

................

sorry for my lack of understanding with what to do with this, but at least when this is done we will be able to do some really cool things with this display. :)

ultra

Edited by ultra
Link to comment
Share on other sites

Hi there,

that already looks very nice!

Regarding your .h / .c question, there are two approaches.

In both cases, create one .h file by hand, which contains the struct info.

In case one, your generator only creates a square_font.h file, which the user can include, when he needs it - the advantage is, that he needs not add a .c file to the makefile - the disadvantage is, when the font is used by more than one module (.c), there will be a linker problem because of redefined data.

In case two, which is more general, your generator should create a square_font.h file, which contains an "extern" definition, so that any module can include it and use that font, and the .c file contains the font data. I would recommend this approach, as the benefits outweigh :)

Example, to keep it simple, i´ve just created one "character" struct, a font is an array of characters. Also, the lazy generator only creates a .h file (method one), this has to be adapted later.


font.h (not generated):

--------

typedef struct character_struct

{  

   u16 bitmap[16];

   u16 left_shift;

   u16 width;

} character;



square_font.h (generated)

------------------------------------

#include "font.h"

character square_font[] = 

{

   {

  	.bitmap = {  0x0, 0x0, 0x0, 0xfe00, 0x200, 0x200, 0xfe00, 0x8200, 0x8200, 0xfe00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0  },

  	.width = 0x07,

  	.left_shift = 0x00

   },

   {

   	...

   }, 

   ...

};

Did not test this in the compiler, may contain some typos but like this the "named" structure initialization should work.

Greets & have fun,

Peter

Edited by Hawkeye
Link to comment
Share on other sites

i'm a little confused.

i don't see an 'extern' definition. does it go like this?

extern character square_font[] = ...

font.h shouldn't be generated, but maybe it'd be easiest for the programmer if i output that to its own file if it doesn't exist?

you said the .c file should contain the font data, but isn't this the font data in the .h file?

.bitmap = { 0x0...

it's looking like i'm closer than i thought to having this completed. all the pieces are in place.

ultra

Link to comment
Share on other sites

Hi ultra,

heheh, yes, me was lazy, thats why the example refers to approach type "one", which is good to start with - once that is done and you can use your font after #include "square_font.h", we can move to the next step, that is put the font extern declaration in the header and the font data in the square_font.c file - its all in the text somewhere :)

Bye,

Peter

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share


×
×
  • Create New...