interrupt problem in ATmega168

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

hi all,
i am using ATmega168.i interfaced ADE7758 ic to my MCU.i am getting some problems in INT0 interrupt.i initialized the INT0 interrupt for fallling Edge trigger. i enabled the internal pull-up in the PD2 pin.before getting the interrupt i am getting 5v in the INT0 pin.after executing the interrupt one time i am not getting 5V in that pin.i am getting 0v constantly in that one.

what may be the problem.the code is below

PORTD=(1<<PD2);//pull-up for INT0
DDRD=0X00;//input
EICRA=0X02;
EIMSK=0X01;

if any body knows please let me know.....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
PORTD=(1<<PD2);//pull-up for INT0 
DDRD=0X00;//input 
EICRA=0X02; 
EIMSK=0X01;

This looks good for the set up of the interrupt, but since it is after the interrupt happens that things go wrong, you need to show us that code.

Also, since INT0 is an input, then what is on the PD2 pin should be whatever you are applying to it.

Regards,
Steve A.

The Board helps those that help themselves.

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

thanks for your reply....

Below is my code.please go through in this and please let me know any problem in this code.and also tell me how to handle the interrupts efficiently..
i connected PD2 pin of the MCU to IRQ pin of the ADE7758.i attached my schematics to this also

#include
#include
#include
#define F_CPU 8000000UL // 8 MHz
#include

void sendbit_lcd(unsigned char data,unsigned cnt);
void senddatabit_lcd(unsigned data,unsigned cnt);
void sendcmd_lcd(unsigned char command);
void write_lcd(unsigned char addr,unsigned char data);
void display_lcd(double data, char keyword);
long int timecount0=0,timecount1=0;
double data=0;
void sendbit_lcd(unsigned char data,unsigned cnt)
{
char i;
if(cnt==6)
data<<=2;
else data=data;

for(i=0;i {

if((data&0x80)==0)
PORTC&=~(1<<PC0);
else
PORTC|=(1<<PC0);
PORTC&=~(1<<PC1);
_delay_us(4);
PORTC|=(1<<PC1);
asm("nop"::);
data<<=1;
}
}

void senddatabit_lcd(unsigned data,unsigned cnt)
{
char i;
for(i=0;i {
if((data&0x01)==0)
PORTC&=~(1<<PC0);
else
PORTC|=(1<<PC0);
PORTC&=~(1<<PC1);
_delay_us(4);
PORTC|=(1<<PC1);
asm("nop"::);
data>>=1;
}
}

void sendcmd_lcd(unsigned char command)
{
PORTC&=~(1<<PC3);
sendbit_lcd(0x80,4);
sendbit_lcd(command,8);
PORTC|=(1<<PC3);
}

void write_lcd(unsigned char addr,unsigned char data)
{
PORTC&=~(1<<PC3);
sendbit_lcd(0xa0,3);
sendbit_lcd(addr,6);
senddatabit_lcd(data,4);
PORTC|=(1<<PC3);
}

void clear_lcd()
{
char j,l=0x00;
for(j=0;j<23;j++)
{
write_lcd(l,0x00);
l++;
}
}

void display_lcd(double data, char keyword)
{
int digit[10] = {0x5f,0x06,0x6b,0x2f,0x36,0x3d,0x7d,0x07,0x7f,0x3f};
char c,temp3,digi,a;
char pos =0x01,dot;
int b[8];
double n;
unsigned long int m;
n=data*10;
m=n;
for(c=0;c<8;c++)
{
b[c]=m%10;
m=m/10;
}
if(b[7]==0)
{
m = n;
for(c=8;c>0;c--)
{
a=m%10;
digi=digit[a];
temp3=digi&0x0f;
write_lcd(pos,temp3);
digi>>=4;
digi&=0x0f;
pos++;
if(pos==0x04)
{
dot=(0x08|digi);
write_lcd(pos,dot);
}
else
write_lcd(pos,digi);
pos++;
m=m/10;
if(m==0)
break;
}

}
else
{
for(c=0;c<=7;c++)
{
digi=digit[b[c]];
temp3=digi&0x0f;
write_lcd(pos,temp3);
digi>>=4;
digi&=0x0f;
pos++;
write_lcd(pos,digi);
pos++;

}
}
switch(keyword)
{
case 'a':
write_lcd(0x15,0x04);
write_lcd(0x16,0x0f);
break;
case 'b':
write_lcd(0x15,0x07);
write_lcd(0x16,0x0b);
break;
case'c':
write_lcd(0x15,0x05);
write_lcd(0x16,0x0b);
break;
case 'd':
write_lcd(0x14,0x08);
}
}
//function for writing 8 bit registers//
void spi_write(char address, long int data)
{
PORTB&=~(1<<PB2);
SPDR=address;
while(!(SPSR&(1<<SPIF)));
SPDR=data;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);

}

//SPI COMMUNICATION//
int spi_read8bit(char address)
{
int result;
result=0;
PORTB&=~(1<<PB2);
SPDR=address;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result=SPDR;
PORTB|=(1<<PB2);
return result;
}
int spi_read16bit(char address)
{
int result;
result=0;
PORTB&=~(1<<PB2);
SPDR=address;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result=SPDR;
result<<=8;
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result|=SPDR;
PORTB|=(1<<PB2);
return result;
}
int spi_read24bit(char address)
{
long int result;
result=0;
PORTB&=~(1<<PB2);
SPDR=address;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result=SPDR;
result<<=8;
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result|=SPDR;
result<<=8;
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
result|=SPDR;
PORTB|=(1<<PB2);
return result;
}

//DELAY//
void delay()
{
int i;
for(i=1000;i>=0;i--)
{
_delay_ms(5);
}
}

//TIMER 0 OVERFLOW INTERRUPT SERVICE ROUTINE//
ISR(TIMER0_OVF_vect)
{
unsigned char csreg;
csreg=SREG;
cli();
timecount0++;
SREG=csreg;
sei();
}

//TIMER 1 OVERFLOW ISR//

ISR(TIMER1_OVF_vect)
{
unsigned char csreg;
csreg=SREG;
cli();
timecount1++;
SREG=csreg;
sei();
}

//external interrupt//
ISR(INT0_vect)
{

data=spi_read24bit(0x1a);
display_lcd(data,'a');
clear_lcd();
data=spi_read16bit(0x01);
display_lcd(data,'a');
clear_lcd();
data=spi_read16bit(0x04);
display_lcd(data,'a');
clear_lcd();
data=spi_read16bit(0x07);
display_lcd(data,'a');
clear_lcd();
sei();
}
int main(void)

{

//PORTS INITIALIZATION//
PORTB=(1<<PB4);
DDRB=(1<<PB2)|(1<<PB3)|(1<<PB5);
PORTC=0X00;
DDRC=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3);
PORTD=(1<<PD2);
DDRD=0X00;
//TIMER/COUNTER 0 INITIALIZATION//
TCCR0A=0X00;
TCCR0B=(1<<CS02)|(1<<CS01)|(1<<CS00);
TCNT0=0X00;
TIFR0=(1<<TOV0);
TIMSK0=(1<<TOIE0);

//TIMER/COUNTER 1 INITIALIZATION//
TCCR1A=0X00;
TCCR1B=(1<<CS12)|(1<<CS11)|(1<<CS10);
TCNT1H=0X00;
TCNT1L=0X00;
TIFR1=(1<<TOV1);
TIMSK1=(1<<TOIE1);
WDTCSR=0X00;
MCUSR=0X00;

//EXTERNAL INTERRUPT INITIALIZATION//
EICRA=0X02;
EIMSK=0X01;
sei();
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0)|(1<<CPHA);

//LCD initialization//

sendcmd_lcd(0x52);//BIAS
sendcmd_lcd(0x02);//SYSTEM ENABLE
sendcmd_lcd(0x06);//LCD ON
clear_lcd();
//writing values in ADE7758 8 bit registers//

spi_write(0x93,0x00);//enable pulse output
spi_write(0x96,0x04);//compmode formula applied to
spi_write(0x95,0x00);//wavemode for phase a current
spi_write(0x97,0x0f);//setting linecycle mode

//writing values in ADE7758 16 bit registers//
//accumulation time in ox1c LINECYC//

PORTB&=~(1<<PB2);
SPDR=0x9c;
while(!(SPSR&(1<<SPIF)));
SPDR=0x01;
while(!(SPSR&(1<<SPIF)));
SPDR=0xff;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);
//writing in ADE7758 24bit reg//
//interrupt mask reg for LENENERGY interrut//
PORTB&=~(1<<PB2);
SPDR=0x98;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
SPDR=0x10;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);
//writing in ADE7758 16bit reg//
//setting APCFDEN //
PORTB&=~(1<<PB2);
SPDR=0xc6;
while(!(SPSR&(1<<SPIF)));
SPDR=0x09;
while(!(SPSR&(1<<SPIF)));
SPDR=0x83;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);

//calibration co-efficients AWG reg//
PORTB&=~(1<<PB2);
SPDR=0xaa;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
SPDR=0x08;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);

PORTB&=~(1<<PB2);
SPDR=0xad;
while(!(SPSR&(1<<SPIF)));
SPDR=0x00;
while(!(SPSR&(1<<SPIF)));
SPDR=0x10;
while(!(SPSR&(1<<SPIF)));
PORTB|=(1<<PB2);

while(1)
{

int freq;
freq= spi_read16bit(0X10);
display_lcd(freq,'d');
clear_lcd();
data=0.0625*freq;
display_lcd(data,'d');
delay();
clear_lcd();
}

}

Attachment(s): 

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

please anybody help me for the above issue
i am still waiting for reply.............

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

Use the "Code" button when you post code (select the code text a press the "Code" button).

In that only interrupt you get do you have a resonable value displayed from here?

data=spi_read24bit(0x1a); 
display_lcd(data,'a'); 

As I understand it is this register read that should allow the IRQ line to go high again.

The SPI communication in general, have you verified that this works?

I do think you are doing too much in the ISR and it may not be the problem now but the SPI communication there can be in conflict with what you do in the main loop.
I suggest you just set a flag in the ISR

volatile unsigned char irq;

ISR(INT0_vect) 
{ 
   irq = 1;
}

And in the main loop

if (irq) {
    irq = 0;
    data=spi_read24bit(0x1a); 
    display_lcd(data,'a'); 
    clear_lcd(); 
    data=spi_read16bit(0x01); 
    display_lcd(data,'a'); 
    clear_lcd(); 
    data=spi_read16bit(0x04); 
    display_lcd(data,'a'); 
    clear_lcd(); 
    data=spi_read16bit(0x07); 
    display_lcd(data,'a'); 
    clear_lcd(); 
}

You would have to redo the loop code to avoid that long delay also.

unsigned char csreg; 
csreg=SREG; 
cli(); 

Code like this inside a ISR is redundant. The interrupts are already disabled inside the ISR and will be re-enabled when the ISR is exited.

long int timecount0=0,timecount1=0; 

You should have these volatile if they will later be used in the mainloop or similar.

/Lars

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

Lajon wrote:

In that only interrupt you get do you have a resonable value displayed from here?

data=spi_read24bit(0x1a); 
display_lcd(data,'a'); 

As I understand it is this register read that should allow the IRQ line to go high again.

The SPI communication in general, have you verified that this works?

You would have to redo the loop code to avoid that long delay also.

/Lars

Thankyou for ur reply..
now I am using flags for interrupts.
ya in that only interrupt also i am getting some garbage values while reading the reg value like below

data=spi_read24bit(0x1a); 
display_lcd(data,'a');

but after that interrupt i am getting constantly low in the IRQ line.

in general spi communication(without interrupt) also while reading registers ,some times i am getting garbage values and some times i am getting resonable values..

so what do you think the problem is ?
and u told that,"You would have to redo the loop code to avoid that long delay also."
which loop code and which delay??

even i connected pull-up to IRQ pin of the ADE7758 and tested once again after one interrupt i am getting low in IRQ pin constantly....

what may be the problem??
reply me as soon as posible..

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

Quote:
in general spi communication(without interrupt) also while reading registers ,some times i am getting garbage values and some times i am getting resonable values..

Well I think you must fix this SPI issue before there is any hope of having the IRQ working. The IRQ line will only go back high after you have read the 0x1a register.

BTW

int spi_read24bit(char address) 

must be

long spi_read24bit(char address) 

Quote:
which loop code and which delay??

This loop and delay():

while(1) 
{ 
   int freq; 
   freq= spi_read16bit(0X10); 
   display_lcd(freq,'d'); 
   clear_lcd(); 
   data=0.0625*freq; 
   display_lcd(data,'d'); 
   delay(); 
   clear_lcd(); 
} 

This is your main loop where (I hope) you now check the interrupt flag variable "irq". Now, you can not have a 5 second delay in that loop if you need resonably fast handling of the irq.
/Lars

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

Thanks,Really i didnt notice that & i just replace that into long and execute without interrupt i am getting reasonable values now.
but it doesn't generate any interrupt..
please tel me the solution for this also......

[quote="LajonThis loop and delay():

while(1) 
{ 
   int freq; 
   freq= spi_read16bit(0X10); 
   display_lcd(freq,'d'); 
   clear_lcd(); 
   data=0.0625*freq; 
   display_lcd(data,'d'); 
   delay(); 
   clear_lcd(); 
} 

This is your main loop where (I hope) you now check the interrupt flag variable "irq". Now, you can not have a 5 second delay in that loop if you need resonably fast handling of the irq.
/Lars

so if i want to display parameters for 5 sec means what can i do now????

please reply me as soon as possible...

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

Quote:
please tel me the solution for this also......

It is not like I am holding back any information :D
You have to debug it, maybe disconnect the IRQ pin (keep the external pullup) and have a look at it. You can also inject a pulse in the INT0 pin and verify that the ISR is called.

Quote:
so if i want to display parameters for 5 sec means what can i do now????

Use a timer (best) or something like this:

int dispCnt = 0;
while(1) { 
    if (dispCnt-- == 0) {
        dispCnt = 5000;
        // ~5s display task here
    } 
    if (irq) {
        irq = 0;
        // handle irq here
    }
    _delay_ms(1);
} 

There can be a shorter or no (better for the irq response time) delay - just adjust the count. This method is not very precise beacuse of loop overhead (and the irq processing in this case). Using a timer would be better - the code would look similar except the dispCnt-- is done in a timer ISR (and no delay in the loop).
/Lars

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

Hi everybody!

 

I've been using ADE7758 with an Arduino 2560. At this moment I can write and read correctly the registers data through SPI. I also get good measures of Irms and Vrms. But I'm having problems with the /IRQ output.
This pin is an open drain output, so it is needed using an external pull-up resistor(10 Ohm) to drive it high level when the internal transistor is off. In my case after programming the device using SPI interface, this output stays high as expected, after the first interruption it goes low and never return to high again. I Know it is necessary to read the IRQ status register for this purpose, but when I read or write to any register after the interrupt (and only in this case) I have no response, I get into a kind of infinite loop.

 

Do you have any ideas what may the problem be? Suggestions?  

 

Thanks a lot!

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

10 ohm?

 

It has been a few years since I used that family, but every app used the IRQ feature.

 

I'm rusty on the family, but could you have many interrupt sources enabled, and thus get many (cascading) interrupt notifications?

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

Not 10 but 10KOhm jaja 

 

I have taken care that the MASK register which enables the different interrupt requested has been written with 0x1000 (Line cicle mode, the event I want to detec) by reading it value after writing it. In fact in one prove I read it constantly in la Loop and it showed always the same value. But the interrupt status register(which must be an only read register) have set another interrupt sources. The strange thing is that even whe the status IRQ register show other events it didn't make /IRQ output low. And when /IRQ goes low my program simply get stuck if I try any kind of communication with ADE7758.  

 

I tried programming other source for the interrupt, the result is the same. 

 

Thanks for the reply, and sorry for my english. 

Last Edited: Mon. Mar 30, 2015 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why would you tack this question on to an 8 year old thread that has nothing to do with the question you have?

Regards,
Steve A.

The Board helps those that help themselves.

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

Well about the date, you have reason, beginning a new thread might be more adequate. But nothing to do? really?

I have a problem with the IRQ in a ATmega2560 based board, once it goes low it never goes high again. The person who started this thread 8 years ago had the same problem, maybe no because the same cause, but I had to try.

prudu:

"i am using ATmega168.i interfaced ADE7758 ic to my MCU.i am getting some problems in INT0 interrupt.i initialized the INT0 interrupt for falling Edge trigger. i enabled the internal pull-up in the PD2 pin.before getting the interrupt i am getting 5v in the INT0 pin.after executing the interrupt one time i am not getting 5V in that pin.i am getting 0v constantly in that one."
I also wrote about other problems that might be related.

Thanks..

 

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

And when /IRQ goes low my program simply get stuck if I try any kind of communication with ADE7758.  

 So, are you sure you configured the interrupt for edge and not level?

 

If you can do no further communication, how do you know which bits are set?

 

 

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

Perhaps I use a different setup than you do.  In ADE7754 and ADE7763 apps, I get an interrupt at zero-crossing.  I simply set a flag to service next time through the main loop.  I thin do simple reads of the VRMS and IRMS register(s).

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

Well I notice I have been using PCINT0 instead of INT0. I changed it and now my /IRQ problem seems to be solved. I do not Know why, even when PCINT0 is for pin change detection, my program get stuck in a loop, but now I'm nearer to get this working fine.

Now my problem seems to be that the irq reset status register saves a wrong value, 1A80 or 1AC0. The LENERGY (line accumulation mode interrupt) bit is set as supposed, but there are other bits. I have programed my irq MASK as 0x1000. I'll check if I don't have overwriting problems. Also I measured the time between interruptions that should be ~10sec (1048 half cicles with one phase to decrease the count at every Zero Cross) and it was OK, so I don't know why there are other bits in my irq status register.

Thanks for the help again!!