G400 Timer Counter Interrupt RLP

Hello,

First, I have to give a lot of credit to Simon from Vilnius his tutorial on RLP was very helpful, keep up the good work!

I’m trying to setup a simple blink led example using a timer counter and interrupt with RLP and have been stuck trying to figure out for the past few days, hoping that I can get some help.

I’ve got the timer counter working, but I don’t think the ISR interrupt handler is being called and also after 16 seconds the board resets, which I believe is due to Watchdog because I think I’m creating some type of a problem.

I’d greatly appreciate it if someone would be able to look over my code to see if I’m setting up the timer counter interrupt correctly, and why the Watchdog reset happens after 16 seconds?

Here is the native code:

void IrqHandler(void *arg)
{
    // disable timer counter interrupt
    RLP->Interrupt.Disable(TC01_IRQn);

    // toggle the led
    int led_pin = 99;
    RLP->GPIO.Writepin(led_pin,!RLP->GPIO.Readpin(led_pin));

    // clear timer counter interrupt
    REG_AIC_ICCR = AIC_ICCR_PID17;

    // enable timer counter interrupt
    RLP->Interrupt.Enable(TC01_IRQn);
}

int SetupInterrupt(void **args)
{
    // disable interrupts
    RLP->Interrupt.GlobalInterruptDisable();

    // install timer counter interrupt
    if (!RLP->Interrupt.Install(TC01_IRQn, IrqHandler, (void*) 0))
    {
        return 0;
    }

    // setup timer counter and compare register

    // enable the clock : TC Channel Control Register : TC_CCR1 : Page 675
    REG_TC0_CCR1 = TC_CCR_CLKEN;

    // RC Compare Trigger Enable :  TC Channel Mode Register : TC_CMR1 : Page 676
    REG_TC0_CMR1 = TC_CMR_CPCTRG; // RC Compare resets the counter and starts the counter clock

    // Compare value : TC Register C : TC_RC1 : Page 684
    REG_TC0_RC1 = 10000000;

    // Software Trigger Command :  TC Channel Control Register : TC_CCR1 : Page 675
    REG_TC0_CCR1 = TC_CCR_SWTRG; // A software trigger is performed: the counter is reset and the clock is started

    // RC Compare : TC Interrupt Enable Register :  TC_IER1 : Page 687
    REG_TC0_IER1 = TC_IER_CPCS; // Enables the RC Compare REG_TC0_IER1

    // end of setup timer counter and compare register

    // enable interrupts
    RLP->Interrupt.GlobalInterruptEnable();
    RLP->Interrupt.Enable(TC01_IRQn);

    return 1;
}

Here is the managed code:

namespace MyFirstRLP
{
    public class Program
    {
        public static void Main()
        {
            // configuring RLP
            RuntimeLoadableProcedures.NativeFunction setupInterrupt = null;
            var compiledDataG400 = Resources.GetBytes(Resources.BinaryResources.MyFirstRLP);
            var elfImageG400 = new RuntimeLoadableProcedures.ElfImage(compiledDataG400);
            elfImageG400.InitializeBssRegion();
            setupInterrupt = elfImageG400.FindFunction("SetupInterrupt");

            // call the RLP SetupInterrupt function
            var result = setupInterrupt.Invoke();

            // if the interrupt was installed check the timer counter value
            if (result == 1)
            {
                // Read the counter value register
                Register TC_CV1_0 = new Register(0xF8008050);

                while (true)
                {
                    Debug.Print("Register Value: " + TC_CV1_0.Value);
                    Thread.Sleep(1000);
                }
            }
            else
            {
                Debug.Print("The interrupt was not installed");
            }
        }
    }
}

Why not use tasks from the available extensions? It is much better.

Hi Gus,

I’ll take a look at tasks, although at this point I don’t know what is better about it.

However, since I’ve spent days trying to figure out the interrupt code I mentioned, I was hoping I could find the reason for the issue just for my own understanding of what is going on. Any ideas or pointers of what to try to figure it out?

Thanks.

Task is almost a fancy timer interrupt. Your code uses timer 0 which is probably used by netmf already.

I tried all 6 timer counters but had the same outcome. In each case I can see the timer counter value increment to the compare value and reset as expected.

However, after 16 seconds it resets, I have the USB sound as it detaches and then heard the USB sound as it attaches. Then this process repeats. Also during the 16 seconds, I don’t think the handler is being called since I don’t see the led toggle on/off.

Also, note that the timer counter by itself does not have an issue, meaning that I don’t get the 16 second reset if I don’t use the interrupt. I only see the 16 second reset when I use timer counter with the interrupt.

What else do you think it could be?

Thanks.

@ let x eq 42 - 16 seconds is the default watchdog timeout on the G400. It seems you are locking something up in the board preventing us from resetting the watchdog internally. (The watchdog is on by default on the G400.)

Hi John,

