Help with non-maskable interrupt

Discussion to talk about software related topics only.
Post Reply
ScottM
Posts: 32
Joined: Mon Feb 01, 2010 10:00 am

Help with non-maskable interrupt

Post by ScottM »

Yes, me again. I've run into yet another snag getting one wire working. It involves the timing of interrupt handling. If you're willing to help, please bear with some explanation:

The project is a weather station, with a handful of devices using one wire, and some digital inputs I'm tying to IRQs.

The problem is that for one of the digital inputs, I need to measure the amount of time the signal is high, vs the amount it spends low, and these intervals can be a few microseconds in length, worst case. So when I get an edge, I have to measure the pin and collect the time, Right Now. As in, within a microsecond (us) or two. Having the interrupt delayed by other interrupts, or anything else, is going to mess this up.

For that reason, I'm not going to be able to use the usual approach for handling the one wire pin: lock out interrupts and do timing loops to decide when to fiddle the pin. One wire requires pin changes as quickly as 6 us and as slowly as 480 us. Locking out interrupts for 6us could affect the aforementioned digital input, and locking out interrupts for 480us could mess up all sorts of things. Timing loops are off the table.

No problem, thought I, I'll just use the DMA to generate interrupts at specific times, and run the one-wire stuff in the interrupt handler. So if I need to pull the pin low for 6 us, and then set it to hiz() for 9 us, and then read it and leave it alone for 60us, I'd just set interrupts to go off at those times, and do one operation in each interrupt. One-wire itself isn't a lot of work - when the interrupt goes off, I only have to set the pin low, or set the pin to hiz(), or read the pin. Easy.

As it turns out, it's not so easy. What I've been trying to do is set the pin in the interrupt handler, and then fiddle the value of the DMA .trr to set the timing interval for the next interrupt. What I'm finding is that interrupts don't get handled when scheduled - I can get called several microseconds late. I assume there's other interrupt stuff happening that's delaying me, or code somewhere that's locking out interrupts for microseconds at a time.

So what I need to do, I guess, is put all this stuff into unmaskable interrupts, so that Now means NOW, not "when you get around to it." All I'm going to do in that interrupt is set the timing of the next interrupt, and read or change a pin; I know about the severe coding limits that apply to interrupt (and especially NMI) code.

So... questions:

I've just come across PIT timers:
http://www.netburner.com/downloads/mod5 ... 70-PIT.pdf .
Am I better off using these timers instead of the DMA timer? (I'm using the DMA timer now only because I came across them first.)

Does anyone have sample code showing the use of PIT or DMA timers with NMI? I know there's assembler involved.

I'd also like anyone to comment on rewriting the DMA timer's .trr value (or the PIT countdown) from inside the timer's interrupt, because I'm not 100% certain this is working reliably with the DMA stuff (timing jitter aside.)

Guidance appreciated. This project is taking a lot longer than I'd hoped...
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: Help with non-maskable interrupt

Post by rnixon »

For your signal high/low measurement, how about using the dma timer in input edge capture mode? They have 13ns resolution, plenty fast enough. I don't have any examples for you though, just know that input capture is there. I would take a look in the freescale manual and see if that will work for you. I try to avoid using nmi if at all possible.

Is this for a weather station product or a home project? If a home project, maybe use an external 1-wire peripheral to offload some of the issues?
ScottM
Posts: 32
Joined: Mon Feb 01, 2010 10:00 am

Re: Help with non-maskable interrupt

Post by ScottM »

>Is this for a weather station product or a home project? If a home project, maybe use an external 1-wire peripheral to offload some of the issues?

Home project, but I'm trying to keep costs down by doing as much in software as possible. (That made more sense before I realized how hard it is to get really accurate, tight timing, but it's still a goal.)
mhoyt
Posts: 9
Joined: Fri Feb 19, 2010 12:17 pm
Location: Blue Bell, Pennsylvania, USA
Contact:

Re: Help with non-maskable interrupt

Post by mhoyt »

I agree with rnixon about using a DMA timer if you want to measure pulse width. The input capture mode of the DMA timer works very well for this purpose, as the timer count is captured by the hardware when a rising or falling edge is detected. If you want to measure both the high and low duration, you can toggle the edge detection bits in the interrupt handler.

I have used this technique with the Analog Devices TMP03 temperature sensor, which generates a pulse width proportional to the temperature, nominally 35Hz at 25C. I've posted my code below. I use this in a project with a MOD5270, which at the same time is doing continuous SPI for communication with a network of PIC chips, and also makes heavy use of the UDP protocol. It works great.

Code: Select all

static vudword t1, t2;

INTERRUPT (TMR2_isr, 0x2700)
{
	static DWORD last_capture;
	sim.timer[2].ter= 1;	//clear the event flag
	if ((sim.timer[2].tmr & 0xc0) == 0x40)	//captured rising edge?
	{
		// capture value is duration of low TMP03 output.
		t2= sim.timer[2].tcr - last_capture;
	}
	else	//captured falling edge... capture value is duration of high TMP03 output.
	{
		t1= sim.timer[2].tcr - last_capture;
	}
	sim.timer[2].tmr ^= 0xc0;	//toggle edge bits so we detect other edge next
	last_capture= sim.timer[2].tcr;
}

void init()
{
	// initialize TEMP input
	J2[35].function (PINJ2_35_TIN2);

	sim.timer[2].tmr= 0x0043;	//capture on rising edge, 1 prescaler, system clock / 1, enable timer, reset timer
	sim.timer[2].txmr= 0;		//no DMA request

	// enable the interrupt controller
	SetIntc ((long)TMR2_isr, 21/*TMR2 interrupt*/, 1, 7);	//lowest priority on lowest interrupt level
}

double getTempC()
{
	if (t2 == 0) return 0;
	return 235 - ((400 * double(t1)) / t2);
}
ScottM
Posts: 32
Joined: Mon Feb 01, 2010 10:00 am

Re: Help with non-maskable interrupt

Post by ScottM »

mhoyt wrote:

Code: Select all

static vudword t1, t2;
...
Promising. Thanks! I'll have to see if this works with my digital signal (which cycles a lot faster than 35Hz), but this would simplify some code.
Last edited by ScottM on Fri Apr 27, 2012 12:49 pm, edited 1 time in total.
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: Help with non-maskable interrupt

Post by rnixon »

Thanks mhoyt. I was not sure if you could switch the edge trigger in the isr or not. Nice clear code!
ecasey
Posts: 164
Joined: Sat Mar 26, 2011 9:34 pm

Re: Help with non-maskable interrupt

Post by ecasey »

Home project, but I'm trying to keep costs down by doing as much in software as possible. (That made more sense before I realized how hard it is to get really accurate, tight timing, but it's still a goal.)
Scott,

I just completed a weather station using a Netburner MOD5282 with some one-wire sensors. You can see a prototype of it running (for a while) at www.echo-point.dyndns.org. It has a few more features than usual. I was going to write software one-wire code, which I had done before for a 68HC11 based temperature logger. I had similar problems with timing and the interrupts, especially because the Geiger counter needs a pulse to create a a 500V bias. Lacking you dedication to software (or aversion to hardware), I got some one-wire samples from the Maxim-ic.com website, and not wanting to have a board made until I was sure of which way to go, I got some SOIC to DIP boards from Mouser (their part #204-00004-01) For about $6.55 (plus shipping) you get three pieces, 8 pin, 18 pin and 24 pin. It was fairly easy to solder onto the SOIC boards with a fine tipped iron, the pads are recessed a bit, so the chip holds still.

The samples I got from Maxim were:
DS2480B Serial to 1-Wire Line Driver
DS2450 1-Wire Quad A/D converter (1 to 16 bit resolution selectable)
DS18B20 1-Wire Temperature sensors.

After working with the DS2480B and the C software that Maxim provided for managing a bunch of 1-wire units, there is no way I would go back to do a software driver.
I put the DS2480B on the 8-Pin SOIC to DIP board.
I put the DS2450 at one end of the 18-pin DIP Board and put a humidity sensor and an LM35 temperature sensor on the other pins and mounted that board in an enclosure outside at the weather station. I could have put the Wind Direction sensor(potentiometer) on one of the A/D pins of the DS2450, but opted to send it to the MOD5282's A/D instead. If I was using a MOD5270, I would have used the DS2450 A/D for the Wind Direction, Barometric Pressure and Water Level (which is a pressure sensor) as well.

One thing to consider is that the DS2480B is designed to maximize the cable lengths. It can also do the "Stiff Pull-Up" to run with only two wires.

All in all, for $6.55 plus shipping, it was well worth doing it with hardware.
Sorry for sounding like a commercial for Maxim.

Ed
Post Reply