Shop OBEX P1 Docs P2 Docs Learn Events
Need help with video driver — Parallax Forums

Need help with video driver

KyeKye Posts: 2,200
edited 2008-12-15 17:41 in Propeller 1
Hello,

I've been trying for a few weeks now to get a video driver working for the propeller chip. I've studied Chips vga driver and followed all his steps to write mine. I checked and rechecked everything he did and everything I did, and it all seems to pan out. However, my driver doesn't work and his does. I can't figure out anymore why what's wrong with my driver.

I used Chips 512x384 2 color bitmap driver as my guide and I wrote a video driver very similiar to his but expanded for 4 color 640 x 480 vga.

If any of the parallax engineers could help me or anyone else that understands how to generate a vga signal it would be very appreciated. Its not a very complex file and its very short with only about 50 lines of code.

I've attached Chip's driver and my own one built from looking very closely at his. Mine driver is fully commented to explain what exaclty I'm trying to do.

Also, I'm using the hydra developement system. The vga does indeed work on the board, there is no hardware problem. Only a software problem with my driver.

Thank you, I really have tried everything and I can't seem to see what his driver does and mine doesn't to generate video. Sigh...

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,

Post Edited (Kye) : 11/25/2008 4:22:43 PM GMT

Comments

  • BaggersBaggers Posts: 3,019
    edited 2008-11-20 19:51
    I've not got much spare time, but had a quick look at it for you, and I'm guessing all that jumping around you're doing as well as only doing 16 pixels per waitvid, it's not doing it fast enough, the other driver is outputting 32 pixels before it needs to do another waitvid.
    that's a quick guess looking at the code, without delving too deeply into it.

    edit: why not try starting with the other driver, and change·that one·first, just to get a feel for it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • KyeKye Posts: 2,200
    edited 2008-11-20 21:46
    Actually, the driver I wrote is literaly Chips driver remodded. The only part I kinda kept the same was the SYNC subrountine. I understand how Chips driver works, except for the main memory acess parts. Beyond that my driver is pratically the same.

    I working on this drive for an embeded systems project. I'm hopping to develope an operating system for the chip. I need to get the vga working first though or I won't have acess to the type of debug capabilites I need.

    If there are any parallax engineers floating arround I would definatly appreciate your help.

    Thank you,

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-21 07:58
    Agreed with Baggers.



    
    :xtile                  rdword  color,color_ptr         'get color word
                            and     color,colormask         'clear h/v bits
                            or      color,hv                'set h/v inactive states             
                            rdlong  pixel,pixel_ptr         'get pixel long
                            waitvid color,pixel             'pass colors and pixels to video
                            add     color_ptr,#2            'point to next color word
                            add     pixel_ptr,#4            'point to next pixel long
                            djnz    x,#:xtile               'another x tile?
    
    
    



    At 640 pixels horizontally, you are gonna need to have a nice, tight loop to blast the pixels to the screen. The loop above is 7 instructions long, and is from the original working driver. From what I can tell, you've got at least 8, with the jump into and out of a subroutine during active pixel time. In addition to the longer loop, you've got a higher pixel clock, and more bits per pixel to deal with. Those two together are gonna cut the number of permissible instructions down to maybe 4 or so!

    If it were me, I would take the working driver and pad the active pixel loop above with nop instructions to see how many extra instructions you have to work with. It's an easy way to measure just how tight that loop needs to be. Just put them in right after the waitvid, one at a time, then run the driver and repeat. If you can roughly double the number of instructions in the loop, you have a shot at moving from 1 to 2 bits per pixel. That's the big impact, because you will need twice the number of waitvids per scanline! If that works out, then take the 512 pixel driver and actually bump it to 2 bits per pixel, and sort out your waitvid mode and timing changes. This way, you keep the number of unknowns low. I find this works well when trying to get a new set of timings up and running.

    After you work through those things at 512 pixels, modifying the existing driver, you are ready to try the 640, after you've obtained some rough timing data. I would repeat the process, working at one bit per pixel, if it were me.

    Again, keep it linear and simple. There really isn't a lot of need to jump around. Just pop the code in, as it happens on the screen, pre-calculating anything you can, so that your active pixel loop is doing the absolute minimum. There is plenty of room in the COG for this activity. Really, you only need a loop in the active pixel portion (if it's fast enough), and one other one to loop the whole frame. Everything else can happen as sequential instructions in the COG. After you get a driver up and running, then it's good to clean it up, if you want to. Or not... if it works, it works, and it's not like the COG is gonna be doing anything else.

    If you run up against the clock, there are a coupla things you can do before having to just flat out use more than one COG.

    You could do inline code, no loop for the active video portion, to shave off the loop instruction. That's pretty easy. Just copy paste the loop a number of times equal to the waitvids you need for the scanline. Could be ~300 or so instructions. If that's too long, due to using the additional option below, make a longer loop, with maybe 10 or so waitvid instruction blocks. That's almost as fast.

    It's also possible to do the same thing, and get rid of the pointer add instructions too. What you do is modify the in-line code block during the hsync. Instead of adding between waitvids, you modify the HUB fetch instructions directly! Use a lot of pointers and just set them all to the values needed for the next scan line. That's gonna get tight in the COG, but it will fit, if you are careful. Do that with a small loop, or maybe worst case another small block of in-line code, maybe looping every 10 pointer updates or so. There is idle time during the Hsync, use it! That could get you down to maybe 5 instructions during your active pixel drawing time. That's roughly, sorta half of the working code. Might be fast enough...

    If those tricks don't get you there, then it's time for more than one COG, or deal with a lower pixel resolution.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net

    Post Edited (potatohead) : 11/21/2008 8:17:42 AM GMT
  • BaggersBaggers Posts: 3,019
    edited 2008-11-21 09:20
    Also on a side note, you do realise there's already a 640x480 4 colour text display driver?
    As I'm guessing you also realise that 640x480 * 4 colour bitmap just won't fit in the HUB-RAM [noparse]:)[/noparse]
    640 * 480 * 2bits per pixel = 76800 bytes.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    http://www.propgfx.co.uk/forum/·home of the PropGFX Lite

    ·
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-21 16:17
    True that.

    Was thinking tiles, and filling part of the display with something, or text from the ROM...

    If there already is a driver like that, then it can do bitmaps just by changing the tile address pointers.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • Timothy D. SwieterTimothy D. Swieter Posts: 1,613
    edited 2008-11-22 00:12
    I am starting to look into the ViewPort program for the Propeller. I think the ViewPort might help to solve this problem because you could compare what the signals look like between Chip's driver and your modified driver. You could see if there are any signals coming out at all or if the timing is off.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Timothy D. Swieter, E.I.
    www.brilldea.com - Prop Blade, LED Painter, RGB LEDs, uOLED-IOC, eProto for SunSPOT, BitScope
    www.tdswieter.com
  • KyeKye Posts: 2,200
    edited 2008-11-22 19:11
    Hey guys, thanks very much for the advice potatoe head.

    I remade the driver into a working version now that just displays a flat color, or a flat color with different colored lines in it, and the color and lines can be controlled by changing a·long within the code.·The driver is using Chip's vga settings however, and I'm slightly confused by exactly what's going on.

    I understand now how fast the loops need to be, its just the the vscl register is confusing me and how exactly are his 512x384 timings really are·1024x768.

    Does anyone have exact timing info that works on the propeller chip for vga? Like all heights and widths, ect.

    Also here's my newer driver, it actually works. But is still being modded.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2008-11-23 01:03
    Okay, I've finished taking control of the whole driver and I have entirely re-wrote it·to fit my needs. I got it at 640x480 @ 60hz - 16x16 tiles 40x30. You may need to adjust your monitor to get the image perfectly centered and such but it works. I have direct control over the pixles, colors and the video scale.

    However, as I said before, I don't quite fully understand how the video scale buffer works. I mean, I've tired altering the pixle and color data in such a way using an xor in line with the waitvid video driver loop and instead of getting a tiling affect from switching the colors or pixles from one color to another every other line I just get a flat balnk color background....This may however,·just be a logic problem.

    If anyone knows where I could find some more information about this it would be appreciated.

    The working file is attached.



    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-23 02:30
    Nice!

    Glad you've got your driver up and running! You are quite welcome and no worries. I had a bit of time and totally grok that $(*%^$%@ feeling when trying to get a driver to actually DO something. With video, it's either excellent, close, or basically nothing. Makes it kind of hard to home in on the right stuff, without a scope. (yeah, one is on my list for sure) Looks like you are off and running.

    On the Propeller, there really isn't a mandated correlation between specific scan timings and the pixels. It's all up to you. The most common approach appears to be to set the PLLA to a base value that has some meaning with regard to the other timings. From there, you then scale things in multiples of that PLLA such that you end up with things happening at the right times and the right levels. "colors" then really is just signal levels! From there, you size the non-active display pixels, and assign them colors such that the right levels and timing occurs. During the active pixel area, you can more or less size your pixels as you want to size them.

    The waitvid operates in 1bpp (32 pixel) 2bpp (16 pixel) 8bpp(4 pixel) frames easily enough. Do some digging on the 8bpp way of doing things, you will find the role of pixels and colors reversed as a nice and simple hack on the waitvid.

    It's also possible to define partial frames. The NTSC text drivers seen around here do that. That's a frame size equal to just 8 pixels, leaving much of the D and S registers unused. That can give large pixels, if you want to do it that way, by way of just referencing how flexible the thing is.

    Chip may have used the faster timing for pixel size and position advantages. Everything operates on your base PLLA frequency. Sometimes, depending on the video task, that can be too coarse to get the sync levels right, or might not permit all the pixel sizes needed.

    Because of all of this, there really isn't any kind of standard timing table. The drivers are software and such a table would really only work for a given driver approach, and only if that driver had been coded in such a way that it would work with variable timings. Many are fixed, and just work with pixels as they need to.

    Again, if it were me, and I had a driver framework up and running, I would probably go and look up the VGA timings, then backtrack through the working driver, doing the math to see where it's all really at. You might be close, right on, or far enough off that some monitors won't deliver the pixel joy! From there, you can then deal with your pixels, based on the options your PLLA timing gives you, and the faster waitvid options. Don't know where you are at speed wise, but it's not a bad idea to stick with the full 16 pixel frames, so you can pull text from the ROM, and or make smaller bitmaps. There just isn't enough RAM to full on display all the pixels.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net

    Post Edited (potatohead) : 11/23/2008 5:23:54 AM GMT
  • KyeKye Posts: 2,200
    edited 2008-11-23 23:21
    Okay guys, I'm almost there. The previous drivers where just made to actually get the video working. Now that I have the video working I'm now trying to get the driver to actually display images now. Here's the rub, I wrote the code that would be needed to actually do the job....it just isn't fast enough because·of two hub instructions that have to be used.

    So, I'll tell everyone how my driver will work in order too see if anyone can help me. The purpose of my the code is·to create a 16x16 video tile driver that takes 16x16 tiles from the character rom bitmap and displays them. This would then allow the user to create an image using the character without need to acutally copy their bitmaps into main memory freeing up alot of space. The driver would then use page flipping to switch between memory locations for the bitmap so any image could be displayed easily. In addition I want to include a mouse driver that would work in between vertical refresh frames to add a mouse overlay onto the image. I'm not too sure about getting the mouse part to work...But actually getting the character tile driver to work would be really awsome for everyone as it would seriously reduce the amount of memory would need to display video.

    So, heres how my driver works. I'm placing the active video driver here for everyone to look at. The inactive video is the same as before with the timings slightly adjusted so everything works out beautifully.

    ' ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Active Video
    ' ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ' //////////////////////Set Reset///////////////////////////////////////////////////////////////////////////// 
    loop                    rdlong  displayBase,      par             ' Get the new display pointer base address.
                            mov     displayPointer,   displayBase     ' Set the display pointer to the new base address.
                            mov     heightCounter,    verticalTiles   ' Set/Reset the vertical tiles to display.
    verticalDisplay         mov     counter,          tileHeight      ' Set/Reset the tile fill counter.     
                            
    tile                    mov     widthCounter,     horizontalTiles ' Set/Reset the horizontal tiles to display. 
    ' //////////////////////Scan Line/////////////////////////////////////////////////////////////////////////////
                            mov     vscl,           tileWidth        ' Set/Reset the video display.
    horizontalDisplay       rdlong  buffer     ,    displayPointer   ' Get the next character address and colors.
                            mov     colorBuffer,    buffer           ' Copy the next character address and colors
                            and     buffer     ,    characterMask    ' Isolate the character address. 
                            and     colorBuffer,    colorTooMask     ' Isolate the colors.
                            add     buffer,         counter          ' Ofset the character address for tile fill.
                            rdlong  pixelBuffer,    buffer           ' Get the next character.
                            shr     buffer     ,    #1               ' Check to see if the character's address is even or odd.
    if_c                    ror     pixelBuffer,    #1               ' Rotate the character's bits right if the character address is odd.
                            or      pixelBuffer,    pixleMask        ' Set the character's odd bits to 1.
                            or      colorBuffer,    colorMask        ' Set horizontal and vertical sync inactive states and the colors white and black.
                            waitvid colorBuffer,    pixelBuffer      ' Display video.
                            add     displayPointer, #1               ' Get ready to get the next character address and color.
                            djnz    widthCounter, #horizontalDisplay ' Display another x tile block.
                            
    ' //////////////////////Horizontal Sync///////////////////////////////////////////////////////////////////////
                            mov     vscl,               frontPorchPixles     '     
                            waitvid horizontalSyncMask, #0                   ' Do Front Porch Pixles.
                            mov     vscl,               horizontalSyncPixles '              
                            waitvid horizontalSyncMask, #1                   ' Do Horizontal Sync Pixles.
                            mov     vscl,               backPorchPixles      '        
                            waitvid horizontalSyncMask, #0                   ' Do Back Porch Pixles.
    ' //////////////////////Next Scan Line////////////////////////////////////////////////////////////////////////                      
                            sub     displayPointer, horizontalTiles   ' Go back to preivous scetion.        
                            djnz    counter,        #tile             ' Do tile fill.
                            
                            add     displayPointer, horizontalTiles   ' Go on to next section.
                            djnz    heightCounter,  #verticalDisplay  ' Display another y tile block.
    


    The loop works like this.

    First it gets a the location of the new display map so it can literary flip pages between different images every time it draws the whole screen and does all the vertical refresh stuff.

    Then it sets up the counters needed for all the looping it needs to do.
    Then it setups of the video scale register appropriately.

    Now, here's the magic.

    Using the new address of the display pointer the driver gets a·word from the main memory which contains in the upper 16 bits - two eight bit colors (ony 6 bits are used though) and in the lower·16bits -another memory character·address.

    Now, the driver then proceeds to duplicate this information and break it up into two words with one containing the two colors and one containing the character·address.

    Then it makes sure that the address which it recieved is ofset so that while the character fill loop is executing the driver will properly fill each tile. This also means that the character address should 1 below the actual address you want.

    Then it uses that offset to get the line from the character you want to display.

    Once it gets the line from the character, as in characters from the main memory in the character map. It checks to see if the address was odd or even. By knowing this the driver can then make sure that the character it wants to read is in the appropriate bit spots while the interleaved character it does not want to display is not in the appropriate bit spots.

    Then the driver sets all the bit spots its not trying to display to one. This also means that the colors which were gotten from the main memory will be displayed and selected when the character is shifted out using wait vid.

    A few mask are applied before the waitvid to ensure this.

    Some of the mask right now may be unnecessary but they are there for the future implementation of the mouse overlay. The idea is that the driver can jump in and out of vertical sync·loops computing the mouse metrics and where the mouse it to produce a mask that can be overlaid at the right moment on the pixles and video so the mouse can then be drawn. I'm still not sure if this is possible but I'm trying to prepare for it.

    Then the driver does all the necessary loops and moves arround the display pointer (which is 1d, basically after every 40 sections you are drawing a new vertical line) arround to produce the image.

    So the question is, how would I rearrange the hub access instructions so that I can actually use them. As of right now, the driver works when the first hub instruction is used. However the two within the loop, enabling one, the other, or both cause the driver to fail....So any help?


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,

    Post Edited (Kye) : 11/23/2008 11:26:33 PM GMT
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-24 06:21
    Probably there isn't time for both hub access instructions to occur. If so, that's not a show stopper.

    Can't you just get the display data directly from the ROM, instead of copying it and masking it? The ROM characters are intended for 2 bits per pixel. What you do is set the colors such that only one of them will be visible at a time, leaving the others black. The data should work as is, given the user of the driver makes appropriate color selections.

    This should be a straightforward loop, where you are keeping track of a tile address and scanlines. Divide the scanlines by 16 to get character offsets. The screen memory then becomes a series of pointers into the ROM, simplifying a lot of the logic, and eliminating the need to do the masking and color isolation operations you are performing.

    In it's simplest form, the display buffer is a series of words, 9 bits of which, define what character is being drawn from the rom. You read the display buffer, multiply it by 16, add the start of the ROM character set, then add the scanline offset to obtain the precise address in the ROM where the character exists. This then gets used directly for pixel data, via one HUB operation. If you make the display buffer a series of longs, that same single HUB access would also net you the color information necessary for it all to work nicely.

    Each long then could be CCCCCCCC, CCCCCCCC, xxxxxxxP, PPPPPPPP Where C is color, P is character to be displayed. Some waste there, but it's gonna be faster. One long per character, then for a reasonably sized screen buffer display, and one where significantly less logic has to occur during the active pixel loop. Maybe that's enough time to allow for the HUB memory fetch from the ROM at pixel time, instead of being forced to do it during blanking time.

    The scan line pointer and base ROM address can be added outside that loop, leaving only one add and a shift for generating the character offset address. The rest is just moving and or maybe shifting the colors into position for use in the waitvid. It looks to me like there is plenty of instruction time for that, given the masking stuff goes away.

    This should all work without having to pre-fetch data like the driver is doing now. Just fetch a long of screen memory, do two operations, like adds or something, then fetch the data from the ROM, move color data to a buffer long, and fire off the waitvid. After the waitvid, update your horizontal pointers, loop back and do it again. Everything else can happen outside that pixel loop.

    As things stand right now, assuming that all works, you've got dead time during hsync, and vsync. A little tiny bit of the hsync will be needed to do the adds for the base address and scan line offsets, but that's it. The rest is free time, that's only broken up by a waitvid on the hsync, and a few waitvids during vsync.

    I'm not sure a mouse driver running in that mess can work in the vsync time only. I do know that only touching the mouse every frame isn't quick enough. The bits per second coming from the mouse encoder will occur faster than that, limiting it's ability to capture fast motions. It wold be necessary to throttle mouse movement, to keep bit rates below the 60Hz limit. (programmed a track ball once, on an 8 bit computer and had this exact problem) Slow, deliberate mouse moves will work correctly. Faster ones might just result in little to no motion as many of the transition bit states are lost during active video time.

    Maybe it's possible to hit the mouse every scan line? If so, then you've got plenty of motion capture throughput. Should work nicely, and you can do it during the HSYNC. I've not done a mouse, so I don't really know how many instructions it takes. You have room for quite a few during HSYNC though. Might be doable.

    If that's at issue, just have the video driver fetch the current mouse position during Vblank, and have another COG handle the mouse movement lower level details, leaving you with some pixel voodoo choices to make to draw the pointer.

    One idea for that would be to determine where the mouse will exist for that frame during vblank time, copy the ROM data necessary to a buffer, and mask in the mouse pointer during Vblank, so it's all ready to go otherwise. Complete this between frame prep with pre-computed scanline offset and base buffer addresses that point to your little two, or four character RAM buffer, instead of the ROM.

    Probably good to have two complete active video loops then. One for ROM graphics generation, and one for the RAM buffer. When the correct number of waitvids have passed, just jump to the mouse routine that knows to pull display data from RAM instead of ROM. Loop once to draw both horizontal character the mouse could occupy, then jump back to the main routine to finish out the scanline. The buffer needs to be two chars high vertically too, or at least be smart enough to know where to put everything so that the mouse graphics in RAM, get drawn in the right place. Again, jump to the alternative active video routine, when it's mouse pointer time, stay with the main one the rest of the time.

    This way, there are no real tricky pixel logic sequences that occur during the active video time. Mouse pointer can only really be in one position per frame, unless you want tearing right? So figure that out in VBLANK, set up the RAM buffer, and just draw that during the impacted scan lines.

    This technique was used on the older 8 bit computers to get moving pointer displays on what would be ROM text display capability screens only, without having to locate the entire character map in RAM. I see no reason why it cannot be done here on the Propeller.

    You probably can put the thing in the COG too, avoiding what might be another difficult HUB fetch during active display time.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-24 06:32
    One other little thing that might help. When you do HUB operations, separate them with two instructions only. That's the optimal amount of time. If you do less, you blow what could be an instructions worth of time waiting. If you do more, then you blow an instruction or worse there too, potentially stealing two instructions of time from that loop.

    rdword xx, yy
    add something, something else
    shl something, something else
    rdlong xx, yy
    etc....

    Sometimes this requires clever sequencing of events to get done, but it's always worth it to get the ideal throughput on the HUB ops. Doing this and pre-calculating everything you can outside the active pixel loop, should free up enough time to explore potential paths to both the text display and mouse.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • KyeKye Posts: 2,200
    edited 2008-11-25 00:37
    Okay, I think I my be able to do something like that. However, How do you use the waitvid and vscl and vcfg·to read directly from the memory??? I Still can't get my mind arround why that works, I understand the characters have been reversed so they shift·out propellerly.·But how do you select between characters???


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2008-11-25 04:38
    Okay, I managed to get the two color selection working and acutally displaying characters and video. It was pretty nice.

    But, I really can't do a mouse overlay with two color video. It really will look very bad unless I make everyhting black and white. Which will be really borning.

    Well, thank you for all the help. I'm going to work on other drivers for my system. And, for anyone who wants a character video driver here it is.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,

    Post Edited (Kye) : 11/25/2008 4:13:15 PM GMT
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-25 05:00
    So let's set the mouse off the table for a moment. Too complex.

    I think the best way to nail this one is a stage at a time. From where I stand, the stages look kind of like this:

    1. Get text display running, using a small display buffer, and pulling pixel data from the ROM.

    2. Implement small 4x4 RAM buffer to mask mouse pointer in.

    Testing on this is done with a working mouse driver, and a small bit of code to update the mouse pointer longs in the COG.

    3. Give reading the mouse a go in the COG during video blanking times.

    Done!

    I don't have the start of the ROM character graphics table handy, so let's just say it starts at $start_of_ROM_chars. These tables are built with two characters per tile, one of one color, and another one of another color, for two bits per pixel color. I believe the masking you are doing is to kind of work around that, and it's costing time needed for the active video display pixel loop.

    To draw the chars on the screen from the ROM, we use the lowest 8 bits of the display buffer long as a character address. So, char 0 would literally equal $start_of_ROM_chars! And if char 0 were located at the upper left of the screen, the first entry in the ROM table, would be loaded into a waitvid, after having the REV instruction applied to it, so the pixels come out in the right order. Now, let's move to the next scan line. We are still on the left side, but one scan line down. The scanline counter is incremented modulo 16, so that it would now equal 1. This is added to the $start_of_ROM_chars, and whatever is at that HUB address gets fed to the waitvid.

    So far, so good.

    To address other chars, we take the lowest 8 bits of the display buffer long, and multiply them by 16. That's a simple SHL, so it's really easy. Now, let's say that character in the top left of the screen is character number 2. To get the ROM address, we multiply 2 by 16, for a total of 32, then add the scan line offset, and let's say we are still on the second scan line, so that makes it 33, then we add the $start_of_ROM_chars, to get the actual address of the ROM graphics pixel data we need. That goes to a RDLONG, to fetch the pixels.

    To keep the active pixel loop short and fast, we can add the scanline offset counter to the $start_of_ROM_chars, because it's the same for the whole scanline, leaving us with only a shift and an add in the active pixel loop to obtain a ROM data address.

    That takes care of where the pixels come from.

    The colors come from the display buffer long! There are four colors to deal with. Color 0 is the background, and two of the others align with the interleaved character data, leaving one color unused. We've got three bytes left in the long, so that's enough to call out the colors necessary to make this work. It's easy, if one of those colors isn't color number three. It then makes sense to shift the colors into the colors argument for the waitvid in such a way that the display buffer data then lets the user call out which char, of the two possible is displayed, and to declare the background color, eliminating the masking and shifting stuff happening right now.

    Each display buffer long then looks like this: (and I didn't think my other one through!)

    00000000-11111111-22222222-CCCCCCCC

    The lower 8 bits are character address data, and the rest are colors 0, 1, 2.

    (more in a bit)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-25 05:33
    A loop then would look like this:

    [noparse][[/noparse]scan line counter 0-15 and ROM char address already added and stored in a temp long]

    fetch a display buffer long from the display buffer (rdlong)

    move it to a temp long

    mask off the color info (and $00_00_00_ff)

    multiply by 16 (shl)

    add this to the scan line sum already computed

    fetch the pixels from the ROM (rdlong)

    reverse them (I think this is needed, haven't worked with the display data in the ROM) rev instruction

    mask off the char data from display buffer long read earlier (and $FF_FF_FF_00)

    shift it right to form colors argument for waitvid

    do the waitvid, directly from the results of the operations above [noparse][[/noparse]might need to not shift the colors...]

    add 4 to the display buffer pointer

    loop back to continue scanline.

    [noparse][[/noparse]update scanline offset pointer, and subtract from the display buffer pointer, so that the same longs are used again for the next scanline]

    Bummer! Saw your post! Oh well. Just so you know, the driver can be full color, applying the technique shown, leaving your one unique color for the mouse pointer!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • KyeKye Posts: 2,200
    edited 2008-11-25 16:20
    Thanks again for the help,

    I can make a 16x16 512 character (upper and lower character parts) addressable display. The problem is that I can't put a mouse pointer on it because there is no time to figure out when in the scanline to add it. And the mouse is very importnat to the GUI user interface I want to use.

    Thus, I think I'll need to do a video buffer...sigh, and unfortunately the propeller chip does not have neough memory so I would need some external device....which is an option I would like to avoid like the plague....

    Maybe there's some kind of fast serial sram module, no?

    Anyway, happy holidays, I won't be back to respond in a while.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Mike GreenMike Green Posts: 23,101
    edited 2008-11-25 16:35
    If you haven't already, you might look at Chip's Tile Driver with Cursor from the Object Exchange under "VGA 1280x1024 Tile Driver w/Cursor".

    He dedicates a cog to the cursor and synchronizes the cursor cog with the other video cogs so that the cursor cog can overlay a cursor on top of the video output as the mouse moves around (the mouse driver requires another cog).
  • potatoheadpotatohead Posts: 10,261
    edited 2008-11-26 05:51
    The trick is to just calculate the mouse position during the VBLANK. Either you have that COG do it, or just use the mouse driver already written and have that COG do it. From the code you have, I don't see this taking more than two COGs. It's probably a lot easier though to just go for the two COGs.

    Either way, you end up with mousex and mousey in the COG somewhere. Say it's from the other COG. You pick up the mouse location during VBLANK, then calculate where it is, in terms of waitvids.

    This is what the little RAM buffer was for.

    You calculate the number of waitvids, by taking the mousex position divided by 16, multiplied by the Y position. Add one counter, to keep track of the number of waitvids that have passed, and increment it in your active video loop.

    Also during the VBLANK, you read the screen buffer longs at the mouse locations, and copy the ROM data they point to over to RAM, where it can be modified. Overlay the mouse pointer there, using ordinary bit masking, and calculate where that's gonna occur with the mouse x modulo 16, and mouse y modulo 16. If this buffer is two tiles wide, and two tiles deep, it's pretty easy to just work from the upper left, shift stuff over the right number of pixels, and start masking the mouse pointer in based on the y position. Think of it like a little tiny graphics screen, with 0,0 at upper left, and it's 32 pixels by 32 pixels. This is enough to cover all four tiles that could be occluded by the mouse pointer.

    There also would be two active video loops. One of them draws from the ROM, and the other one draws from the RAM, when it's waitvid comes up. The RAM one is written a bit differently so that it does not fetch the chars from the ROM, but from the RAM, and has a different start address offset, because the RAM buffer is only 2x2 tiles. Once this starts, you continue for 32 scanlines, hopping to the alternative routine for the two impacted tiles, using the main routine for the rest of the tiles.

    I'm pretty sure you can put the RAM buffer in the HUB, if you want to. The drawing time isn't any different, so if it works from the ROM, it can work from the RAM.

    The other piece of the puzzle lies in the colors. Since there are four available, one is the background, two are for either even or odd chars, and the remaining one is for the mouse. To display a specific char from the ROM, you just set it's color to something other than what the background color is, and you will see it. To switch chars, you just switch colors, no bit mashing required.

    "The character definitions are numbered 0 to 255 from left-to-right, then top-to-bottom, per the diagram below. They are arranged as
    follows: Each pair of adjacent even-odd characters is merged together to form 32 longs. The first character pair is located in $8000-
    $807F. The second pair occupies $8080-$80FF, and so on, until the last pair fills $BF80-$BFFF. The character pairs are merged such
    that each character's 16 horizontal pixels (per row) are spaced apart and interleaved with their neighbors' such that the even character
    takes bits 0, 2, 4, ...30, and the odd character takes bits 1, 3, 5, ...31. The leftmost pixels are in the lowest bits, while the rightmost
    pixels are in the highest bits. This forms a long for each row of pixels in the character pair. 32 such longs, building from top row down
    to bottom, make up the complete merged-pair definition. The definitions are encoded in this manner so that a COG video peripheral
    can handle the merged longs directly, using color selection to display either the even or the odd character."

    --->http://forums.parallax.com/forums/attach.aspx?a=5975

    That's a 4 color screen, not a two color one, just FYI. Color 0 will be background, color 1 is one char, color 2 is another one, and color 3 can be something else, like the mouse.

    Done this way, there is no masking in of the mouse during active video time. It's all done in the vblank, where there is lots of time. That is the key to a lot of this video stuff, as time during the scan line is scarce.

    Having said all of that, the driver Mike references is pretty darn cool. The display is nice, and it's capable of bitmap graphics due to how the tile addressing is done. On that driver, each tile address is stored in the display buffer, in a tiles array. If you want graphics somewhere, you point that tile, or tiles to an area of RAM, where the graphics are stored. Additionally, the graphics library works with the screen layout format, giving you a bunch of handy graphics primitives to work with. All you do is point that to the RAM graphics area, and let it know the size of that area.

    Another COG will output the cursor data, in tandem with the one doing the display. This is an electrical overlay, so it's like a hardware cursor of sorts. There is no software masking, just two video generators outputting on the same pins at the same time. As long as the cursor is bright, it works out just fine.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • KyeKye Posts: 2,200
    edited 2008-12-09 04:05
    Argh! I must revive this topic again.

    So, I have my vga driver now and I moving on to write the graphics engine. But, I felt like I need to refine the driver so it would be a bit better.

    So...

    Here's the problem.

    PUB vgaExecute(colorSettings, displayBase) | temp 
      temp := (colorSettings << 16) | displayBase
      cognew(@initilization, temp)
    

                            mov     buffer,         par             ' Get color settings and display base address.
                            and     buffer,         colorMask       ' Seperate color settings address.
                            shr     buffer,         #16             ' Move color settings address into lower 16 bits. 
                            rdlong  colorBuffer,    buffer          ' Get color settings.
    


    Here's what I'm trying to do.

    First, I pass the vgaExecute method the address of a variable that holds a 32 bit four color value for the video generator. I also pass the address of a variable that holds the base address of a display buffer. The reason for this being then is that I can use page flipping to change between display buffers.

    So... Now I want to cram both of these addresses into the par·register when the cog starts up.
    What I do then is I shift the colorSettings value (which should hold a 16bit address) up by 16 so its in the top word, and then I or it by the display Base value which should leave one address in the top 16 bits and one address in the bottom 16 bits.

    Then, inside the driver I try to seperate these values again. I can seperate the display base address properly which also the driver to diplay valid information. However the color address seems to go just to zero or something.

    I'm not sure where theres an error, I should be able to do this right? I even tried spliting up the shift into four shr #4 statements thinking I could only shift up to four times per command, but still no luck.

    What I'm currently getting with this code is an unchaning value for the color....I can't seem to edit it. I know however the error is in the shifts and such because if I force an address into the rdlong statement I can change· the color again.


    Please note that there are no timing problems and everything works except the color. also, colorMask = $FFFF_0000 to clear the bottom 16 bits.
    Also, color mask may not be necessary since I'm shifting over them.

    Please help, thankyou.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • potatoheadpotatohead Posts: 10,261
    edited 2008-12-09 04:12
    Better to just use PAR to point to a block of sequentially defined parameters.

    eg:

    long  params
    
    params[noparse][[/noparse] 1] := display_buffer_address
    params[noparse][[/noparse] 2] := colors
    ...
    
    



    Use @params in your cognew, so that PAR contains the address of the first array element.

    In the video driver COG, read these during initial setup. One nice time is right after configuring the pins and the video generator.

    Then, every VBLANK, before the frame begins, read them again, and reset pointers and colors, if needed.

    
         mov   A, PAR 'get the address loaded, so we can use it
       rdlong  A, parameter1
         add    A, #4
       rdlong  A, parameter2
         add   A, #4
    ...
    
    



    PAR is a one time shot. So you load up a value and pass it. The COG sees what is in PAR, and that's it. No more communication. If you want stuff to happen dynamically, you need to establish a common HUB address, then have the COG read it, when it makes sense to do so.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net

    Post Edited (potatohead) : 12/9/2008 4:26:46 AM GMT
  • KyeKye Posts: 2,200
    edited 2008-12-09 04:47
    Ah, yes I could do that. Thanks.

    However, I've gone and just placed the vga driver inside the engine and I think I found a nice way to bypass that problem.


    in the master spin code.
      colorSettings := $FF_FF_FF_FF             //Colors equal to zero 
      displayBase   := @displayBuffer[noparse][[/noparse]0]       //base of display buffer.
    

      displayBaseAddress   := @colorSettings   //Sets values in the asm driver 
      colorSettingsAddress := @displayBase    //Sets values in the asm driver 
      
      cogDriver                               // Starts the driver
    


    inside of the asm driver
    displayBaseAddress      res      1     
    colorSettingsAddress    res      1   
    
    


    The idea is that that I compile the asm driver with the address of the pointers to the addresses of the drivers settings.

    But the compilier won't let me do this.

    Any ideas?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • potatoheadpotatohead Posts: 10,261
    edited 2008-12-09 04:58
    Haven't done that, but let's assume it works. Somebody else is going to come through and confirm that, or you will!

    If you are setting the VALUE of displaybase equal to the ADDRESS of displaybuffer then it's value is what is needed in the COG, not it's address.

    Also colorSettings is a value being set to another value. In that case, colorSettingsAddress is the POINTER to the VALUE contained in colorSettings.

    So you need to get POINTERS and VALUES sorted.

    I'm not sure compiling that in at compile time works however. I'll let somebody comment, while you sort the pointer and value thing out.

    ...or just setup a nice, simple array in your top object, plug your values in, and pass that to the COG.

    Another option is to put your parameter longs in DAT, and pass the address of those!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • KyeKye Posts: 2,200
    edited 2008-12-09 05:06
    mmm, I just needed to change res to long. Thanks.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • potatoheadpotatohead Posts: 10,261
    edited 2008-12-09 05:44
    Nice to know that works then.

    Cheers!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
  • KyeKye Posts: 2,200
    edited 2008-12-15 02:59
    Eh, I need to revive this post again.

    So here's what's up. I just basically finished making a video engine and character map to display data on screen at the vga signal frequency. Now, so far, after·fixing my·past intial problems I haven't hit anymore road bumps until now.

    I'm now trying my driver on other monitors and I am finding that it doesn't work as expected. I'm getting varying results also.

    On one montior the monitor turns on but displays nothing, on another the montior constanly wakes up and goes to sleep.

    Since the driver works on the montior I programmed it on I believe the code is sound. However, I this some of the settings may be off.

    So,·what would mostlikely cause the driver to work on one monitor and not others?

    I think it might be the pixle clock but I'm not sure it adjusting it does anything...because it should be dead on.
    The monitor I programed it on is the optiquest 22wb -·wide screen 22 inch. The monitor has a nice feature where it auto adjust any image sent to it. Because of this the monitor may have fixed a faulty signal.



    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2008-12-15 03:09
    Er, belay that, I think I screwed up the vertical sync timing sections....I'm not sure how, but I coppied over my old code and it worked again.

    Yeah, anyway, I've pretty much have a whole video engine worked out now. Since the community gave me alot of help developing it I think I shouldn't be selfish and keep the code to myself.

    So, When I finish I'll post my character map and video engine driver.

    But, i still would like to know what would cause the video to not work on one monitor compared to another.

    Thanks,


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,

    Post Edited (Kye) : 12/15/2008 4:43:06 AM GMT
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-12-15 03:47
    Some multisync monitors have preprogrammed "lock-in" ranges outside of which their PLLs cannot operate (if they even use PLLs for synchronization). Your Optiquest is, more than likely, more forgiving than most for handling non-standard sync frequencies.

    Once you post your code, I'm sure it will get tried on a wide range of monitors with various capabilities. That will be the true test, which we all look forward to! smile.gif

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Just a few PropSTICK Kit bare PCBs left!
  • KyeKye Posts: 2,200
    edited 2008-12-15 17:41
    Okay guys, here are the binary and eeprom image files. Unfortunately, I don't quite fully know what license to realse my driver under since I am developing it for a comercial application and I cannot give away all my rights under the MIT license that parallax uses.

    I am willing to release the code but I don't want to be carless with it. If anyone needs somewhere to start from the videoDriver.spin files (not the one with new tacked on to it)·will be a good place to make your own vga driver. Anyway, here they are.

    Oh, and if you look closely, you'll realize that I wrote all the characters myself...3000 lines of code...argh!

    Also, the demo will only work on the hyrda system.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,

    Post Edited (Kye) : 12/15/2008 5:47:24 PM GMT
Sign In or Register to comment.