
投稿日 2014/10/03
PICを使うに当たって苦労するのがクロック設定です。
必要もないような高い周波数で使っていたりすることはよくあります。
クロックはPICを使用する上での基本ですし、何といっても消費電力に直接かかわってくるものなので、しっかり理解しておきたいものです。かく言う私も、新しいCPUモデルを使うときは、四苦八苦しています。
PICのクロック回路は、考え方は同じようなものですが、CPUモデルによって微妙に違いがあります。一般的には上位モデルほど複雑多機能なクロックシステムを持っています。
たとえば以前PIC24シリーズの24F16K102のクロック設定について投稿しましたが、XLP(超低消費電力)のモデルでは特に重要です。
今回は、最近実験で便利に使っている秋月電子のPICマイコンモジュールに搭載されているPIC18F4553のクロック設定をまとめ、最後に簡単なプログラムで動作確認してみました。
PIC18F4553は18F4550のADコンバータを10bitから12bitにするなど、いくつかの改良が行われたものですが、ベースは18F4550です。このため機能のほとんどは18F4550のデータシートに記載されており、改良点のみ18F4553のデータシートに記載されています。このため、クロック設定については18F4550のデーターシートを見ることになります。

PIC 18F4550/18F4553のクロックシステム
microchip社 18f4550のデータシートより抜粋
上図は18f4550/4553のクロックシステムです。
主な特徴を上げると、
Primary Oscillator
外部クロック源(水晶振動子(XT,HS)や水晶発振器(EC)など)を接続できます。水晶振動子の周波数範囲によりXTとHSの指定があります。水晶発振器はECで指定します。最高48MHzまで。外部クロック源をつなぐOSC2ピンはGPIOのRA6と共通です。ECをつなぐような場合でOSC2ピンを使わない場合、RA6として使えるように設定できます。
Primary OscillatorはPLLに入れて96MHzに逓倍し、それを分周して48, 32, 24, 16MHzを作ることも可能です。
Secondary Oscillator
Timer1 Oscillatorともいいます。
Internal Oscillator
内蔵の発信器です。外部クロック源がなくても使えるようになっています。Internal Oscillatorのひとつはクロック源が8MHz(INTOSC)です。これらを分周して4, 2, 1MHz, 500KHz, 250KHz, 125KHz, 31KHzが作れます。もうひとつは31KHz(INTRC)です。
USB用クロックの48MHzはPrimary OscillatorをPLLで逓倍し96MHzにし、それを1/2に分周して作っています。USBのクロックはInternal Oscillator(INTOSC)からは作れません。これはUSBクロックには精度が必要なためも一因かと思います。
CPUと周辺(USB以外)用クロックは、Primary OscillatorとSecondary Oscillator、Internal Oscillatorの3つのクロックソースから選べます。
プログラムの実行中に変更できる設定とできない設定
消費電力と処理スピードにクリチカルなアプリケーションでは重要です。
クロックには多くの設定とその組み合わせがありますが、大きく分けるとコンフィグレーションレジスタ(CONFIGx)で設定する(ここではハードウェア・コンフィグレーションを呼ぶ)ものと、ISRのOSCCONレジスタで設定する(ソフトウェア・コンフィグレーションと呼ぶ)ものがあります。ハードウェア・コンフィグレーションはフラッシュROMにプログラムを焼くときに決まるので実行中の変更はできません。対してOSCCONでの設定はプログラムの実行時に変更可能です。OSCCONによるソフトウェア・コンフィグレーションでは、処理スピードを上げたい場合にはクロックスピードを上げ、遅くていいから消費電力を抑えたいような場合は低速クロックに切り替えるというようなことが可能です。(XLPをうたっているCPUはこのようなことがもっと柔軟にできるように設計されているようです)
ソフトウェア・コンフィグレーション(OSCCONで設定できるもの)
IDLEN: Sleep命令実行時にCPUをIdleにするかSleepにするか
IRCF: Internal Oscillatorの周波数設定(分周比の指定) 8, 4, 2, 1MHz, 500, 250, 125, 31KHzが選べる。
SCS: Primary Oscillator、Secondary Oscillator(Timer1 Oscillator)、Internal Oscillatorのいずれがを選ぶ
以上のように、SCSでクロックソースを選べるようになっていますし、Internal OscillatorはIRCFで周波数(実際には分周比)を変更できます。これら以外はすべてハードウェア・コンフィグレーションで設定しておきます。
ハードウェア・コンフィグレーション
これはプログラムをフラッシュROMに焼くときに設定するものです。やっていることは、CONFIGxレジスタのビット設定です。CONFIGxレジスタはメモリの特別な場所にあるレジスタです。(レジスタとは言えないかもしれませんが)

PIC 18F4553のコンフィグレーション・レジスタとその初期値
microchip社 18f4553のデータシートより抜粋
CONFIGxレジスタの設定にはコンパイラーに対する疑似命令 #pragma configを使います。設定は数値やビットパターンで行ってもよいのですが、便利なシンボルが定義されているので使ったほうがよいと思います。この設定用シンボルの説明はCコンパイラ XC8の以下のフォルダに、各CPUモデル毎のhtmlファイルにあるので、いつでも参照できます。
C:\Program Files\microchip\xc8\v1.xx\docs/chips\18f4553.html
実際の設定例
たとえばPrimary Oscillatorに20MHz(HS)の水晶振動子をつないで、ハードウェア・コンフィグレーションで、1/5分周(PLLDIV = 5)してPLLに4MHzを入力(PLLの入力は4MHzと決まっている)し、PLL出力 96MHzを作って、それを1/2に分周してUSB用の48MHzを得ます。つまりPrimary OscillatorをUSBのクロック源とします。
20MHzを1/2分周(CPUDIV = OSC2_PLL3)し、Primary Oscillator 10MHzを作ります。
プログラムの実行開始後の初期設定で、OSCCONのICRFをInternal Oscillator 4MHz(8MHzの1/2分周)に設定しておきます。次にOSCCONのSCSをPrimary Oscillatorに設定し1秒間隔でLEDを5回点滅させます。その後SCSでInternal Oscillatorに切り替え、2.5秒間隔でLEDを5回点滅させ、以降繰り返します。LEDの点滅スピードが変わるのでクロックが変更されていることがわかります。
点滅スピードはdelay_ms()で作りますが、_XTAL_FREQは10000000固定なので、クロックが変われば点滅スピードも変わります。
各項目で他に設定できる値はコメントにしてあります。
クロック関連以外の設定も含みますがほとんどはディセーブルかOFFです。
main.c
#include <xc.h>
#include <p18f4553.h>
//#pragma config Settings
//Register: CONFIG1L @ 0x300000
//CPUDIV = System Clock Postscaler Selection bits
#pragma config CPUDIV = OSC2_PLL3 //[Primary Oscillator Src: /2][96 MHz PLL Src: /3]
//#pragma config CPUDIV = OSC4_PLL6 //[Primary Oscillator Src: /4][96 MHz PLL Src: /6]
//#pragma config CPUDIV = OSC1_PLL2 //[Primary Oscillator Src: /1][96 MHz PLL Src: /2]
//#pragma config CPUDIV = OSC3_PLL4 //[Primary Oscillator Src: /3][96 MHz PLL Src: /4]
//PLLDIV = PLL Prescaler Selection bits
//#pragma config PLLDIV = 12 //Divide by 12 (48 MHz oscillator input)
//#pragma config PLLDIV = 4 //Divide by 4 (16 MHz oscillator input)
#pragma config PLLDIV = 5 //Divide by 5 (20 MHz oscillator input)
//#pragma config PLLDIV = 6 //Divide by 6 (24 MHz oscillator input)
//#pragma config PLLDIV = 1 //No prescale (4 MHz oscillator input drives PLL directly)
//#pragma config PLLDIV = 10 //Divide by 10 (40 MHz oscillator input)
//#pragma config PLLDIV = 2 //Divide by 2 (8 MHz oscillator input)
//#pragma config PLLDIV = 3 //Divide by 3 (12 MHz oscillator input)
//USBDIV = USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1)
//#pragma config USBDIV = 1 //USB clock source comes directly from the primary oscillator block with no postscale
#pragma config USBDIV = 2 //USB clock source comes from the 96 MHz PLL divided by 2
//Register: CONFIG1H @ 0x300001
//FCMEN = Fail-Safe Clock Monitor Enable bit
//#pragma config FCMEN = ON //Fail-Safe Clock Monitor enabled
#pragma config FCMEN = OFF //Fail-Safe Clock Monitor disabled
//IESO = Internal/External Oscillator Switchover bit
//#pragma config IESO = ON //Oscillator Switchover mode enabled
#pragma config IESO = OFF //Oscillator Switchover mode disabled
//FOSC = Oscillator Selection bits
#pragma config FOSC = HS //HS oscillator (HS)
//#pragma config FOSC = XTPLL_XT //XT oscillator, PLL enabled (XTPLL)
//#pragma config FOSC = ECPLLIO_EC //EC oscillator, PLL enabled, port function on RA6 (ECPIO)
//#pragma config FOSC = INTOSC_XT //Internal oscillator, XT used by USB (INTXT)
//#pragma config FOSC = INTOSC_EC //Internal oscillator, CLKO function on RA6, EC used by USB (INTCKO)
//#pragma config FOSC = ECPLL_EC //EC oscillator, PLL enabled, CLKO function on RA6 (ECPLL)
//#pragma config FOSC = EC_EC //EC oscillator, CLKO function on RA6 (EC)
//#pragma config FOSC = ECIO_EC //EC oscillator, port function on RA6 (ECIO)
//#pragma config FOSC = XT_XT //XT oscillator (XT)
//#pragma config FOSC = HSPLL_HS //HS oscillator, PLL enabled (HSPLL)
//#pragma config FOSC = INTOSC_HS //Internal oscillator, HS oscillator used by USB (INTHS)
//#pragma config FOSC = INTOSCIO_EC //Internal oscillator, port function on RA6, EC used by USB (INTIO)
//Register: CONFIG2L @ 0x300002
//PWRT = Power-up Timer Enable bit
#pragma config PWRT = OFF //PWRT disabled
//#pragma config PWRT = ON //PWRT enabled
//VREGEN = USB Voltage Regulator Enable bit
//#pragma config VREGEN = ON //USB voltage regulator enabled
#pragma config VREGEN = OFF //USB voltage regulator disabled
//BORV = Brown-out Reset Voltage bits
//#pragma config BORV = 0 //Maximum setting
//#pragma config BORV = 1
//#pragma config BORV = 2
#pragma config BORV = 3 //Minimum setting
//BOR = Brown-out Reset Enable bits
//#pragma config BOR = SOFT //Brown-out Reset enabled and controlled by software (SBOREN is enabled)
#pragma config BOR = ON //Brown-out Reset enabled in hardware only (SBOREN is disabled)
//#pragma config BOR = OFF //Brown-out Reset disabled in hardware and software
//#pragma config BOR = ON_ACTIVE //Brown-out Reset enabled in hardware only and disabled in Sleep mode (S
BOREN is disabled)
//Register: CONFIG2H @ 0x300003
//WDTPS = Watchdog Timer Postscale Select bits
//#pragma config WDTPS = 16384 //1:16384
//#pragma config WDTPS = 128 //1:128
//#pragma config WDTPS = 4 //1:4
//#pragma config WDTPS = 4096 //1:4096
//#pragma config WDTPS = 2048 //1:2048
//#pragma config WDTPS = 1024 //1:1024
//#pragma config WDTPS = 256 //1:256
//#pragma config WDTPS = 32 //1:32
#pragma config WDTPS = 32768 //1:32768
//#pragma config WDTPS = 16 //1:16
//#pragma config WDTPS = 8 //1:8
//#pragma config WDTPS = 1 //1:1
//#pragma config WDTPS = 8192 //1:8192
//#pragma config WDTPS = 512 //1:512
//#pragma config WDTPS = 2 //1:2
//#pragma config WDTPS = 64 //1:64
//WDT = Watchdog Timer Enable bit
//#pragma config WDT = ON //WDT enabled
#pragma config WDT = OFF //WDT disabled (control is placed on the SWDTEN bit)
//Register: CONFIG3H @ 0x300005
//CCP2MX = CCP2 MUX bit
//#pragma config CCP2MX = ON //CCP2 input/output is multiplexed with RC1
#pragma config CCP2MX = OFF //CCP2 input/output is multiplexed with RB3
//PBADEN = PORTB A/D Enable bit
//#pragma config PBADEN = ON //PORTB<4:0> pins are configured as analog input channels on Reset
#pragma config PBADEN = OFF //PORTB<4:0> pins are configured as digital I/O on Reset
//MCLRE = MCLR Pin Enable bit
#pragma config MCLRE = ON //MCLR pin enabled; RE3 input pin disabled
//#pragma config MCLRE = OFF //RE3 input pin enabled; MCLR pin disabled
//LPT1OSC = Low-Power Timer 1 Oscillator Enable bit
//#pragma config LPT1OSC = ON //Timer1 configured for low-power operation
#pragma config LPT1OSC = OFF //Timer1 configured for higher power operation
//Register: CONFIG4L @ 0x300006
//STVREN = Stack Full/Underflow Reset Enable bit
#pragma config STVREN = ON //Stack full/underflow will cause Reset
//#pragma config STVREN = OFF //Stack full/underflow will not cause Reset
//DEBUG = Background Debugger Enable bit
#pragma config DEBUG = OFF //Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
//#pragma config DEBUG = ON //Background debugger enabled, RB6 and RB7 are dedicated to In-Circuit Debug
//ICPRT = Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit
//#pragma config ICPRT = ON //ICPORT enabled
#pragma config ICPRT = OFF //ICPORT disabled
//LVP = Single-Supply ICSP Enable bit
//#pragma config LVP = ON //Single-Supply ICSP enabled
#pragma config LVP = OFF //Single-Supply ICSP disabled
//XINST = Extended Instruction Set Enable bit
//#pragma config XINST = ON //Instruction set extension and Indexed Addressing mode enabled
#pragma config XINST = OFF //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
//Register: CONFIG5L @ 0x300008
//CP0 = Code Protection bit
#pragma config CP0 = OFF //Block 0 (000800-001FFFh) is not code-protected
//#pragma config CP0 = ON //Block 0 (000800-001FFFh) is code-protected
//CP1 = Code Protection bit
#pragma config CP1 = OFF //Block 1 (002000-003FFFh) is not code-protected
//#pragma config CP1 = ON //Block 1 (002000-003FFFh) is code-protected
//CP2 = Code Protection bit
#pragma config CP2 = OFF //Block 2 (004000-005FFFh) is not code-protected
//#pragma config CP2 = ON //Block 2 (004000-005FFFh) is code-protected
//CP3 = Code Protection bit
#pragma config CP3 = OFF //Block 3 (006000-007FFFh) is not code-protected
//#pragma config CP3 = ON //Block 3 (006000-007FFFh) is code-protected
//Register: CONFIG5H @ 0x300009
//CPB = Boot Block Code Protection bit
#pragma config CPB = OFF //Boot block (000000-0007FFh) is not code-protected
//#pragma config CPB = ON //Boot block (000000-0007FFh) is code-protected
//CPD = Data EEPROM Code Protection bit
#pragma config CPD = OFF //Data EEPROM is not code-protected
//#pragma config CPD = ON //Data EEPROM is code-protected
//Register: CONFIG6L @ 0x30000A
//WRT0 = Write Protection bit
#pragma config WRT0 = OFF //Block 0 (000800-001FFFh) is not write-protected
//#pragma config WRT0 = ON //Block 0 (000800-001FFFh) is write-protected
//WRT1 = Write Protection bit
#pragma config WRT1 = OFF //Block 1 (002000-003FFFh) is not write-protected
//#pragma config WRT1 = ON //Block 1 (002000-003FFFh) is write-protected
//WRT2 = Write Protection bit
#pragma config WRT2 = OFF //Block 2 (004000-005FFFh) is not write-protected
//#pragma config WRT2 = ON //Block 2 (004000-005FFFh) is write-protected
//WRT3 = Write Protection bit
#pragma config WRT3 = OFF //Block 3 (006000-007FFFh) is not write-protected
//#pragma config WRT3 = ON //Block 3 (006000-007FFFh) is write-protected
//Register: CONFIG6H @ 0x30000B
//WRTB = Boot Block Write Protection bit
#pragma config WRTB = OFF //Boot block (000000-0007FFh) is not write-protected
//#pragma config WRTB = ON //Boot block (000000-0007FFh) is write-protected
//WRTC = Configuration Register Write Protection bit
#pragma config WRTC = OFF //Configuration registers (300000-3000FFh) are not write-protected
//#pragma config WRTC = ON //Configuration registers (300000-3000FFh) are write-protected
//WRTD = Data EEPROM Write Protection bit
#pragma config WRTD = OFF //Data EEPROM is not write-protected
//#pragma config WRTD = ON //Data EEPROM is write-protected
//Register: CONFIG7L @ 0x30000C
//EBTR0 = Table Read Protection bit
#pragma config EBTR0 = OFF //Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks
//#pragma config EBTR0 = ON //Block 0 (000800-001FFFh) is protected from table reads executed in other blocks
//EBTR1 = Table Read Protection bit
#pragma config EBTR1 = OFF //Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks
//#pragma config EBTR1 = ON //Block 1 (002000-003FFFh) is protected from table reads executed in other blocks
//EBTR2 = Table Read Protection bit
#pragma config EBTR2 = OFF //Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks
//#pragma config EBTR2 = ON //Block 2 (004000-005FFFh) is protected from table reads executed in other blocks
//EBTR3 = Table Read Protection bit
#pragma config EBTR3 = OFF //Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks
//#pragma config EBTR3 = ON //Block 3 (006000-007FFFh) is protected from table reads executed in other blocks
//Register: CONFIG7H @ 0x30000D
//EBTRB = Boot Block Table Read Protection bit
#pragma config EBTRB = OFF //Boot block (000000-0007FFh) is not protected from table reads executed in other blocks
//#pragma config EBTRB = ON //Boot block (000000-0007FFh) is protected from table reads executed in other blocks
#define PRIMARY_OSC 0
#define INTERNAL_OSC 2
#define INTERNAL_OSC_FREQ 6 //4MHz
#define LED PORTEbits.RE2
#define _XTAL_FREQ 10000000 //_delat_ms()のクロック周波数設定は10MHz
void delay_ms(int time){
int i;
for(i = 0; i < time; i++) __delay_ms(1);
}
void main(void){
ADCON1 = 0b00001111; //All Digital I/O
CMCON = 0b00000111; // No Comparator
TRISEbits.RE2 = 0; //GPIO RE2 = OUTPUT
OSCCONbits.IRCF = INTERNAL_OSC_FREQ; //Internal Oscillatorを4MHzに設定しておく
while(1){
OSCCONbits.SCS = PRIMARY_OSC; //Primary Oscillator(10MHz)に切り替える
for(int i = 0; i < 10; i++){
LED = !LED; //LEDを点滅させる
delay_ms(500); //500mS間隔
}
OSCCONbits.SCS = INTERNAL_OSC; //Internal Oscillator に切り替える
while(OSCCONbits.IOFS == 0); //Internal Oscillatorが安定か確認
for(int i = 0; i < 10; i++){
LED = !LED; //LEDを点滅させる
delay_ms(500); //10MHz/4MHz x 500ms = 1.25S間隔
}
} //while
} //main
(JF1VRR)