TAP-PicMicrocontroler

C2C-Cコンパイラに関するページ


c2cコンパイラを中心としたPICに関する情報を掲示しています。

PICでCコンパイラを使う利点は、わずらわしいページング処理を自動で行ってくれるということがあります。メモリがリニアではないためにあいたところに変数を作ってくれます。もちろん、アセンブラの方がタイトなコードが記述できますが、常に仕様変更が起こる可能性のある場合などにおいては、よりすばやくコーディングが可能となると思います。

c2cコンパイラに関しては、フリーであることが最大の利点です(Linux版のみ)。作者曰く、最近のバージョンはWin版は期間のみ制限で機能はフル機能だそうです。まあ、アセンブラより速く開発ができるかもしれないといった感じです。いくつかの注意点さえ守れば結構ドメインな処理ができるので私には使いやすいです。またあたらしいチップができたときやバグの対策も早いです。(私のときはメール送って3,4日で解決してくれました)

  PICをc2cで開発する 
PIC用Linux版フリーCコンパイラであるc2cコンパイラについてのレポートです。16F877を使用したペリフェラル関連(ADCなど)のプログラム例があります。
●c2cコンパイラーの使い方
●c2cコンパイラのプログラム例やライブラリ
●Links


   c2cコンパイラーの使い方

●c2cコンパイラーについて

c2cコンパイラーはPIC,SXなどのための専用Cコンパイラーです。

c2cコンパイラーのページ

c2cコンパイラーはLinux版に限りフリーソフトとなっているようです。
The Linux version of the compiler is free for non-profit use and shareware for commercial use.
とのことです。現在のバージョンは3.27.8であり、結構使えるものとなってきているようです。
不都合(バグ?)もいくつかありますが、そこだけ注意すれば使えるのではないかと思います。いずれにせよこのようなすばらしいソフトをフリーで公開していただけるだけでも、作者のPavelさんはじめ関係者に感謝したいと思います。

Win版の最新版はポインタなども使えたり、c++やパスカルまであります。

●インストール

インストールといっても展開してできた実行ファイルを実行するだけです。どこかのフォルダに展開してシンボリックリンク(c2cという名前にしておきましょう)を作ってパスを通しておきましょう。

ためしに

c2c

と実行してみると

C2C-plus 3.27.8e C-compiler.  Copyright(c) 1998-99,2000 by Pavel Baranov.
pavel@worldonline.nl
Free copy for non-profit use
Shareware copy for commercial use
-I<include file>	assembler include file name
-o<output file>		output file name
-vs<num>		variable start address
-ndi			no default interrupt handler
-ols			one local space
-lib			output is a library
-P<processor>		generate code for <processor>
-SXHEX			generate hex-file for Scenix target
-md			mul/div as separate functions(not inline)
-nosc			generate code for all functions
-Ox			extra optimization levels(0,1 or 2)
-SRC			insert C-code into assembler
-D<string>		defines the <string>
-nsc			don't save context during interrupt
-? or -h		this help
Supported processors:
SX18L      SX28L      SX18       SX28       PIC12C508  PIC12C508A PIC12C509
PIC12C509A PIC12CR509APIC12CE518 PIC12CE519 PIC16C52   PIC16C54   PIC16CR54
PIC16C55   PIC16C56   PIC16CR56  PIC16C57   PIC16CR57  PIC16C58   PIC16CR58
PIC16C61   PIC16C62   PIC16C62A  PIC16C62B  PIC16CR62  PIC16C63   PIC16C63A
PIC16CR63  PIC16C64   PIC16C64A  PIC16CR64  PIC16C65   PIC16C65A  PIC16C65B
PIC16CR65  PIC16C66   PIC16C67   PIC16C71   PIC16C72   PIC16C72A  PIC16CR72
PIC16C73   PIC16C73A  PIC16C73B  PIC16C74   PIC16C74A  PIC16C74B  PIC16C76
PIC16C77   PIC16F83   PIC16CR83  PIC16C84   PIC16F84   PIC16F84A  PIC16CR84
PIC16C620  PIC16C620A PIC16CR620APIC16C621  PIC16C621A PIC16C622  PIC16C622A
PIC16CE623 PIC16CE624 PIC16CE625 PIC16F627  PIC16F628  PIC16C641  PIC16C642
PIC16C661  PIC16C662  PIC16C710  PIC16C711  PIC16C712  PIC16C715  PIC16C716
PIC16C773  PIC16C774  PIC16F873  PIC16F874  PIC16F876  PIC16F877  PIC16C923
PIC16C924

こんな感じでバージョン、対応機種などが表示されます。説明書も入っています。

実行ファイル形式で公開されてるせいか、Slackware7.0では動きましたがそれ以前のバージョンでは動きませんでした。Vineでは動きました。RedHat系で開発されているようです。

●使い方

ためしに何かコンパイルしてみましょう。

test.c : **********

int x;
char func(char a);
void main(void)
{
	char i;
	
	x = 0;
	for(i = 0;i < 10;i++){
		x = x + func(i);
	}
}
char func(char a)
{
	return (a + 1);
}
void interrupt(void)
{
	x = x + 1;
}

