ikkei blog

電子工作やパズルのブログです。主にLEDを使った電子工作をやっています。

mikroCを試してみたらリエントラントになってないと言うエラーが

2013年06月21日 01時43分57秒 | PIC
今使っているのが、PIC16F678  ROMが2Kしかありません。
まだ、全部の機能が入っていないのに、RAM 93%、ROM 86%とひっ迫してきました。

XC8も有料版だと劇的に違うらしいのですが、そんな余裕はないので、
なんとか、フリーのコンパイラを探してみました。

すると、mikroCと言うのが、デモ版でも2Kまでコンパイル出来るらしいというので
さっそく、試してみました。

今のソースを入れてみたら、エラーの嵐。
ビット型が無いので、TXIFは、PIR1.TXIF と言う風に書かないとダメなのです。

ま、これは仕方ないので、どのレジスタなのか確認しながら
書き直せば良いだけです。
あとは、Configとか、設定でやらないといけないとか、
いろいろ有りましたが、ちょっと修正するだけでいけそうです。

あらかた、エラーが無くなってきたのですが、
例のシリアル送信の関数でこんなエラーが出ました。

Reentrancy is not allowed: function 'serial_tx1' called from two threads com.c

んー、リエントラントになってないか...
確かに受信割り込みの中からもACK返答で使ってるからなぁ。
でも、こんなエラー XC8では出なかったし。

と言うことで、文法的には XC8 より mikroCの方がチェックが厳しいのかも知れません。
ただ、今回のように半二重通信の場合、送信中に受信は出来ない訳で、実際には問題有りません。
Warning ウォーニングでも良かったんじゃないかと思ってしまいます。

ま、それらも別関数を作って、エラーが無くなりましたが、
結局RAM領域がオーバーフローしてしまいました。
えー、ダメじゃん。

XC8よりコード効率が高いかと思ったのですが、RAMが溢れては仕方有りません。

んー、やっぱりライセンス料払わないとダメかなぁ。

PICのparity generator はこうだ!

2013年06月19日 00時51分17秒 | PIC
先のサムチェック同様、なんとかして欲しいのがパリティジェネレータです。
大抵のマイコンのシリアルIFにはパリティビットを設定でき、
ハードで、パリティの計算もやってくれます。

ところが、ハードが貧弱なPICにはパリティビットは有っても
パリティジェネレータは有りません。
それは、ソフトでやってね。ってことだと思うのですが、
だったら、ソース付けとけって言いたいですね。

と言うのも、前任者はわざわざ4ビットのパリティ表を作って
2回参照して作っていたからです。

ググっても、1ビットずつ8回ループを回すと言った研修の演習のようなソースが。
もちろん、海外ならすごいコードが出てきます。
でも、アセンブラなので、SWAPとかCでは書けないコードを使っています。

で、私のコードはずばりこれです。
unsigned char get_parity(unsigned char w){
	w ^= w >> 4;
	w ^= w >> 2;
	w ^= w >> 1;
	return( w & 0x01 );
}
これは、偶数パリティの場合。
奇数の場合は、returnのところを
return( w & 0x01 ^ 0x01 );
に変えます。

トリッキーではないでしょ。

さらに、もう一つ言いたいことは、パリティって、
8ビットのパリティと 1ビットのパリティビット 
ではなく、9ビットのパリティだと言うことです。

9ビット分のパリティを計算して、それが0(偶数)なのか、1(奇数)なのか
と言うことなのです。

