Shop OBEX P1 Docs P2 Docs Learn Events
uOLed-96-Prop ROCKS, but a few bitmap qestions... — Parallax Forums

uOLed-96-Prop ROCKS, but a few bitmap qestions...

bassmasterbassmaster Posts: 181
edited 2007-11-03 05:21 in Propeller 1
I am wanting to paint a bitmap from the sd card, I think I know how to do it, but does the bitmap have to be 16 bit?, i.e. to send 2 bytes to a pixel at a time to paint a 16bit 8k bitmap from the SD card would be slower than 8 bits,·does the bitmap have to be in 16 bit? or can I send a 256 color , 8 bits (one byte) for a 96X64 image. It would be not as pretty but alot more can fit into the sd card. Or am i way off base on how to do it?

I should use write_GRAM_word for the 2 byte 16 bit images, and the write_gram_byte for 8 bit 256 color right?··· Correct me if the sequence is wrong....

'...'snip...
Set_Full_Screen
Write_Start_GRAM

'loop to eof...
--'add code to READ the bmp from the sd into nextbyte until EOF
·· Write_GRAM_Byte(nextbyte) ' for 8 bit bmp's?
'end loop

Write_Stop_GRAM
...'do other stuff



Thanks...

Bassmaster

(Yep, I am back, Fishing is over for 2007 season, made it to 40th Place Angler of the year in the nation, but missed the cut-off for registration for the regionals, Still was in the money cut like 15 out of 20 tournaments this season, with 4 First Place wins!, now its time to get bak into the Microcontroller stuff for the winter.. A lot has changed since I have been gone, you all have done a great job making the Prop even better!, I am definately going to get a few more of these OLEDS and Hitts protoboard!, wow, alot to catch up on....)



Post Edited (bassmaster) : 10/26/2007 7:30:11 PM GMT

