XC8 understanding __delay_ms() - Page 1
Forum section: electronics / general

author: DTJ
author_rank: Super Contributor
timestamp: November 27, 2014, 09:00:53 am
content: Dummy question time!Using MPLABX, XC8 with an 18F25k22 uC.The __delay_ms() functions seem way off and I'm not sure if my problem is the oscillator set up.I think I have the oscillator set up for a direct HF internal 16MHz oscillator (see configs in code below).Executing a "__delay_ms(20)" generates a delay of 320mS which is 16 times what I expected.Executing a "__delay_us(20)" generates a delay of 320uS which is again 16 times what I expected.If I just toggle the pin as shown immediately below I measure an "on" time of 4uSLATBbits.LATB0 = 1; // RB-0 to HighLATBbits.LATB0 = 0; // RB-0 to LOWIf the clock time is 16MHz, that gives 4MHz instructing rate or 4 instructions / uS.I'm new to programming in C, the old BSF in assembler took 1 cycle - does the same apply for "LATBbits.LATB0 = 1"Help - what am I doing wrong!Thanks.#include<p18f25k22.h> // [[[[Include the PIC18F550 Headers]]]]]]/* COMPILER DIRECTIVES FOR CHIP CONFIGURATION BITS*/#pragma config PLLCFG = OFF //PLL is off#pragma config PRICLKEN = ON //Primary clock enabled#pragma config FCMEN = ON //Fail-Safe Clock Monitor enabled#pragma config IESO = OFF //Oscillator Switchover mode disabled#pragma config FOSC = INTIO67 // osc config - enables RA6/7 with int osc.//#pragma config FOSC = INTIO7 // osc config - Internal osc block, CLKOUT on OSC2#pragma config BOREN = OFF //Brown-out Reset disabled in h/w & s/w#pragma config BORV = 220 //Brown Out Voltage: 2.2V#pragma config PWRTEN = OFF //PWRT disabled#pragma config WDTEN = OFF, WDTPS = 32768 // WDT off, post scaled 32768#pragma config STVREN = ON //Stack full/underflow will not cause Rst#pragma config XINST = OFF //Inst set & Index Add disab. Legacy mode#pragma config CP0 = OFF //Block 0 not code-protected#pragma config CP1 = OFF //Block 1 not code-protected#pragma config CPD = OFF //Data EEPROM not code-protected#pragma config CPB = OFF //Boot block not code-protected#pragma config WRT0 = OFF //Block 0 not write-protected#pragma config WRT1 = OFF //Block 1 not write-protected#pragma config WRTB = OFF //Boot block not write-protected#pragma config WRTC = OFF //Config registers not write-protected#pragma config WRTD = OFF //Data EEPROM not write-protected#pragma config EBTR0 = OFF //Blk0 not prot frm tbl read in other blk#pragma config EBTR1 = OFF //Blk1 not prot frm tbl read in other blk#pragma config EBTRB = OFF //Boot not prot from tbl rd in other blk#pragma config HFOFST = OFF //Sys clk held off till HFINTOSC stable#pragma config LVP = OFF //Single-Supply ICSP disabled//#pragma config BBSIZ = OFF //1k boot block size#define _XTAL_FREQ 16000000 //required by __delay_ms() / __delay_us() functionsvoid main(void){TRISB = 0b11111110 ; // PORT B Setting:while(1){LATBbits.LATB0 = 1; // RB-0 to High__delay_ms(20);LATBbits.LATB0 = 0; // RB-0 to LOW__delay_ms(20);}}/* THE END */

author: dannyf
author_rank: Super Contributor
timestamp: November 27, 2014, 09:11:00 am
content: QuoteThat should be enough to tell you what's going on.In situations like this, it is very helpful to go through the datasheet, particularly the clock trees, and see which clock option is used and which (default) setting is applied.Then, you can easily spot the issue.

author: bookaboo
author_rank: Frequent Contributor
timestamp: November 27, 2014, 09:41:01 am
content: Probably the osc config bits."#pragma config PLLCFG = OFF //PLL is off"Try setting this to "on". Not sure about XC8 and 18F but I usually define "FCY" to whatever value is needed.

author: DTJ
author_rank: Super Contributor
timestamp: November 27, 2014, 11:51:08 am
content: Hi Danny, yep it's always in the data sheet, just a matter of identifying it!Hi Bookaboo, I tried enabling the PLL, it didn't help. From looking at the data sheet I think I need the PLL off. I'm not sure on the "FCY" I'm guessing its the equivalent of the line: #define _XTAL_FREQ 16000000Looking at the code I can now see a problem but am not sure how to correct it properly.OSCCON should contain 0b0111 11xx which selects HFINTOSC of 16MHz. HFINTOSC freq is set by bits 6,5,4.It actually contains 0b0011 00xx meaning that the HFINTOSC is set to 1MHz - which explains the 16 fold error in the delays.What is the correct way of configuring OSCCON. Do I just do this:OSCCON = 0b01111100;/or something else?Thanks for your help & suggestions fellas.

author: Wilksey
author_rank: Super Contributor
timestamp: November 27, 2014, 12:09:19 pm
content: Check the OSCCON register.You can write directly to the register i.e. OSCCON = xxxor I think you can access individual bits with something like:OSCCONbits.XXX = xxxIt's been a while since I wrote code for the 18F's delay routines, but from memory (bad) I think that is what is required.

author: DTJ
author_rank: Super Contributor
timestamp: November 27, 2014, 12:39:54 pm
content: Cheers Wilksey, some Googling turned up up the little routine below which is a little tidier and easier to read than just putting OSCCON = 0bxxxxxxxxvoid ConfigureOscillator(void){OSCCONbits.IRCF = 0b101;OSCCONbits.SCS = 0b00;OSCTUNEbits.PLLEN = 0b1;}

author: AndyC_772
author_rank: Super Contributor
timestamp: November 27, 2014, 12:41:55 pm
content: The data sheet won't help if it's the delay function that has the problem, rather than the configuration of the chip itself.If you have the device configured for Fosc = 16 MHz, then the instruction rate is 4MHz. The device takes four clocks per instruction, so Fosc/4 is the instruction rate.I don't use Microchip's libraries myself, but I'd guess that the __delay_ms function requires a value to be defined to tell it what the clock speed is. If that's not set correctly, then the delays it generates will all be wrong by the same factor.Consider using timers yourself directly, rather than using a library. If you use the library, how do you know it's not trying to use hardware (in this case, timers) that you're already using elsewhere for more important purposes?

author: NegativeONE
author_rank: Contributor
timestamp: November 27, 2014, 12:53:07 pm
content: Use this line:#pragma config FOSC = HS// Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)instead of #pragma config FOSC = INTIO67and:#include <xc.h>instead of #include<p18f25k22.h>

author: dannyf
author_rank: Super Contributor
timestamp: November 27, 2014, 01:26:51 pm
content: QuoteGoogling may get you a piece of code but unlikely to tell you what went wrong and you may struggle with the same issue next time.The datasheet is the answer. If you go through the clock tree, your issue is so obvious.

author: DTJ
author_rank: Super Contributor
timestamp: November 27, 2014, 02:13:26 pm
content: Hey Danny, that's correct.As mentioned I discovered what I was doing wrong. I was not configuring OSCCON correctly.Google simply confirmed I was on the right track and provided me with a couple of different methods of implementing it.

author: dannyf
author_rank: Super Contributor
timestamp: November 27, 2014, 03:07:54 pm
content: Specifically, the internal RC source is controlled by the IRCFn bits, which default to 1Mhz (/16).The solution after that is simple. The other "fixes" mentioned are not applicable to you at all.Always read the datasheet, as it is the most efficient / correct way to solve your problems.

author: Wilksey
author_rank: Super Contributor
timestamp: November 27, 2014, 05:17:26 pm
content: No worries,All other settings were correct, you were just missing the OSCCON bits, IRCF was the bit(s) I was thinking of, but couldn't remember what it was! lol

