Author Topic: _XTAL_FREQ ?  (Read 2433 times)

0 Members and 1 Guest are viewing this topic.

Offline 0xFFF0

  • Regular Contributor
  • *
  • Posts: 52
  • Country: de
_XTAL_FREQ ?
« on: June 30, 2018, 07:34:14 pm »
A question about the PIC18F46K20. This PIC has 16 MHz. With PLL enabled, it can be increased up to 64 MHz. Do I have to set the _XTAL_FREQ to 64.000.000 now?

eyample:

#define _XTAL_FREQ 16000000UL //16 MHz

//PLLEN: Frequency Multiplier PLL for HFINTOSC Enable bit(1)
//1 = PLL enabled for HFINTOSC (8 MHz and 16 MHz only)
//0 = PLL disabled
OSCTUNEbits.PLLEN = 1;

   

best regards!

 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 10430
Re: _XTAL_FREQ ?
« Reply #1 on: June 30, 2018, 08:00:32 pm »
_XTAL_FREQ dates back to the HiTech C era (Microchip bought HiTech to acquire their compiler), from before PICs with PLLs were common.   It needs to be defined as the clock frequency of the CPU core, after any prescaling and PLLs.

I find it helpful to define:
Code: [Select]
#define KHz *1000UL
#define MHz *1000000UL
so I can do:
Code: [Select]
#define _XTAL_FREQ (64 MHz)or:
Code: [Select]
#define _XTAL_FREQ (125 KHz)as it significantly reduces the risk of miscounting the number of '0' digits in the frequency.
 

Offline 0xFFF0

  • Regular Contributor
  • *
  • Posts: 52
  • Country: de
Re: _XTAL_FREQ ?
« Reply #2 on: June 30, 2018, 10:00:58 pm »
nice idea!

Code: [Select]
#define KHz *1000UL
#define MHz KHz KHz
#define _XTAL_FREQ (64 MHz)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 3490
  • Country: us
Re: _XTAL_FREQ ?
« Reply #3 on: July 01, 2018, 08:55:37 am »
Quote
#define _XTAL_FREQ ((uint32_t)64e6)
??
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3789
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: _XTAL_FREQ ?
« Reply #4 on: July 01, 2018, 08:59:14 am »
do not use the float conversion, you may encounter some nasty rounding on numbers that are not exactly multiples of powers of 2.  (for example the crystal of 3.579545MHz commonly used for uart baudrate division ;) )

//EDIT: 18.432 may be a better example, as this number will definitely get screwed into 18 431 999.
« Last Edit: July 01, 2018, 09:04:42 am by Yansi »
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 10430
Re: _XTAL_FREQ ?
« Reply #5 on: July 01, 2018, 09:15:56 am »
OTOH unless you are using something a lot better than a commercial grade crystal or oscillator module,  float rounding errors aren't going to matter as the typical frequency tolerance of +/- 10 to 30 ppm is a far greater source of error.

Also, the compiler's standard headers use float maths to calculate delays from _XTAL_FREQ.  Here's the #defines from v1.3x pic.h:
Code: [Select]
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
 

Offline Yansi

  • Super Contributor
  • ***
  • Posts: 3789
  • Country: 00
  • STM32, STM8, AVR, 8051
Re: _XTAL_FREQ ?
« Reply #6 on: July 01, 2018, 09:45:25 am »
It seems to me you have just said that rounding errors do not exist.  You be better aware of them, rather than saying it does not exist.

Yes it does. For example if you want to derive a 115200 baud from the 18.432 crystal, you will typically need to divide by 10 to get the typical 115200*16 oversampling base clock.

If you divide 18431999 by 115200 and then by 16, you will get 9. Yes, nine, that is 10% off.  (Note that more things have to be fucked up for this to happen, but I very easily see how this can happen in many amateur software projcts.)

You better understand the behavior of float operations, rather than saying "meh, that is just negligible". No it is not.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 4204
  • Country: fi
Re: _XTAL_FREQ ?
« Reply #7 on: July 01, 2018, 10:04:13 am »
It seems to me you have just said that rounding errors do not exist.  You be better aware of them, rather than saying it does not exist.

Yes it does. For example if you want to derive a 115200 baud from the 18.432 crystal, you will typically need to divide by 10 to get the typical 115200*16 oversampling base clock.

If you divide 18431999 by 115200 and then by 16, you will get 9. Yes, nine, that is 10% off.  (Note that more things have to be fucked up for this to happen, but I very easily see how this can happen in many amateur software projcts.)

This is why you don't just simply calculate the baud rate divisors with a simple single mathematic operator and call it the day.