ここで

c2c -PPIC16F877 test.c

と実行するとtest.asmができます。*.asmファイルはそのままMPLABに読み込んで*.hexファイルを作りライターで書き込むことができます。

test.asm : **********

; This file was generated by C2C-plus compiler version 3.27.8e
	include "p16F877.inc"
	;Variables *****************************************
_intr_tmp_0000                  equ 0x70
_code_tmp_0000                  equ 0x71
_code_tmp_0001                  equ 0x72
_code_tmp_0002                  equ 0x73
__int_save_cont_W               equ 0x74
__int_save_cont_STATUS          equ 0x75
__int_save_cont_FSR             equ 0x76
__int_save_cont_PCLATH          equ 0x77
param00_func                    equ 0x78
_i_main                         equ 0x79
_x                              equ 0x7a
	ORG 0
	clrf PCLATH
	goto start__code
	ORG 4
_interrupt
_interrupt__code
	movwf __int_save_cont_W
	swapf __int_save_cont_W, F
	swapf STATUS, W
	movwf __int_save_cont_STATUS
	swapf FSR, W
	movwf __int_save_cont_FSR
	swapf PCLATH, W
	movwf __int_save_cont_PCLATH
	clrf PCLATH
	movf _x+1, W
	movwf _intr_tmp_0000 
	movlw 0
	addwf _intr_tmp_0000 , F
	movf _x, W
	addlw D'1'
	btfsc STATUS, C
	incf _intr_tmp_0000 , F
	movwf _x
	movf _intr_tmp_0000 , W
	movwf _x+D'1'
	swapf __int_save_cont_PCLATH, W
	movwf PCLATH
	swapf __int_save_cont_FSR, W
	movwf FSR
	swapf __int_save_cont_STATUS, W
	movwf STATUS
	swapf __int_save_cont_W, W
	retfie
_interrupt__end
_func
	goto _func__code
start__code
_main__code
	clrf _x
	clrf _x+D'1'
	clrf _i_main
label_0000
	movlw D'10'
	subwf _i_main, W
	btfsc STATUS, C
	goto label_0001
	movf _x+1, W
	movwf _code_tmp_0000 
	movf _x, W
	movwf _code_tmp_0001 
	movf _i_main, W
	movwf param00_func
	call _func
	bcf PCLATH, 3
	bcf PCLATH, 4
	addwf _code_tmp_0001 , W
	btfsc STATUS, C
	incf _code_tmp_0000 , F
	movwf _x
	movf _code_tmp_0000 , W
	movwf _x+D'1'
	incf _i_main, F
	goto label_0000
label_0001
_main__end
_func__code
	clrf _code_tmp_0002 
	movf param00_func, W
	addlw D'1'
	btfsc STATUS, C
	incf _code_tmp_0002 , F
	return
_func__end
	END

このような出力になりました。割り込みも使えます(コンテクストの保存・復帰もやってくれます)。またPICのアセンブラコーディングの際の例にもなりそうです。ただCコンパイラとしての汎用性のためかアセンブラよりも冗長な部分が多いのは確かです。(基本がC言語が関数でくくる仕様のためでしょうか)

●コンパイラについて

c2cコンパイラーの特徴および注意点(バグではなくて仕様です的な)をまとめてみたいと思います。

・プロセッサの指定について
コンパイルオプションで-PPIC16F877としてみましたが、-PPIC16F84とした場合とはまったく異なるコードを吐き出します。F877でコンパイルした場合は毎回RAMページングやCODEページングテーブルの参照をしていますが、F84でコンパイルした場合にはこのようなコードは見当たりません。よってF84の場合にはRAMページング(TRISAなど)を明示的に行う必要があります。

これに関しては私もF877のプログラム時にPavelさんにmailを送ってpage correctionを改良していただきました。毎回correctionを行うように提案したのですが、このためか少し冗長なコンパイルを行うようになってしまったようです。このあたりがPICとCコンパイラーの相性の悪いところでしょう。(ほかのコンパイラはどうなってるんでしょうか?)

・割り込みに関して
通常ホビーで使うのはF84とF877くらいでしょうか。F877では0x70以降のバンク共通メモリにコンテキストをsaveしてくれます。(3.27.6以降)

・プログラム上の注意
できないこと(バグではなく実装がされていないものも含む)をあげたいと思います。

----コードページングの問題----
コードがページングをまたがる際に処置をしてくれません。つまり1関数内でページングを超えてはいけないということです。別関数として別コードページに関数をおくことは可能です。そこで関数の開始番地をある程度指定(制御)しなくてはなりません。ただしこの仕様の方がコードを管理しやすいと思います。

----算術命令について----
++,--などはありますが+=,-=などはできません。またC言語的な美しさ(トリッキーさ)を求めたような?命令は避けたほうがよいでしょう。
使える演算子は
+,-,*,/,<<,>>,++,--
くらいと思ったほうがよさそうです(現状では実際に使えません)。また入れ子をすると余計にRAMを食いますのでこれも避けたほうがよさそうです。

