PIC18F14K50 (4)

Microchip 社の USB フレームワークコンパイルには同社の「C18」コンパイラが必要ですが、無償でダウンロードできる「評価版」には、60 日経過すると最適化機能が制限されるという制約があります。
そのため、対象のチップに関する経験が少ないままコンパイラをダウンロードして使い始めると、内蔵モジュールの扱いに慣れてきたころに最適化の制約がかかるという悲しい状態になってしまいます。
単なるアプリケーションであれば、最適化レベルが下がっても、どうということはないのですが、ブートローダなどのように、コード・サイズに絶対的な制約があるものに手を入れようとした場合には、最適化レベルが下がってしまうのは困ります。
そので、C18 コンパイラを使い始める前に、他のフリーな言語を使用して経験を積むことにしました。
それは、最近知ったのですが、「JALv2」というコンパイラです。
JAL」というと、どこかの景気の悪い会社みたいですが、「Just Another Language」の意味で、「JALv2」 を簡単に言えば、

ということになります。
言語仕様が強固に定まっているわけでないので、現在のコンパイラで通るソース・プログラムが、将来のコンパイラでも通用するのかという、「永続性」に不安もありますし、他のアーキテクチャマイコンで使える「可搬性」もないのですが、そこを割り切って、プログラムは「書き捨て」「使い捨て」でいいや、と考えれば価値はあります。
コンパイラ本体は

http://www.casadeyork.com/jalv2/

からダウンロードできますが、サポートされているデバイスの数が限られているので、「jallib」プロジェクト

http://code.google.com/p/jallib/

から最新版の「jallib-pack-2.4m-0.5.0.zip」をダウンロードして使います。
コンパイラ本体、デバイス・ファイル、ドキュメント、サンプル・プログラムなどが含まれており、PIC18F14K50 デバイスもサポートされています。
18F14K50 のレジスタ設定プログラムを JALv2 で書いて示しますが、単にレジスタをビット単位で設定しているだけなので、特に JALv2 の文法について理解する必要もなく、「--」以降がコメントとして扱われることだけを知っていれば十分です。 (C/C++ の「//」に相当)
下に「555」相当の機能に設定するプログラムを示します。
前回の図の設定をプログラムとして表現したものです。

--------------------------------------------------
-- 18f14k50_555_1.jal:
--
-- "555" type oscillator for PIC18F14K50
-- using comparator / SR-Latch / Vref (DAC1) module
-- Vdd ratiometoric operation
--
-- 18F14K50   "555"
--   pin       pin
--   ---       ---
--    6         3   (OUTPUT)
--   15        2,6  (TRIGGER, THRESHOLD)
--   16        --   (External 1/3 Vdd divider)
--------------------------------------------------
-- START OF TARGET CHIP DEPENDENT DECLARATIONS ---

include 18f14k50

if (PIC_18F14K50 == target_chip) then
-- 12 MHz crystal x4 PLL = 48 MHz clock
  pragma target clock 48_000_000
-- use with Microchip HID bootloader (2 K Word = 4 K byte)
  pragma bootloader loader18 4096
end if

-- END OF TARGET CHIP DEPENDENT DECLARATIONS ---
------------------------------------------------

procedure vref_init() is
  REFCON0_FVR1EN = 1   -- enable Fixed Voltage Reference 1
  REFCON0_FVR1S1 = 1   -- 4 x 1.024 V
  REFCON0_FVR1S0 = 1   -- 4 x 1.024 V
  REFCON1_D1EN   = 1   -- DAC1 enable
  REFCON1_DAC1OE = 0   -- DAC1 Output disable
  REFCON1_D1PSS  = 0x0 -- DAC1 Positive Source Select = Vdd
  REFCON1_D1NSS0 = 0   -- DAC1 Negative Source Select = Vss
  REFCON2        = 21  -- DAC1 out = (21/32) vdd = (2/3) Vdd
end procedure

procedure comparator_init() is
  CM1CON0_C1ON   = 1 -- C1 ON
  CM1CON0_C1OE   = 0 -- C1 internal only
  CM1CON0_C1POL  = 1 -- C1 inverted
  CM1CON0_C1SP   = 1 -- C1 high speed
  CM1CON0_C1R    = 1 -- C1 C1VIN+ = C1Vref
  CM1CON0_C1CH   = 1 -- C1 C1VIN- = C12IN1- (pin 15)

  CM2CON0_C2ON   = 1 -- C2 ON
  CM2CON0_C2OE   = 0 -- C2 internal only
  CM2CON0_C2POL  = 0 -- C2 not inverted
  CM2CON0_C2SP   = 1 -- C1 high speed
  CM2CON0_C2R    = 0 -- C2 C2VIN+ = C12IN+  (pin 16)
  CM2CON0_C2CH   = 1 -- C2 C2VIN- = C12IN1- (pin 15)
  
  CM2CON1_C1RSEL = 0 -- C1 C1Vref = Vref
  CM2CON1_C1HYS  = 0 -- C1 hysteresis disabled
--  CM2CON1_C1HYS  = 1 -- C1 hysteresis enabled
  CM2CON1_C1SYNC = 0 -- C1 output asynchronous
  
  CM2CON1_C2RSEL = 1 -- C2 C2Vref = FVR
  CM2CON1_C2HYS  = 0 -- C2 hysteresis disabled
--  CM2CON1_C2HYS  = 1 -- C2 hysteresis enabled
  CM2CON1_C2SYNC = 0 -- C2 output asynchronous
  
-- set tri-state mode for comparator/vref input pins
  TRISC_TRISC0   = 1 -- RC0/AN4/C12IN+/VREF+  (pin 16)
  TRISC_TRISC1   = 1 -- RC1/AN5/C12IN1-/VREF- (pin 15)
--  TRISC_TRISC2   = 1 -- RC2/AN6/C12IN2-/CVREF (pin 14)
--  TRISC_TRISC3   = 1 -- RC3/AN7/C12IN3-/PGM   (pin 7)

-- enable analog input for comparator/vref
  JANSEL_ANS4    = 1 -- RC0/AN4/C12IN+/VREF+  (pin 16)
  JANSEL_ANS5    = 1 -- RC1/AN5/C12IN1-/VREF- (pin 15)
--  JANSEL_ANS6    = 1 -- RC2/AN6/C12IN2-/CVREF (pin 14)
--  JANSEL_ANS7    = 1 -- RC3/AN7/C12IN3-/PGM   (pin 7)
end procedure

procedure SR_Latch_init() is
  SRCON0_SRLEN  = 1 -- SR Latch enabled
  SRCON0_SRQEN  = 0 -- SR Latch Q  out disabled
  SRCON0_SRNQEN = 1 -- SR Latch Q* out enabled on RC4/SRQ pin
  
  TRISC_TRISC4  = 0 -- set RC4/SRQ pin to output
  
  SRCON1        = 0x00 -- at first, disable all S/R inputs
  SRCON1_SRSC1E = 1 -- SR Latch C1   set enabled
  SRCON1_SRRC2E = 1 -- SR Latch C2 reset enabled
end procedure
  
vref_init()
comparator_init()
SR_Latch_init()

この設定では、コンパレータ 1 の比較電圧を内蔵の Vref モジュールで Vdd の約 2/3 に設定しており、コンパレータ 2 の比較電圧は外部で Vdd を抵抗分圧して作り出し、16 番ピンから入力するようになっています。
6 番ピンと 15 番ピンとの間に 120 kΩ の抵抗をつなぎ、容量はストレー容量だけの状態で、約 480 kHz で発振しました。
15 番ピンにオシロのプローブをつないだり、手で触れたりすると 200 kHz 程度まで周波数が落ち、容量が検知できることが分かります。
この構成では、タイミング・コンデンサの充放電電流は Vdd に依存するのですが、コンパレータの比較電圧も Vdd 依存なので、両者がキャンセルし合って、いわゆる「レシオメトリック」動作となって、出力周波数には Vdd 依存性がなくなります。(理想的な場合)
アナログ・シンセの VCO では、アンチログ回路の出力電流がタイミング・コンデンサの充電電流となり、この電流を Vdd に依存しない一定値に保つなら、コンパレータの比較電圧も定電圧とする必要があります。
下のプログラムでは、コンパレータ 1 の比較電圧には内蔵 1.024 V 基準電圧の 4 倍の 4.096 V を与え、コンパレータ 2 の比較電圧には Vref (DAC1) 回路で (8/32) = (1/4) 倍に分圧した 1.024 V を与えています。

--------------------------------------------------
-- 18f14k50_555_2.jal:
--
-- "555" type oscillator for PIC18F14K50
-- using comparator / SR-Latch / Vref (DAC1) module
-- internal fixed voltage reference (Vdd independent) used
--
-- 18F14K50   "555"
--   pin       pin
--   ---       ---
--    6         3   (OUTPUT)
--   15        2,6  (TRIGGER, THRESHOLD)
--------------------------------------------------
-- START OF TARGET CHIP DEPENDENT DECLARATIONS ---

include 18f14k50

if (PIC_18F14K50 == target_chip) then
-- 12 MHz crystal x4 PLL = 48 MHz clock
  pragma target clock 48_000_000
-- use with Microchip HID bootloader (2 K Word = 4 K byte)
  pragma bootloader loader18 4096
end if

-- END OF TARGET CHIP DEPENDENT DECLARATIONS ---
------------------------------------------------

procedure vref_init() is
  REFCON0_FVR1EN = 1   -- enable Fixed Voltage Reference 1
  REFCON0_FVR1S1 = 1   -- 4 x 1.024 V
  REFCON0_FVR1S0 = 1   -- 4 x 1.024 V
  REFCON1_D1EN   = 1   -- DAC1 enable
  REFCON1_DAC1OE = 0   -- DAC1 Output disable
  REFCON1_D1PSS  = 0x2 -- DAC1 Positive Source Select = FVR
  REFCON1_D1NSS0 = 0   -- DAC1 Negative Source Select = Vss
  REFCON2        = 8   -- DAC1 out = 4.096 * (8/32) = 1.024 V
end procedure

procedure comparator_init() is
  CM1CON0_C1ON   = 1 -- C1 ON
  CM1CON0_C1OE   = 0 -- C1 internal only
  CM1CON0_C1POL  = 1 -- C1 inverted
  CM1CON0_C1SP   = 1 -- C1 high speed
  CM1CON0_C1R    = 1 -- C1 C1VIN+ = C1Vref
  CM1CON0_C1CH   = 1 -- C1 C1VIN- = C12IN1- (pin 15)

  CM2CON0_C2ON   = 1 -- C2 ON
  CM2CON0_C2OE   = 0 -- C2 internal only
  CM2CON0_C2POL  = 0 -- C2 not inverted
  CM2CON0_C2SP   = 1 -- C1 high speed
  CM2CON0_C2R    = 1 -- C2 C2VIN+ = C2Vref
  CM2CON0_C2CH   = 1 -- C2 C2VIN- = C12IN1- (pin 15)
  
  CM2CON1_C1RSEL = 1 -- C1 C1Vref = FVR
--  CM2CON1_C1HYS  = 0 -- C1 hysteresis disabled
  CM2CON1_C1HYS  = 1 -- C1 hysteresis enabled
  CM2CON1_C1SYNC = 0 -- C1 output asynchronous
  
  CM2CON1_C2RSEL = 0 -- C2 C2Vref = Vref
--  CM2CON1_C2HYS  = 0 -- C2 hysteresis disabled
  CM2CON1_C2HYS  = 1 -- C2 hysteresis enabled
  CM2CON1_C2SYNC = 0 -- C2 output asynchronous
  
-- set tri-state mode for comparator/vref input pins
--  TRISC_TRISC0   = 1 -- RC0/AN4/C12IN+/VREF+  (pin 16)
  TRISC_TRISC1   = 1 -- RC1/AN5/C12IN1-/VREF- (pin 15)
--  TRISC_TRISC2   = 1 -- RC2/AN6/C12IN2-/CVREF (pin 14)
--  TRISC_TRISC3   = 1 -- RC3/AN7/C12IN3-/PGM   (pin 7)

-- enable analog input for comparator/vref
--  JANSEL_ANS4    = 1 -- RC0/AN4/C12IN+/VREF+  (pin 16)
  JANSEL_ANS5    = 1 -- RC1/AN5/C12IN1-/VREF- (pin 15)
--  JANSEL_ANS6    = 1 -- RC2/AN6/C12IN2-/CVREF (pin 14)
--  JANSEL_ANS7    = 1 -- RC3/AN7/C12IN3-/PGM   (pin 7)
end procedure

procedure SR_Latch_init() is
  SRCON0_SRLEN  = 1 -- SR Latch enabled
  SRCON0_SRQEN  = 0 -- SR Latch Q  out disabled
  SRCON0_SRNQEN = 1 -- SR Latch Q* out enabled on RC4/SRQ pin
  
  TRISC_TRISC4  = 0 -- set RC4/SRQ pin to output
  
  SRCON1        = 0x00 -- at first, disable all S/R inputs
  SRCON1_SRSC1E = 1 -- SR Latch C1   set enabled
  SRCON1_SRRC2E = 1 -- SR Latch C2 reset enabled
end procedure
  
vref_init()
comparator_init()
SR_Latch_init()

この設定では、120 kΩ + ストレー容量で、約 280 kHz で発振しました。
前の例より周波数が下がっているのは、前の例では振幅が約 1.7 V だったのに対し、この例では、振幅が約 3 V と大きくなっているためです。