PIC32MX MIPS32 割り込み Port反転

2016年9月21日

修正:PIC32にはinvというアセンブラ命令があり、ビット反転できます。
plib.hにはPORTToggleBitsというのがあるので、それを使うのが安全でしょう。
アセンブラを見た感じ、この関数を使わないとダメみたいです。

下は、例によって何を言っているのか分からないのでスルーで。酔ってったからかもw


以前 SH2 を使ったことがあるので、最近と言うか今さら気になったこと。
PIC32MX は MIPS32 か MIPS16 命令を使っているわけだが、LATA とかポート出力で、
LATAbits.RA1 = 0;
を実行すると、上位の割り込みで同じアドレスを変更するプログラムが有る場合、おかしなことにならないか。ということ。
アセンブラレベルでは以下になる。(コンパイラがどうアセンブラを作るかですが、それは置いといてざっくり言ってこんな感じ。


LATAbits.RA0 = a ? 1 : 0;
↓
if(a) {
LATA = LATA | 0x0001;
}
else {
LATA = LATA & 0xFFFE;
};

この場合、LATA のアドレスを読み出し、&とか|とかして LATA のアドレスに書き戻している。
参照・変更・書き戻し
この処理を上位と下位(mainも)の割り込みで同じことをした場合、下位で LATA を書き戻す直前に、上位の割り込みが入り同じことをしても上位のプログラムが終了後、下位のプログラムで LATA を書き潰す
こう言った同じアドレスを個別の割り込みで変更する場合には、下位の方で割り込みを禁止すると問題が起きない。
そういえば CoreTimer を調べたときにサンプルコードが、割り込みを止めて、割り込みフラグ有効にして、割り込みを有効にしていた。
で、なぜ SH2 の話で PIC32 が気になったかと言うと、今までの PIC では「bit set/clear」があったが(無かった)、PIC32 は MIPS 命令なので、「bit set/clear」あるのか?と言うこと。
MIPS は RISC 系で、今までは CISC。なかったので、どうなんだろう。命令セットみる限りだと RISC になるのかな?
とりあえず H8 とかと同じ感じでビットフィールドを触ると危険と言うことで。
「bit set/clear」とは、変数の好きな場所にいきなり bit 単位で書く事が出来る事。参照・変更・書き戻しがない。
アセンブラ的には、


LATAbits.RA0 = a ? 1 : 0;
↓
if(a) {
bit set LATAbits.RA0;
}
else {
bit clear LATAbits.RA0;
}

今までの PIC は 有ったはず。PIC18 はあるのを知っていて、多分 dsPIC33 でもあると思う。
有ると決め打ちしていたので、これも怪しい。
PIC32 で、LATAbits.RA1 = 0;
を、逆アセンブルしてみた。ADDI を使っている。
MIPS は全然知らないので、調べてみたところ、単純にレジスタのデータをいじっているだけらしい。
最初に書いたプログラムとして実行されている。なのでポートも RA1 を変更している間に RA2 を変更しても上書きされる。
この動き、名前が付いていた気がするのですが、ぐぐっても見つかりませんでした。
PIC32 では今まで通りにいかない。bit 単位でも割り込みを禁止しなければならない。


unsigned int int_status;
int_status = INTDisableInterrupts();
LATAbits.RA0 = a ? 1 : 0;
INTRestoreInterrupts(int_status);

大抵、変数への書き込みは1か所で、参照をあちこち。なんて感じで知らなくても問題ないプログラムになっていることが多い。 しかし、ポートはまずい。Enable ラインが割り込み1で、R/W が割り込み2など、組み込みではポートの書き換えはざらで、割り込みを禁止するか、ハードウェアを RA RB 単位で分けるかしなければならない。 変数も BYTE で宣言していても、DWORD で RAM を確保している場合がある。この辺は完全にコンパイラの気分次第なので、そいう言うこともあるぞと。気にとめてプログラムを書きましょう。 32bit 単位での処理が速いためで、LATA のレジスタは 32bit になっている。 MIPS の命令を見た感じ、BYTE 書き込みも出来る命令が有るようなので、問題なさげ。 それでも一応構造体の宣言は、


typedef union _pack {
typedef struct _pack {
unsigend char a0;
unsigend char a1;
unsigend char a2;
unsigend char a3;
unsigend char a4;
unsigend char a5;
unsigend char a6;
unsigend char a7;
} byte;
typedef struct _pack {
unsigend short a0;
unsigend short a1:
} word;
} _a;
BYTE UART_BUFF[sizeof(_a)];
_a *a;
a = (_a*)UART_BUFF;
BYTE HEDDER;
HEDDER = (*a).byte.a1;

「_pack」を付けましょう。コンパイラによっては「#pragma pack」とか色々です。BYTE なのに DWORD 取ったりすることが有ります。
変数の隙間を埋めると言うことです。32bit MPU なので、BYTE x 8 が DWORD x 8 として取ってしまう可能性があるためで、明示的にそれを禁止する書式です。
上記のプログラムの様に、BYTE 配列に UART 受信データを入れて、構造体でキャストして、プロトコル解析とか。
構造体の宣言に _PACK が付いていないと、構造体に隙間が有った時おかしなことになります。
32bit MPU とか 16bit もですが、アセンブラ命令は有るので、多分付けなくても問題なさそうですが。
移植コピペとか~、一応そういう処理が存在するので、アーキテクチャやコンパイラの動きも不明なので、存在する記述は使いましょう。みたいな。
そして、「_PACK」や「#pragma」は C で規格として存在していないと思います。なので2種類以上の書き方があるわけです。
XC とかのフォルダにある「PIC32MX220F032B」というファイル、ヘッダー一覧に入れておくといいでしょう。packで検索すれば、どうやっていいかわかるかな?
ビットフィールドでは、ビッグエンディアン、リトルエンディアン。この違いもありまして、上から bit0 か、下から bit0 とか。確認した方がいいです。上記のファイルで LATA で検索すれば、上からなのか下からなのか分かります。
さらにコンパイラによったり。
私はプログラムの include ヘッダーに、
#include “Compiler.h"
XC32 と C32 のマクロとかを自動判別して、コンパイルしてくれる。
#include “GenericTypeDefs.h"
は、typdef でビットフィールドとか、BYTE とかを定義しているので、そこを見た方が早いか。
重要なのは、「MPLAB IDE」と「MPLAB X IDE」どちらを使うか。
「MPLAB X IDE」を使わないと、#define を解析してくれないので、どこが生きているのか全然わからない。
CDC のサンプルとか全 PIC 対応なので、#ifdef が多すぎて訳わかめです。「MPLAB X IDE」の方がいいです。
さて問題。
int a;
は、何ビットか。

16bit 以上と C では定義されていたはず。むかーしの話なのですが、多分今もそうかと。
8bit MPU なら、BYTE を2つ使って 16bit で処理するため、255 以下の数値しか使わなければ、BYTE 使った方が早いです。
16bit MPU は当然 16bit。32bitで MIPS はどうなんでしょう。
サンプルの割り込み処理で、unsigned int; なんて書いていますが、コンパイラの仕様書見ないと分からないのかな?
それとも、今は C の仕様で 32bit MPU は 32bit と決まっているのでしょうか。
gcc 使っているのはわかりますが、ん~、マクロの説明で戻り値がその値と書いてあるなら問題ないのでしょう。
int は最低でも 16bit 以上」と、考えておけば問題ないでしょう。
マクロの戻り値にそう書いてあるなら、そのマクロ自体は int の長さがどうであれ気にする必要は無いと思いますが。


1つ注意が。何かの PIC のエラッタで、「割り込みをいじってすぐになにがしかをすると反映されない。」
とか見たことが有ります。設定レジスタだったはずなので、main 起動の Loop 前の初期化でその後もう触らないなら問題ないかと。
エラッタがまいるのよねぇ
M16C のリンカが同じ関数名が有る場合、リンク時にエラーかワーニングが出るはずなのですが、何も言わないのでおkなのかと思っていたところ、有り得ない場所へジャンプするので調べたら同じ関数名だったと。
頭に static を付けるとおkだったかな。コンパイラのバージョンアップでそこを修正したと後になって出てきましたが。
突貫中なんだから頼むよと。(私が文句というか、報告したような。)
static を付けるか、機能ごとのソースコードの関数名に機能名を付加するとか。
リンクの map ファイルが名前ソートする場合、ソースファイル内の関数名の頭を同じ文字付加すると分かりやすい。
RP2などタイマの設定で、あるタイミングで書き換えると反映されない。とか、量産しておかしいという話が来る。
そうなんです。エラッタなのでその時はメーカーは知らなかったと。
マスクROM使っていたはずなので、大変なことになっていたような。
他の部署だったので「くわばらくわばら」みたいな。まじこえっす。
しばらくは、Flash で出荷して様子を見るんですが。プログラム自体のバグとか(´Д`)


ということで、PIC32MX の出力ポートは超気を使わなければなりません。←ということが分かった。

PIC32

Posted by saba