Author Topic: XC8 understanding __delay_ms()  (Read 19377 times)

0 Members and 1 Guest are viewing this topic.

Offline DTJ

  • Frequent Contributor
  • **
  • Posts: 883
  • Country: au
XC8 understanding __delay_ms()
« on: November 27, 2014, 09:00:53 am »
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 4uS

                LATBbits.LATB0 = 1;   // RB-0 to High
      LATBbits.LATB0 = 0;    // RB-0 to LOW


If 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() functions

void 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 */
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: XC8 understanding __delay_ms()
« Reply #1 on: November 27, 2014, 09:11:00 am »
Quote
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.

That 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.
================================
https://dannyelectronics.wordpress.com/
 

Offline bookaboo

  • Frequent Contributor
  • **
  • Posts: 604
  • Country: ie
Re: XC8 understanding __delay_ms()
« Reply #2 on: November 27, 2014, 09:41:01 am »
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.
 

Offline DTJ

  • Frequent Contributor
  • **
  • Posts: 883
  • Country: au
Re: XC8 understanding __delay_ms()
« Reply #3 on: November 27, 2014, 11:51:08 am »
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 16000000

Looking 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.

 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1153
Re: XC8 understanding __delay_ms()
« Reply #4 on: November 27, 2014, 12:09:19 pm »
Check the OSCCON register.

You can write directly to the register i.e. OSCCON = xxx

or I think you can access individual bits with something like:
OSCCONbits.XXX = xxx

It'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.
 

Offline DTJ

  • Frequent Contributor
  • **
  • Posts: 883
  • Country: au
Re: XC8 understanding __delay_ms()
« Reply #5 on: November 27, 2014, 12:39:54 pm »
Cheers Wilksey, some Googling turned up up the little routine below which is a little tidier and easier to read than just putting OSCCON = 0bxxxxxxxx


void ConfigureOscillator(void)
{
    OSCCONbits.IRCF     = 0b101;
    OSCCONbits.SCS      = 0b00;
    OSCTUNEbits.PLLEN   = 0b1;
}

 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 3503
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: XC8 understanding __delay_ms()
« Reply #6 on: November 27, 2014, 12:41:55 pm »
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?

Offline NegativeONE

  • Contributor
  • Posts: 20
  • Country: pl
    • NegativeONE - personal page
Re: XC8 understanding __delay_ms()
« Reply #7 on: November 27, 2014, 12:53:07 pm »
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 = INTIO67

and:

#include <xc.h>

instead of  #include<p18f25k22.h> 
ONE never notices what has been done;
ONE can only see what remains to be done;

http://www.negativeone.pl
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: XC8 understanding __delay_ms()
« Reply #8 on: November 27, 2014, 01:26:51 pm »
Quote
some Googling ...

Googling 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.
================================
https://dannyelectronics.wordpress.com/
 

Offline DTJ

  • Frequent Contributor
  • **
  • Posts: 883
  • Country: au
Re: XC8 understanding __delay_ms()
« Reply #9 on: November 27, 2014, 02:13:26 pm »
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. ;)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: XC8 understanding __delay_ms()
« Reply #10 on: November 27, 2014, 03:07:54 pm »
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.
================================
https://dannyelectronics.wordpress.com/
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1153
Re: XC8 understanding __delay_ms()
« Reply #11 on: November 27, 2014, 05:17:26 pm »
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
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1303
  • Country: no
Re: XC8 understanding __delay_ms()
« Reply #12 on: November 27, 2014, 09:44:58 pm »
The datasheet is the answer. If you go through the clock tree, your issue is so obvious.

Wish 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 )

void ConfigureOscillator(void)
{
    OSCCONbits.IRCF     = 0b101;
    OSCCONbits.SCS      = 0b00;
    OSCTUNEbits.PLLEN   = 0b1;
}
From 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?

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 = INTIO67


#include <xc.h>
instead of  #include<p18f25k22.h> 

This 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.pdf
And 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/

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: XC8 understanding __delay_ms()
« Reply #13 on: November 28, 2014, 02:44:04 am »
Quote
the figure 2-2

and 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; or
2) 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.
================================
https://dannyelectronics.wordpress.com/
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 3103
  • Country: us
Re: XC8 understanding __delay_ms()
« Reply #14 on: November 28, 2014, 02:50:24 am »
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...)
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1303
  • Country: no
Re: XC8 understanding __delay_ms()
« Reply #15 on: November 28, 2014, 09:33:35 am »
Quote
the figure 2-2

and 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; or
2) 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.

Aha, 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.
 

Offline Wilksey

  • Super Contributor
  • ***
  • Posts: 1153
Re: XC8 understanding __delay_ms()
« Reply #16 on: November 28, 2014, 12:21:11 pm »
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.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: XC8 understanding __delay_ms()
« Reply #17 on: November 28, 2014, 12:34:10 pm »
Quote
The __delay_ms uses only _XTAL_FREQ as it's knowledge of the clockfrequency?

Setting _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.
================================
https://dannyelectronics.wordpress.com/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf