MOD54415 HiRes Timer vs Watchdog

for everything else
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

MOD54415 HiRes Timer vs Watchdog

Post by jediengineer »

Hi all,

I'm trying to implement a timer based interrupt routine into my code. I need the timer to run in the background and not delay the program. I'm not sure f I should use the HiRes timer or the Watchdog timer for this - The HiRes timer seems to suggest that it will delay the program when called instead of running in the background... Can someone clarify this? Thanks!!
Ridgeglider
Posts: 513
Joined: Sat Apr 26, 2008 7:14 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by Ridgeglider »

The Hi Res timer can certainly work in background/IRQ mode although it can also be configured to poll a delay.
However, for many timer based apps, particularly repeat events at a fixed mSec to second interval, it may be overkill.
I'd look at the PIT timer. One-time usec delays are easy, but if they are regular, things will bog down.
Can't remember of the top of my head, but I think the PIT is 16 bit resolution, while the "Hi-res" uses the DMA timer module which is 32 bit resolution.
Also remember that the OSTime delay tick uses PIT ch 0, and debugger uses ch 3 I'm pretty sure.

See:

C:\nburn\examples\MOD5441X\PIT-Timer\main.cpp and in particular the built in function InitPitOSSem() which posts a semaphore in every PIT ISR.

See: C:\nburn\MOD5441X\system\pitr_sem.cpp and C:\nburn\MOD5441X\include\pitr_sem.h

For background on the PIT module, see the appnote on the PIT for the MOD5270: http://www.netburner.com/support/docume ... mer-2/file which can be ported to the 54415 fairly easily.
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by jediengineer »

Aaah, thanks Ridgeglider, that's some useful info!! I need a consistent timer that will interrupt at 1 second intervals, one that will interrupt at 0.2 seconds, and one that interrupts at 0.1 second intervals - always gets restarted and only one is running at a time... Sounds like the HiRes timer is the one I need. The ISR doesn't do anything too fancy - just read a MUX and ADC, send a UDP packet, and restart itself. That's all. I would assume that I could set up one timer to do all that, and just change the timer value at whatever point I need?
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: MOD54415 HiRes Timer vs Watchdog

Post by dciliske »

That you can. Though, do note that there is a setup time for defining a new delay time/frequency of tens of microseconds. If you need tighter timing, you can either a) learn the hardware and implement your timing directly and simply store the values, or b) setup multiple timers and just start/stop them as needed.
Dan Ciliske
Project Engineer
Netburner, Inc
Ridgeglider
Posts: 513
Joined: Sat Apr 26, 2008 7:14 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by Ridgeglider »

Not to plug the PIT too hard, take a look at the PIT example C:\nburn\examples\MOD5441X\PIT-Timer and the 1 sec code is already set up to post a semaphore from an ISR to a pending task for you! Instead of doing the MUX, ADC, and UDP start from within an ISR, consider doing it in a task that pends on the semaphore. The switch from ISR to task is about 6 uSec (Dan?). To change the period, simply disable the PIT ISR, set a state variable to indicate MUX/ADC/UDP, then recall the InitPitOSSem() function. Your task would check the state and act on the MUX, ADC, or UDP job accordingly. I think the PIT may have lower overhead than the HiRes and although you do need another task it should probably use less stack space than a default task stack.
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by jediengineer »

Thanks Dan, I did use 3 separate timers. As the system reaches it's critical points it will switch timers correctly - I've proved that out. But I did hit a snag with them...

Also, Thanks RidgeGlider, it sounds awesome, but I'm gonna confess, I know far too little about semaphores and how they work. I tried using them once or twice and if I follow a code example, I'm fine but truly understanding them is where I falter and being able to use them properly will take some figuring out in my abundant spare time... :P But for you and Dan to consider, here's what I've done so far:

This code executes in my UserMain() loop immediately before the main while() loop:

Code: Select all

    timer0 = HiResTimer::getHiResTimer(0);									// initialize HiRes timer0
    timer1 = HiResTimer::getHiResTimer(0);									// initialize HiRes timer1
    timer2 = HiResTimer::getHiResTimer(0);									// initialize HiRes timer2

    timer0->setInterruptFunction(timer_ISR); 								// Point timer interrupt call-back to timer_ISR()
    timer1->setInterruptFunction(timer_ISR); 								// Point timer interrupt call-back to timer_ISR()
    timer2->setInterruptFunction(timer_ISR); 								// Point timer interrupt call-back to timer_ISR()

    timer0->init(0.95);														// initial start of timer is ~1 second per data poll - <1sec to ensure CWT reset.
    timer1->init(0.2);														// initial start of timer is 1/5th second per data poll.
    timer2->init(0.1);														// initial start of timer is 1/10th second per data poll.

    timer0->start();														// start timer0 for 1x per second poll
followed by the CWT set up for 1.07 second intervals:

Code: Select all

    unsigned short settings = 0;											// simple masking variable for CWCR

    settings |= 0x8000;														// sets CWCR as read-only - bit 15
    settings |= 0x001B;														// sets timeout to 1.07 seconds - bits 4-0
    settings |= 0x00C0;														// bit 7 = enable, bits 6-5 = generate system reset on timeout

    sim2.scm.cwcr = settings;												// load CWCR - starts WDT immediately

My ISR routines call the ADC and MUX functions form their class BUT... the software now freezes as soon as the DSPIStart() function is called. I saw this initially when CWT kept rebooting the system. Once disabed, and with a little debug work, I saw the system freeze up each time when stepping into that function. Disabling the HIRes Timer (using only one to start) allowed everything to work again. Is there a specific reason this would happen? The SPI channels are running at 10MHz and 16MHz (MUX and ADC respectively) so I can't see why the SPI function would freeze - the process is really fast... Any ideas?