author: neslekkim
author_rank: Super Contributor
timestamp: November 27, 2014, 09:44:58 pm
content: Quote from: dannyf on November 27, 2014, 01:26:51 pmWish there was an guide on how to read these datasheets..What exactly do you mean with clock tree?, I have been trying to read this datasheet, and the closest I get is 2.2 Oscillator control, and the figure 2-2 on the other page?(this doc:http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf)Quote from: DTJ on November 27, 2014, 12:39:54 pmFrom that figure, and also what's written on 2.7, Oscillator tuning, I would think this gives 16Mzh? 101=4Mhz, and PLLEN=1 is 4z that?But why would that give correct result from __delay_ms?Quote from: NegativeONE on November 27, 2014, 12:53:07 pmQuote from: NegativeONE on November 27, 2014, 12:53:07 pmThis I found out earlier also, tried to look up all these device headers, but xc.h did everything easier, It's documented on page 27 here:http://ww1.microchip.com/downloads/en/DeviceDoc/MPLAB_XC8_C_Compiler_User_Guide.pdfAnd I found the __delay_ms documented on page 63 and 330 in that document, but could'n find detailed info about fosc=hs and stuff like that.I think that using xc.h gave me the correct _XTAL_FREQ which I thought gave me correct result, but the code is on another computer, and I did never check if it actually was correct, it just looked right..I used this board:https://www.tindie.com/products/TAUTIC/28-pin-pic18f26k22-development-board/

author: dannyf
author_rank: Super Contributor
timestamp: November 28, 2014, 02:44:04 am
content: Quoteand more importantly, figure 2-1: it shows how the various clock sources are routed and what registers control the routing.In this case, HFINTOSC is routed through IRCF2..0, as shown on figure 2-2. The actual setting is on page 32 where you can see that IRCF2..0 is defaulted to 0b011 (footnote 3) = 1Mhz.vs. the default _XTAL_FREQ of 16Mhz, you can explain 100% of the 16:1 timing error.Once that's cleared, the fix is easy:1) keep the default IRCFn settings and change _XTAL_FREQ to 1Mhz; or2) change the IRCFn to 0b111 (16Mhz) and retain the existing _XTAL_FREQ definition.All of that can be learned via a quick scan of the datasheet. And the clocking section is typically the first section you read in any datasheet.

author: westfw
author_rank: Super Contributor
timestamp: November 28, 2014, 02:50:24 am
content: Also, are you sure that whatever programming procedure you're using actually propagates the #pragma directives to the chip fuses? (Atmel AVR has some high-level compiler bits for setting the fuses, but MOST of the programming procedures don't do anything with them...)

author: neslekkim
author_rank: Super Contributor
timestamp: November 28, 2014, 09:33:35 am
content: Quote from: dannyf on November 28, 2014, 02:44:04 amAha, so you need to self, make sure that you set te IRCF to an correct clocksource, and also set _XTAL_FREQ correct?, I would guess _XTAL_FREQ are set to the defaultvalue for the choosen chip?The __delay_ms uses only _XTAL_FREQ as it's knowledge of the clockfrequency?For you people who have many years of experience reading these, i can understand that a quick read will tell all, but for beginners, it's lot of not so easy stuff, that's why i would like an datasheet reading guide, or otherwise learn this in an structured fashion.

author: Wilksey
author_rank: Super Contributor
timestamp: November 28, 2014, 12:21:11 pm
content: The function uses the _XTAL_FREQ to calculate it's timings etc, but unless the physical clock is set correctly then it won't work properly.If you set the frequency to 16MHz but tell the delay function you have a 8MHz clock then things are going to go wrong, don't forget that the delay functions just waste cycles, personally I use a hardware timer with flags.With the internal clock you have to make sure the clock frequency bit is set correctly in the register, otherwise the instructions will not execute at the correct speed, they will execute slower or faster, depending on which way the clock was wrongly set.If you have a RTC clock at 32HKz, the software is set to tick at a specific rate based on the knowledge that the input clock is 32KHz, if you suddenly change this clock for a 1MHz crystal for example, then the RTC is going to be counting at about 30 x the original speed.

author: dannyf
author_rank: Super Contributor
timestamp: November 28, 2014, 12:34:10 pm
content: QuoteSetting _XTAL_FREQ does nothing to the mcu itself: the mcu runs whatever frequency it is set to run, regardless of _XTAL_FREQ.All _XTAL_FREQ does is to tell the delay routines the speed at which the instructions are executed so that the delays execute the right amount of instructions -> to achieve the right elapse of time.As to datasheets, you have to read them to understand how the device works. Particularly true for larger chips with more complex peripherals. You will also need to read the datasheet in conjunction with the associated device header files, and compiler manuals to know how to access the peripherals in your programming environment.There is simply no other way around that.