Unknown Clock

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

If I am willing to lose accuracy with the built in delay functions, is it absolutely critical to know the clock speed at compile time?

I'm trying to write some software that will function on two different board types (same MCU) with two different speed crystals. At power up, the board will read an identifier out of EEPROM to tell the software what board type it is running on, which will configure the rest of the software behavior (including setting the baud rates appropriately for its UART interfaces). Is there any other drawback to having an incorrect clock specified at run time?

I would probably specify something halfway between the two crystal frequencies.

Science is not consensus. Science is numbers.

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

You can always do a runtime if statement, choosing one of two delays according to the retrieved clock indicator.

But, then, you would have to "spoof" half of the delay calls at compile time because they will compile on the basis of the F_CPU specified when it is compiled. Those other ones need to produce the correct delay at the other F_CPU when compiled with the first F_CPU.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Skip the built in delay functions.

Your eprom tells you which board it's installed in. This will let you know what the clock frequency is. You can then figure your own delays.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

Jim,

Thanks for the info. I don't use a lot of delays in this code, so it isn't particularly troubling. I am more concerned about some other effect of an unknown clock that I am not thinking about at this time.

Science is not consensus. Science is numbers.

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

Quote:

I am more concerned about some other effect of an unknown clock that I am not thinking about at this time.

Well it's how you are reliant on the clock that needs thinking about. For example suppose you use a UART. You can do the usual:

#define F_CPU 8000000UL
#define BAUD 9600
#define UBRRVAL (F_CPU/(BAUD * 16UL)) -1 

..

UBRR = UBRRVAL;

but this only builds correctly for the 8MHz case. To handle this at run time you need something like:

#define BAUD 9600
#define UBRRVAL8M (8000000UL/(BAUD * 16UL)) -1 
#define UBRRVAL36M (3686400UL/(BAUD * 16UL)) -1 

..
if (model == MODELTYPE_1) { // 8MHz
 UBRR = UBRRVAL8M;
}
else if (model == MODELTYPE_2) { // 3.6864MHz
 UBRR = UBRRVAL36M;
}

You can do something similar where you calculate things like timer prescalers based on F_CPU. In fact, wherever you use F_CPU you need to paths to cope with the two model types at run time - it can no longer all be reliant on a single compile-time calculated constant - though as this shows you can have two compile time constants and a single run time decision of which to use. In fact the run time code could be more clearly expressed as:

UBRR = (model == MODELTYPE_1) ? UBRRVAL8M : UBRRVAL36M;

though that's really just semantics.

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

Baud rate, ADC clock prescale, timer prescales, timer compare values, and such can all be adjusted at run-time. You just need to include the code to do it.

The biggie is the supplied delay functions that require constant arguments at compile time. One of the things I would do to reduce the delay "footprint" is to use a function as a wrapper around calls to delays that are used in more than one place. That way, there is only one instance of that delay in the body of your code. Then, you can provide, in a single spot, two, each tailored to one of the two clocks.

By the way, as far as I know, if you use built-in delay functions, you HAVE to have an F_CPU declared at compile time. So, as far as your code is concerned, the clock is NOT unknown.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Quote:

By the way, as far as I know, if you use built-in delay functions, you HAVE to have an F_CPU declared at compile time. So, as far as your code is concerned, the clock is NOT unknown.

That's fairly easy to cope with (assuming you will accept 1ms granularity):

// file1.c
#define F_CPU 8000000UL
#include 
void delay_1ms_8M(void) {
  _delay_ms(1);
}
// file2.c
#define F_CPU 3686400UL
#include 
void delay_1ms_36M(void) {
  _delay_ms(1);
}
// main.c
void delay_1ms_8M(void);
void delay_1ms_36M(void);
int main(void) {
 if (model == MODELTYPE_1) {
   _delay_1ms_8M();
 else {
   _delay_1ms_36M();
 }
}

In fact you could expand this to:

// file1.c
#define F_CPU 8000000UL
#include 
void delay_1ms_8M(unsigned int n) {
  while(n--) {
    _delay_ms(1);
  }
}

which gives the further advantage of runtime settable delays.

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

Well that sounds simple enough if you just use single delay that is an average of both crystal speeds, as long as you can guarantee every delay you need fits within tolerance you need. I don't know what kind of requirements you have, but sometimes the requirement is that some delay is at least a given length, or at most a given length, and even more rarely between a minimum and maximum length, which you can take into account.

I think if you can use a single function for delays that delays an integral multiple of a given time (like 1ms or 100us), it does not cost much to first check the system type and then call the relevant delay_ms_freq1 or delay_ms_freq2 accordinly.

But if you need something special, like some very special exact delay on both systems, you could have a function pointer that points to a delay of xyz microseconds, and you initialize the function pointer based on system type.

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

There have been some excellent suggestions here -- in particular, how to handle timer prescalers (I hadn't thought that far ahead yet).

Again, as I said in the first post, I am willing to deal with some error for the built in _delay functions...

Science is not consensus. Science is numbers.

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

Fair warning:

You aren't very far from me. You may wish to move

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

Rather than move, I say we just set up a sticky thread in OT for Chicago Madness Freaks Meetup -- there have to be more than two of us in the area.

I recently heard an ad on the radio touting that the city has over 1200 dining/drinking establishments. Seeing as I have a 21 month old, I have only visited something like 5 in the last year and a half. Surely there is one where 'freaks can meet to bash PICs (and the Packers - a mutual enemy of the Bears and the Lions).

Science is not consensus. Science is numbers.

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

I'm at the Chicago Botanic in the model railroad garden almost every weekend, May through October. Your 21 month old will love it.

PIC bashing is my specialty:D

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

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

hobbss wrote:
There have been some excellent suggestions here -- in particular, how to handle timer prescalers (I hadn't thought that far ahead yet).

Again, as I said in the first post, I am willing to deal with some error for the built in _delay functions...

In fact most likely you should not touch the prescaler, but the TOP or compare value it counts to before overflowing. So in each system you will be able to get a timer interrupt after an exact amount of crystal cycles, so both systems with different crystals can have a 1kHz system tick timer interrupt if you wanted. Or 100Hz or anything.

But timers are better for timekeeping and scheduling events like updating a display 10 times per second. But not good for generating software SPI clocks for example, which are better to do with delays. We don't know what you will use those delays for, but of course in a real world it does not matter if you just use delays, and the display will update 9 or 11 times per second instead depending on actual crystal.

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

Good advice. I do use the the timers for event scheduling (i.e., servicing an HTTP server, closing a PID, etc.). Slight variations in frequency do not matter for my application (even the PID). I will have to search the code (somewhat laborious in AVR 4.18 -- I have found searching in a project is vastly improved in AVR 6.0), but I don't think I have many of the built in delays at all.

Science is not consensus. Science is numbers.

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

how big it the difference in clock speed anyway?

As you are using an eeprom you could also store the specific values in there during testing. During loading you clear the eeprom and during testing/configuration you put in the right values. This ensures that if in the future you need to change one of the crystals you do not have to change the code, just load a new eeprom image.

The biggest problem will be the UART, it has to be relative close to the expected value or you will be getting bit errors that will mess-up communication.

regards