MUX Code:

Code: Select all

void funcs::MUX_Read()					// reads mux inputs and returns them to caller
{
	WORD MUX_OUT[32];
	BYTE MUX_Tx[3], MUX_Rx[3];												// MUX TX Buffer. Not receiving data from the mux so MUX_Rx might not be used...
	MUX_Tx[0] = 0x40;														// sends address and r/w code to gpio expander - 0b01000000
	MUX_Tx[1] = 0x0A;														// loads register address code to set output latch - OLAT
	if (enabled)
	{
		// poll all mux positions - inputs listed as s1-s32, but coded from 0 to 31
		for (BYTE i = 0; i < 32; i ++)
		{
			J2[33] = 0;															// enable IO
			MUX_Tx[2] = i;                                             			// writes the incremented position to OLAT of the 8b breakout
			J1[5] = 0;															// MUX CS line drop
			J1[6] = 0;															// MUX WR line drop
			J1[7] = 1;															// MUX EN line high
			DSPIStart(1, MUX_Tx, MUX_Rx, 3, NULL, true);						// Data to GPIO breakout to switch mux
			while(!DSPIdone(1));												// release when done
			if (J2[32])
			{
				MUX_OUT[i] = MYSYS_FAULT_FOUND;									// loads a "pin on" value (chosen so as not to be 1 or 0)
				faultset(MYSYS_MUX[i], true);									// sets specific fault
			}
			else
			{
				MUX_OUT[i] = MYSYS_NO_FAULT;									// loads a "pin off" value (chosen so as not to be a 1 or 0)
				faultset(MYSYS_MUX[i], false);									// clears specific fault
			}
			J1[6] = 1;															// MUX WR line high
			J1[5] = 1;															// MUX CS line high
			J1[7] = 0;															// MUX EN line drop
		}
		for (volatile int i = 0; i < 32; i++)
		{
			iprintf("Channel:  0x%X", MYSYS_MUX[i]);
			if (MUX_OUT[i] == MYSYS_FAULT_FOUND) iprintf("  Fault.\r\n");
			else iprintf("   No Fualt.\r\n");
			OSTimeDly(TICKS_PER_SECOND/20);
		}
	}
}
RidgeGlider, I'll try messing with semaphores over the weekend and see if I can wrap my brain around them. I'm not new to C and C++ anymore, but I'm still a bit of a newb, not that it's an excuse. But I'm willing to investigate since you are proposing a great alternative. But I would appreciate your input on the error if you could be so kind. Thanks!!
Ridgeglider
Posts: 513
Joined: Sat Apr 26, 2008 7:14 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by Ridgeglider »

Jedi: I have not gone thru your code in detail, but a cursory inspection suggests that the MUX code polls 32 positions, and for each, starts and then waits for the DSPI to complete. It also calls some iprintf() functions. IMO this is WAY to much to be happening inside an ISR, even at the low rates you mention. Again, IMO, this would be much better implemented in a task triggered by a semaphore posted by the timer ISR. As I mentioned earlier, the PIT timer example already will post that periodic semaphore. All you need to do is create a task something like:
void FunctionForMyMuxTask (void *pd) {
while (1) {
OSSemPend( &MyTimerISRSemaphore, 0);
MuxRead();
}
}

Then you create the Semaphore: OS_SEM MyISRTimerSemaphore ;
Init the semaphore: OSSemInit( &MyISRTimerSemaphore, 0);
create the MuxTask using something like: OSSimpleTaskCreate( &FunctionForMyMuxTask , MAIN_PRIO + 1);

Look at the NB Semaphore demo at: C:\nburn\examples\StandardStack\RTOS\OSSemaphore
I've also attached a few add'l semaphore project examples that build on the NB example.
Maybe these will be helpful in familiarizing you w/ tasks?
Attachments
SemaphoreExamples.zip
(1.62 MiB) Downloaded 579 times
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: MOD54415 HiRes Timer vs Watchdog

Post by dciliske »

Yea... you really can't call drivers in an IRQ. It turns out, a lot of them rely on interrupts triggering to work. You really want to have the timer post to a semaphore that a task is waiting on and then have the task perform the actual... task.

-Dan
Dan Ciliske
Project Engineer
Netburner, Inc
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by jediengineer »

Thanks Dan, so I'm assuming that RidgeGlider was correct then in recommending the PIT. Unless the HiRes Timer works with semaphores... Can't call drivers in IRQ - I would assume this applies to the external Pin IRQs as well?

RidgeGlider - I'm going to give it a go with the HiRes timer and a semaphore first, then try the PIT. I'll update when I get it going. I may also post a few questions if I get stuck but I'll do my best not to.
Ridgeglider
Posts: 513
Joined: Sat Apr 26, 2008 7:14 am

Re: MOD54415 HiRes Timer vs Watchdog

Post by Ridgeglider »

Jedi: Bottom line, both the PIT and the DMA timer (aka the HiRes when used w/ the NB interface) are hardware driven timing modules. Both can operate in polled mode, or w/ISRs, and sometimes, importantly by manipulating specific IO lines completely w/o any processor overhead (eg no ISRs!) after they're configured and turned on. To use the HiRes w/ a semaphore just define a function that posts the semaphore, and point the timer to run upon completion using setInterruptFunction(). You will need a task that pends on the semaphore. Either timer will work, the PIT just costs less and is simpler I think. Of course, it would not hurt to read up on the PIT or DMA modules in the Freescale manual!
Post Reply