Shop OBEX P1 Docs P2 Docs Learn Events
Video squashed sprite — Parallax Forums

Video squashed sprite

BocephusBocephus Posts: 58
edited 2012-09-13 09:30 in Propeller 1
I'm studying how to make video and I have generated top, center, and bottom scans with different colors. I decided to make a simple stick man sprite and attempt to introduce it into the scans. It worked somewhat as expected since the stick man is clearly in the video but the sprite is short and squatty.

How do I make the sprite stay at 16x16?

Also, how would I make a 16x16 sprite take up a larger area? Such as in my code below in the center_scanlines section, where there would be 144 lines available to scale the sprite over.

Next_Frame                        ' video loop
        mov     r1, #60           ' 262-18 = 244 available   
:top_scanlines
        mov     vscl, clkperpixel8_clkperframe12     
        waitvid color_index, hsync_pixels                                    
        mov     vscl, active_vid_values       
        waitvid color_blue, pixel_pattern                          
        djnz    r1, #:top_scanlines

        mov     r1, #128
:center_scanlines
        mov     vscl, clkperpixel8_clkperframe12     
        waitvid color_index, hsync_pixels                                    
        mov     vscl, active_vid_values
        waitvid color_white, pixel_pattern                         
        djnz    r1, #:center_scanlines
        
        ' ========== man bitmap ==========
        mov     r1, #16
        mov     index, #man_bitmap        
:man_scanlines 
        mov     vscl, clkperpixel8_clkperframe12     
        waitvid color_index, hsync_pixels
        movs    :show_man,index        
        mov     vscl, active_vid_values        
:show_man                                                                     
        waitvid man_palette_map, 0-0
        add     index, #1                        
        djnz    r1, #:man_scanlines
        ' ================================
        
        mov     r1, #40
:bottom_scanlines
        mov     vscl, clkperpixel8_clkperframe12     
        waitvid color_index, hsync_pixels                                    
        mov     vscl, active_vid_values                                                                      
        waitvid color_green, pixel_pattern                         
        djnz    r1, #:bottom_scanlines

        call    #Vsync_High
        call    #Vsync_Low
        call    #Vsync_High                        
        jmp     #Next_Frame       ' end video loop

«1

