HInt Counter timing

For anything related to VDP (plane, color, sprite, tiles)

Moderators: BigEvilCorporation, Mask of Destiny

Post Reply
mitchConnor
Newbie
Posts: 8
Joined: Tue Jul 16, 2013 9:25 pm
Location: Darmstadt, Germany

HInt Counter timing

Post by mitchConnor » Fri Jul 19, 2013 11:32 am

Here I am again. Didn't think I would run into the next issue so quickly...
I have now extended my color switching solution to use a lookup table that has two entries, one for color and one for the next line skip value (HInt counter). I'll just show you some code, it's simple:

Code: Select all

typedef struct GradientEntry
{
	u16 color;
	u8 skip;
} GradientEntry;

void Gradient_start(GradientEntry * lut)
{
	s_lut = lut;
	s_index = 0;

	*((vu32*)GFX_CTRL_PORT) = 0xc0000000;
	*((vu16*)GFX_DATA_PORT) = s_lut[s_index].color;

	VDP_setHIntCounter(s_lut[s_index].skip - 1);

	s_index++;
}

void Gradient_setNextColor()
{
	VDP_setHIntCounter(s_lut[s_index].skip - 1);
	// prepare the palette 0 color 0 switch by writing the corresponding value to the VDP control port	
	*((vu32*)GFX_CTRL_PORT) = 0xc0000000;
	u16 color = s_lut[s_index].color;
	// wait until the HBlank becomes true _again_ (that is actually the next line after the one for which this interrupt was triggered)
	while((*((vu16*)GFX_CTRL_PORT) & VDP_HBLANK_FLAG) == 0);
	// now immediately write the color. the time is very short, and if we'd wait just a little too long we'd see the old color flickering in the next line
	*((vu16*)GFX_DATA_PORT) = color;

	s_index++;
}
Gradient_start() gets called at VBlank and Gradient_setNextColor() is called at each HInt.

And the test gradient I use:

Code: Select all

const GradientEntry defaultGradient[] = 
{
	{0, 20},
	{0xffff, 40},
	{0x7, 0xff}
};
So what I was intending to do: Draw 0 (black) for 20 lines. (This first color and hint counter gets set in VBlank). Then draw white for 40 lines. Then draw some kind of red for the rest (0xff is more than the whole screen, so HInt shouldn't get called anymore).

But what happens instead:
Black 20 lines.
White 20 lines.
Red 40 lines.
Black for the rest of the screen.

Obviously the HInt counter is one off when called from HBlank. But I don't understand why. I'm very sure my code doesn't have an off-by-one error, so it's probably something hardware-related. Can somebody explain?

(The SEGA doc says "The horizontal interrupt is controlled by a line counter in register #10. If this line counter is changed at each interrupt, the desired spacing of interrupts may be achieved.", and that's what I'm trying to do)

TmEE co.(TM)
Very interested
Posts: 2440
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Post by TmEE co.(TM) » Fri Jul 19, 2013 11:34 am

The counter gets reloaded with value in the VDP register when interrupt happens, not when you write the value in.
You write 20 now, and it takes effect starting from the next int.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

mitchConnor
Newbie
Posts: 8
Joined: Tue Jul 16, 2013 9:25 pm
Location: Darmstadt, Germany

Post by mitchConnor » Fri Jul 19, 2013 12:04 pm

Ok, that's almost what I thought. Good to have confirmation though, thanks.

So with the following modifications it works:

1. Gradient_setNextColor() looks one ahead for the skip value. (because for clarity I want to keep my LUT format the same)
2. The skip value of the first entry gets halved because I can't prevent it from getting "executed" twice.

That's it :)

Post Reply