Comm devices with divisors are often so quantized in the baud rate options (off-by-one leading to massive errors) that you really have two options:
1) Hardcode the divisor value, calculate the resulting baud rate manually, and document it as a comment
Pros:
 - very robust and reliable, no ugly surprises in baud rate generation, little surface area for bugs
Cons:
 - non-generic, you need to remember to recalculate if you change the baud rate or the crystal, and there's a risk you forget to do that

2) Write (or find an existing) a proper function that sets the divisor for the minimum error, and reports the calculated error, and provides a way to abort operation if the error is outside valid range
Basically, calc_divider(min_baud, preferred_baud, max_baud, clk) which returns success or failure.

Pros:
- when done right, is generic; you can change crystals and baud rates, and use this function before you do that to calculate the viability of doing so
Cons:
- a lot of surface area for bugs, or wrong concepts of implementation. Actually I have never seen this done right...

Option 2 is far worse if you do it in a half-arsed way.

Just assigning some mathematical operation in the baud divisor register looks easy and "generic", but is a recipe for disaster. It's only going to work for some certain values, while it deceivingly looks generic. So you would need to comment "don't change this constant"; it's better to use the literal directly in the assignment.
« Last Edit: July 01, 2018, 10:10:02 am by Siwastaja »
 
The following users thanked this post: Ian.M

Offline 0xFFF0

  • Regular Contributor
  • *
  • Posts: 52
  • Country: de
Re: _XTAL_FREQ ?
« Reply #8 on: July 01, 2018, 10:52:25 am »
little improved...

//------------------------------------------------------------------------------
#define KHz *1000UL
#define MHz KHz KHz
#define _XTAL_FREQ (64 MHz)

#define BAUD 9600UL
#define SPBRG_VALUE ((uint8_t)(_XTAL_FREQ/(64UL*BAUD)-1))

//------------------------------------------------------------------------------
void EUSART_Initialize(void)
{
    //Asynchronous Transmission Set-up
    SPBRG = SPBRG_VALUE ; //Baud rate setting
    SPBRGH = 0x00;
...
« Last Edit: July 01, 2018, 11:29:58 am by 0xFFF0 »
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5122
  • Country: gb
Re: _XTAL_FREQ ?
« Reply #9 on: July 01, 2018, 05:17:58 pm »
It seems to me you have just said that rounding errors do not exist.  You be better aware of them, rather than saying it does not exist.

Yes it does. For example if you want to derive a 115200 baud from the 18.432 crystal, you will typically need to divide by 10 to get the typical 115200*16 oversampling base clock.

If you divide 18431999 by 115200 and then by 16, you will get 9. Yes, nine, that is 10% off.  (Note that more things have to be fucked up for this to happen, but I very easily see how this can happen in many amateur software projcts.)

You better understand the behavior of float operations, rather than saying "meh, that is just negligible". No it is not.

You also get increased inaccuracies if you just truncate using integer arithmetic as typically it will always round down.

The solution is to do a compile time compilation in double and add a 0.4999 at the point just before casting to int.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 3490
  • Country: us
Re: _XTAL_FREQ ?
« Reply #10 on: July 01, 2018, 10:40:20 pm »
Quote
18.432 may be a better example, as this number will definitely get screwed into 18 431 999.
Do you?  Prove it!

Code: [Select]
WWHackintosh<10109> avr-gdb
GNU gdb (AVR_8_bit_GNU_Toolchain_3.6.1_495) 7.8

(gdb) print (long)18.432e6
$2 = 18432000(gdb) print (long) 3.57954e6
$3 = 3579540
I agree that you need to be careful as the number of digits approaches the resolution of your FP format.  And I agree that it's a bad idea to define your clockrate as an actual floating point value.   But in my example, we're converting directly from the FP constant to the appropriate integer, which ought to yield exact results not subject to subtle errors thereafter.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2579
  • Country: ca
Re: _XTAL_FREQ ?
« Reply #11 on: July 01, 2018, 11:13:37 pm »
The oscillator accuracy is below even the float precision. Doubles are way more precise than your oscillator can be. There's absolutely no harm done by using floating point calculations
 
The following users thanked this post: Ian.M

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 10430
Re: _XTAL_FREQ ?
« Reply #12 on: July 01, 2018, 11:41:57 pm »
May I add ONE word to your reply? (red italics below)
The oscillator accuracy is below even the float precision. Doubles are way more precise than your oscillator can be. There's absolutely no harm done by using floating point calculations correctly

Yes, as long as you are using 32 bit or better floats.   If you are using Microchip's 24 bit floats,  the precision is comparable to the tolerance of a 30 ppm crystal, which is still  tiny compared to the bit rate tolerance for just about any asynchronous, and most self-clocked synchronous serial interfaces.
« Last Edit: July 01, 2018, 11:45:17 pm by Ian.M »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf