勉強用のメモを残します。。間違いなどがあれば、その都度修正しますが、指摘などがあればコメントお願いします。
目次
SH-2A用テストボードの作成
雑誌付録のマイコンには周辺機器がほとんどありませんので、市販のボードを買うor自作するかのどちらかになります。今回の場合はもちろん、そんな専用ボードが売っているわけがありませんので、まずはテストボードを作りたいと思います。必要な周辺機器はこんな感じです↓
SH-2Aは+3.3Vで駆動しているため、ADコンバータの測定範囲も0-3.3Vとなります。ですが、純正ECUの基準電圧は+5.0Vのため、スロットル全開時の+5.0V近くは測定できないことにありますので、分圧して+3.3Vの範囲に収める必要があります。スロットル開閉センサ・吸気圧力センサに関しては、下記の回路を使用します。
ダイオードは、+3.3V以上の電圧(スパークノイズなど)が入力された場合の保護として入れています。
ハードウェア割り込みのタイミングはクランクパルスです。解析結果より±10V程度あり、安全のためフォトカプラで絶縁します。
細かい回路定数などは実験しながら決定したいと思います。
イグニッションコイル・インジェクタの駆動に必要な周辺回路のメモ。トランジスタ技術2004年1月号のP183に、フォト・カプラ:
TLP351を用いた回路例があったので、こちらを参考にしようと思います。
TLP351自体がパワーMOSFET・IGBT駆動用に設計されており、マイコン出力とも絶縁できるため保護回路も兼ねているようです。
- インジェクション・イグニッション・ステッピングモータ用モニタリング回路
駆動電圧は+12Vありますのでハードウェア割り込み(IRQ)用回路同様、フォトカプラにて絶縁して使用します。
IACバルブの調査完了後、更新予定
定番のFT232RLを使用します。テストボードでは
ユニット化された商品がありますので、こちらを使う予定です。
- SDカードソケット(ECUプログラム・データロガー用)
Interface2010年7月号P64に掲載されいている回路図を参考にしました。こちらの例ではSD-CARDとの接続はSPIになります。
SH-2A関連Tips(gcc固有?)
IRQ割り込みについて
/* CPU割り込み処理 */
void CPU_IRQInterrupt(void)
{
int stat;
stat = *IRQRR;
// if (stat & 1) { /* IRQ0割り込み発生 */
// if (stat & 2) { /* IRQ1割り込み発生 */
// if (stat & 4) { /* IRQ2割り込み発生 */
// if (stat & 8) { /* IRQ3割り込み発生 */
/* 割り込み処理関数呼び出し */
// }
/* 割り込み要求クリア(エッジ割り込み設定時のみ) */
*IRQRR = 0x00F0; /* IRQ3~0クリア */
}
SH-2AのハードウェアマニュアルによるとIRQ例外割り込み発生時、IRQRR内のフラグは0に畳まれてしまうため、上記割り込み関数では複数のIRQ割り込みを判断することはできないようです。私の改造したソースではIRQ0,IRQ1それぞれベクターテーブルと割り込み関数を作成し、対処しています。
SDカードローダーによるブート後のSDカードの使用について
1週間ほど悩みましたが一応動作が確認できましたので、まとめます。
原因はmmc.c内のpower_on()にある省電力レジスタ「CPG.STBCR5.BIT.MSTP51」がうまく解除できないため、SPI0のレジスタの設定が一切できず(SPI0が動いていない)、データ送信処理「rcvr_spi()」で固まっていました。(省電力レジスタ:ONの操作は、SDカードローダがアプリを起動する直前のpower_off()内で操作している模様・・・)
試行錯誤の結果、「CPG.STBCR5.BIT.MSTP51」の書き換えを「CPG.STBCR5.WORD = 0」に変更とダミーリードを追加し、とりあえずSPI0の動作ならびにSDカードへのアクセスが可能となりました。(ビットアクセスがなぜNGなのか・・・謎です・・・)
static
void power_on (void) /* MMC制御回路を使用可能にする */
{
DBGMSG("ENTER\n");
BYTE temp;
// CPG.STBCR5.BIT.MSTP51 = 0; /* SPI0モジュール有効化 */
CPG.STBCR5.BYTE = 0; /* SPI0モジュール有効化 */
temp = CPG.STBCR5.BYTE; /* ダミーリード */
教訓としては
- 関連モジュールのレジスタ(特に開始レジスタ)を確認するべし!
- レジスタが正常に書き換えられていない場合、省電力による停止を疑え!!
ということでしょうか・・・
とりあえず
ごみ箱にサンプルソース「SD_sample1.zip」を格納していますので、興味のある方は参考にしてみてください m(_ _)m
デバッグログ出力・保存について
UARTによる出力
前提としてprintf()(又は同等のラッパー関数)でUART出力できるとします。まぁよくある手ではありますが、デバッグ表示用マクロを組み込むと簡単になります。
#define DBGMSG(...) printf("DEBUG(%s():%d):", __FUNCTION__, __LINE__);printf(__VA_ARGS__);printf("\n");
int main(void)
{
DBGMSG("ENTER");
}
※__FUNCTION__:関数名マクロ
※__LINE__ :行数
※__VA_ARGS__ :可変引数マクロ(...の内容を展開)
とするとUART出力では「DEBUG(main():(xxx))」 「ENTER」 「\n」 が順次表示されます。もっと良い方法があればとは思いますが、馬鹿の一つ覚えのようにコレを使っています。。
ファイル保存
デバッグ中、UART出力に処理が取られ、必要処理の遅延が発生することが増えてきました。解決方法としては「UART表示より処理が高速なファイル保存にする(ただし、リアルタイムでの確認は不可)」「優先度低のタスクでデバッグ表示処理させる」の2点を考えました。
「UART表示より処理が高速なファイル保存にする」についてはSDカードに保存すれば、とりあえず実現可能です。
「優先度低のタスクでデバッグ表示処理させる」についてはmain()関数で処理することで実現させます。
主な処理の流れとしては、2次元のリングバッファ(例:DEBUG_BUF[64][128])を介し、ECU処理(主にタイマ・IRQ割り込み)にデバッグログを溜め込み、main()関数でファイル保存となります。
ただリングバッファに書き込む内容ですが、上記のようなデバッグマクロですと、細切れになり非効率ですので、1行分をリングバッファに書き込むようにしています・・・っが、これが結構面倒です。。
#define DBGMSG(s,...) sprintf(DEBUG_BUF[CURRENT_INDEX], "D(%s():%d):"s"\n", __FUNCTION__, __LINE__, __VA_ARGS__);
長いですね、、、一応これで実現可能です。
レジスタバンクを無理やり使う
SH-2Aにはレジスタバンクという割り込み例外発生時に自動的にレジスタを退避する機能が実装されており、これを使うと効率的な割り込み処理が実現できるようです。
参考にしたInterface7月号のサンプルプログラムではレジスタバンクを使用しておらず、下記のようにスタックにレジスタを退避する処理となっていました。
_IRQ0_exception:
#PC,SR以外のレジスタをスタックに退避する
sts.l macl,@-r15
sts.l mach,@-r15
stc.l vbr,@-r15
stc.l gbr,@-r15
sts.l pr,@-r15
mov.l r14,@-r15
:
mov.l r0,@-r15
mov.l _IRQ0Interrupt_addr, r1
jsr @r1
nop
#PC,SR以外のレジスタをスタックから復帰する
mov.l @r15+,r0
:
mov.l @r15+,r14
lds.l @r15+,pr
ldc.l @r15+,gbr
ldc.l @r15+,vbr
lds.l @r15+,mach
lds.l @r15+,macl
# 例外からリターン
RTE
nop
_IRQ0Interrupt_addr:
.long _IRQ0Interrupt
そこで、試しに下記のようにRESBANKに変更してみた結果、レジスタバンクがとりあえず動くようです・・・(ただし15個のレジスタバンクがオーバーフローした場合、自力でスタックにレジスタを退避する必要はあるのですが、設計保障ということで今回は無視しています・・・)
_IRQ0_exception:
mov.l _IRQ0Interrupt_addr, r1
jsr @r1
nop
RESBANK
RTE
nop
.align 0x4
_IRQ0Interrupt_addr:
.long _IRQ0Interrupt
INTC.IBNR.BIT.BE = 1; // NMI以外の全割り込みでバンクを使用する
オーバーフローについての対応は後ほどということで・・・
PowerTools True WinChart for .NET の使い方
2Dグラフのサンプルコード
もっとも単純と思われる2Dグラフ表示のコードです。グラフの種類や各種設定はフォームデザインより変更できますので、思い思いにいじってみて下さい。ここでは、とりあえずWinChartにデータを渡すところのみを抜粋します。
// 変数宣言
double[] datavalueX;
int[] datavalueY;
データとして渡せる値は、byte型・int型・long型・double型などの配列が使えるようです。
// 2Dグラフ描画
private void drow2DChart()
{
C1.Win.C1Chart.ChartDataSeries series1 = c1Chart1.ChartGroups.Group0.ChartData.SeriesList[0];
series1.X.CopyDataIn( datavalueX );
series1.Y.CopyDataIn( datavalueY );
}
あとは、X軸・Y軸にデータを渡すだけで描画してくれます。
私が作った
Windowsアプリでは、上記を0.2秒間隔で更新することによりアニメーションを実現しています。
本当はもっと効率のよい方法があると思うのですが、、、ToDoアイテムということで(^^;)
3Dフラグのサンプルコード
こちらはWinChartの3D棒グラフのサンプルを改造したものになります。データは11×17としています。もう少しキレイな書き方があると思うのですが・・・鋭意調査中です。
// 変数・オブジェクト宣言
private double[,] mapData;
Chart3DDataSetGrid mapData_set = null;
グラフに渡すデータはdoubule型の2次元配列のみのようです。
// フォーム
public Form1()
{
InitializeComponent();
initData();
}
// データセットの初期化
private void initData()
{
mapData = (double[,])Array.CreateInstance(typeof(double), 11, 17);
for (int i = 0; i < 11; i++)
{
for (int j = 0; j < 17; j++)
{
mapData[i, j] = (double)(i * j);
}
}
// 3Dグラフ描画
mapData_set = new Chart3DDataSetGrid(0, 0, 11, 17, mapData);
c1Chart3D1.ChartGroups[0].ChartData.SetGrid = mapData_set;
}
Chart3DDataSetGridにてデータサイズとデータそのものを渡しています。とりあえず上記で3D棒グラフが描画できるようです。。。
最終更新:2010年09月11日 19:41