Comments

  • bassmasterbassmaster Posts: 181
    edited 2007-10-26 20:24
    I think I found some of my answers in the uoled-128 manual...

    "Due to the high
    colour depth of the μOLED, a pixel colour value will not fit into a single byte, a
    byte can only hold a maximum value of 255. Therefore the colour is
    represented as a 2 byte value, colour(msb:lsb)."

    So all bitmaps must be 16bit, And use the PutPixel method after the gram right....? Correct?

    Anyway I have limited knowledge of graphical displays and graphical formats, besides vga text modes, this is my first time trying my hand at graphics.

    Thanks,

    Sean
  • bassmasterbassmaster Posts: 181
    edited 2007-10-26 21:42
    nevermind, I got it.
  • bassmasterbassmaster Posts: 181
    edited 2007-10-27 02:49
    Well, kind of, I do not have any software to convert 24bit to 16 bit, so after looking for a freeware program (anyone still have the old shareware Lview?) I decided to try my luck with 256 colors..

    taking my avatar to the left, and in paint saving it as a 256 color 8 bit image, I got it to work, but the colors are yellowish/orangish, and the uoled whines... Any Idea's? the image is 96X72, do the extra 8 bytes matter? Code is hard coded for this bitmap for testing, maybe my math is wrong.

    PUB Drawbm

    oled.Set_GRAM_Access (0, 95, 0, 63)

    oled.Set_Contrast(10) 'does not appear to work here with GRAM , and definately locks up after start_GRAM

    oled.Write_Start_GRAM

    REPEAT temp from 7989 to 1299 'strsize(bitmap) to 1299
    oled.Write_GRAM_word (bitmap[noparse][[/noparse]temp]<<8 ) 'kind of works...

    oled.Write_Stop_GRAM

    Sean

    Post Edited (bassmaster) : 10/27/2007 2:55:02 AM GMT
  • DufferDuffer Posts: 374
    edited 2007-10-27 03:14
    Bassmaster,
    It sounds like you've found the secret to outputting an image to the uOLED-96_PROPs screen. It's no secret. The code for doing it is already in the object. It's the PutPixel method (Without the conversion of RGB to 16 bit color).

    PutPixel, if effect, outputs a 1x1 pixel "image" to the screen. The thing to understand is that the "Set_GRAM_Access (X, 95, Y, 63)" line mearly defines a rectangle in screen RAM that accepts two bytes per pixel of color information to light one pixel. The line could have read: Set_GRAM_Access (X, X +1, Y, Y +1) because the PutPixel Method only writes two bytes and lights one pixel.

    Example for a 40x40 16 bit raw image file to be drawn at origin 0,0 on the screen:

      Set_GRAM_Access (0,39,0,39)
     
      REPEAT 1600                                      40 x 40 pixels
        ' code here to read two bytes of raw image data from source
        ' into a Long, R                
        OUTA[noparse][[/noparse]CS_OLED] := 0
        OUTA[noparse][[/noparse]WR_OLED] := 0
        OUTA[noparse][[/noparse]7..0] := R.byte[noparse][[/noparse]1]                        ' MSB
        OUTA[noparse][[/noparse]WR_OLED] := 1
        OUTA[noparse][[/noparse]WR_OLED] := 0
        OUTA[noparse][[/noparse]7..0] := R.byte[noparse][[/noparse]0]                        ' LSB
        OUTA[noparse][[/noparse]WR_OLED] := 1
        OUTA[noparse][[/noparse]CS_OLED] := 1
     
    

    it's this simple because you don't have to keep track of where the next pixel will be written. That's taken care of by the controller because you defined the screen area explicitly with the Set_GRAM_Access. The display controller incriments the column and row addresses in GRAM·automatically for you. This fact is not obvious in the PutPixel routine because only one pixel is written to GRAM.

    If your raw image file is a 24 bit color image, you would read three bytes from your source, convert it ti 16 bit color (you can use the RGB to 16 bit line that's at the beginning of the PutPixel routine) and the rest is the same.

    Have fun,···· Duffer

    The quickest and easiest way to get 16 bit raw image data onto the uSD card so that you can continue to experiment is the use The Graphics Composer from 4D. You can remove the uSD from the 96-PROP, put the uSD into a card reader on your PC (usually with a uSD to SD adapter) and then point the Graphics Composer to the drive letter of the card reader and start loading your images (see the GC docs for details), The GC does all the heavy lifting as far as understanding all the various image formats and all that. A text file·(same name as your GC project Name)·is created by the GC that indicates the beginning and the length of each graphic image on the uSD. Everything you need to "fill in the blanks" in your code is in the text file.



    Post Edited (Duffer) : 10/27/2007 3:28:44 AM GMT
  • bassmasterbassmaster Posts: 181
    edited 2007-10-27 18:49
    The Graphics composer crashes and can not write to my sd card, it just hangs, I have not got it to finish any conversion, any other applications? I have installed 15 shareware appsand GNU apps, in the last day, and still have not foulnd one that writes 16bit (preferably raw) images.

    Also I could not get the put pixel to work at all.

    I know i am doing something wrong, just at a loss... your statement "The display controller incriments the column and row addresses in GRAM automatically for you" and then the "The line could have read: Set_GRAM_Access (X, X +1, Y, Y +1) " were also tried without success,

    here is just one of my variations... the /2 is due to my trying the origional somewhat successfull code mentioned above. FYI I have it working with better colors using the code from the putpixel.

    pub drawbm


    oled.Set_GRAM_Access (0,95/2,0 ,63/2 )

    oled.Set_Contrast(10) 'does not appear to work here with GRAM , and definately locks up after start_GRAM

    oled.Write_Start_GRAM
    REPEAT temp from ((95) * (63)) to 0 ' 7989 to 1299 '' 0 to 3720
    oled.putpixel(x+1,y+1,(bitmap[noparse][[/noparse]temp]>> 3)<<11,(bitmap[noparse][[/noparse]temp]>> 2)<<5,bitmap[noparse][[/noparse]temp] >> 3)
    if y > 63/2
    y := y - y + 1
    if x > 95 /2
    x := x - x + 1

    oled.Write_Stop_GRAM
  • DufferDuffer Posts: 374
    edited 2007-10-27 19:28
    Bassmaster,

    I would suggest that you try something a bit simpler to start with. For example, try using the code in my post above (you don't need to use the Write_Start_GRAM and Write_Stop_GRAM calls, you can use the register writes directly) and try a loop to ouput 5-10 pixels of the same color (it should produce a horizontal line starting at the X,Y of the Set_GRAM_Access statement. I would remove the Set_Contrast statement as it serves no purpose here. The default contrast setting should work fine.

    Once you're comfortable with outputting multiple pixels, it's just a matter of changing the code to define the display area that you wish to write to and setting up the loop to read the source image color data.

    If you're having trouble with the Graphics Composer, please post to the 4D Systems forum at:

    http://www.websitetoolbox.com/tool/mb/4d·, under the Graphics Composer section. That should be your first choice for support for 4D products/software.

    Duffer
  • bassmasterbassmaster Posts: 181
    edited 2007-10-28 00:24
    Thanks, I guess I was not clear, I can paint images using your code snippit, but no matter how I do it I can not get the image in 256 color to look correct, so I will have to find some software to convert to 16bit. I bit shifted everything the way I think it should be for 8 bit, and also used your example in the object for a 24bit image and still get flakey colors, like right now I am looking at your Eye on the uoled but the image is greenish. I am now convinced it is in my bit-shifting.

    Your image of the eye is 8 bit but it always looks like its missing a primary color on the display depending on my bit shifting... i.e here it is missing red...

    oled.Set_GRAM_Access (0,59,0,30)
    temp := 0

    REPEAT 3720 ' 40 x 40 pixels

    OUTA[noparse][[/noparse]CS_OLED] := 0
    OUTA[noparse][[/noparse]WR_OLED] := 0
    OUTA[noparse][[/noparse]7..0] := ((bitmap[noparse][[/noparse]temp])>>3) ' MSB
    OUTA[noparse][[/noparse]WR_OLED] := 1
    OUTA[noparse][[/noparse]WR_OLED] := 0
    OUTA[noparse][[/noparse]7..0] := (bitmap[noparse][[/noparse]temp]) ' LSB
    OUTA[noparse][[/noparse]WR_OLED] := 1
    OUTA[noparse][[/noparse]CS_OLED] := 1
    temp++

    Post Edited (bassmaster) : 10/28/2007 3:57:25 AM GMT
  • LawsonLawson Posts: 870
    edited 2007-10-28 00:45
    @Duffer: When I read through the example object earlier, GRAM usage was the weakest part. The example code clearly shows how to write a single pixel on the OLED via GRAM, but only hints at how to write multiple pixels.

    Like for instance, If I modified PutPixel to be Put2Pixels by doubling the block of code that writes out the pixel data would I get a two pixel row or column of pixels? Or what happens if someone uses a Set_GRAM_Access(x,x,y,y)? Or what happens with a Set_GRAM_Access(0,4,0,4) If I output 60 bytes of data? (30 pixels x 2 bytes each to a 5x5=25 pixel window) How about a Set_GRAM_Access(0,4,0,4), write out 10 pixels, draw a line using "Line", and then write out the last 15 pixels?

    Also, where can we find detailed current consumption info for the OLED panel used?

    My 2 Cents,
    Marty

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Lunch cures all problems! have you had lunch?
  • bassmasterbassmaster Posts: 181
    edited 2007-10-28 05:42
    ok, all formatting is now understood.. just need to get the colors right. fyi, my latest IPOD nano case came with some nice screen protectors that fit nicely on the uoled.

    Duffer, good job on the object, its been a challenge though, but thanks for getting it started.

    Sean
  • deSilvadeSilva Posts: 2,967
    edited 2007-10-28 07:11
    What is the structure of the 16 bit colour data in the OLED?
    A PC 16 bit format generally uses 6 bit R, 5 bit G, 5 bit B
    A 8 bit PC format is ALWAYS palette coded, however there are standard paletts..

    As I find none if these considerations in this thread I wonder what you are doing...
  • bassmasterbassmaster Posts: 181
    edited 2007-10-28 14:22
    its been a pain, even for a sr. systems engineer to get a grip on this mess,... first of all, Here are some of my thoughts on this little display.

    The code Duffer wrote for the object is really a cool start. but not a complete object... AND the display is priced very well if a small form factor is
    your goal. Look at the cost of the prop-stamp or the other all inclusive packages out there, then add up a oled on top of it.

    Pro's:

    1. tiny form factor.
    2. able to power , build, test your imaging code all with a usb cable and the uUsb doohicky. I can hide it behind my laptop and work on it at work without my boss knowing... hehe
    3. if you want you can make a ribbon out of spare ribbon cables so you can use a prop plug/clip if you have a 780xx (5v regulator) on your breadboard. (you can also do this without a ribbon , but I am not a proponent of smashing a $80.00 fragile device w/ a 10 pin header into my solderless boards.
    4. like most hobbies, where is the fun in having someone else do "ALL" the work for you? would you buy a prebuilt alsready painted plastic model? BUT SEE THE CONS:


    Cons..

    1. API, still looking intor this one wheather or not this thing has access to all the features as its cousins with the onboard processors.
    2. cost compared to the uled's with onboard proceesors, serial command sets.
    3. In retrospect for my needs, I should have researched more and bought one with the serial api. As it is already well defined. And requires just implementation.
    4. POWER. It ran for only 5 minutes on the demo with a brand new fully charged (measured 4.51 nominal volts) 3.6v lion 2032 battery. Where a pic I have running
    phandersons logic anylyzer powering na 3v LED, and pulsing 2 othe led's on 2 pins ran all day long with the batteries twin.
    I know this is not the same comparison, but I would have expected a bit longer out of the 3.3v regulator.


    As for the bitmaps, I am trying to get an object that writes any bitmap to the screen, reads the header, strips it, resizes images too big, and pumps it to the display.

    I found a dos program bmp2raw.exe that converts any bmp image into a raw image...

    C BMP2RAW Converter V1.0 (c) 1998 Hartenberger J
  • bassmasterbassmaster Posts: 181
    edited 2007-10-28 14:48
    One thing, I used the following:

    _CLKMODE = XTAL1 '+ PLL16X
    _XINFREQ = 8_000_000

    And it runs fine, a little slow on painting an 8 k image but scrolling and other features are the same at 8mhz, should save power now.

    Sean
  • Fred HawkinsFred Hawkins Posts: 997
    edited 2007-10-28 15:38
    Sean,
    Where does the 8K image come from? The SDcard?
  • bassmasterbassmaster Posts: 181
    edited 2007-10-28 15:51
    Fred, I am sure this is not difficult, and is my next step, the object exchange already has the code I need for the sd card, and I have read and written to one with the prop last year.

    But right now I am focusing on getting the image to display the correct colors. The 8k image is in the spin demo for now. Just use bmp2raw and put the output file in your prop directory, it then is part of the program.


    bitmap file "ocean.r08"
  • J.A.B.J.A.B. Posts: 13
    edited 2007-11-01 22:47
    [noparse][[/noparse]quote]
    REPEAT 6144 ' 96x64 pixels

    OUTA[noparse][[/noparse]CS_OLED] := 0
    OUTA[noparse][[/noparse]WR_OLED] := 0
    OUTA[noparse][[/noparse]7..0] := ((bitmap[noparse][[/noparse]temp]<<3) >> 6) 'MSB
    OUTA[noparse][[/noparse]WR_OLED] := 1
    OUTA[noparse][[/noparse]WR_OLED] := 0
    OUTA[noparse][[/noparse]7..0] := ((bitmap[noparse][[/noparse]temp])>>6)<<2 ' LSB
    OUTA[noparse][[/noparse]WR_OLED] := 1
    OUTA[noparse][[/noparse]CS_OLED] := 1
    temp++


    Hi, complete newbie at the Propeller, but I have done some graphics programming.

    That loop will not work for 256color (8bit) graphics since they use palette lookup.
    A 8bit graphics file first contains a table with 256 colors (24bit/2byte whatever suits the OLED best), and then each pixel contains a 8bit pointer for that color table.

    You need someting like: colortable[noparse]/noparse]bitmap[noparse][[/noparse]temp

    Post Edited (J.A.B.) : 11/1/2007 10:57:44 PM GMT
  • Adoy EsiwAdoy Esiw Posts: 10
    edited 2007-11-02 05:02
    JAB,

    It should be obvious to someone who has "done some graphics programming" that the code is sending two bytes per pixel (that's 16 bits, 65K colors). Also, palette lookup and color tables have nothing to with the way the graphics controller accepts color data. It accepts raw 16 bit color data for each pixel. You "familiarity" with PC graphics will not help you to understand how these types of displays work nor how they are made to work with the Propeller chip. Have a look at the Propeller object··for the uOLED-96-PROP, when you become a bit more familiar with the SPIN language, for a better understanding of how this actually works.

    Adoy

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    One's true identity can only be learned through reflection.
  • J.A.B.J.A.B. Posts: 13
    edited 2007-11-02 16:34
    I am sorry if my lack of understating the uOLED-96-PROP which I have never touched, is offending.
    But if the file which Bassmaster refers to in the first post is a normal 8-bit bmp graphics file, then it uses palette lookup.
    And no matter how much I look at this, I can not see how the loop in question would address that.

    I would then first translate the bmp palette color table into a new 16bpp color table matching the native format of the display, combine the new color table with the original pixel data, and store this as a new raw file on the SD card. Then I would modify the loop to handle 8-bit graphics with palette lookup.
  • Adoy EsiwAdoy Esiw Posts: 10
    edited 2007-11-02 17:31
    JAB,

    No offense taken. I was just surprised that after having admitted that you knew nearly nothing about the Propeller and certainly nothing about the workings of the particular display architecture, your post did not contain a single question. Instead, you chose to make statements, that to anyone who HAS used the "offending" code to produce the desired results, are clearly lacking in understanding of both the process and the code.

    If you make statements instead of asking questions, you'll never get the answers you want/need.

    The things that you suggest "you would do", would not work. In order to use the 256 color (8 bit) mode for this module, a change must be made to the InitOLED method to change from the default 65K color (16 bit) mode to the 256 color (8 bit) mode. Changing this "mode" causes·the display controller to·require only one byte written to GRAM in order to increment to the next position in GRAM (instead of requireing 2 bytes in 65k color mode)·Then you would simply change the write loop to write ONE byte per pixel. As for the input file (whether 8 bit or 16 bit) being "normal", it's not, and the simplest way to create the raw data file is to use the 4D Graphics Composer to decode a PC compatible image/movie into a raw data stream acceptable to the display controller.

    Adoy


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    One's true identity can only be learned through reflection.

    Post Edited (Adoy Esiw) : 11/2/2007 5:49:17 PM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-11-02 18:08
    @Adoy: Have mercy with the young ones. DeSilva started here with little patience some months ago ... he has learned smile.gif

    Post Edited (deSilva) : 11/2/2007 7:21:34 PM GMT
  • J.A.B.J.A.B. Posts: 13
    edited 2007-11-02 22:25
    Adoy:

    Thank you for a informative reply, which I suspect also will be helpful to bassmaster, since he was referring to the loop in question with regards to 256 color graphics.
    Having a dedicated 8-bit mode should simplify a lot, but with the downside that you can not mix 65K and 256 color graphics.
    But if the new loop now is a single byte copy per pixel. You must first somehow define the palette colors, do you not?
  • HarleyHarley Posts: 997
    edited 2007-11-02 22:28
    "....Have mercy with the young ones. DeSilva started here with little patience some months ago ... he has learned"

    What a wonderful revelation; thanks DeSilva.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
  • Greg PGreg P Posts: 58
    edited 2007-11-03 05:21
    To display a large BMP image file directly from an SD card without prior "scaling down to size" using a PC paint program requires a little mathematical magic. Simply undersampling a 1440x960 pixel BMP file by skipping every 15 pixels horizontally and vertically to produce a 96x64 image for output to the OLED display won't work.

    I would suggest color averaging. If the image could be divided into a number of 15x15 pixel blocks, and the individual RGB values are available within the image as they are with 24-bit RGB BMP files (no lookup color table necessary) , one could simply separately total the red, green, and blue values of each pixel within the block, then divide by the number of blocks to obtain a composite average color for use by the OLED display:

    RED-average = (Sum of all pixel RED values within block) / (number of blocks)
    GREEN-average = ...likewise ....
    BLUE=average = ..... likewise ...

    The three averaged values together become the average color to be assigned to a single OLED pixel. This task may be too much to ask of the propeller because its limited memory would require additional SD card reads in order to retrieve all the pixels of a single block... although it seems like you could store a temporary 'decimated by 15' sum of adjacent pixels in a row, awaiting the opportunity to continue the summing upon reading the next row from the SD card memory.

    I'm considering resurrecting some old (but fast) Visual Basic 6 code that will allow me to import either BMP or JPG images and read individual pixel RGB values. I will design it to run in 'batch mode' sampling every image in a directory automatically, performing optimal color averaging, with conversion to 16-bit OLED display compatible data. Running my own code will allow me to take advantage of my existing 115.2kbaud serial interface to the Propeller. I could then 'on the fly' sample the resulting image quality as displayed by the OLED display by simply sending the propeller a serial stream of data for writing directly to the display. At 115.2 Kbaud, I could update the display in about 1.1 seconds ... not too bad.

    Note: a single 96x64x2-byte image would require 12,282 bytes (exactly 24 512-byte sectors) of storage. For a 2GB uSD card that's 174,848 images !!!

    There are some clever algorithms out there for obtaining the average color of two pixels. Simply adding R,G,and B values of a 15x15 block is quick. The division by 15^2 (255) IN ASSEMBLY is not so quick ... but still that's only 96x64 (or 6144) division operations in total for the whole image... perhaps not so bad? If the image were of the right size, a 16x16 block would be much better as 16^2 is 2^8, and a simple Shift-Right-8-Bits operation replaces the integer division operation entirely.

    One neat trick I came across while searching the web:

    www.compuphase.com/graphic/scale3.htm

    typedef unsigned long PIXEL;
    
    #define AVERAGE(a, b)   ( ((((a) ^ (b)) & 0xfffefefeL) >> 1) + ((a) & (b))
    
    



    Here a and b are the full 24-bit colors of two adjacent pixels stored as two LONG values like this:

    a == byte3 - byte2 - byte1 - byte0
    dummy -red- -green- -blue-

    b == byte3 - byte2 - byte1 - byte0
    dummy -red- -green- -blue-


    A ^ B is an XOR operation, A & B is an AND operation. The 0xFFFEFEFE value is a mask which zeroes the LSB bit of each R, G, and B value in the XOR product prior to a single shift bit right operation. The '+' is an addition, not an OR operation.

    So five propeller instructions would be required to average the red, green, and blue values of two pixels using this method.

    To simply add the two sets of R,G,and B values then divide by 2 (SHR 1 bit) requires 6 propeller instructions ... not much of an improvement right ?

    The advantage ( I believe .. I've never tried this myself !) comes from the fact that the total operation can be accomplished 'on the fly' without having to 'extract' the R, G, and B values before doing each addition. Also there is no OVERFLOW possible, so the averaged result is self-contained within the LONG variable result.

    Here goes a test of the algorithm .......

    PIXEL-A: (64,32,230) (40H, 20H, E6H) == 004020E6h
    PIXEL-B: (110,240,250) (6EH, F0H, FAH) == 006EF0FAh

    PIXEL-AVG: (87,136,240)

    The simple add & divide approach:
    ======================
    RED:
    (64 + 110)/2 = 87
    GREEN:
    (32 + 240)/2 = 136
    BLUE:
    (230 + 250)/2 = 240


    The fancy method:
    ============
    PIXA ^ PIXB = 00 2E D0 1Ch (XOR)
    MASK: FF FE FE FE
    MASKED VAL: 00 2E D0 1Ch (XOR result ANDed with MASK)
    SHIFT RIGHT: 00 17 68 0Eh (Same as above but shifted RIGHT 1-BIT)
    +
    PIXA & PIXB = 00 40 20 E2h (AND of both pixels)
    SUM RESULT: 00 57 88 F0h ==> 00, 87, 136, 240d (WOW ! IT REALLY WORKS !!)
Sign In or Register to comment.