0
\$\begingroup\$

Background

I am designing a simple lamp dimmer using the Atmel ATTiny441 microcontroller. To this end, I have designed a very basic zero-cross detector which feeds the external interrupt pin (INT0) on the micro.

Unfortunately, I am seeing unreliable triggering of the external interrupt. Despite having both ISC00 and ISC01 set to enable rising edge triggering I am seeing a trigger on both edges.

Consider the following:

Waveform1

In the above, yellow is mains power, purple is the zero-cross detect signal and teal is an output pin (PA1, in this case) which should invert on every rising edge to form a square wave in phase with the 60Hz from mains. As you can see, there are spurious triggers which cause an irregular waveform.

Zooming into one of the runt pulses, we see:

Waveform2

Clearly triggering on the falling edge. I was able to get this behavior by manually clearing the INTF0 flag in the ISR (see code below). Prior to this enhancement, the triggering was especially flaky:

Waveform3

Notice the tiny pulse on the rising edge. My suspicion here is that the detect signal is rising too slowly, causing multiple interrupts in the transition region.

Questions

  1. Is there a good way to verify this assumption?

  2. My current pullup is 4.7K however many places online recommend 10K. Is there a good method to determine suitable pullup values?

  3. The Datasheet doesn't list any minimum rise times (that I can find); What is a good value to shoot for?

  4. The heavy-lifting in my zero-cross detector is done by a 4N25; Am I seeing such a slow rise because of the amplification region of the phototransistor?

  5. If so, should this be addressed in the 7.5K limiting resistor on the HV side or the 4.7K pullup on the LV side?

  6. The catch-all: am I completely off-base and the issue is somewhere else completely?

Additional Information

I have set up the zero-crossing detector circuit as follows:

Schematic

This is fed into the INT0 pin of the micro. Note that some currently DNIed components are also powered from the bridge rectifier, hence the lines leading off page.

The code to set up and service the interrupt is pretty basic:

#include <avr/interrupt.h>
#include <avr/io.h>

#define ENA_PROTECTED_IO_REG    0xD8

FUSES = 
{
    .low = (LFUSE_DEFAULT & (FUSE_CKOUT)) | ~(FUSE_CKDIV8),
    .high = HFUSE_DEFAULT,
    .extended = EFUSE_DEFAULT,
};

ISR(INT0_vect)
{
    PORTA ^= 0x02;
    GIFR |= _BV(INTF0);    // This solves multiple triggers on the same rising edge
}

int main(){

    // Enable INT0, trigger on rising edge
    CCP = ENA_PROTECTED_IO_REG;              // Required to write to MCUCR
    MCUCR |= (_BV(ISC00) | _BV(ISC01));      // Trigger on rising edge
    GIMSK |= _BV(INT0);                      // Enable INT0 interrupt

    // Global interrupt enable
    sei();

    DDRA = 0x02;
    PORTA = 0x00;

    while (1) { }
}
\$\endgroup\$
  • \$\begingroup\$ The external interrupts have no filtering, and clearly any hysteresis present at the IO stage is not enough. Can you try feeding the signal to an Input Capture pin as they can have some filtering? Or feeding the signal to Comparator Input pin as that can have extra hysteresis? Another way to test is to just add 74HC14 schmitt trigger there to square up the pulse for you. Or put a transistor there. Or sample the signal with ADC to see where it is going. \$\endgroup\$ – Justme Feb 16 at 10:22
  • \$\begingroup\$ Using one of the Input Compare Channels with the Input Capture Noise Canceler enabled fixed the issue. Pretty cool feature I didn't even know existed when I picked out the chip :-). If you wouldn't mind writing this up with a bit of discourse on some of the generic questions above (3 - 5 particularly), I would gladly accept it. \$\endgroup\$ – MysteryMoose Feb 16 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.