SPI Ram Video Mode

Topics related to the API, programming discussions & questions, coding tips, bugs, etc. should go here.
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

Forums are a bit quiet so I'll bump this. Right now all I do is work and sleep (dream about work) 24/7 but had a couple hours the last few nights to do some Uzebox. First created what is essentially Mode 3 with SPI vram (8 bit) and user defined vram width(scrolling 5.5 cycle only, 16 bit width no rollover), but as discussed it will be too slow for random vram seeks so did not fix SetTile/ProcessSprites/etc. to work like this, though manual vram/tile/ram tile inserts proved it would work.

I wanted to keep 8 bit vram as with this scheme it would be full 256 rom tiles (almost always enough for games I do)....but vram must be 16bit because there is no good place for an extra multiple by tile size in the rom tile loop. Perhaps at 6 cycles somehow, but I did not look far into that as I am firmly decided on scrolling 32 tiles wide only, so begrudingly accepted that there are other good points to 16bit vram too.

Meh, a crap ton of sliding things around SPI access to make it fit timing, and I ended up having to inline the hsync_pulse just to get the address and first 2 tiles in before the scanline. All the next row/tile code had to be intermingled with SPI command/MSB too, but it works. Now also manual inserts into the ram tile list work, and really there is nothing slow about this scheme at all, where the link scheme(Jubatian showed it earlier, only possible way this could work) does not need sorting, just counting 255 (or > 31 as end of line values) and a couple link adjustments to insert, where ProcessSprites is probably fine in C(not done yet, but not hard when I have time).

Anyway I have yet to repair scrolling as the change to the ram tile list setup is quite large, so ram tiles in the first 2 columns don't work right yet. But I am closing in on the point where it is totally usable and I think will be fast for the right games not touching vram too much. Also, ram tile tricks are still possible actually just with a bit more screwing around, but some versatility is lost versus Mode 3 here. Still, this mode is entirely for high resolution and color depth while still having enough ram tiles that CPU is the bottleneck, so something had to bend for that versus M3. So far I have seen no ill effect at 50 ram tiles, and of course scrolling logic is extremely simplified from a games point of view.

I will post a demo when I fix the scrolling, but right now I can plot ram tiles and load up SMB3 level 1 and CUzeBox has no red lines! LSB of 2nd tile hits just barely before needing to jump for scrolling(ram tiles already determined prior), so I will have to hold off celebrating until I am 100% sure everything works in this setup. Really enjoying asm on a level I didn't before, hopefully not shooting myself in the foot for UCC.
User avatar
Artcfox
Posts: 1382
Joined: Thu Jun 04, 2015 5:35 pm
Contact:

Re: SPI Ram Video Mode

Post by Artcfox »

Sweet! New video modes galore.

I hear you about the work/sleep thing. That's exactly how I feel right now too!
User avatar
Jubatian
Posts: 1563
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPI Ram Video Mode

Post by Jubatian »

Nice, good to see some SPI RAM related stuff! By the way when tampering with the lead-in code, you can always chop off cycles from HSYNC_USABLE_CYCLES (in videoMode3.def.h, line 216). You may optimize it later, first just get it to work (I guess this could solve your problem of "LSB of 2nd tile hits just barely before needing to jump for scrolling", at least in Mode 3, the lead-in producing the pixels of the partial leftmost tile is not interleaved with anything complex).
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

That may have made things easier though I believe I already wrestled the major portions into their general home. Pretty much brute forced everything, and I am sure I wasted much more time than would have been necessary. But I am trying to push past some personal boundaries I have with asm(never having an exciting "big picture" which would drive me to complete the required work for something useful). Without CUzeBox I would have jumped to doing something else instead quite honestly, just that it allows extremely rapid testing to avoid (frustrating!)unforeseen consequences that need tracking down.

Currently working on the sprite parts. I need access functions for that, and since SPI Ram is already married into this mode, I will just create some simple(asm) ones which cooperate with the kernel usage transparently. I want SetTile/GetTile to work normally, and in general the user to not have to worry about how the SPI Ram actually works or what the kernel is doing behind the scenes. I don't think that is too difficult, nor will it be a huge performance impact, which I will elaborate on when I get there. If I see a minor performance trade for ease of use/development efficiency I will probably take it. This mode has 0 compile time options so far, and I could allow 1 or 2 if needed to eliminate code for that allowing full manual control(with a volatile flag indicating SPI was accessed by the kernel). I have documented to the hilt even trivial things in the asm, as my goal is to maybe show an asm newbie as me how to do this stuff.

The exciting part for me is seeing how little code it could take to scroll back and forth through the entire first level of SMB3, and have the turtles walking with collision(objects stored in SPI ram, due to the sequential access for updates probably ok). So far it appears this code can be significantly smaller and easier than normal vram modes. Collision could be easier even covering things off screen, if objects are in SPI Ram, since an array of bits can occupy the otherwise used ram for objects.

Thinking on an independently scrolling split screen approach with 1 black scanline in between, which eliminates the need for an overlay since you can choose not to scroll one of them and vram is 16bit. That part seems reasonable, but making sprites work with that might have pitfalls I don't yet see.

BTW was anyone already working on a Mode 14, or is that number up for grabs?
User avatar
Jubatian
Posts: 1563
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPI Ram Video Mode

Post by Jubatian »

D3thAdd3r wrote: Sat May 26, 2018 11:16 pmBTW was anyone already working on a Mode 14, or is that number up for grabs?
I think CunningFellow's Tempest mode was labeled Mode 14 for a while, so better leave that reserved for that. I had never seen any reference for Mode 15 though, so that should be free.

With SPI RAM, scrolling is sure simple when you can have the whole map in the SPI RAM!

Having a good, easy to understand interface is sure important. Now I am working on that with Mode 52, to have it reasonably easy to understand and usable with standards-compliant portable C, which both calls for novel ways of doing some things compared to my other modes. I will likely rework Mode 748 as well to match this when I am done with this (nobody seems to be using it yet, so although it is in Master, I don't think it would be a problem). Possibly I will replace Mode 74 later (deprecate for a new, similar mode), to have similar interface in all of these. I guess it isn't adapted for a reason, it is truly a huge complex mess to understand (not impossible, but someone who just wants to make a game sure wouldn't want to be bogged down by that).
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

Jubatian wrote: Sun May 27, 2018 3:37 pm I think CunningFellow's Tempest mode was labeled Mode 14 for a while, so better leave that reserved for that. I had never seen any reference for Mode 15 though, so that should be free.
Was not aware of that, thanks, Mode 15 it is then!
Jubatian wrote: Sun May 27, 2018 3:37 pm I will likely rework Mode 748 as well to match this when I am done with this (nobody seems to be using it yet, so although it is in Master, I don't think it would be a problem).
I am vowing to make a space shooter with some Mode 74* variant, but the time is still a ways off before I even start that project.
Jubatian wrote: Sun May 27, 2018 3:37 pm Possibly I will replace Mode 74 later (deprecate for a new, similar mode), to have similar interface in all of these. I guess it isn't adapted for a reason, it is truly a huge complex mess to understand (not impossible, but someone who just wants to make a game sure wouldn't want to be bogged down by that).
M74* is so powerful I imagine there is complexity inherent in having that level of control/specification. A good problem to have for a moderate to advance developer probably. Grobian99 must have figured it out pretty quickly though by the demo, since he made Storm Force with it immediately. If there is possibilities to have easier options to get started, that could be even more powerful then. It is very well documented, so for sure that helps balance things out. Interested to see where you go on this front.

I was going to start talking about how simplified SPI Ram access could work....turns out I don't have a clue! I just started throwing something together to get an idea of how bad it would be. What I came up with is an atrocity fit for neither man nor beast to witness, now I am thinking a more drastic approach is in order unless there is some angle I don't see. I will start a Mode 15 thread so I will actually have some development history documented(maybe I would write some tutorial along with it, as I have a first hand account of what the hang ups are for beginners). It looks like this is going to be plenty of backend development before it is done :? I will probably rant more about non-Mode 15 stuff here as I am thinking about other types of SPI vram uses too.
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

I think my approach so far is fundamentally wrong. Here is the abomination I have come up with so far, and it seems pointless to even finish this contraption, but it demonstrates my understanding of what would be required(which I hope is wrong!):

Code: Select all

.section .text.delay17
delay17:
		; 3 = rcall
	nop	; 4
	lpm	; 7
	lpm	; 10
	lpm	; 13
	ret	; 17

;***********************************
; read bytes from SPI Ram into '644 ram
; C-callable
; r24:r25 = upper bit of SPI Ram address(only r24 bit 0 used)
; r22:r23 = lower 16 bits of SPI Ram address
; r20:r21 = address to write bytes to('644 ram)
; r18:r19 = length of data
; Returns: none
; r18-r27, r30-r31 need no restore
;************************************
.section .text.SPIRread
SPIRread:
; This function relies on a volatile variable which signals if the kernel interrupted to generate a non-blank video frame(requiring SPI Ram access)
; Control is returned only when the frame is done, and the kernel disables SPI Ram beforehand. So there is no need to worry about messing up the
; kernel's display, nor sending bogus SPI bytes before the next volatile check(as it is disabled). If spir_dirty(2) == 1 then we need to start the
; entire operation over to rebuild the state we need. This function trades some cycles to offer a simplified interface to the developer. Manual
; SPI Ram control should be done(consulting spir_dirty) if higher performance is necessary.
	movw	ZL, r20			; prepare pointer to write data to '644 ram
	ldi	r26, 0			; need a register to write 0
	sts	spir_dirty2, r26	; **protect against race condition** set to 0, if it is 1 later assume we were interrupted at a critical point
	lds	r25, spir_dirty		; the kernel will set this variable any time is uses SPI Ram to draw a frame
	sts	spir_dirty, r26		; **race condition** zero it immediately(volatile variable), check if it changed later
	cpi	r25, 1			; has the kernel used SPI Ram since we last did?
	breq	SPIRread_do_enable	; we must start from scratch if so
	lds	r25, spir_dirty2	; reload to detect if we were interrupted between loading and storing 0 to spir_dirty
	cpi	r25, 1			; the kernel has interrupted in between the last few instructions?
	breq	SPIRread_do_enable	; must start over then
	lds	r25, spir_state		; not interrupted, get the current operating state of the SPI Ram(recorded in previous function call)
	cpi	r25, SPIR_READ		; are we already in read mode?
	breq	SPIRread_skip_enable	; don't disable if so, save time setting up *if* we are already at the address we want

SPIRread_do_enable:
	sbi	SR_PORT, SR_PIN		; disable SPI Ram to clear whatever mode it is currently in
	ldi	r25, SPIR_READ		; load the state we are putting SPI Ram in
	sts	spir_state, r25		; store the state, so we can avoid setup next time if possible
	cbi	SR_PORT, SR_PIN		; enable SPI Ram

	ldi	r25, SPIR_READ		; SPIR_READ is the same number as the sequential read command for the SPI Ram
	out	SR_DR, r25		; output the command, then wait 17 cycles before sending the next

	rcall	delay17			; wait for SPI Ram to be ready for next byte
	out	SR_DR, r24		; output the destination address MSB to SPI Ram

	rcall	delay17			; wait for SPI Ram to be ready for next byte
	out	SR_DR, r23		; output the destination address MidSB to SPI Ram

	rcall	delay17			; wait for SPI Ram to be ready for next byte
	out	SR_DR, r22		; output the destination address LSB to SPI Ram
					; > 17 cycles will occur before the following read

SPIRread_skip_enable:
	lds	r25, spir_offset+0	; get the offset the SPI Ram is currently pointed to
	cp	r25, r22		; compare destination LSB of target against what the LSB of SPI Ram currently is
	brne	SPIRread_do_enable	; current offset does not match the specified destination, must start from scratch

	lds	r25, spir_offset+1	; get the offset the SPI Ram is currently pointed to
	cp	r25, r23		; compare destination MidSB of target against what the MidSB of SPI Ram currently is
	brne	SPIRread_do_enable	; current offset does not match the specified destination, must start from scratch

	lds	r25, spir_offset+2	; get the offset the SPI Ram is currently pointed to
	cp	r25, r24		; compare destination MSB of target against what the MSB of SPI Ram currently is
	brne	SPIRread_do_enable	; current offset does not match the specified destination, must start from scratch

SPIRread_ready:
	cpse	r20, r26		; is the LSB of length 0?
	rjmp	SPIRread_loop_enter	; otherwise read bytes(quickest possible entry is not so quick....)
	cpse	r21, r26		; is the MSB of length 0?
	rjmp	SPIRread_loop_enter	; otherwise read bytes
	; store new offset...
	ret				; else the user requested a 0 byte read(just wanted to set the mode and offset?)

SPIRread_loop_enter:
	rjmp	.			; pad timing if length LSB was not 0
	out	SR_DR, r16		; queue first byte read from SPI Ram
	push	r24			; save address MSBit
	push	r23			; save address LSBytes
	push	r22			; if we are interrupted somewhere within this loop...
	push	r19			; ...we will need a fresh call state to start over
	push	r18			; save LSByte of length
	movw	r26, r18		; move length to r26 so we can use sbiw
SPIRread_loop:
	
	lds	r25, spir_dirty		; this is a volatile variable, see if the kernel interrupted and changed it
	cpi	r25, 1			; did the kernel use SPI Ram to draw the screen since we started?
	breq	SPIRread_interrupted	; then our state is no longer valid, must restore then rebuild from the start
	rjmp	.
	in	r25, SR_DR		; read byte from SPI Ram
	out	SR_DR, r25		; queue next byte read from SPI Ram
	st	Z+, r25			; store byte in '644 ram
	lds	r25, spir_dirty2	; another volatile variable to double check
	cpi	r25, 1			; interrupted?
	breq	SPIRread_interrupted	; need to restore and start over
	sbiw	r26, 1
	breq	SPIRread_end		; done writing bytes
	rjmp	SPIRread_loop		

SPIRread_end:
	pop	r18			; eat the stack leftovers that we no longer need
	pop	r19			; if we had been interrupted in the last pass through...
	pop	r22			; ...they would have been useful
	pop	r23
	pop	r24
	ret

SPIRread_interrupted:
	pop	r18			; restore and try again.....
	pop	r19
	pop	r22
	pop	r23
	pop	r24
	sts	spir_dirty, r26
	sts	spir_dirty2, r26
	rjmp	SPIRread
A quick scan through that taking the shortest path possible, it is clear that the best case scenario for this function is extremely slow. One problem is that there is a race condition. I think the only way to avoid it, is to have 2 flags, though I am not 100% sure this way solves it either. I thought to just offer the user 2 functions, SPIRread()/SPIRwrite(), and you can use them as a form of seek by doing a length of 0. The next time it is called, if the SPI Ram is in the right mode, and pointing to the right location, it can perform the operation without repeating the setup. The only advantage is that the user doesn't have to do this stuff like they currently would with the SPI Ram Library. Ultimately, the normal library is already really easy to use and comprehend, though it is not race safe. Now I am sort of wondering if it is better to offer the "spi_ram_dirty" flags, and let the user handle it?

My other idea which I am really warming up to, is to simply disable interrupts during the setup. Then enable, and test the flag after it is done. If the interrupt happened during this period it should "queue" and immediately fire when interrupts are enable. I think the video mode should be able to readjust itself to not even have a too long setup line then?

That I have seen, it works pretty well just to do the heavy read/writes at the beginning of the frame, then do not miss frames! I wonder if it even needs to be race safe, or if that is some hidden bomb I hand off to the user?

*maybe some funny stuff in there, I am not used to doing asm called by C or the conventions on it just yet.
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

Ok, unless someone knows why it is a ghastly idea, I much prefer just disabling interrupts and the user having common sense if they run into issues. Trying to hide too much doesn't seem to have a real advantage, and it seems this mode is not very complicated anyway.

Rough draft, it seems this is fairly safe, semi-fast, and is really easy to use:

Code: Select all

.section .text.delay17
delay17:
		; 3 = rcall
	lpm	; 6
delay14:
	lpm	; 9
delay11:
	lpm	; 12
	nop	; 13
	ret	; 17

;*******************************************************;
; r25:r24 = address to write to('644 ram)		;
; r23:r22 = length of data				;
; r21:r20 = r20.0 = MSBit of SPI Ram address to read	;
; r19:r18 = lower 16 bits of SPI Ram address to read	;
;*******************************************************;
.section .text.SPIRread
SPIRread:

	; Interrupts are disabled during this function. If a vsync interrupt does occur, it will be queued and immediately
	; fire when interrupts are enabled. TODO make sure frame code can adjust for some deviation. The onus is on the user
	; to do longer reads at the beginning of the frame(or disable rendering), and to adjust things if their game frequently
	; has bad video timing. Though, occasional frame skewing seems better than some other alternatives..

	cli				; disable interrupts for the remained of the function, do reads early, do them quick!
	out	SR_DR, r25		; queue the next read, in case we are at the location we want already(no harm done otherwise)

	push	YH			; Must I restore Y?
	push	YL
	movw	ZL, r24			; prepare Z for writes to '644 ram
	movw	r24, r22		; move length to r24 for sbiw
	ldi	YH, SPIR_READ
	lds	YL, spir_state		; get the state the SPI Ram is in from previous operations
	cp	YH, YL			; already in read mode?
	brne	SPIRread_do_setup	; have to setup from the start if not
	
	lds	YL, spir_offset+0	; get the offset the SPI Ram is currently in from previous operations
	cpse	YL, r18			; compare against read target LSB
	rjmp	SPIRread_do_setup	; offset does not match the target, must start over
	lds	YL, spir_offset+1	; get the SPI Ram offset MidSB
	cpse	YL, r19			; compare against read target MidSB
	rjmp	SPIRread_do_setup	; offset does not match the target, must start over
	lds	YL, spir_offset+2	; get the SPI Ram offset MSB
	cpse	YL, r20			; compare against read target MSB
	rjmp	SPIRread_do_setup	; offset does not match the target, must start over

SPIRread_loop:				; else we are already at the byte we want to read!
	in	YL, SR_DR		; read the first byte
	out	SR_DR, YL		; queue next read
	st	Z+, YL			; store to '644 ram
	lds	XL, spir_offset+0	; get the currently stored SPI Ram offset
	lds	XH, spir_offset+1
	adiw	XL, 1			; increment for new SPI Ram offset
	sts	spir_offset+0, XL	; do this outside for MSBit?**save for next time
	sts	spir_offset+1, XH	; do this outside for MSBit?**cycles to burn for SPI wait...
	sbiw	r24			; decrement 16 bit length
	breq	SPIRread_end		; done reading?
	rjmp	SPIRread_loopp

	; TODO, set spir_offset+2 to 1 if we crossed a boundary(easier to take lds XL/XH out of the loop?)
SPIRread_end:
	sts	spir_state, r24		; store state so we know where we are at next time
	sei				; our state is stored, OK to enable interrupts now
	pop	YL
	pop	YH
	ret
	
SPIRread_do_setup:
	sbi	SR_PORT, SR_PIN		; disable SPI Ram to clear whatever mode it is currently in
	sts	spir_state, YH		; store the state, so we can avoid setup next time if possible
	cbi	SR_PORT, SR_PIN		; enable SPI Ram

	out	SR_DR, YH		; send sequential read command
	rcall	delay17
	out	SR_DR, r20		; send MSBit of read address
	rcall	delay17
	out	SR_DR, r19		; send MidSB of read address
	rcall	delay17
	out	SR_DR, r18		; send LSB of read address
	
	sts	spir_offset+0, r18	; save current SPI Ram offset LSB
	sts	spir_offset+1, r19	; save current SPI Ram offset MidSB
	sts	spir_offset+2, r20	; save current SPI Ram offset MSBit
	rcall	delay11			; wait for SPI Ram to be ready
	out	SR_DR, r18		; queue read for first byte
	rcall	delay14			; wait for SPI Ram to be ready...
	nop				; .
	rjmp	SPIRread_loop
Probably doesn't work as is and not tested, I am just trying to compare approaches on a coarse level before I go too crazy. This seems ok to me versus whatever horrible beast that previous thing was.

BTW can I always count on r0 being 0 when called from C, and must I always restore if I clobber it or any weird caveats around that?

EDIT - ok this one I will finish and use. If the user calls this and it is already at the location(which can happen frequently if good practices are used), then he needn't worry about data corruption nor where the SPI Ram is currently pointed. If not doing enormous write late in the frame, probably never sees a video issue? In the ideal case, the first byte is in by cycle 26, and bytes are read and stored at the maximum possible SPI speed. The write case should be similar..running with it!
User avatar
Jubatian
Posts: 1563
Joined: Thu Oct 01, 2015 9:44 pm
Location: Hungary
Contact:

Re: SPI Ram Video Mode

Post by Jubatian »

Disabling interrupts is not a good idea at all as it isn't only the video frame which needs precise timing. Every 1820 cycles there is a HSync, which also needs exact timing. When you prepare for interrupt disable in main, you would have to take the longest disable period in cycles, and add that time for syncing. For example if you had a 100 cycle disable (about the minimum for reading or writing a byte from SPI RAM), with appropriate kernel code, you would have 100 extra cycles lost in every scanline, which is a lot.

I am thinking about rewriting the sync code in the kernel similar to that in Flight of a Dragon, as there are even some bugs in it as of now. Two important problems are that one, you can not really call SetRenderingParameters() arbitrarily during games as there are race conditions which may cause losing sync for a frame, while this could be useful, especially with SPI RAM stuff (where the game might occasionally prefer to just transfer large stuff from SD to SPI RAM, fast). Another one is a video mode design problem, that is, that if the video mode doesn't output that many lines as many is set by SetRenderingParameters(), sync breaks. FoaD fixes both, and it isn't anything difficult, the kernel should just transfer to the frame routine, and let it running for as many lines as it wants to (even now, it can not forcibly terminate the frame routine, so there is no part of the behavior which could be called beneficial).

Anyway, the point is that with such a rewrite, GPIOR0 migth receive some flags to be used by video modes and such, one good candidate could be a "video frame processed" flag which could be used by a video mode to signal that its frame routine ran. That flag could be used then to fix up things if the video frame broke something sensitive.

However I think it can not, and should not be attempted to be hidden entirely as display artifacts (flicker) will still likely happen, it is not a good code when you unintentionally run out of VBlank time, and accessing the SD card would still break severely if interrupted (card may deadlock, also locking up the SPI RAM, needing reinit). Using the SPI RAM from interrupt (video frame) is risky, and demands appropriate design aware of the risky nature! Disabling the video frame (at least SPI usage in it) is one of these when accessing the SD card.

(By the way with M748 you could do exactly that: Disable the mode for the duration of your sensitive code doing anything on the SPI, and enable afterwards. You will get ugly flicker if you run out of VBlank, but nothing will actually break).
User avatar
D3thAdd3r
Posts: 3221
Joined: Wed Apr 29, 2009 10:00 am
Location: Minneapolis, United States

Re: SPI Ram Video Mode

Post by D3thAdd3r »

I got a bit carried away not thinking of hsync, and can't think of any way to cooperate that with disabled interrupts. Interrupts must be on then.

With interrupts I see no alternative to pushing the entire state before proceeding, then determining if it was interrupted after it is done. All the SPI bytes(to a now disabled SPI Ram as the video mode leaves it when done), shouldn't hurt anything except wasting time. If interrupted, restore and do the entire thing over again. Lots of added cycles before the first read to push, and lots of pop overhead if just reading a few bytes. Perhaps the user actually is in the best position to manage this, being in total control of when things are triggered. Starting to care less and less about making SetTile/GetTile vsync safe.
Jubatian wrote: Mon May 28, 2018 5:56 am (By the way with M748 you could do exactly that: Disable the mode for the duration of your sensitive code doing anything on the SPI, and enable afterwards. You will get ugly flicker if you run out of VBlank, but nothing will actually break).
I think you mean an entire frame? It must be something different you mean though, since I don't see why flicker would happen so long as this state lasts the same length as a normal drawn frame. I have some placeholder for something that just loops and sends hsync for an entire frame(not tested), there is a crazy amount of cycles not being used which directs my attention at that. I might have had this idea in the past and for some reason someone said it wouldn't work, but I can't think of why it would be impossible.

There should be some way possible to have a user scanline callback then. If the frame is disabled and outputting all black(so not touching SPI Ram), hsync pulse can be sent out, and Timer 1 setup as normal, except then calling a user callback to use those 1440-overhead cycles for something good. That callback would most likely need to be asm, but in some example of a screen with 200 lines tall, there must be something the user could pull off in ~200*1440= 288,000 cycles. At minimum, this could be used to display an error message if there is no SPI Ram on the system, or some type of other novel effects when the SPI Ram is busy. The asm could even be free from exact cycle counting..maybe, if it checked Timer 1 at least once on it's longest path. What do you think? I am going to try that unless there is some real deal breaker you see that makes it impossible. At system boot, the kernel can set this callback to a default one which is just a black pixel then "rjmp .-4", and the user need not care about it unless they want to.
Jubatian wrote: Mon May 28, 2018 5:56 am Using the SPI RAM from interrupt (video frame) is risky, and demands appropriate design aware of the risky nature! Disabling the video frame (at least SPI usage in it) is one of these when accessing the SD card.
This is how I felt originally, and now I have come full circle back to agreeing with this sentiment :roll:
Post Reply