This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interrupts

I have hardware interrupts firing off of a timer, but they do not seem to fire when program is occupied with another function. Since my code runs in a loop, my interrupts don't get called.

 

Can someone please point me in a direction that will help to solve this issue?

 

Thanks,

Jason

  • Can you please provide more context surrounding this problem and the system in general? The only time an interrupt will not 'fire' is if the IER bit or the GIE is disabled. Even if the event is not mapped to one of the CPU interrupts the event still happens - it is just never captured by the CPU.

    In your case every time the count register matches the period register the event should happen and the corresponding IFR bit will be set. If the timer's IER bit or the GIE is not set then that interrupt will not make it to the CPU.

    The other potential cause of this issue could be due to the nature of a tightly packed loop. If you have a software loop that uses 6 cycles (branch instruction + delay slots) per iteration then the CPU will never be interrupted. This is fairly uncommon but far from impossible.

    Also, for  clarity would you mind posting which processor you are using?

  • Hey-

    I am using the DM648.  I am trying to hinge off of HW4, and used the c64_enableIER function to enable it, sending the parameter c64_EINT4.

    HW4 interupt is set to hinge off of 69, which corresponds to timer1 register tim12.  It has dispatch checked, and it calls function _Timer1_TINT12_isr, which is in the same file as where I set up my timers as a void function.  But the interrupt does not fire even though the timer is changing.  I have also tried this on other HW#'s not having much luck.

    I also made sure that the bios.ECM.ENABLE is set to 1.

     

    Thanks,

    Jason

  • Jason Zutty said:

    I am using the DM648.  I am trying to hinge off of HW4, and used the c64_enableIER function to enable it, sending the parameter c64_EINT4.

    HW4 interupt is set to hinge off of 69, which corresponds to timer1 register tim12.  It has dispatch checked, and it calls function _Timer1_TINT12_isr, which is in the same file as where I set up my timers as a void function.  But the interrupt does not fire even though the timer is changing.  I have also tried this on other HW#'s not having much luck.

    Thanks for the added context. So I see that you are attempting to trigger the ISR Timer1_TINT12_isr() on HWI_INT4 based on an event from TINT1L. So let's run through a quick check list of what should be done to service these interrupts.

    First, the interrupt source should be defined within the HWI_INT4 properties (this is event 69 as per the device datasheet). Second, the ISR function should be defined within the HWI_INT4 properties. Next, the dispatcher should be enabled so as to properly perform a context switch when moving between the currently executed code and your ISR. From the sounds of it you have already done this, but if you'd like to throw your .tcf file up here I can take a look. These are the only pre-application code and run-time steps you need to take.

    Moving to application code you as the user are responsible for enabling the IER bit. Because you have mapped the TINT1L bit to HWI_INT4 you should be safe by writing 0x0010 to the IER register. Using C64_enableIER(c64_EINT4); should suffice.

    Next you need to write your ISR. Make absolutely certain that you are not using the interrupt keyword here. The interrupt keyword and the Dispatcher will not play nicely, so if both are used bad things happen very quickly (essentially your stack will be destroyed).

    Finally, we come to the enabling of the GIE bit. Because BIOS requires a hardware timer to operate its scheduler it will turn on the GIE bit during the BIOS_start phase which takes place after leaving main. This brings me to another point - because the scheduler requires a hardware timer to function you need to make sure that you are not attempting to use the same timer. Off the top of my head I cannot think which of you (your code or BIOS) would win this fight, but you need to make sure this isn't occuring anyway.

    Jason Zutty said:
    I also made sure that the bios.ECM.ENABLE is set to 1.
    Note that the ECM was created for users who need to service more than 12 interrupts. Because the C6000 only supports 12 customizable interrupts the ECM is a sort of MUX for the other 100-something other potential events. If you are not mapping the Event Combine Manager's events 0-3 to any of the HWI_INTn then the ECM need not be enabled.

  • I see... so it seems that I am missing the GIE bit... how do I enable it?

  • Just a friendly reminder that BIOS turns on the GIE bit. The user should never need to touch the GIE bit unless manually disabling it - this should otherwise be taken care of by BIOS.

    In any case, just for your knowledge you can turn this on through the use of the HWI_enable() function. Note that if you are manually disabling the GIE bit through HWI_disable() that it returns the previous value of the GIE bit. If the GIE is already disabled when you disable it you do not want to enable it when you are through as this could cause unintended events to be serviced. Instead you can use the HWI_restore() function and pass it the return value of HWI_disable(). For example...

    int prevGIE;

    prevGIE = HWI_disable();

    ... //Code

    HWI_restore(prevGIE);
  • Well... just to verify I am not manually disabling it anywhere, but I tried enabling it anyway.  It still isn't hitting the callback...  I am not sure what else I need to do in order to get this to work.

     

    Thanks for the continued help!

  • Would you mind zipping up your .tcf file and posting it here?

  • Hmmm having some networking issues here.  I'll try and do it on monday.

     

    Thanks so much,

    Jason

  • Jason,

    I did not see anything inherently wrong with your BIOS configuration. As such I felt it might be easier to create a quick little example project that I know works and send it your way. The Timer configuration will not match yours completely, but it should work nonetheless. Please give the attached project a shot and let me know if you are able to get this to run.

    *edit* I suggest single-stepping through the code in main and visually comparing the instruction to the changes in the registers.

    dm648_int.zip
  • Your code works very nicely, and thank you for taking the time to put that together, but when I try to tie it in to my code (video_preview with some modifications), it seems to have adverse effects when dealing with the video implementation, specifically when capChan is created... any ideas?

  • My example didn't do any driver configuration/instantiation, so I would guess this is where you are getting stuck. Specifically, you probably want to start by checking your config file under Input/Output->Device Drivers.

  • Well it seems to me, I can get the video to work.  I can get the timers to work.  It's the integration that seems to be failing.  The best I can seem to get is the timers working, but no interrupts firing...

  • Can you look at the value of the INTMUX1 register (0x01800104) at run-time (just halt the processor at some point after the system starts) and see if the lowest byte is 0x45 (decimal 69)? The only reason I can think of off the top of my head is that something else is reconfiguring the INTMUX at run-time.

  • Lowest byte seems to be 0x45

  • So you have been able to verify that the TIM12 counter is counting and, when it hits the PRD limit, resetting. You have also confirmed that the IER[4] bit is high and that the GIE is not inadvertently disabled at run-time. I'm starting to run out of ideas!

    If you are feeling ambitious you could go look at the ISTP register which is effectively a pointer to the interrupt vector table and verify that the INT4 vector includes a branch to your ISR.

    This is a long shot but by chance do you have the optimizer turned on - and if so, is there a chance that the contents of your ISR are being optimized out?

  • What are the addresses of the IER[4] bit and GIE bit and ISTP register?

     

    No, no optimizing at this time.

  • Actually, none of these are memory-mapped and require special assembly instructions to access them; however, the c6x.h header file found in the RTS does allow you to access these through C. If you look inside this header you will see numerous declarations similar to the following:

    extern __cregister volatile unsigned int IER;

    Once this header is included you can read this register with something like temp = IER;. If you do not need to access these at run-time you can always View->Registers->Core Registers where the IER, CSR (which includes the GIE bit) and ISTP are on display.

  • Okay,

    As far as I can tell, IER = 0x5B9B, at that location, memory seems to be ---------------

    CSR = 0x10000103, at that location, memory is also ---------------------

    But ISTP = 0xE4053C80, at that location memory has the string $package/cfg/video_preview_x64Pcfg.s62:908:908$, hwi4

     

    Any insights?

     

    ---EDIT---

    Apparently the dashes were because the debugger was having trouble.

    if I try the following:

    temp = (unsigned int *) IER

    printf("IER 4 is %d \n", temp[4]);

    I get "IER 4 is 0".

    for the csr:

    temp = (unsigned int *)CSR

    printf("CSR is %d \n",*temp);

    I get "CSR is 0".

  • Okay... after a bit more tweaking I have found out that:

     

    the csr is enabled (0x7 which makes the GIE bit 1)

    and

    the IE4 is not (IER is 0x80, which makes the bit corresponding to IER4 0)...

     

    What's going on? I run C64_enableIER before checking... shouldn't that enable the right bit in the IER?

  • But then again, when analyzing the code in the example that you sent me, when I examine the IER, the bit corresponding to IE4 is also set to 0... What's going on?

  • When I ran it IER[4] was indeed set to '1' when i stepped over that function. Are you sure it's not being disabled someplace else?

  • Jason Zutty said:

    printf("IER 4 is %d \n", temp[4]);

    This is not right. IER is a single register and when you saved the value into temp you are indexing a completely different word in the printf. Keep in mind that I stated these are not Memory-Mapped Registers which is why you cannot view them in the memory or watch windows. The printf is a good way to view these values as is the View->Registers window. Tweak your printf to look like the following and then analyze that value. IER bit 4 (IER & 0x00000010) is the one you are looking for.

    printf("IER is %d \n", temp);

  • Hey -

    Yeah that was from an older line... I since got that modified, but it still shows zero.  I modified your code and attached it, this way it more closely mirrors what my code is actually doing.  The interrupt fires, but the IER and CSR bits are not what I'd expect them to be.

    Of course in my actual code, the interrupts don't fire... I am starting to think it's because too much is going on in my loops, wheras this program has nothing... but it is able to interrupt the infinite loops in this program, so I don't know if the amount of processing going on in the loop is relevant.

    dm648_int.zip
  • Jason Zutty said:
    printf("IER is 0x%x \n",*(volatile unsigned int *) IER & 0x10);

    There's no need to cast the IER as a pointer. The code you copied out of the C6x.h header file is telling the compiler that this is a special register accessible only by a special assembly instruction (I think it's mvc). When you write something like IER & 0x10 this is ANDing the VALUE of the IER register with 0x10. When you typecast this value as * (volatile unsigned int *) you are now pointing to a location specified by the value of the register, but because you already have that value this is not necessary.

    Remove the typecast in your printf statements and you should start to see all the valid addresses. Another way to go around this is to open View->Registers->Core Registers and look for the IER about 3/4 of the way down the list. This would show you the actual value of this register without having to worry about this programatically.

  • Well... I made those changes, but now it says that IER is 0x10.... this came from IER & 0x10.... not sure how that one worked out.... shouldn't I expect to see 0x1?

  • You see 0x10 because that is what you are masking. If you wanted to see a one you would need to do something like ((IER >> 4) & 0x1);. The IER bit you are looking for is the 5th bit in the register. Bits 0-3 are reserved (Reset, NMI, RTDX, RTDX), so the first maskable bit for INT4 is the 5th bit.

  • Great!  so I modified my actual code that this is all building into... it shows both the GIE and IE4 bits set... but still the interrupt doesn't fire like it did in the other program... what could be the cause?

  • Jason Zutty said:
    I am starting to think it's because too much is going on in my loops. . .

    You mentioned this before but I forgot to touch on it. The only time a loop can prevent interrupts from occuring is when either interrupts have been manually disabled (IER bits and/or GIE bit) or your loop is so tightly packed that there is a constant branch (rare, but possible). This loop would have to be only 6 cycles (branch cycle + 5 delay slots which would be filled with other operations). Note that the C64x+ core introduced a cool little feature called SPLOOP which basically prevents this scenario from occuring by forcing a clean breaking point out of the loop. Additionally you can try adding the compiler switch -mi=100 (or some other number) which will tell the compiler to briefly break the loop cleanly which will allow for interrupts to fire, then re-enter immediately after (more on this in section 2.12 of the Compiler Guide). Note however that if you have the optimizer disabled (which you mentioned) and have not hand-written an assembly loop that this tightly-packed loop is not going to be the culprit.

  • My code is basically a modified video_preview function, so it calls lots of FVIDs and IMGlib functions, some of which say that they are hand optomized, but in any case -mi=100 did not do the trick... I don't know what could be the problem...

  • Jason,

    Do you have a working test case I can test out? I am out of ideas without having something to work with.

  • Ugh.... so after all that, I think it was something conflicting in a UART file I had attached... thanks for all your help though! 

     

    I really appreciate it!