Video Novice needs advice about screen updates
R Baggett
Posts: 225
in Propeller 2
I have based my HMI on the P2_SolarPanelMonitorDemo. I notice update flickering as it is redrawn about every 20 mS.
I wish to avoid this flickering.
- I could just redraw on change. this may be practical, but would probably still be noticeable in the redrawn part of the screen.
- I notice PUB routines waitForVsync(display) and waitForBlanking(display) in P2VideoDrv. I assume these are provided as an aid to avoid my problem, but are not used in P2SimpleVideo which is an object of the solar panel demo.
Should I mod P2SimpleVideo to use one of these, or modify it to expose these to my program?
Which would be best to use?
Warning, I have almost no idea of what I am doing... I just have some vague recollection that syncing changes to one of these events is the way to do this...
Thanks!

Comments
OK I added:
PUB GateChange() vid.waitForBlanking(@display)to P2SimpleVideo and then did
repeat video.GateChange() HmiDemo() waitms(20)in my HMI, the flicker is gone, but I wonder what will happen as the update gets more complicated.. Current plan is to start sprinkling more calls to GateChange() as needed if flickers return.. any better way?
I think the main problem is that the drawing is not double-buffered. I.e. displaying the same buffer that is being drawn to.
If you made the update more complex it would start to flicker again or show glitchy scanlines.
The way to avoid flicker is to have two buffers, draw to the one that's not visible, then swap them (i.e. swap display base pointer and drawing pointer). Don't have the code here, so idk if it's difficult to make that change.
Ada is correct. If you want to do more complex updates that will take longer than a frame of time to create (16ms or 20ms for 50Hz) to generate, you are best to move to a double buffered solution where you build the new image in a different frame buffer while the prior frame buffer is being displayed. The low level APIs in p2videodrv related to this are:
PUB setSource(region, buf) - sets a (hub or external) memory address where the region sources its frame buffer from.
PUB getSource(region) - reads it back
You'll need to do the same thing you did with your GateChange API to expose this to the higher levels - or build it into a modified p2simplevideo.spin2 file API.
Also you'll need a way to select which buffer you are drawing into and flip that each time you want to output the updated screen. This can be done slower than 60Hz and it'll still look okay as updates will be consistent without glitches but it will start to slow down the information update rate on screen - for real-time dials this might be noticeable below say 10-20Hz or so, depending on your application.
Looking at the demo, it seemed VonSzarvas opted for a single buffer (for simplicity) so his gfx writes currently always start at base address 0 (via the constant called "RAM"). This would need to be extended and made aware of the current offset (screen) selected to be drawn into. Not too difficult if you create a global variable and make use of it in the API calls where needed when computing the memory address of the write. E.g in PUB getAddr(x,y) for example. EDIT: Note that you need to logically OR in (1<<28) to the source address in the API call to setSource to select "external bus 1" as the video address space - a zero in this top nibble would use HUB RAM instead of PSRAM on the P2 Edge for example.
You'd co-ordinate that global value change with the source address each time you flip the two buffers. Shouldn't be too difficult to achieve with a small amount of code.
Thanks to Both!
I think I have enough here to do this.
Extreme speed is not required. This is meant to be better than the glacial speed of tkinter on a pi-like OBC. (Updating the HMI for 12 units under test was actually taking longer than the tests!)
@rogloh,
I don't really understand region.. is this what I imagine as something that maps to a region (Rectangular?) on the screen? It might solve an additional problem if I could use the same code to map to say, 12 similar regions on the screen.
A region is a horizontal rectangular subset of the screen with the full screen width and 1-n number of pixels high (like a group of rows or row of a text screen, but with pixels instead of rows). The displayed frame gets drawn by navigating a sequence of regions you tied together in a linked list type of structure. Each region can be of different type (text/gfx), have any height in pixels, and use any gfx bit depth (eg. you could start with some true-color 24bpp graphics, then have some text rows, then some monochrome 1bpp graphics etc) and you can mix and match these at will. You can also dynamically move them around in the list and offset them or change their heights to slide them up/down and re-order them on screen providing some nice graphical effects when done synchronously with the vertical sync. A member of the display structure points to the start of this list. If/when it runs out of regions before the screen ends it will display the selected border colour. A screen should have one or more regions. If it has zero regions, it will just display the border colour to the end of the screen.
The APIs are all being documented. I have a document here I am still working on that could be of some use, although it's in flux and so may not always match the driver you are using, esp. when talking about the unreleased features and the next gen video timing structure. But probably 99% of it will still apply.
I'll need to think on that. It's both more/less than I had hoped...
Thanks much for the docs!