_XTAL_FREQ ? - Page 1
Forum section: electronics / general

author: 0xFFF0
author_rank: Regular Contributor
timestamp: June 30, 2018, 07:34:14 pm
content: 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 disabledOSCTUNEbits.PLLEN = 1;best regards!

author: Ian.M
author_rank: Super Contributor
timestamp: June 30, 2018, 08:00:32 pm
content: _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:#define KHz *1000UL#define MHz *1000000ULso I can do:Code:#define _XTAL_FREQ (64 MHz)or:Code:#define _XTAL_FREQ (125 KHz)as it significantly reduces the risk of miscounting the number of '0' digits in the frequency.

author: 0xFFF0
author_rank: Regular Contributor
timestamp: June 30, 2018, 10:00:58 pm
content: nice idea!Code:#define KHz *1000UL#define MHz KHz KHz#define _XTAL_FREQ (64 MHz)

author: westfw
author_rank: Super Contributor
timestamp: July 01, 2018, 08:55:37 am
content: Quote??

author: Yansi
author_rank: Super Contributor
timestamp: July 01, 2018, 08:59:14 am
content: 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.

author: Ian.M
author_rank: Super Contributor
timestamp: July 01, 2018, 09:15:56 am
content: 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:#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

author: Yansi
author_rank: Super Contributor
timestamp: July 01, 2018, 09:45:25 am
content: 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.

author: Siwastaja
author_rank: Super Contributor
timestamp: July 01, 2018, 10:04:13 am
content: Quote from: Yansi on July 01, 2018, 09:45:25 amThis 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 commentPros:- very robust and reliable, no ugly surprises in baud rate generation, little surface area for bugsCons:- 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 that2) 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 rangeBasically, 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 soCons:- 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 deceivinglylooksgeneric. So you would need to comment "don't change this constant"; it's better to use the literal directly in the assignment.

author: 0xFFF0
author_rank: Regular Contributor
timestamp: July 01, 2018, 10:52:25 am
content: 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-upSPBRG = SPBRG_VALUE ; //Baud rate settingSPBRGH = 0x00;...

author: Howardlong
author_rank: Super Contributor
timestamp: July 01, 2018, 05:17:58 pm
content: Quote from: Yansi on July 01, 2018, 09:45:25 amYou 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.

author: westfw
author_rank: Super Contributor
timestamp: July 01, 2018, 10:40:20 pm
content: QuoteDo you? Prove it!Code:WWHackintosh<10109> avr-gdbGNU 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 = 3579540I 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.

author: NorthGuy
author_rank: Super Contributor
timestamp: July 01, 2018, 11:13:37 pm
content: 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

author: Ian.M
author_rank: Super Contributor
timestamp: July 01, 2018, 11:41:57 pm
content: May I add ONE word to your reply? (red italics below)Quote from: NorthGuy on July 01, 2018, 11:13:37 pmYes, 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.