Ext. int. not working at start up if frequency on input

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've done a few projects were I've monitored pulse width with an ext. int. Over the projects I have noticed that if I have my frequency generator applying a frequency (10hz say) on the ext. int. when I power the processor up the ext. int. will not function until I remove the signal, then reapply it.

I've seen this on Tiny12s, Tiny45s and Mega168s. It's not really a huge deal, but I would still like to know why this happens and if there is a way to fix it.

Anyone know?

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It must be something fundamental in your code, or hardware implementation. I can guarantee that there is nothing in the hardware of the AVR that is causing this.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting.

I had initially assumed that my code may have something to do with it, but on my latest project I didn't recycle any code and I have the same issue.

My ext. int. in this case is just incrementing a register each time it is tripped (triggers on falling edge).

The current hardware is simple - a 10K ohm external pull up resistor and my frequency generator output (from memory I believe it is just a (-) open collector output).

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Let's see your external int setup code. The short answer is that you want to clear the flag bits in EIFR when you are ready to start normal operations.

Here is the scenario:

-- At some point in your program, before EIMSK and EICR_ and related are totally set up, the external int fires and sets the bit in EIFR.

-- Then, when you >>do<< get it all set up and are waiting for an edge or whatever, when it >>does<< come the bit is already set and the ISR is not invoked.

Hmmm--I've done lots and lots of AVR apps and I can't think of what the "bulletproof" sequence is--for a repetitive signal I don't worry about the race and whether there is one more or one less "hit". Here is how CodeVision Wizard does it in the chip init sequence, when interrupts are off:

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: On
// INT1 Mode: Rising Edge
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x0F;
EIMSK=0x03;
EIFR=0x03; <== this is what you need
PCICR=0x00;
...
sei(); // enable global interrupts

So EIMSK is set with global interrupts off--nothing happens.
EIFR is cleared. There is a bit of a race between these two statements, but there will always be this race. Depending on the particular requirements I suppose one could do it twice. But consider the two cases: There already was a bit in EIFR, so it is cleared. The next trigger will fire the ISR. Or there is no bit set, and the write to EIFR is harmless.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Kevin,

As a general rule one should not apply a voltage, (signal), to an unpowered micro. Ideally the micro powers up before any external inputs are applied. Depending on the configuration inside the micro, you might find that you are actually partially powering the chip from your signal. This really messes things up, as the micro does not go through its defined start up sequence, and is only partially "operating".

I'm not sure if this is the issue you are experiencing or not, but thought I'd mention it.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
; Set up external interupt
ldi temp1, (1<<ISC01)                  ; Sets external interupt 0 to trigger on falling edge
sts EICRA, temp1

ldi temp1, (1<<Int0)                   ; Enables Ext Int0 Interupt
out EIMSK, temp1

ldi temp1, (1<<IntF0)                  ; Clears Int Flag
out EIFR, temp1

; Set up ADC
ldi temp1, (1<<RefS0)
sts ADMUX, temp1                       ; Sets up ADC to use AVcc

ldi temp1, (1<<ADEN | 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0)
sts ADCSRA, temp1                      ; Enables ADC, sets prescaler to 128


; Set up Timer2 for winder running detection
ldi temp1, (1<<CS22|1<<CS21|1<<CS20)
sts TCCR2B, temp1                      ; Sets prescaler to 1024 (and starts timer)

ldi temp1, (1<<TOIE2)
sts TIMSK2, temp1                      ; Enables Overflow Int 


; Set up PWM output (timer 0)
;PWM = Fast PWM, Top = 0xFF  Prescale = 64, WGM02/01/00 = 011, Com0A1/0 = 10 (set at ovf, clear at match)
ldi temp1, (1<<Com0A1|1<<WGM01|1<<WGM00)
out TCCR0A, temp1                      ; Sets up Com (Clear on compare match) and WGM (Fast PWM)

ldi temp1, (1<<CS01|1<<CS00)
out TCCR0B, temp1                      ; Sets prescaler to x64 (and starts timer)

clr temp1
out OCR0A, temp1                       ; Clears OCR0A (PWM trigger value)

ldi temp1, (1<<TOIE0)
sts Timsk0, temp1                      ; Enables overflow interupt - reset trigger value each overflow

; Set up TWI port for I2C communications with screen

I2CSetup:
; Use TWBR-TWI value of 85 - 43K at 8mhz and 99K at 18.432mhz
; Pull up resistors should be >~1500ohms
; Value to be written next is stored in TWDR
ldi temp1, 0x55                        ; Loads value for clock value
sts TWBR, temp1                        ; Sets clock value

ldi temp1, (1<<TWEn | 1<<TWIE)         ; Enables TWI and Enables TWI Interupt
sts TWCR, temp1                        ; Writes config bits - doesn NOT start communications

wdr

Timer1Setup:
;Timer1 is a 16 bit counter used to generate interupts on a controlled interval
;This interupt is used to update the screen.  At 18.432mhz the screen will update every ~.9 seconds
; and the screen will change every ~2.7 seconds
;ldi temp1, (1<<CS11)|(1<<CS10)         ; Loads x64 prescaler
ldi temp1, (1<<CS12)                   ; Loads x256 prescaler
sts TCCR1B, temp1                      ; Starts timer

ldi temp1, (1<<TOIE1)                  ; Loads value to enable overflow interupt
sts TIMSK1, temp1                      ; Enables overflow int.

CodeStart:

sei                                    ; Enables global Ints

I did not originally have the flag reset line of code in the program - I added it and still have the same issue.

None of my other ints are effected (times still work, I2C works great, etc).

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
Hi Kevin,

As a general rule one should not apply a voltage, (signal), to an unpowered micro. Ideally the micro powers up before any external inputs are applied. Depending on the configuration inside the micro, you might find that you are actually partially powering the chip from your signal. This really messes things up, as the micro does not go through its defined start up sequence, and is only partially "operating".

I'm not sure if this is the issue you are experiencing or not, but thought I'd mention it.

JC

That's something I was thinking may be an issue. Most of my projects are all driven by one power supply so it has never been an issue in the past. This particular controller is reading off an encoder from another machine - so it is feasable that the encoder will be on and running before my circuit is energized. Luckily my project isn't critical and if it didn't work until the encoder was shut off and started again it won't hurt anything.

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

Here is the scenario:

-- At some point in your program, before EIMSK and EICR_ and related are totally set up, the external int fires and sets the bit in EIFR.

-- Then, when you >>do<< get it all set up and are waiting for an edge or whatever, when it >>does<< come the bit is already set and the ISR is not invoked.

Except when the EIMSK bit becomes set, and the flag in EIFR is set the ISR will fire immediately because it is a *pending* interrupt (assuming global interrupts are enabled, otherwise it will fire when they are finally enabled). The edge trigger is not on the edge of the flag, but rather on the edge of the input signal. The trigger is what sets the flag. The firing of the interrupt will clear the flag. If it were a level interrupt, the only way to clear the flag would be to clear the condition on the pin. (The ISR would repetitively fire, unless disabled)

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

Last Edited: Fri. May 8, 2009 - 04:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could easily test this by routing the encoder signal(s) through a physical relay.

Power up your circuit, then energize the relay, (with a switch for testing, or a micro bit if you have a spare pin available), then your code.

I know nobody likes mechanical, power hunger parts these days, but it would give you some useful info, and save you starring at your code all day, if that is not the issue.

It also gives you a work-around if that is the issue. Building one vs building thousands... One relay gets the job done, token cost.

You might also consider a chip like an analog switch, but you would have to read their data sheet carefully to prevent the same problem. Can they have an input signal present prior to being powered?...

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the encoder signal is open collector, there is no problem, as long as the pull-up on the signal is powered by the same supply as the AVR. If it is not, place a diode on the input signal, such that it is only able to sink current, and then use a pull-up powered by the AVR's supply to generate the high.

The initialization looks to be fine. Let's see what your ISR looks like.

As for setup, the general "safe" way is to:
1) set the sense mode
2) clear the flag
3) enable the interrupt in the mask register
4) enable global interrupts

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
As a general rule one should not apply a voltage, (signal), to an unpowered micro. Ideally the micro powers up before any external inputs are applied. Depending on the configuration inside the micro, you might find that you are actually partially powering the chip from your signal. This really messes things up, as the micro does not go through its defined start up sequence, and is only partially "operating".

I'm not sure if this is the issue you are experiencing or not, but thought I'd mention it.

JC

Using the AVR's BOD will alleviate this problem, as the chip will only start running once a valid operating threshold has been reached. This may cause cycling of the AVR, as once it starts up, the current draw could be enough to return it to a brown-out (reset) condition. Thus it will never be in a funky state of operation. All registers will be at their known reset values on start-up.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As the other subsystems seem to be working OK, I speculate it isn't a parasitic power situation. But perhaps--maybe the INT logic is getting latched up.

I'd try polling the flag in EIFR; maybe output to an LED or something. that might give a hint.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kpierson wrote:

; Set up external interupt
[etc.]


This doesn't show too much of what may be relevant.

You should strip down the code to the absolute minimum needed to reproduce the problem, and then post it ALL.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
IInt0:
; Increments registers to keep track of feet pulled.
push temp1
in temp1, SREG
push temp1
push temp2

lds temp1, FtCountL
inc temp1                              ; Increments foot counter each pulse
sts FtCountL, temp1

brne WinderRunningStatus

lds temp1, FtCountH
inc temp1
sts FtCountH, temp1

WinderRunningStatus:
; Controls Winder Running status bit and LED

sbrc Status, WinderRunb                ; If winder already running skip this routine
rjmp ResetWinderOffCt

lds temp1, FtCountH
tst temp1                              ; Checks high value to see if there are any numbers in it
breq WinderRunningLowCheck

sbr Status, WinderRun                  ; Sets status bit that winder is running
sbr Status, WinderStart                ; Sets bit to show winder just started
sbi PortD, RunLEDOut                   ; Turns on winder running LED

rjmp ResetWinderOffCt

WinderRunningLowCheck:

lds temp1, FtCountL
cpi temp1, 0x05                        ; Reads in low value and compares it to 5
brlo IInt0Exit                         ; If low exit

sbr Status, WinderRun                  ; Sets status bit that winder is running
sbr Status, WinderStart                ; Sets bit to show winder just started
sbi PortD, RunLEDOut                   ; Turns on winder running LED

ResetWinderOffCt:
clr temp1
sts WinderOffCt, temp1                 ; Resets WinderOffCt when pulses are received

IInt0Exit:

pop temp2
pop temp1
out SReg, temp1
pop temp1

   reti

The project I am working on controls a variable speed lube applicator wheel on a paper winder. The FtCount variable is the data from the encoder - it pulses one time per foot pulled. The ext. int. is also used to determine when the winder is running or when it is shut off (in conjunction with one of the timers).

The frequency generator I am currently using does swing between 0 and 5 vdc so it is possible that the unit is providing power to the input pin with the controller is not powered.

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kevin,

You are suspecting hardware issues, right?

Why then don't you write a very simple test program - just initialize what is needed, add a simplistic EXTINT ISR toggling a LED, and an infinite loop doing nothing. Then apply you signals as you do with the "real application", observe results, post with that simplistic program.

Divide and conquer.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thats not a bad idea - let me work on it a bit.

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I stripped out all the other code and I can't seem to recreate the issue which supports the theory it is software based. Currently I'm only running one timer (flashed an LED) and the ext int (flashes the LED every 64 ext ints).

I think next I'm going to reset the EI flag in my main routine and see if that eliminates the issue. The only thing I can think of at this point is that for some reason the flag is being set and not actually called or reset for some reason. By clearing the flag every cycle that should eliminate that theory as being the cause.

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just eliminated the flag not resetting from being an issue. Resetting the flag at the beginning of each cycle didn't help at all.

--------------------------------
Kevin Pierson

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Without you showing more I don't think anybody can help you further.

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

wek wrote:
Without you showing more I don't think anybody can help you further.

JW

Yes, I do realize this. However, you guys already helped me - I now at least know it's software related!

--------------------------------
Kevin Pierson