You are right, however I’m stuck at trying to find out what is causing it. Why would installing the timer counter interrupt with code listed below lock it up?

If someone could try using a timer counter interrupt to see if they can reproduce it or let me know what could be happening that would be much appreciated.

   
// install timer counter interrupt
if (!RLP->Interrupt.Install(TC01_IRQn, IrqHandler, (void*) 0))
{
    return 0;
}

@ let x eq 42 - The NETMF core is most likely using Timer 1 internally. Since the G400 is closed source only GHI could tell you which timers are available for you to use and which they have used in their port. The other option is trail and error but that is risky as is might not always be reliable as the firmware/port evolves.

1 Like

Hi taylorza,

I read in the datasheet @ Smart | Connected | Secure | Microchip Technology on page 658 there are 6 independent timers, I tried all 6 of them and I see the same issue. This makes me think I missing something when installing the interrupt or within the handler function.

@ let x eq 42 - The best I can offer is to try it this weekend and see if I can get it to work. Ideally GHI might be able to offer some advice here since the code available for the implementation of this functionality it is hard to wager a guess as to what you might be doing wrong, but I would be interested to give it a try and let you know what I find.

1 Like

I would search for existing examples for this MCU. To confirm that you set the timer correctly. All required registers and the right order.

This week I had some more time to look at this and spent some time looking over the datasheet and no matter what I do I end up with the watchdog reset (I don’t think the call to the handler function is even working) trying with all 6 timer counters.

At this point I’m wondering if any of the timer counters work with interrupts, I’d really appreciate if GHI folks or anyone can provide a working example for the G400 using a timer counter with an interrupt, that will really help me try to figure out what I’m doing wrong. I’ve searched the forum but haven’t found an example.

Can someone provide a working timer counter + interrupt example for G400?

Wohoo, I figured this out today. The timer counter interrupt is triggering and calling my ISR.

So the the only thing I had incorrect with my code I posted was that I was clearing the timer counter interrupt in the ISR:



But I actually needed to read the timer counter status register which I believe clears the status bit to acknowledge the interrupt:


```cpp]REG_TC0_SR1;[/code


It's sad though no one picked up on this for almost a month but hope this helps someone else that might run into this.

One thing that still remains though is why the WatchDog still resets after 16 seconds, as far as I can tell everything is working and nothing is locked.  When I disable the Watchdog, everything works fine and nothing is locking up so not sure on that yet.

Glad you have figured it out. Not many on the forum mess with low level code. Managed code mostly. As for the watchdog. You supposed to reset it before it expires, I think. Resetting it is the indication for the watchdog that your application is running.

Sweet.

Watchdog control is tricky. It can only be configured (that is, disabled/enabled) one time after power up. That means GHI cannot disable it, or otherwise your managed code will not be able to enable it again. By default, watchdog is enabled on the CPU, so GHI firmware has to reset it internally all the time, until you explicitly and permanently disable it in your code. I suspect there’s a dedicated timer doing just that, so maybe your timers interfere with it somehow.

It is an old topic, but perhaps the information can be useful to somebody. I needed 0,2ms timer event, so tried to experiment with timer interrupts also. Here is what I found:
Simon from Vilnius (thanks for great RLP tutorial, labai padėjo :slight_smile: ) is right - restart is caused by watchdog timer. It is possible to periodically write key and reset bit to WDT_CR from managed code, and the the module doesnt reset any more. But I have noticed, that LAN doesnt work in this case. I dont remember correctly, but I think I2C also fails. So this is not the best solution.
I checked the registers and the reason this happens is because GHI use timer interrupt internally (I think for TC0 channel 0 comparison B). Disabling this interrupt from managed code (setting bit in TC_IDR) without using RLP causes similar reset behavior. So I assume, that registering interrupt in native code effectively “steals” it from GHI firmware and causes malfunctions.
So far I have made a simple work-around - I programmed a timer to act as waveform generator and connected its output (TIO pin) to free input and configured external interrupt (rising edge trigerred) in native code using RLP functions. So I have an interrupt with interval of 0,2ms with some minor jitter.
I think this type of work-around is awkward and it would be much better to have a possibility to call a normal interrupt, because timing is still not very stable and I think it is influenced by LAN communication (apparently because external LAN module also uses external interrupt). It would allow much more flexibility if timer interrupts were possible.
The main problem here is that in ARM micro controllers groups of hardware have only one interrupt vector (not like in for example AVR, where each event has its own vector). So when the firmware uses only one event on a timer, nothing else remains to user. I think GHI could simply add this functionality - they would need to only add a check for interrupt source in their timer interrupt handler and add a call-back to native user function (I think something similar is done with external interrupts). This would allow to use the modules in most of real-time applications with critical timing.

1 Like

Well, at least you made it! Without RLP you wouldn’t have done it at all… This is another example of how important RLP feature is, and, unfortunately, G80 will not have it :frowning: