P/ECE研究室〜S1C33分室
* Tue Jan 22 22:01:37 JST 2002 Naoyuki Sawa
前回、高速DMAに較べてインテリジェントDMAは理解しづらそうだ、と書きましたが、この推測は間違っていました。
実際に試したところ、単純に使うだけならば、高速DMAよりもインテリジェントDMAの方が簡単でした。
もっとも、実用的に使うならば割り込みが絡んできます。インテリジェントDMAの割り込みは、予想通り難解です。
実は、まだ理解できていません。ハードウェアトリガやDMA完了割り込みについては、今後の課題とさせてください。
なお、P/ECEのシステムプログラムは、インテリジェントDMAを全く使っていませんので、ぶつかる心配はありません。
インテリジェントDMAには、次のような特徴があります。
- 設定情報をメモリ上に置いて使う。
- 128チャネルものDMAが利用できる。
- 一回のトリガで複数のチャネルを起動できる(リンク機能)。
1.の特徴により、構造体で指示を与える、メモリコピー関数の呼び出しのように扱うことができます。
例えるなら、pclSprite系関数みたいな感じです。
メモリ上に作成する設定情報の構造体は、c33208.hでIDMA_ST構造体として定義されています。
128チャネル分すべての構造体を用意する必要はありません。チャネル0〜必要なチャネルまでの配列だけで充分です。
2.の特徴。インテリジェントDMAは高速DMAと違い、チャネルによってトリガ要因が決めうちとなっています。
決めうちなので、高速DMAのように割り込み要因の選択を行う必要がありません。
チャネル | トリガ要因
|
0 | ソフトウェアトリガ
|
1〜4 | ポート入力、またはソフトウェアトリガ
|
5〜6 | 高速DMA完了、またはソフトウェアトリガ
|
7〜18 | 16ビットタイマ、またはソフトウェアトリガ
|
19〜22 | 8ビットタイマ、またはソフトウェアトリガ
|
23〜26 | シリアル送受信、またはソフトウェアトリガ
|
27 | A/D変換完了、またはソフトウェアトリガ
|
28〜31 | ポート入力、またはソフトウェアトリガ
|
32〜127 | ソフトウェアトリガ
|
ちなみに、c33208.hのコメントには、次のように記述されていました。
チャネル | トリガ要因
|
0 | 予約
|
1〜4 | ポート入力、またはソフトウェアトリガ
|
5〜6 | 高速DMA完了、またはソフトウェアトリガ
|
7〜18 | 16ビットタイマ、またはソフトウェアトリガ
|
19〜22 | 8ビットタイマ、またはソフトウェアトリガ
|
23〜26 | シリアル送受信、またはソフトウェアトリガ
|
27 | A/D変換完了、またはソフトウェアトリガ
|
28〜31 | ポート入力、またはソフトウェアトリガ
|
32〜39 | ソフトウェアトリガ
|
想像ですが、S1C33208からS1C33209に変わった時に、機能強化としてIDMAチャネルが増えたのではないでしょうか。
チャネル0が予約となっていること、S1C33209のマニュアルではチャネル0について特に説明がないのが気になりますが、
今回実験したところ、チャネル0をソフトウェアトリガで問題なく使うことができました。
3.の特徴を利用すると、一回のトリガで複数のDMA転送を行うことができます。
注意が必要なのは、一つ目のチャネルの転送が完了しなくても、次のチャネルが起動するという点です。
言い換えると、一つ目のチャネルの転送完了(カウンタ=0)によって二つ目のチャネルが起動するのではなく、
一つ目のチャネルへのトリガが同時に二つ目、三つ目、...のチャネルへのトリガにもなる、ということです。
今回の実験でリンク機能も試してみましたが、実用的に使うにはちょっとくふうが必要かも知れません。
それでは、実験です。ソース
まず、前回、高速DMAでやったのと同じことを、インテリジェントDMAのチャネル0を使って行ってみました。
高速DMAでの結果と同じですね。
次に、リンク機能の実験です。チャネル0〜5をリンクして、各チャネルで2バイト(全角1文字)ずつ転送します。
転送元の文字列データは、こんな感じです。
/* 0 1 2 3 4 5 6 7 8 9*/
char msg_new[] = "あいうえおかきくけこ" /*0x*/
"さしすせそたちつての" /*1x*/
"なにぬねのはひふへほ" /*2x*/
"まみむめもやゆよらり" /*3x*/
"るれろわをん"; /*4x*/
ここから2バイトづつ抽出して、一回だけのトリガで「せいてんなり」という文字列を作ってみます。
このプログラムでは、リンク機能のほかに、ハーフワード単位の転送も試してみました。
各チャネルは2バイトづつ転送しているのですが、1バイト×2ではなく、2バイト×1と設定しました。
ところでハーフワード単位の転送を行う場合、転送元や転送先アドレスがハーフワード境界に整列していないとどうなるのでしょうか?
考えられるのは、
- 何らかの例外が発生
- 間違ったアドレスに転送
といったところです。実際に試してみたところ、どうやら2.の動作となるようです。
具体的には、転送単位をハーフワードとした場合、転送元と転送先アドレスのビット0は、設定情報に書いた値にかかわらず"0"と見なされます。
例えば、アドレス0x0010〜に"0123456789"という文字列があり、アドレス0x0011から3ハーフワードを転送しようとしたとしましょう。
その結果、転送されるのは、期待した"123456"ではなく、"012345"となります。0x0011のビット0の"1"が無視され、0x0010と見なされたからです。
ここでは転送元アドレスについて説明しましたが、転送先アドレスについても同様でした。
もうひとつ、自分自身にリンクしたらどうなるか?の実験もやってみました。
すなわち、チャネル0のリンクフィールドにチャネル0を指定したらどうなるか?ということです。
結果を申しますと、期待通り、ハングアップしました。自分自身にリンクしてはいけません。
P/ECEのシステムプログラムはインテリジェントDMAを使っていないので、「カーネルいちゃもんコーナー」はお休みです。
その代わりに、c33208.hの間違い記述らしきものを指摘しておきます。
設定情報の構造体IDMA_STの定義において、次のような記述がありますが、
union {
volatile struct {
unsigned int TC : 24; /* Data transfer counter */
unsigned int LINKCHN : 7; /* IDMA link field */
unsigned int LINKEN : 1; /* IDAM link enable */
} bBLK;
volatile struct {
unsigned int BLKLEN : 8; /* Block size */
unsigned int TC : 16; /* Data transfer counter */
unsigned int LINKCHN : 7; /* IDMA link field */
unsigned int LINKEN : 1; /* IDMA link enable */
} bSIN;
volatile unsigned int uiTC;
} rTC;
明らかにbBLKとbSINが逆です。
ブロックモードでbBLKを使おうとすると、BLKLENフィールドがないのでコンパイルエラーとなって気づきますが、
シングルや連続転送モードでbSINを使うと、必要なフィールドは全てそろってしまっている(ただし位置は違う)ので、気づかない恐れがあります。
危険度は中、といったところでしょうか。
次回は、16ビットタイマかシリアルコントローラを試してみたいと思います。
(続きます...)
nsawa@piece-me.org