These tilted lines actually look more like "visible area (or scanline as a whole) too narrow / hsync freq too high" (if they tilted the other way, that'd mean it's too wide)
Have you verified that the driver that is supplying the sync is running the same mode as you? (your monitor should tell you)
While I can never be 100% sure, I have checked it and it looks good. It is a 640x240 driver that signals as 640x480. My monitor does pick it up properly, but it doesn't think it's a 640 x 480. It's a simple mod of the standard bitmap driver. I have checked the settings (constant presets), but I could be wrong. The only two differences it has to mine is the pixel clock (30 mhz instead of 25) and distribution of porches. I'm using the tinyvga timings. I'll try finding another driver and see if it helps. Also, is 25 mhz pixel clock too slow for 640 x 480?
Well yeah, if the pixel clock is different all the timings change around! The nominal pixel clock for 640x480@60Hz is 25.175 MHz - if you use 30 MHz without changing the metrics, you get 640x480@71Hz (most monitors will have no problem with this). Try running with the normal sync pins (and without the other driver "scaffold") again and see what happens.
I realise this. However, the other driver I was using didn't add or subtract from the timings. It just shuffled the mix of sync time and porch time. I think I'll switch drivers instead. Also, I've been trying without the scaffold for every change I make. I think this seclnd driver is just dodgy.
I use the VGA_Text.spin one that comes with PropTool (which internally uses VGA.spin). Low memory usage, blank screen and IIRC standard timing by default.
Did not realise vga_text was just black by default. Huge thanks for the tip and all the generous help you have given me so far. I'll try it out tomorrow, it's pretty late over here.
Ahh wait I remember, actually, it's NOT black by default, but you can set it to emit sync only by gving it your VGA basepin +1 (instead of +7). i.e. for basepin 16 you'd start it with
Is it? Ahh, never realized that. (Although the horizontal resolution it does really doesn't matter for this purpose, as long as the timing is vaguely right)
That link you provided back to the MicroVGA looks like it is based upon an ARM7 design I did back in 2005 where I bit-bashed VGA under interrupts. The original chip was an LPC2106 with 64k RAM but the one I entered into the design contest was based on the newer LPC2138 at the time. Once they realized that fast I/O matters, they produced the LPC2148 and I was able to have much less jitter in the video. I had to do preinterrupts to let things settle before the actual line interrupt itself. I still managed to do wave audio from files and run a foreground program plus serial coms etc. Then I discovered the Propeller and VGA was so much better and easier.
So, where are you at with your driver. Can you post the latest version as I can check it.
This is the very original though:
Funny thing is that I have found that there were a lot of people claiming the design as their own or taking the credit for it, many years after I had designed and published the details. I used IAR workbench since the ARM assembler was totally unlimited and free back then.
Here is the latest code. The sections altered to accommodate debugging have been marked with a "normal" + commented-out version, and the debug lines have "debug" above them. VGA_Text_640 is just VGA_Text. I just copied it into my project directory to test what would happen if I altered the horizontal ticks to be 640. It just broke the text driver, so I reverted it.
Adding instructions between waitvids is unlikely to help you.
Waitvids, once started, run continuously and in the background.
This is done so you have time to set the next one up while the current one is streaming the signal.
It is helpful to think of them like you do the signal, which is one unbroken chain of levels.
To affect when things happen, set the number of pixels in a waitvid frame, the pixel clock, and the PLLA value.
Should a waitvid end without another one being setup, the streamer keeps going with whatever data happens to be on the D and S busses at the time. Unless one is doing tricks, that data is never what you want.
What you want to do is kick off a waitvid, then get the next one setup and the waitvid instruction for the next one executed so it can continue the signal without it being interrupted.
The tilt you are seeing is signal timing off due to the chain of waitvids being broken, or the timing values being set incorrectly.
In most drivers, timing values for non active signals are different from the active regions.
One important value to get a handle on is total PLLA per line. That has to remain constant, unless the driver does interlaced video, and in that case, one line will be half as many PLLA.
Figure out what the total PLLA per line is for a working driver, and make sure whatever you do adds up to that, and the waitvids all execute before the ones coming before them.
I know that I want to be ready for when the waitvid strikes. I was just adding and removing instructions to see what effect on the display it had. I knew it wouldn't fix anything, but I tried it to see if it'd give me any indication of what's going wrong
Okay, so swapping the pixel rate calculation for a more precise precalculated value (read: ripped from a driver that calculates it in-place), I've approximately flattened the lines.
Well, you made me do it - I got out my VGA monitor and debugged it here.
Lots of changes, so I've just attached the fixed code and will give you diff here:
--- main_broken.spin 2020-07-20 04:44:59.613969400 +0200
+++ main_fixed.spin 2020-07-20 04:47:48.638637100 +0200
@@ -18,6 +18,10 @@
vertical_synch = 2
vertical_back_porch = 33
+ hsynch_gp = 1
+ vsynch_gp = 0
+
+ pingroup = 2
' These are the inactive states of the synch lines, meaning the state they're in during visible drawing on the screen
' They must be set to either 0 or 1 depending on the video mode
@@ -30,7 +34,7 @@
'normalstate = (hsynch_inactive << 1 + vsynch_inactive) * $0101
'debug
- normalstate = ((hsynch_inactive << 1 + vsynch_inactive) << 2) * $0101
+ normalstate = (hsynch_inactive << hsynch_gp + vsynch_inactive <<vsynch_gp) * $0101
DAT
scrbuf long $00000000[5100]
@@ -39,7 +43,7 @@
bmp: "VGA64_BMPEngine"
PUB start
- bmp.BMPEngineStart(2, 1, horizontal_resolution, vertical_resolution, @scrbuf)
+ 'bmp.BMPEngineStart(0, 1, horizontal_resolution, vertical_resolution, @scrbuf)
cognew(@asm_entry, 0) 'launch assembly program in COG 1
DAT
org 0
@@ -70,6 +74,7 @@
call #hsynch
djnz line, #hline 'Are we still doing visible lines?
+ 'jmp #hline
mov synch_lines, #vertical_front_porch 'do vertical front porch lines
call #vblank
@@ -89,11 +94,11 @@
vblank mov vscl, hres
waitvid synch_active, #0
-hsynch mov vscl, horizontal_front_porch 'Set FrameClocks to the front porch pixel value
+hsynch mov vscl, #horizontal_front_porch 'Set FrameClocks to the front porch pixel value
waitvid synch_active, #0 'Do the front porch pixels (no pixels, no hsynch)
- mov vscl, horizontal_synch 'Set FrameClocks to the sync pulse pixel value
+ mov vscl, #horizontal_synch 'Set FrameClocks to the sync pulse pixel value
waitvid synch_active, #1 'Do the horizontal synch pulse (no pixels, hsynch on)
- mov vscl, horizontal_back_porch 'Set FrameClocks to the back porch pixel value
+ mov vscl, #horizontal_back_porch 'Set FrameClocks to the back porch pixel value
waitvid synch_active, #0 'Do the horizontal back porch pixels (no pixels, no hsynch)
djnz synch_lines, #vblank 'Do another line of synch?
@@ -102,38 +107,38 @@
hsynch_ret ret
-vconfig long $300004ff
-reg_dir long $ff0000
+vconfig long $300000ff + pingroup<<9
+reg_dir long $ff << (pingroup*8)
vscl_pixel long 1 << 12 + 16
-pix_clk long $14242aee
+pix_clk long $14242aee
hres long horizontal_resolution
-vres long vertical_resolution / 2
+vres long vertical_resolution
'pixel_data long $0055aaff
-colour long $FF00FFFF
-'colour_mask long $fcfcfcfc
+colour long $FFAA5500
+colour_mask long $fcfcfcfc
'debug
-pixel_data long 0
+pixel_data long %%333322211110000
'colour long 0
-colour_mask long $f0f0f0f0
+'colour_mask long $f0f0f0f0
-synch_normal long normalstate
+synch_normal long normalstate*$01010101
' This is a special colour, wherein colour 0 is normal state, while colour 1 is hsynch active (but vsynch inactive)
' When in vsync, vsynch is active on both colours
-'synch_active long normalstate ^ $200
+synch_active long normalstate ^ ((|<hsynch_gp)<<8)
'debug
-synch_active long normalstate ^ $800
+'synch_active long normalstate ^ $800
'normal
-'vsynch_bflip long $101
+vsynch_bflip long (|<vsynch_gp)*$101
'debug
-vsynch_bflip long $404
+'vsynch_bflip long $404
line res 1
@@ -141,4 +146,4 @@
synch_lines res 1
h_groups res 1
-synch res 1
\ No newline at end of file
+synch res 1
Thank you so, so, so, so, so much. While your code didn't want to compile on my end, for some reason, doing a diff between the two helped me find the fix. It was really stupid mistake, forgetting the immediate on the synch vscl durations. I cannot express how thankful I am for your help, or how sorry I am for making you put up with my stupidity. Really, a thousand cheers to you.
Comments
Have you verified that the driver that is supplying the sync is running the same mode as you? (your monitor should tell you)
So, where are you at with your driver. Can you post the latest version as I can check it.
This is the very original though:
Funny thing is that I have found that there were a lot of people claiming the design as their own or taking the credit for it, many years after I had designed and published the details. I used IAR workbench since the ARM assembler was totally unlimited and free back then.
Waitvids, once started, run continuously and in the background.
This is done so you have time to set the next one up while the current one is streaming the signal.
It is helpful to think of them like you do the signal, which is one unbroken chain of levels.
To affect when things happen, set the number of pixels in a waitvid frame, the pixel clock, and the PLLA value.
Should a waitvid end without another one being setup, the streamer keeps going with whatever data happens to be on the D and S busses at the time. Unless one is doing tricks, that data is never what you want.
What you want to do is kick off a waitvid, then get the next one setup and the waitvid instruction for the next one executed so it can continue the signal without it being interrupted.
The tilt you are seeing is signal timing off due to the chain of waitvids being broken, or the timing values being set incorrectly.
In most drivers, timing values for non active signals are different from the active regions.
One important value to get a handle on is total PLLA per line. That has to remain constant, unless the driver does interlaced video, and in that case, one line will be half as many PLLA.
Figure out what the total PLLA per line is for a working driver, and make sure whatever you do adds up to that, and the waitvids all execute before the ones coming before them.
Lots of changes, so I've just attached the fixed code and will give you diff here: