Upper registers

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

HI,

I am attempting to read TCNT3 and I can't figure out how to do it. Help would be appreciated. No matter how I try, I just get garbage.

Thanks,

Daniel

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

Sorry, that is on the mega162.

Daniel

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

If you are using assembly, it sounds like you first have to read TCNT3L, then read TCNT3H

in r16,TCNT3L
in r17,TCNT3H

What have you tried?

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

Hi and thanks for the reply,

I am using Codevision, and I have spent hours on what should be straightforward. The latest example of code that I am using is,

interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here

static unsigned char counter;
long int Timer3;
unsigned char temp[12];
counter++;
Timer3 = (long int) TCNT3H;
TCNT3H = 0;

if(counter > 121)
{
ltoa(Timer3,temp);

puts(temp);
counter = 0;

}

The if(counter) statement is just to slow down the output. Right now, at this time, I am getting all zero's for the output.

I have gotten lots of other stuff, such as a number that counts down by ten, etc. Below is the setup for the External interrupts and the timer3, thanks,

What I want to do is to read the value of the timer and then set it to zero. At this point, I can't even get the high register to read, nor the low, let alone the entire register.

Daniel

//*************** External Interrupt init *************

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: On
// INT1 Mode: Rising Edge
// INT2: On
// INT2 Mode: Rising Edge
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: Off
GICR|=0xE0;
MCUCR=0x0F;
EMCUCR=0x01;
GIFR=0xE0;

//*********** Timer 3 initialization **************

// Timer/Counter 3 initialization
// Clock value: 3710.000 kHz
// Mode: Normal top=FFFFh
// Noise Canceler: Off
// Input Capture on Falling Edge
// OC3A output: Set
// OC3B output: Clear
TCCR3A=0xE0;
TCCR3B=0x01;
TCNT3H=0x00;
TCNT3L=0x00;
ICR3H=0x00;
ICR3L=0x00;
OCR3AH=0x01;
OCR3AL=0x00;
OCR3BH=0xa0;
OCR3BL=0x10;
}

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

Oh, should have mentioned, I first did all of this for timer1 under interrupt 0 and had no problems at all. When I tried to do the same thing under interrupt one, using the second timer, I ran into all of these problems.

Although I didn't show it, interrupt 0 is working correctly and is resetting itself to a zero value every loop. It is almost as if they are sharing something, and one is screwing up the other, though Interrupt 0 continues to always work fine with timer1.

Daniel

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

You are cruisin' for a bruisin' doing those time-consuming operations in an ISR. You may also be inviting stack problems, are certainly continually cascading interrupts, and flat-out won't work with interrupt-driven UART comms.

ISRs--get in, do your business, & get out.

// Main program, globals
unsigned char got_milk;  // flag that new data has been parked in the ISR
unsigned int milk; // and the data from TCNT3
...
// Main program, main loop

if (got_milk)
    {
    // DO SOMETHING WITH MILK;  ISR WILL NO OVERWRITE SO NO INTERLOCKING 
    got_milk = 0;  // clear flag preparing for next
    }
...
// in ISR
...
if (!got_milk)
    {
    got_milk = 1;
    milk = TCNT3;
    }

With the above scheme or similar you can whak around with the "milk" value as long as you like.

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

Try TCNT3=0x0000;

I think the compiler will deal with the high and low aspect.

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

Hi,

I am only sending out the information in the interrupt until I get it working then I will move it to the main loop. Due to the real time nature of what I am doing, I will have to check flags and the like before allowing the serial port to be used. It gives me less to troubleshoot if I do it right in the INT until I get it working and then move it out.

The TCNT3 does not work as it is not defined in the mega162.h header file. The high and low bytes are, but not the word. There is no TCNT3 for codevision. The TCNT1 did work fine, and I suppose that is why I had no problem with the first version of this in EXT INT0, so you are on the right track.

It appears as if the chip does not really have a Timer 3

Daniel

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

I think you put me on the right track with the TCNT3 read. Since the datasheet itself says that this is how it is supposed to be done and yet CodevisionAVR doesn't have it defined then that tells me that there may be a problem with the compiler.

(Well, for sure there is, because if you try to do things the way they are shown in the example in the datasheet, (using TCNT3) the Codevision Compiler doesn't even recognize TCNT3.) If one part is screwed up so clearly that it is that obvious, then why would I think the rest of it would work?

So, I will write my own definitions for TCNT3L and TCNT3H and see if that flies,

Thanks,

Daniel

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

Quote:
...It gives me less to troubleshoot if I do it right in the INT until I get it working and then move it out. ...

I'd say it gives you >>more<<, but suit yourself.

Quote:
...The TCNT3 does not work as it is not defined in the mega162.h header file. The high and low bytes are, but not the word. There is no TCNT3 for codevision. The TCNT1 ...

Well, look in the header file & make your own cast if you want to--just make sure that the bytes are accessed in the correct order.

There is an sfrb for TCNT1H & TCNT1L, as well as an sfrw for TCNT1. Those two registers can be reached with I/O instructions such as in & out. The TCNT3H & TCNT3L can only be reached through the SRAM address space via lds & sts.

CV probably cannot guarantee the order of access in generic C statements via the pointer-and-cast method. It might work OK; I think I've done it in the past (cast to an unsigned int *). Try out a test program and see the order.

In any case, you should be able to get just as hgood results doing the read-the-low-byte-first-and-OR-it with-the-high-byte-shifted-left-8 routine. Or just drop into ASM & hammer out the two LDS/STS pairs.

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

Sorry if I misled you, I am not sure about the Codevison approach. I think what Codevison has defined is more reliable than my guess.

Did you try it reading TCNT3L first, then reading TCNT3H?
Your posted code shows reading the other way around, but the order is important in assembly, so it may also be important in CV

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

yes, you need to read/write both the low and high registers for the 16bit timers, as internally there is a temp register used. Also note that the reason it worked for timer 0 is that it's only an 8 bit timer, so there is only one register to hit.

And read write order is important. Some compilers will take care of this for you, if it offers a 16bit definition, if it only offers the 8 bit names, then you will need to take care of the order yourself.

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

Well, I am not at work anymore, but I did see in the datasheet that you are supposed to read the registers low first. I figured that since these registers were SRAM that it probably wouldn't matter, but I am pretty sure I tried it anyway.

I used TCNT1 with Timer1 before, I have not used timer 0, though I did use EXT INT0.

Also, in the example that I posted I am only reading the high byte. When I tried reading the low byte, I did get values other than zero, however, I could tell that they were not probably not correct as they were bouncing around much more than what I was reading would bounce.

So, only reading the low byte doesn't work, only reading the high doesn't work, and I am pretty sure that reading first the low and then the high also doesn't work.

I will quit trying to use the built in stuff that is supposed to make things easier and just either write my own assembly code, or else play around a bit with things like assigning a global variable to that address, etc.

The datasheet says that the compiler will have defined this for me and that I can use TCNT3, so their example is only one line of code.

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

ratherbeboating wrote:
Well, I am not at work anymore, but I did see in the datasheet that you are supposed to read the registers low first. I figured that since these registers were SRAM that it probably wouldn't matter, but I am pretty sure I tried it anyway.

The registers are memory mapped into the SRAM space, as IO space on the AVR is limited, they however are not SRAM.

Reading the low byte will load TEMP with the high byte, this way your read is consistant. Then reading the high byte, will return the value captured in the TEMP register. Writing involves the opposite order. HIGH is writen to load the TEMP register, and low is writen to writen the entire 16bit value into the actual register in the AVR's core.

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

Oh, that makes sense. I guess I was confused by this excerpt from the help files in Codevision.
"It is important to note that bit selector access to I/O registers located in internal SRAM above address 5Fh (like PORTF for the ATmega128 for example) will not work, because the CBI, SBI, SBIC and SBIS instructions can’t be used for SRAM access." So, I "assumed" it was SRAM.

I am pretty sure that you have offered the correct solution. Thank you very much for your time,

Daniel