XMEGA16 RTC ISR

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

Tryin' for a RTC to LCD . I init the RTC of my xmega16 correctly for a 1s ISR
www.avrfreaks.net/index.php?name...

1) but the LCD counts down ( after the 1st second ), 9... 0 !!? seconds is (global)
volatile static uint8_t. I'm trying to display sec_units correctly , then work on other digits.

ISR(RTC_OVF_vect)
{
seconds++;

//set_led;

if ( seconds == 10 ) seconds = 0;

//seconds %= 10;
seconds += 0x30;
set_lcd_xy( 3,11 );
putchar( seconds );
   
}

When i used linear code , above stuff works, but the .lss for the ISR is:

seconds++;
 224:	80 91 31 20 	lds	r24, 0x2031
 228:	8f 5f       	subi	r24, 0xFF	; 255
 22a:	80 93 31 20 	sts	0x2031, r24
set_lcd_xy( 3,10 );
putchar( sek );
*/
//seconds = temp;
//seconds %= 10;
seconds += 0x30;
 22e:	80 91 31 20 	lds	r24, 0x2031
 232:	80 5d       	subi	r24, 0xD0	; 208
 234:	80 93 31 20 	sts	0x2031, r24
set_lcd_xy( 3,11 );
 238:	83 e0       	ldi	r24, 0x03	; 3
 23a:	6b e0       	ldi	r22, 0x0B	; 11
 23c:	0e 94 66 07 	call	0xecc	; 0xecc 
putchar( seconds );
 240:	80 91 31 20 	lds	r24, 0x2031
 244:	0e 94 de 06 	call	0xdbc	; 0xdbc 

Edit:

Now correct. seconds got trashed by seconds += 0x30;, so a temp reg. is needed.

ISR(RTC_OVF_vect)
{

++seconds;
temp = seconds;
//set_led;
if ( seconds == 10 ) { seconds = 0;temp = seconds; }
// temp = 99;
/*
sek = seconds / 10;
sek += 0x30;
set_lcd_xy( 3,10 );
putchar( sek );
*/
//seconds = temp;
//seconds %= 10;
seconds += 0x30;

set_lcd_xy( 3,11 );
putchar( seconds );
 seconds = temp;  
}

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Sat. Oct 16, 2010 - 06:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
seconds += 0x30; 
set_lcd_xy( 3,11 ); 
putchar( seconds );

In the first line where you are obviously converting it to ASCII, you are modifying the variable, which is probably not what you should be doing and will cause something to prang up on your second & subsequent interrupts.

Instead, give that line the flick & modify the third line to give.

set_lcd_xy( 3,11 ); 
putchar( seconds+0x30 );

Having written that, you are calling two functions from a interrupt routine which is not a good idea! In fact it is a very bad idea!

Instead, in the ISR, set a flag in a global variable and then let main check the flag, and do the processing of the clock task that needs to be done and then clear the flag so that it only runs onec.

// in main

 for(;;)
 {
   if(FLAG)
   { 
       set_lcd_xy( 3,11 ); 
       putchar( seconds );     
   }
 }

Variable "seconds" no longer needs to be a global variable either.

Edit. Between you posting & me responding you seem to have solved the problem. My comments regarding no doing this in the interrupt routine still hold.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

It is generally unwise to do ANY slow operations inside an ISR(). Writing to an lcd is always slow.

Just handle your timing variables in the ISR:

ISR(RTC_OVF_vect)
{
    if (++sec > 59) {
        sec = 0;
        if (++min > 59) {
            min = 0;
            if (++hour > 23) {
                hour = 0;
                ...
            }
        }
    }
}

You can maintain the actual ascii digits in a buffer if you prefer. This is handy for an easy 'print'

ISR(RTC_OVF_vect)
{
    if (++unitsec > '9') {
        unitsec = '0';
        if (++tensec > '5') {
             tensec = '0';
             ...
        }
    }
}

A handy way of doing the printing every second, is to set a flag in the ISR(). Then your main() routine just says:

if (flag) {
    flag = 0;
    print_time();
}

Remember to declare flag, sec, min, hour... as volatile.

David.

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

Just adding to david.prentice's comments.
Why is it bad to have lengthy interrupts?
1. No other interrupts can occur during this time & you may miss events.

2. What if your interrupt occurs, whilst main , or a function that main calls is sending stuff to the LCD and the LCD routine is interrupted.
If your interrupt routine, then also sends stuff to the LCD, what do you thing will happen to the first write to the LCD and subsequenctly when the interrupt is finished and the original LCD call is allowed to complete, what do you think will happen to the stuff that the interrupt service wrote. They will both prang up!

3. If I think long enough there will be other reasons,
but the above two will suffice for now.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Thanks freaks !! I had already planned on just setting a
flag in the ISR once i got the RTC to work right. But i really like what lee did

set_lcd_xy( 3,11 );
putchar( seconds + 0x30 );

and it's more eff. / compact ! I went from 4204 prgm bytes to 4184 :D

David, we're on the same w.length on tracking each digit ( see code below ); they're volatile. But if i did cnt. to 60s wouldn't i HAVE to use / and % to get the 2 seconds digits ( no other efficient options )?

Looking at my .lss from my prv. post , is there ANY way to get the compiler, winavr, to just hold seconds in rXX so it doesn't store it then immediately load it ( opt. = s )?

 ISR( flag = 0;)
.
.
.
RTC_Disp{

uint8_t  temp, temp2, temp3;

if ( flag == 0 ) (  // test for 0 uses 1 less
//instruction ( cpi )

++seconds;
temp = seconds;

if ( seconds == 10 ) 

   { seconds = 0; temp = seconds; 
     ++sek;
     if ( sek == 6 ) 
        
		{ sek = 0; //temp2 = sek; 
          ++minute; 
          temp3 = minute;        
          set_lcd_xy( 3,8 );
          putchar( minute += 0x30);
          minute = temp3;        
		}
		
	 temp2 = sek;
     //sek += 0x30;
    
	 set_lcd_xy( 3,10 );
     putchar( sek += 0x30);
     sek = temp2;
   }
     
//seconds += 0x30;
set_lcd_xy( 3,11 );
putchar( seconds += 0x30);
seconds = temp;
  
flag = 0xFF;
})

edit: I'm not paying attention: Lee you said to do

seconds + 0x30;

, so i did that and NO temp vars. Now 4114 bytes down from 4204!!!

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

Quote:
I had already planned on just setting a
flag in the ISR once i got the RTC to work right.

It is best to start, by doing the right things first!

That reminds me about the student who comes with a jumble of un-indented code and not a comment in sight and asks, can you see what is wrong.
When reminded, of the need to indent code and add comments from the start, retorts with, "I find it easier to do after the code works". Enough said!

Same advise applies to using good variables names.

The "sek" is the unit of currency, but "temp" is obviously a temporary value!

Write your code as if it is poetry, it is meant to be read & understood!

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Quote:
Write your code as if it is poetry, it is meant to be read & understood!

Sounds good to me. I save a few bytes if i declare the 3 time vars. as volatile instead of static; i'd have thought IN THIS CASE that they'd be equal in use of ram.

thanks in advance

jerome

edit: Lee i just incorporated ( + 0x30 ) in my putchar() itself ( now i don't have to put it in at each invocation -- Muchas gracias )

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1