Comments

  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-20 22:48
    Seems to me the sprite is 16x16, but that your pixel aspect ratio isn't what you think it is.

    In the horizontal direction, your VCSL can control the size of the "pixels". You will need to figure out how you want to do your active pixel area timing, in terms of PLLA cycles / scan line.

    In the vertical direction, you will need to duplicate your sprite data, either one scan, two scans, etc... high to get scaling in that direction.

    Make each pixel a unique, contrasting color, and write the sprite to the display. If all the pixels can actually be seen, then you have a scaling matter, meaning you need to manage your pixel timing horizontally to get your aspect ratio closer to what you are envisioning.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • BocephusBocephus Posts: 58
    edited 2010-01-21 18:12
    potatohead, you are correct about my issue being horizontal scaling. In the code I posted earlier my 16 pixel wide sprite is spread across the entire screen width. I've tried to change the horizontal scaling but my understanding is obviously flawed. I'm not sure how to load more than one long into a scan line. I tried adding a loop after the waitvid man_palette_map,0-0 to add more longs to fill in the rest of the line but it failed. When I changed the cpp / cpf it really got distorted.

    I'll read some more about this tonight and have another go at it.
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-22 19:28
    At a high level, here is what needs to happen for the scaling.

    For NTSC video, each scan line is a multiple of the PLLA, and the PLLA is derived from the colorburst. There is the sync area, which is always the same timing. The rest can vary.

    The key here is to calculate how many PLLA cycles you have on the scanline.

    Subtract those cycles needed for the sync.

    Then you determine what your porch size is, and the porch is the overscan border, just for reference. Subtract those, leaving you with your active video area cycles. The active video area is also known as the safe area. On older computers, this is "the graphics screen" with the porches being "the border".

    I like to use 2560 cycles for this area because it maps perfectly to the color cycle, and provides common, meaningful resolutions in the active area.

    The key for exploring this is to get everything setup so that you can vary the pixel timings in the active area. I find it handy to have a few different loops.

    There is the frame loop, and this one just runs over and over, for a non-interlaced display. If you are doing interlace, that loop runs as two different states, one for the even frame, one for the odd frame. For starting out, I would ignore this, just doing non-interlaced video.

    Inside the frame loop, you've got:

    VSYNC
    Top border, consisting of blank scanlines, drawn at color $02. These are just two waitvids. One for the HSYNC pulse, and one more to draw the whole scanline blank. The PLLA cycle count of these two waitvids needs to equal your PLLA / scanline.

    When the top border is done, you enter the first line of the active area. This consists of the same HSYNC waitvid, a shorter border waitvid done exactly the same way the blank scan line was done, just shorter to consume the PLLA cycles for your border.

    Then you have a loop! This is your graphics loop. What this loop does is fetch pixels from the display buffer, load the waitvid, then repeat for as many pixels as you have in the active area.

    Finish off with your other border, on the right, done the same way the other border is done.

    To change waitvid timing, you do this just prior to executing the next waitvid. The waitvid currently running, won't generally be impacted by a VSCL change, leaving you time to get the next waitvid setup.

    Once started, you keep waitvids running, only changing the timing of them to get the various parts of the screen done.

    Let's say your active area is 2560 PLLA. Here is how it all breaks down.

    Before I do that, know that waitvids operate either one bit per pixel, two bits per pixel, or 8 bits per pixel, with a trick where the colors are actually pixels, and you use the waitvid in reverse from how you use it at one and two bits per pixel.

    For one and two bits per pixel, the waitvid is "waitvid colors, pixels" where the colors long has the four color definitions, one byte per color, and pixels is the actual bit pattern drawn to the screen.

    For 8 bits per pixel, and only about 80-130 of the colors are actually useful, the waitvid is "waitvid colors, #%3210" What that does is define 4 pixels, one of each color, transforming the colors long into just pixels! You can find examples of this sprinkled throughout many video drivers.

    Ok then, now it's time to figure out the frame.

    Let's say one bit per pixel is being used. Since pixels is a long, that means you get up to 32 pixels per waitvid! Let's say it's 32, and calculate.

    For a 160 pixel screen, we first get the number of waitvids needed. That's 160/32 = 5 waitvids. Your active graphics loop will execute 5 times then.

    Now we figure out the VSCL. There are two numbers needed.

    PLLA per pixel = 2560 PLLA per active scanline / 160 pixels = 16 PLLA per pixel.

    Now we figure out the size of the waitvid frame, which is the total number of pixels to be output per frame. That's 16x32 = 512 PLLA per waitvid.

    Now you take the info, put it into a VSCL, and execute it just prior to entering into your active pixel loop. When your active pixel loop ends, you load another VSCL to set the timing for the border.

    A 2 bit per pixel screen means 16 pixels per waitvid max. so then:

    2560 / 160 = 16 PLLA / pixel, nothing changes here.

    16 x 16 = 256 PLLA / waitvid = 10 waitvids, so the math checks out perfectly.

    If one bit per pixel is 5 waitvids, then two bits will be 10 waitvids per active scanline.

    Now, 8 bits per pixel mode means only 4 pixels per waitvid, so that's

    16x4 = 64 PLLA / waitvid frame.

    2560 / 64 = 40 waitvids, each fetching 4 bytes = 160 pixels or 160 bytes.

    Now you can see as the data rate goes up, you have less and less free cycles to run your active pixel loop, and this is the dynamic of propeller resolution, bits per pixel, clock speed and HUB - COG memory interaction plays out.

    One more example then, let's choose a 320 pixel display, 2 bits per pixel, for a 320 pixel 4 color display.

    2560 / 320 = 8 PLLA per pixel.

    Note that a minimum of 16 PLLA per pixel is required for the propeller to output a full color display. Anything less than that will overdrive the color, resulting in artifacting. This can be a good thing as my wiki entry shows here:

    propeller.wikispaces.com/Colors

    ...but can be a bad thing depending on how you code your video signal. That's a topic for another day though, just know this is true for now.

    So then, 2 bits per pixel means 16 pixels per waitvid max, so we divide

    320 pixels / 16 = 20 waitvids being necessary per active scan line.

    Finally, the waitvid frame = 8 * 16 = 128 PLLA per waitvid.

    These calculations can be seen in the potatotext driver, linked in my sig.

    Eric Ball wrote up some nice NTSC templates you can use to build a simple bitmap screen. Search his posts and you will find it. I don't have the link handy at the moment. That's what I would do starting out as bitmaps require the least code, and are easy to setup test data cases for. Once you get a bitmap running, and have good control over resolution, color, borders, etc... you then can start to work on sprites, tiles and other things.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 1/22/2010 7:53:16 PM GMT
  • trodosstrodoss Posts: 577
    edited 2010-01-25 23:58
    @potatohead,

    I am trying to implement a Vwait in a 2-color text driver (similar to some of your first 8x8 drivers) and ran into a snag.·

    I tried putting the Vwait after the frame draw loop, but it does not seem to work quite like I had thought it would.

    Is it something easy that I am missing?

    Thanks,

    --trodoss

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Game(s) Mythic Flight (0.9)
    Utilities Font Editors (AIGeneric, Potato_Text, etc.)
  • BocephusBocephus Posts: 58
    edited 2010-01-26 08:31
    Thanks for the detailed response potatohead. I'll look for the templates you suggested.
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-26 22:15
    Trodoss, I'll get you some vblank info. Work is stiff right now.

    Bocephus: Cool. Just walk it through, one step at a time. Remember to think your scan line through, and make changes that can be seen, and life goes much better in video land.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-26 23:56
    Trodoss,

    Go ahead and post some code, if you want to.

    Here is what needs to happen for a VBLANK flag. There are two approaches.

    1. Have the TV driver write it's blanking status to the HUB.

    2. Have the TV driver write it's draw status to the HUB, only.

    For both approaches, what you need to do is establish a HUB address to hold the data, and make sure both the TV driver and your parent SPIN program have access to it. Easiest way to do this is to include it in your stack of variables, whose address is passed to the TV cog, when started.

    From the parent SPIN program, containing that parameter block, you reference it with @VBLANK. In the TV COG, you need to capture it's address, then store that address in a long for use with a wrlong instruction or two. That can look like this:

    In your parameter block, you've got this in a DAT zone:

    DAT

    x_pixels -- long 160
    y_pixels -- long 192
    screen -- @screen_buffer
    VBLANK -- long 0

    When the SPIN program that calls the TV COG wants to read the flag, it's just @VBLANK, which will point right to the DAT. In the TV COG, you would do this:

    mov Address, PAR
    rdlong cog_x_pixelvalue, Address
    add Address, #4
    rdlong cog_y_pixelvalue, Address
    add Address, #4
    rdlong cog_screen, Address
    ***add Address, #4
    ***mov cog_VBLANK, Address.

    In the COG dat, it's handy to have constants:

    one -- long 1
    zero -- long 0

    Note the last two lines are actually writing the address to the COG, so it can be used like this:

    wrlong one, cog_VBLANK

    Be really sure you understand that. When you save a pointer to an address, you generally use MOV because the address is being captured in a COG long, so you can write to it later on. When you save a value, you use a rdlong, so that you fetch what is at that address! (I got hosed on this multiple times)

    Once you get all that done, you can write values to the HUB, to be acted upon by the higher level COG that needs to interact with the TV cog.

    In your video code, you put a "wrlong one, cog_VBLANK" at the end of your graphics frame. This is right after you've drawn the last scan line with graphics on it, thus indicating that you are in the blanking period. It's not exactly VBLANK, but it's great because the TV beam is done, meaning you can change stuff with no worries, and that's the point of it, so that's where I would put it.

    You do a "wrlong zero, cog_VBLANK" right as you start drawing graphics scan lines. This means the TV beam is painting a picture, so it's best to NOT make changes, or flicker will be seen.

    That's approach number one, and is used in some of my older drivers, and the ones Andre' included with HYDRA.

    Approach number 2 is all about writes from the TV cog, and reads and writes in the higher level cog, and is the approach used in the new 8x8 driver code.

    In this scenario, the TV COG writes a one, when the scan lines start, and that's it! For an interlaced display, either a one or a two is written, depending on even or odd frame. That's needed because the two frames are different. So, let's assume non-interlaced display then.

    A simple "wrlong one, cog_VBLANK", right as the graphics start indicates the display is no longer blanking, and is actually drawing.

    The higher level COG writes a zero, then waits for it to transition to a one, just to sync up with the display. Then it writes another zero, then does it's drawing while checking the VBLANK flag address. It keeps drawing, until it sees the one placed there by the TV COG, at which point it sees that, stops to sync up, then writes it's zero again.

    The second method is good for multiple cogs making a display. The first one is fine for most things.

    Really, the first method is all about the TV cog controlling everything. Other cogs just see the flags and do stuff. This is the easiest way.

    The second method causes a handshake to occur as the resetting of the flag happens in one cog, and the setting of it happens in another COG. More complex, but necessary in most instances of multi-cog drivers. That took me a long while to grok too. (I had to go peek at other drivers!)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 1/27/2010 12:07:42 AM GMT
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 00:02
    Assuming the above gets sorted out, then there is the problem of what to do with the flag.

    In a single buffer scenario, where you are using the flag to prevent screen artifacts, really, you've got to clear the whole screen, then draw everything before the graphics start.

    And if you don't have time, then you have to have logic so that the movement of things is spread out over multiple frames, and or to leave some of the display static (don't clear whole screen), or limit that which is seen each frame.

    Not sure which problems you have, but we can talk about them! Maybe others will jump in too.

    Oh, and don't get frustrated over that. Know what I'm frustrated over? Fricking simple game logic in FREEWAY. I can make a video driver sing, but I can't seem to get simple game states sorted, LOL!!

    So, you will probably see me asking for some more hints here in the near future. Funny how this stuff works. [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 01:51
    I didn't see the code you posted.

    The pointer -vs- address part, I wrote on above, is the problem.

    In one of your programs, you need to setup a DAT for your shared variable, then communicate it to the other programs. I would put it in your LinkDemo_TV_Text_001 program.

    DAT
    
    VBLANK  long 0  'shared flag for VBLANK.
    
    



    Communicate it to both the Linkdemo_001, and LinkDemo_TV_001 programs.

    For Linkdemo_001, you need to add a method in LinkDemo_TV_Text_001 to pass the pointer as a returned value. That looks like this:

    PUB GetPtrToVblank
    
            result                  := @VBLANK
    
    



    What that does is return the address of the VBLANK location in the HUB for the DAT variable to be shared.

    From Linkdemo_001, just call it like this:

    VBLANK_address := Text.GetPtrToVblank

    Now you have the address in the Hub stored in the variable VBLANK_address. Use VBLANK_address to tell SPIN where to get the data to wait on.

    Going the other way, communicate it to the Linkdemo_TV_001, using the address from the PAR register, like I wrote above. You have a rdlong instead of a mov. That will get the contents of whatever the address points to, not the address!!

                            mov     C, PAR                 ' get parameter block address
                            rdlong  A, C                   ' get screen address
                            mov     bmp, A                 ' store another copy
                            
                            add     C, #4                  'index to fonttab address
                            rdlong  fonttab, C             'store it      
    
                            add     C, #4                  'index to Vsync variable
                            mov     VSyncPtr, C            'store it 
    
    



    Now VSyncPtr and the variable you use in your top level linkdemo_001 will contain the same VALUE, which is a POINTER, or ADDRESS to a specific HUB memory location.

    When the TV COG writes it, the top level program can read it.

    I might have time for more later, but that is a start. In your Linkdemo_001, you've got a Vwait procedure that needs to actually read the VblankPtr, not set a value. I don't have a prop hooked up, so I'll just tell you that. Can't run stuff at the moment [noparse]:([/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • trodosstrodoss Posts: 577
    edited 2010-01-27 02:54
    @potatohead,
    Thanks!

    Pointer vs address...should have known! I have run into that before in just Spin code.
    I will try the code changes mentioned and see how it goes.

    Technically I could solve timing issues by going with a double buffer approach (like I did for the Mythic Flight code). One of these days I need to post my VCS: Joust code. That one was pretty fun, but much thanks goes to Baggers (who did all the hard work).

    I was trying to see if I could avoid the space required for "double buffering," since I will be, in effect packing as much "game" as I can into the Prop's limited resources that are left. Should be doable hopefully, since it has been done in Bagger's work. Granted, I am no Baggers [noparse];)[/noparse] May require turning it into a "multicog" driver though (to handle the rendering of scanlines, like the new Potato_Text driver). A lot of that...still figuring out, but I understand the "how" much better.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Game(s) Mythic Flight (0.9)
    Utilities Font Editors (AIGeneric, Potato_Text, etc.)
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 15:25
    Yeah, pointers are tough. I stumble on them regularly. This is one of the first things I look for when something doesn't work.

    Not a lot can be done with one COG. A look at my currently failed KABOOM project will show you the limits there. It's a single COG dynamic display, and it can't quite do that game. That's two sprites per line.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • trodosstrodoss Posts: 577
    edited 2010-01-27 15:48
    Haven't looked at KABOOM in a while.

    Looking at the code though I think I now see how you were using the VBLANK in KABOOM_TV_18. I might give that a try and see how it works (just passing the value 1-way).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Game(s) Mythic Flight (0.9)
    Utilities Font Editors (AIGeneric, Potato_Text, etc.)
  • trodosstrodoss Posts: 577
    edited 2010-01-27 16:13
    Looking at KABOOM did help [noparse];)[/noparse]

    I have a version that works better, but it looks like I will have to work on the rendering.· It is a little too slow to render the background, then draw the character on top.

    Thanks for the help!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Game(s) Mythic Flight (0.9)
    Utilities Font Editors (AIGeneric, Potato_Text, etc.)
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 16:31
    Case in point why posting stuff is a good idea, even when a person is stuck. The ideas that did work, are still good ideas. Really hate that sitting there though. Gotta come back to it.

    Yeah, I should have thought quick how the Vblank worked on that one. It's right where you want to be. Cool. Would have saved some typing.

    I've learned lots of new stuff, meaning I think that one could work for me now. Frankly, I think one COG can do those graphics. There are much better ways to do things. When I get through fighting myself on FREEWAY, I've got to revisit that one. Doing the Vblank that way is solid though. No worries there, just don't go down the road I did for sprites!

    It's too dynamic, and wastes a lot of blanking time doing nothing, or stuff that could be done more efficiently. Still, it's a nice benchmark as to what can be done in a COG.

    You should look at the VCS like driver Baggers wrote. The graphics style might not appeal to you, but his sprite renderer, and how it's got the Vblank stuff setup is very good. It can operate all the way down to 2 COGs, and do quite a bit with those COGs. In video, going from one COG to two is a huge jump. Potatotext is possible because of that, where if you look at the older 8x8 drivers, they are sweet, but have a lot of limitations.

    It's key to know what is expensive and what isn't. Baggers has shown us a lot in that regard.

    Color lookups are expensive as hell. That one thing is why Potatotext is a two COG deal. Where it's possible to move color lookups out of your video COG, do it. Sprite bit masking is also very expensive. So, if you need to overlay sprites with background, do it with simple bit sizes. The trade-off is more HUB memory needed for data, but then the data being possible to draw to screen with less COG effort.

    Good progress! I like video projects to a fault!! So much fun to mess with the beam and timing.... [noparse]:)[/noparse] I'm glad I could help some.

    @Bocephus: Hope you don't mind the video chatter on your thread... Please jump right back in anytime. Looks like we just kind of started talking here. Sorry about that.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 1/27/2010 4:39:26 PM GMT
  • BocephusBocephus Posts: 58
    edited 2010-01-27 17:53
    Y'all go right ahead, I'm enjoying reading and learning with every post.

    After looking at the code trodoss posted I realize that I can't be far from making my sprite stand up correctly. My inability to solve this is driving me crazy. I will attach the code that I am using to learn this and if either of y'all have a moment maybe you will see the issue immediately. I started with the hel driver and butchered it down to the attached.

    Btw, on entry why do you jump over the variables instead of placing them at the end with the others?
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 18:39
    Well, I just had a quick look.

    Are you doing things in the COG for learning purposes only?

    The first thing that stuck out was having your sprite object in the COG. For an object or two, that works ok, but the reality is you need to pull your data from the HUB.

    The second thing that leaps out at me is your code right now is kind of drawing a fixed object to the screen. That's a great learning pass, but will very quickly end up a dead end, as objects need to move around.

    The jump over variables bit is a clever way of making quick, in COG tables without having to add an offset address. If the data is located at COG address 0, then the index can be used directly. If the data is somewhere else in the COG, then it's the index, plus the offset address, which slows the whole works down.

    Frankly, once you get into index, plus offset, everything goes just as fast from the HUB as it does the COG. Also on that, you can't do much more than just do very simple displays with only the COG, meaning the sooner you start pulling data from the HUB, the better!

    Does the program you have attached run as is, and are you on a HYDRA?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • BocephusBocephus Posts: 58
    edited 2010-01-27 19:02
    Yeah I am doing things in the cog for learning purposes. Point taken about pulling from the hub. The program runs as is on the hydra. I commented out my attempt at padding the horizontal line that failed. Something is just not sinking in for me.
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-27 19:35
    I think you need a loop for your active scan lines, and a counter variable, and an index to HUB data to get this running. More later, if I can cram it in!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • potatoheadpotatohead Posts: 10,261
    edited 2010-01-30 20:09
    Ahh.. the weekend. I've got some good Prop time. Bocephus, did you write any newer code? I'm thinking about running the bit you've got to see if I can contribute anything. If you've gone a different direction, or have it worked out, let me know.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • BocephusBocephus Posts: 58
    edited 2010-01-31 05:27
    Hey potatohead, I have a house full of company, courtesy of the ice and snow we received this week, and I haven't been able to code or study at all. Hopefully everyone's power will be back on by Monday and I'll get some time to play again.
  • Cluso99Cluso99 Posts: 18,069
    edited 2010-02-08 03:12
    Thanks for the detail potatohead. I will digest it as I have been trying to understand the video generation process.

    I am presuming that with a single pin (1 resistor), we can only get B&W. Is there any way we could use a 2 or 3 resistor voltage divider connected to the prop pin and use tristate to get 3 states?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz

    Post Edited (Cluso99) : 2/8/2010 3:21:58 AM GMT
  • potatoheadpotatohead Posts: 10,261
    edited 2010-02-08 04:10
    I don't know whether or not that makes sense electrically. On the software end, generating the color signal will entirely consume one COG. Any useful driver would have to then be a two cog, scan line buffer style driver.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • trodosstrodoss Posts: 577
    edited 2010-02-23 15:23
    TommyReed said...

    thx U

    Second, or third, or fourth·that!
    It took a lot of reading/re-reading over to see what I was missing, but I finally got it.

    Thanks!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Game(s) Mythic Flight
    Utilities Font Editors (AIGeneric, Potato_Text, etc.)
  • potatoheadpotatohead Posts: 10,261
    edited 2010-02-25 06:22
    Excellent!!

    I'm glad it helped. Right now, I'm stuck in a do or die real work project, and just have been checking in to read the goings on.

    I do believe the contributor above may be spam, however.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    8x8 color 80 Column NTSC Text Object
    Safety Tip: Life is as good as YOU think it is!
  • jharris1993jharris1993 Posts: 7
    edited 2012-09-09 21:01
    @Everybody

    Wow!

    I used to eat TV receiver system design and repair for LUNCH - but that was a loooong time ago. This stuff is a real wake-up call. (You should see the dust flying outta my brain!)

    I just picked up a Propeller board, and when I found out it could do video - Hot Damn! - you had my interest bigtime. At the risk of potentially hijacking this thread, let me ask a couple of questions:

    1. So far, I have seen much on code to actually DO the video - various demos, etc. However I have seen NOTHING about how to actually attach a Propeller to some video output device, be it a TV or a VGA monitor. I would be very surprised if it were as simple as plugging a few pins from a 15 pin VGA connector into the Propeller board's header.

    2. The Propeller board I have, (P8X32A Quick Start), supposedly has one video generator per cog/core/whatever. Why? To drive more than one video output device at a time? Mux the video signals to create something awesome, (or awful? :-) )

    3: (Possibly WAY off topic) I see it over and over again that the designers of the P8X32A decided that implementing interrupts was not necessary. (say WHAT?!!) However, when I see things like "wait[something]", it just gets my teeth on edge as I can think of dozens of things a cog could be doing (especially with video!) instead of standing around waiting for some event. Any idea why? Or maybe I should just go looking for a forum on the P8X32A itself?

    In any event, I am going to have to read this particular forum at least several times more - AND try some of the code when I find out how to hook this thing up to a monitor! - just to begin to understand what you folks are talking about.

    Again, Wow!! you guys rock!

    Thanks!

    Jim (JR)

    p.s. Is there anyway to "report" a reply? Hopefully the admin's will clobber that blasted spam entry!
  • Mike GreenMike Green Posts: 23,101
    edited 2012-09-09 21:22
    @jharris1993,
    1) Look at the schematic for the Propeller Demo Board. There's a link to it on the webstore product page for it. This shows how to attach a Prop to either a TV or VGA display (or both). Essentially, you need a few resistors to create a DAC for the TV or several DACs, one for each VGA color signal. There is a 1-pin video driver that only needs a single series resistor for B&W TV.

    2) The 8 cogs are identical, so each includes a video generator which is not really very sophisticated. A lot of the video generation is done in software. For large VGA text displays, a single cog isn't fast enough to fetch a line of text, convert to scan lines of pixels, then actually display the pixels. Several cogs can be synchronized so, while one cog is displaying 8 or more lines of pixels, other cogs are fetching and rendering other lines of text to be ready to swap roles for the next group of scan lines. You can also have different simultaneous displays on a TV and VGA display or two TVs. I've done this for debugging with the main display on a TV or VGA and a debug display on a TV.

    3) This has been discussed ad-nauseum. The decision to not have interrupts was very deliberate and has to do mostly with making it easy to create deterministic code. Remember that a cog that's waiting for something or stopped draws almost no power. Cogs that are producing video are often very very busy and the WAITVID does not wait long. It's used more for synchronization. It's fairly easy to write code for cogs that is multitasking. The FullDuplexSerial driver for example switches between receive and transmit co-routines. There's even a 4-port serial driver that switches among receive and transmit for up to 4 separate serial ports.
  • jharris1993jharris1993 Posts: 7
    edited 2012-09-13 08:54
    Mike,

    Re: #3
    I have been having a running discussion with Jeff Martin about a number of things, including the lack of interrupts. I sent him this analysis of the logic behind it.


    On a more technical note – Re: our discussion about interrupts.
    I have been thinking about that for a while now and when you think of it, an interrupt controller is not much more than a limited use microcontroller pre-programmed with some kind of interrupt servicing logic.

    Thinking along those lines, it should be doable, (Easy? Dunno.), to take one core and program it as a dedicated interrupt controller using locks and a shared memory pool to communicate with other cores that wish to use its services. In fact, with a little more effort, it might be able to program something in assembler that would dedicate a core (say #7), to act as a “programmable” interrupt controller accessible by the other system cores.

    With a little bit of handshaking between the devices via shared memory – a particular core could request interrupt services in a particular way, (i.e. interrupt prioritization, passing an interrupt ID, etc.), to make this a general purpose “device” as it were. The only drawback is that any core wanting to use the services of the “interrupt” core would have to poll for a status bit/flag/whatever to see if there is any mail. Which, from a design standpoint, gets under my skin. But that’s me. Maybe when I get the time, (yea, right!), I’ll sit down and write a general purpose interrupt controller program for the Propeller. BTW, if you want to take my analysis and put it somewhere, maybe in a “Why no interrupts?” FAQ, feel free to do so.


    If I am understanding you rightly, in a video role, you have multiple cores running the video - one core retrieving the data and streaming it out the video pin whereas another, core(s) act as a pre-processor, assembling the video data, so that the streaming core can send it. And rather than using interrupts, they sync through a shared memory pool. Right?

    Thanks again!

    Jim (JR)
  • jharris1993jharris1993 Posts: 7
    edited 2012-09-13 08:58
    p.s.

    I have a Propeller "Quick Start" board, (model 40000, rev A). Is this what you mean by the demo board? It sure doesn't look like it, I'd LOVE to find a schematic for the Quick Start board so that I know what to hook where.

    Thanks again!

    Jim (JR)
  • Mike GreenMike Green Posts: 23,101
    edited 2012-09-13 09:14
    When you have multiple cogs sharing the task of video generation, they actually change roles over time. Typically one cog is outputting scan lines while one or more other cogs are fetching text (usually) from shared (hub) memory and building future scan lines using some kind of font tables. Once the scan lines are built, these other cogs wait for a signal from the current output cog, then they switch roles and the cog doing output starts to build a group of future scan lines while one of the other cogs begins to output its (now) buffered scan lines. Since the video pins can be shared across cogs, this is as simple as disabling the one video generator and starting up a different one in another cog. The same code (with a few changed parameter values) is running in all of the cogs involved.

    Here's the webstore page for the Demo Board. There's a link to the schematic under the RoHS banner.

    There's a link to the QuickStart schematic on this webpage.
  • Mike GreenMike Green Posts: 23,101
    edited 2012-09-13 09:30
    An interrupt controller requires some way for the controller to force execution of a particular piece of code. That's why it's called an "interrupt", because it interrupts the normal flow of control, saving at least the existing contents of the program counter, possibly other state information as well like flags and register contents that can be restored later when the interrupt routine returns to the point of the interruption.

    The Propeller has no way to do this. One cog cannot force another cog to do anything other than stop (be reset) and one cog cannot access the memory of another cog. A cog can wait for an external event, but this is hardware polling, not interrupts.

    Since Spin is interpreted (not directly executed by the hardware), it would be possible to make a modified Spin interpreter that uses polling to create an interrupt capability for Spin. The same thing could be done with the LMM and XMM interpreters used for the C implementations on the Propeller, but that's not the same thing as a hardware interrupt facility and it would significantly impact the speed of the interpreter.
Sign In or Register to comment.