だから、送信時は8ビット分のパリティの結果を9ビット目に代入し、
void tx_byte(unsigned char data){
TX9D = get_parity(data);
TXREG = data;
txptr++;
}
受信時は8ビット分のパリティの結果と9ビット目をEXORして、0になるかチェックします。
ついでに、他のエラービットもチェック出来ます。
奇数パリティの場合、結果は1になるので、上記のように1を追加して、結果が0になるようにします。
void serial_rx(void){
unsigned char work;
if (rxptr < RXMAX){
work = RCREG;
if (((get_parity(work) ^ RCSTA) & 0x07) == 0){ // error check
if (rxptr <RXSIZE){
rxbuf[rxptr] = work;
}
rxptr++;
sum += work;
..........
ところで、組み込みでシリアルを使おうとすると、
当然、割り込みを使わざるを得ません。

でも、PICの本では、受信は割り込み処理で書かれていても、
送信はTXIFをポーリングするだけの処理が多いようです。
これでは、実際には使い物になりません。

9600ボーなら、10バイト程度でも10ms以上かかってしまうので、
待ってられないからです。

だから、送信も割り込みを使わざるを得ません。
でも、そう言う例はPIC本では見られません。

私のコードはこれです。
// シリアル出力開始 1バイト目出力と2バイト目セット
void serial_tx1(unsigned char num){
tx_num = num;
txptr = 0;
while(TXIF == 0); // ***
tx_byte(txbuf[txptr]);
if (tx_num > 1){
while(TXIF == 0);
tx_byte(txbuf[txptr]);
TXIE = 1; // serial tx interrupt enable
}
}


// シリアル割り込みで3バイト目以降セット
void serial_tx2(void){
tx_byte(txbuf[txptr]);
if (txptr >= tx_num){
TXIE = 0; // serial tx interrupt disable
}
}

txbuf[]に送信データをセットして、送信バイト数をパラメータにセットしてserial_tx1をコールします。
通常、送信したあと返事を待って送信するので、***の行は無くても構いません。

割り込み部分はこんな感じです。
//  interrupt
void interrupt ISP(void){
// serial rx interrupt
if (RCIF && RCIE){
serial_rx();
// serial tx interrupt
} else if (TXIF && TXIE){
serial_tx2();
// timer interrupt
} else if (T0IF){
TMR0 = T_STEP;
T0IF = 0;
timer0();
}
}
TXIF && TXIE の部分は TXIF & TXIE でも、良さそうですが、3バイト多くなってしまいます。
しかし、PICの場合、割り込みのエントリーが1つしかないので、
イネーブルフラグも見ないといけないのは、なんだかなぁ。って感じです。

多くのベクター方式の割り込みなら、こんな面倒なことはありません。
このあたりも、PIC本には受信割り込みだけの例しか無く、
イネーブルフラグも見ないといけないなんて、書いてません。

私が、学校でPICのアセンブラを教えるのはダメだと言う理由の一つに
このような、PIC固有の付帯事項(他のマイコンではほとんど出てこないので、知っていても応用できない)
が多すぎることなのです。

ほとんどの学生はこれら付帯事項を理解するのにおなか一杯になってしまい、
肝心のアセンブラコーディングの本質にたどり着かないのです。
結果、習ったはずなのに応用課程で何も出来ない人続出ってことに。

しかし、PICに使われている記号やニーモニックはなぜにこんなに不統一なのでしょうか?
送信がTXIF なのに、受信はRXIFではなくRCIF
タイマ0は、T0IEなのに、タイマ1は、TM1IEだったり、
こんな行き当たりばったりをユーザに押しつけないで欲しいものです。



Fusion PCB に基板発注したらpendingだって

2013年06月18日 21時15分29秒 | 電子工作
先日、Fusion PCBに基板を発注したら、
status: Pending.

って言われてしまった。

you should add the global outline on it.

どうやら、面付けした場合に全体の外形線が必要だったみたい。
だと思ったよ。orz

仕様通りのコーディングよりも意図をくみ取るコーディング

2013年06月17日 22時56分37秒 | 組み込みソフト
昔のコーディングは限られたROM容量に収めるために
1バイトでも少なくするために職人技や、トリックコードを使ったものですが、
最近ではCPUのスピードも上がり、ROM,RAMなどリソースも潤沢なため、
誰が見ても分かるようにトリッキーなコードを書かないのが推奨されています。
研修では、私もそのように教えてきました。

でも、これってコード書くのつまらなくないですか?

ところが、PICやAVRなどリソースが限られているマイコンだと
工夫のしどころがあるし、おもしろみのあるコードが書けます。


例えば、
チェックサムの計算ですが、
送信時にはデータ部の合計値の下8ビットの2の補数をチェックサムとします。

この場合、受信時にどうするか?

前任者の書いたコードはアセンブラでこんな感じです。

データ部の合計値の8ビットはsumという変数に入れたあと、
	COMF	sum,F  ;反転
	INCF	sum,W  ;+1
	XORWF	INDF,W ;チェックサムと照合

んー、確かに2の補数ってのは反転して1を加えたもので、
チェックサムと合っているかをチェックしています。
教科書に書いてあるかのように、仕様通りです。

悪くは有りません。ちゃんと正しく動作します。

でもね。
なぜ、チェックサムにわざわざ2の補数を使っているのか、
照合するだけだったら、合計値のままでも構わないでしょう。

2の補数を使っている意図をくみ取れなかったのでしょうか?
sum の2の補数というのは -sum と言うこと。

だから、
データ部だけでなく、チェックサムまで含めて合計すると 0 になるのです。
つまり、受信時にはチェックサムまで含めて合計したあと
0 になっているかをチェックするだけで良いのです。
アセンブラならなおさらコード量が削減できます。

でも、そんなコードを書いたら
意図の分からない人にはチンプンカンプン、
なんか変なことやってんじゃないの、
大丈夫?!
って逆にダメ印を付けられそう。

あー、やだやだ。
この程度で職人コードって言われたくない。

私は意図をくみ取ったスマートなコードを書きたい。
そうでなければ、コーディングの面白さがありません。


「ちっちゃいーの」でメッセージ表示

2013年06月16日 16時40分02秒 | Arduino
「ちっちゃいーの」ですが、NT京都で宿題を頂いていました。
それは、パターンではなくメッセージを切り替えて表示したいと言う物でした。

サンプルからの修正は簡単に出来そうだと思っていたのですが、
けっこう大変で、今になってしまいました。

ついでに、長いメッセージも出来るように、
文字列をROMに配置するようにしてみました。


ここからダウンロードして下さい。
メッセージを入れ換える場合、半角英数はそのまま、
ひらがなやカタカナは付属のExcelの変換表に1文字づつ入れて変換して下さい。