----変数、標準関数について----
配列についてですが、配列の番地の指定時に変数を使うとFSRを使ってIndirectアクセスを行います。そうするとスピードがかなり遅くなってしまいます。数字で指定したときはそのままdirectにアクセスしているようです。
またswitch(x)のxに配列を使うことはできません(たぶんバグですが、もうだいぶPavelさんにメールを送りつけてしまったので、これ以上送るのは申し訳ないです、笑)。またswitch後はbreakしなくてもswitchを抜けてしまいます(これにもはまりました)。

----機能レジスタについて----
最近になって拡張された機能レジスタはユーザー側が作るほうがよいという見解を示しているようです。たとえばF877のEEPROMアクセスについては、
char _EEDATA@0x10c;
char _EEADR@0x10d;
char _EEDATAH@0x10e;
char _EEADRH@0x10f;
char _EECON1@0x18c;
char _EECON2@0x18d;
といった感じで再定義しなおしています。この仕様でいいと思います。ただしどのPICにも実装されていてしかもアドレスが同じもの(FSR,OPTIONなど)は実装されています。

----ライブラリや関数について----
ライブラリはほとんどありません。(説明書を参考ください、ソフトウェアシリアル通信はbuilt inされています。)
また関数のコールは避けて迷わすgoto命令を使ったほうがすっきりして早いです。PICはスタックが浅いのでこの方がよいでしょう。

----const charについて----
このバージョンでは使用しないほうがいいと思います。0x00-0xff,0x100-0x1ffといった境界でバグります。これらの対処はなされていませんので(現バージョンでは)、自分でルーチンを作ったほうがよさそうです。(関数にラッピングして関数の開始番地を指定するなど。)

----continue文について----
continue文を実行するとfor(i=0;i<4;i++)文などでiをインクリメントしてくれません。for文の最後にジャンプ(goto文などで)するようにしないといけません。

----インラインアセンブラについて----
インラインアセンブラ上ではページング処理はもちろん行ってくれません。そこで、アセンブラを書くときは

はじめに
char page0@0x20
char x@0x21;
と変数の番地を設定しておきCプログラム中で
page0 = 0;/*dummy*/
といった形でダミーの書き込みを行ってページングを合わせます。
(コンパイラ自身にページングを認識させるため)その後、
asm:start_asm
asm{
movf _x,w
addlw d'10'
movwf _w
}
asm:end_asm

のようにすればページングを処理できます。アセンブラで扱う変数のアドレスを合わせることとアセンブラに入る前にページをあわせるためのダミー処理を入れれば大丈夫です。

----ビルトインdelay_sについて----
引き数のパラメータがページ0以外に設定されたとき動きません。delay_ms,delay_usは動くので秒単位のディレーは自分で作成したほうがいいです。

・まとめ
大体以上の点を守ればとても便利な感じです。基本はアセンブラの拡張のようなものだと思います。早く手軽にプログラムが作れる点ではよい選択になるのではないかと思います。

●書き込みまでの流れについて

コンパイルしたアセンブラファイルをMPLABに読み込みコンパイルします。できたものを書き込みます。私はSAMBAを利用してWIN95からLinux上のファイルを更新し、コンパイルして、WIN95へ持ってきて後の作業をWIN95で行っています。けれどもはじめは文字コードを変換するのを忘れて少しはまりました、笑。秋月の書き込みキットをバージョンアップしながら使用しています。

・追伸(2000/06/16)
と書たところ、Linuxで秋月ライタを使えるプログラムを作成されている方からメールをいただきました。宮本さんのページです。早速使ってみたところGoodでした(秋月ライターより早い?)。F877やF84その他主要なPICはgpasmに対応しているのですべてLinux上で開発できそうです。とても快適です。


   c2c-lib

プログラムの例をおいておきます。

これです。

16F877用です。これくらいのプログラムが可能です。
LCD,ADC,シリアル通信,EEPROMアクセス,タイマー割り込みなどの例と関数があります。
const charも使っていますが、これは実際は使用しないほうがいいです(上述)。私はEEPROMに書き込み時に書いておきそれを文字列として使用しています。

c2c -PPIC16F877 test.c

でコンパイルします。

注意点 :
・プログラム開始番地を指定してページングがプログラムの流れの中で起こらないようにしている。
・最初にペリフェラル関連の定義をしている。
・ディレイ用の#pragmaを指定している。


   感想

C2Cコンパイラは作者いわく、最も低価格なコンパイラだそうです。私にとってはとてもダイレクトな構造のコンパイラでとても使いやすいです。バグは多いですし(多分上記のでほとんどだと思う)、ライブラリに期待するような短期間の開発には向かないかもしれませんが、ライブラリは自分で書くよとか、インラインアセンブラでバリバリという時にはいい選択になるかも知れません。Win用のものはもう少し進んでいるはずなのでそれはまた別の機会に調べてみたいと思います。


return to home page