HInt Counter timing
Posted: 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:
Gradient_start() gets called at VBlank and Gradient_setNextColor() is called at each HInt.
And the test gradient I use:
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)
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++;
}
And the test gradient I use:
Code: Select all
const GradientEntry defaultGradient[] =
{
{0, 20},
{0xffff, 40},
{0x7, 0xff}
};
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)