So, rather than trying to launch straight into my PVBCC project (which is a lot of pseudocode right now) I’ve been writing a lot of small demos to try to understand the hardware better, and take baby steps rather than trying to write some killer-app all at once. (Last coding competition I tried to tackle a project that was way above my skill level, then got frustrated and left the scene for a while because of it.) I think that in order to make coding timed actions such as animations, clocks, etc. easier, I should learn to use interrupts. (Specifically, I’m trying to learn how to use a timer interrupt, but I’d also like to learn to use keypad interrupts.) So last night, I tried to code a small demo that would display a clock onscreen, showing the time since program startup. I set up the timer registers to what I thought were the right values…
//Set timer period (50 cycles of 20 microseconds = 1 millisecond) HW_REGS[TLR]=50; //Set up timer interrupt: 20us resolution, interrupt enabled, timer enabled HW_REGS[TCR]=0x19;
And then I put some code in the tim_vector() procedure. The problem seemed to be that the code in the interrupt vector wasn’t getting run. I also tried another method: rather than using the interrupt vector, I tried waiting for the flag in TCR that indicated zero was reached to be set…
//Wait until timer reaches zero while (!(HW_REGS[TCR]&0x02)); //Clear status flag HW_REGS[TCR] |= 0x04; update_clock();
But that didn’t work either. I think the rest of my code works, as if I eliminate all the bits having to do with the timer, the clock’s digits will increment just fine (Although not at the right speed.) Based on this thread, it looks like the timer interrupt vector was messed up in earlier gccvb versions, but I think I’m also probably doing something wrong. I’ve attached my demo, could anyone who has used these beasts before give me a push in the right direction? (The version I’ve attached doesn’t use the vector, it just tries to check the zero flag, but in the other version the contents of update_clock() were put in the tim_vector() procedure.)
I also wanted this to be a thread on general interrupt use, because I’ve searched David Tucker’s programming manual, Google, and PVB, and I couldn’t find much information. I found this thread by jorgeche, which seems to indicate that old versions of gccvb were having problems with this, as well as Alberto Covarrubias’ animation tutorial, but nothing that really gave me a concrete idea of what to do. I was hoping that maybe we could collect what everyone knows about interrupts so that it could be added to the wiki…
This is what I do to make my function timer_hnd() interrupt the main function and get executed every 20 ms:
extern u32 tim_vector; // Timer Interrupt Handler void timer_hnd() { timer_int(0); VIP_REGS[INTCLR] = VIP_REGS[INTPND]; timer_enable(0); timer_clearstat(); timer_enable(1); //Do your stuff here timer_int(1); set_intlevel(0); } int main() { //setup timer interrupts tim_vector = (u32)(timer_hnd); VIP_REGS[INTCLR] = VIP_REGS[INTPND]; VIP_REGS[INTENB] = 0x00; set_intlevel(0); INT_ENABLE; //setup timer timer_freq(TIMER_100US); timer_set(TIME_MS(20)); timer_clearstat(); timer_int(1); timer_enable(1); while(1) //Do your stuff here }
Hey Dan, could you attach the libgccvb.h you use (or whatever contains all those “timer_*” functions)? Thanks!
Ah, sorry! My “libgccvb” consists of lots of separate files, here is the one with the timer functions:
Thanks Dan!
(Actually, after I posted the request, dasi gave it to me on IRC, but I’m glad it’s here for completeness of the thread.)
I don’t know how, but the libgccvb I’ve been using is missing that stuff 😕 Now I’m wondering what else it’s missing… I guess I’ll have to go through every version I can find and compile (no pun intended) a new one. Or I could just wait until I need something and bother you again 😉
Huh, I checked what your function code did and what I did and it looks like it’s about the same thing. I’ll try your functions, and I’ll look through my code a couple more times… It looks like I’m on the right track, but I’m doing something wrong.
I’m still using the libgccvb.h that came with KR155E’s old introductory demo. I get the feeling that there are several versions around, and that everyone is adding features to their version, but no one is sharing. (Don’t get me wrong, everyone is free to do what they want with their code, but if the community is going open-source…) Am I using the same version as everyone else, or is there a more complete one? (And where do I get the libraries that everyone seems to be using in their affine demos?)
- This reply was modified 14 years, 5 months ago by Fwirt.
Sorry for double posting (I usually notice things after I’ve already posted once, and by then I can’t edit my original post…) It looks like I did the timer setup steps, but not all this…
//setup timer interrupts tim_vector = (u32)(timer_hnd); VIP_REGS[INTCLR] = VIP_REGS[INTPND]; VIP_REGS[INTENB] = 0x00; set_intlevel(0); INT_ENABLE;
And while I have the timer library DanB provided, I don’t have the library that provides set_intlevel() (or INT_ENABLE for that matter.) My questions are:
1) Where can I get these libraries?
2) I can’t find clear definitions for the purposes of INTCLR, INTPND, and INTENB (But I assume INTENB is interrupt enable.) So what exactly does the above code snippet do? (What effect making INTCLR equal to INTPND have? Is INT_ENABLE the same as something like VIP_REGS[INTENB] = 0x01? What exactly is set_intlevel() supposed to do?) Thanks for your help (and patience)!
As far as I know, DogP’s modified libgccvb.h and the libgccvb headers that were included in gccvb_06-20-05.rar are the most recent versions of libgccvb. The libgccvb.h included in KR155E’s demo is an ealier version.
- This reply was modified 14 years, 5 months ago by dasi.
Attachments:
And while I have the timer library DanB provided, I don’t have the library that provides set_intlevel() (or INT_ENABLE for that matter.) My questions are:
1) Where can I get these libraries?
They are defined in asm.h that dasi provided above.
Ah, thanks dasi! I didn’t have any of these files before… This should make things a bit easier. 😀
Edit: I also just noticed that interrupts.h defines the interrupt vectors. This explains why I ran into that problem compiling code w/ gccvb4 when no one else did…
- This reply was modified 14 years, 5 months ago by Fwirt.
Well, in using the version of libgccvb that dasi provided, I’ve hit a new snag: my old code is not working. Specifically, it will compile with no problems, but at runtime nothing is getting drawn to the screen. Here’s a link to the simplest demo I’ve written. If you change the code to use the old libgccvb (comment out the WA stuff, uncomment the vbSetWorld stuff, and switch the include) it will work just fine, but in its current state, using the new libgccvb, it doesn’t seem to do anything. The new version seems to offer more features, so I’d really like to get started using it… Are there any pitfalls that I should know about?
I re-packaged and attached your code, for posterity and to see if it would go through for me (I thought maybe the attachment thing didn’t like bz2 files, or something; 7zips seem to work).
I have looked, but cannot find the bug. I modified your makefile (no need for the header to be compiled or depended upon) and some of your code, but it looks like it should have worked before, and still doesn’t. Something is getting mis-compiled, because none of your code seems to be running at all. As a quick test, I put this inside the while(1) loop (which should actually be a for(;;) loop):
VIP_REGS[BKCOL] = ~VIP_REGS[BKCOL];
It should make the screen blink on every frame, if all is well. No blinky…
Another symptom is that the character data is in the ROM, but it’s not being copied to the VIP (according to Red Dragon). If I had a way to step through the code, I could probably figure it out…
Also, in vip.h, the VIP_REGS pointer needs to be volatile, like:
volatile u16* const VIP_REGS = (u16*)0x0005F800;
I wish I could be of more help…
Attachments:
dasi figured it out… The “const” needs to be removed from the VIP_REGS declaration:
volatile u16* VIP_REGS = (u16*)0x0005F800;
Thanks, dasi!
I feel like I’m kind of nagging at this point… Thank you all so much for the help, but it seems I’m kind of back to where I started. My code is displaying again, but it seems that with the code that DanB provided, the interrupt code is only getting called once… After poring over the official VB development manual (which RunnerPack reminded me about) I reduced DanB’s code down to what I think are only timer specific interrupt settings. I’ve also tweaked around with my code, and I know that update_clock() works, so I’m not quite sure what’s going wrong… I attached my code again, is there anything that I need to do to get the interrupt to trigger more than once?
There’s something a little confusing about your code… You have all the “xxx_vector” functions defined in your code, but in my gccVB installation (4.2.2 under Cygwin) those are already defined in crt0 as pointers located in the jump table. I get errors if I try to redefine them. The way I understand it, as in DanB’s code, you would A) define these as externals, and B) set them equal to the address of your handler function(s). Something like this (from DanB’s snippet):
tim_vector = (u32)(timer_hnd);
I think you should go to this post and download the attachment.
It needs to be edited to uncomment the column table stuff (just look for a big commented block, you can’t miss it) then assembled:
v810-as.exe crt0.s -o crt0.o
And copied to /usr/local/v810/lib/crt0.o.
I also noticed that you commented out the contents of the interrupts.h you included with your previous code. These will have to be restored.
Anyway, I fixed your code as outlined above and it works in Mednafen (although I didn’t have font.h, so I substituted the IPD screen chars and it looks funky :-P). You’ll find it attached.
You should also stop being embarrassed or worried about seeking help. The community (and this forum, specifically) is here for that very reason! I wish more people were as eager as you are to learn new things. Also, I feel I must praise you for using the proper spelling of the word “poring”. I’m glad to know spelling isn’t a completely lost art 😉
YES! IT’S ALIIIVE!!!
So that broken crt0 was causing the problem… 😛 I wonder why it didn’t work for me when it worked for everyone else? Oh well, with that solved, now timer interrupts are working as they should. Now I’m feeling like I’m on more solid ground… Thanks again to everyone! (And thanks for the comment on spelling, RunnerPack. I really appreciate that.)
On a side note, when I was looking through jorgeche’s crt0.s that I compiled, I noticed that it defines .global _rom_title… Since my games aren’t called Snowball Wars, I just refilled the relevant data with the proper blanks, but is there any way I could use this in my code to set the rom info?
Maybe I’ll add some of what I learned about timer interrupts to the wiki if I get a chance to write up a solid article…
Fwirt wrote:
YES! IT’S ALIIIVE!!!
Congratulations, Herr Doktor 😉
So that broken crt0 was causing the problem… 😛 I wonder why it didn’t work for me when it worked for everyone else?
That’s a good question. I hope whoever is working on the gcc patch project checks the crt0 code they’re using.
On a side note, when I was looking through jorgeche’s crt0.s that I compiled, I noticed that it defines .global _rom_title… Since my games aren’t called Snowball Wars, I just refilled the relevant data with the proper blanks, but is there any way I could use this in my code to set the rom info?
Not really, since it defines an address in ROM. But, you could move this code out to an assembly file in your project, which is exactly how the old win32 version worked–that’s what the whole .vbh file business was about. You just have to make sure the reset and other interrupt handlers are correct and that you put things at the right addresses.
Maybe I’ll add some of what I learned about timer interrupts to the wiki if I get a chance to write up a solid article…
That would be great! Just don’t let it interfere with work on your compo entry. 😉