高性能マイコン、SH2A(SH7262)を使ってみる
インターフェイス誌、2010年5月号付録、SH2A基板でSDカードを操作してみます。SH7262はかなり高速な動作をするので、SPIポートでどれだけのスピードが可能か、検証してみます。基板の水晶は、USBポートにも使えるように48MHzとなっており、CPUはこの3倍なので、SH3のスピードに迫ります。これだけ早いと、SPIポートの操作によるシステムオーバーヘッドも少なくなり、ソフト転送でもかなりのスピードが期待できます。
この基板は、3枚も購入しておきながら、買った当初にLEDの点滅をしただけで、そのままになっていました。動かし方も忘れていて、Hewを立ち上げたものの、USBシリアルのCOM番号が変わっていて、それを探すことからになりました。_| ̄|○
このURLでは、最終的にはGCCでコンパイルして、ROM化まで行うことを目指します。付録基板、SH7262は、内臓RAMが非常に大きく、その代わり内臓フラッシュメモリ上で動作させるという構成ではなく、シリアルROMにプログラムを入れておいて、RAMにコピーして動かすスタイルとなっていて、SH3以上のハイエンドマイコンの構成になっています。
モニタを移植 SDカードとの接続回路図 ←重要 追記 SDカード操作の機能 2011.7.16 デバッグ用USBを認識しない。ガーン。_| ̄|○ 2011.7.27
修正。追記 2011.8.1 ←重要 SROMのブートローダーで直接ユーザープログラムを起動
SDカードのCSがLowの時、SROMのCSを無効( High )にする。
SH用GCCクロス開発環境 ( Cygwin ) を作成して、これでソフト開発 ←GCCでのコードは、Hewより1〜2割ほど短くなる
処理速度検証 2011.12.6 Dhrystone 2.1 で、186,780 Dhrystones/sec 同クロック換算で LPC2388 ( ARM7 ) の1.5倍
シリアルポートを有効化して、UARTの動作確認をしてみる
Hewではソースレベルでプログラムのデバッグには便利ですが、SH2Aの内部レジスタをインタラクティブに値を設定するには不便なようです。新しく使うポートやその動作は、プログラムにソースを書いてステップ実行してみるには手順が多すぎます。そこで、指定したアドレスのメモリをすばやく変更できるモニタを先に移植します。その為に、操作ポートとしてRS232Cを使いますから、使えそうなUARTをテストして、1バイトの入出力を確かめ、動作が確認できると、モニタのBIOSに組み込み、Hewでコンパイル、デバッグという手順で、RS232C経由のモニタを完成させます。このURLのページのTOPで で説明している、SDカードの操作例は、すべてこのような方法にしているので、そのソースをほとんどそのまま使います。変更箇所は、BIOSと、CPU特有の初期設定(これに1番手間がかかる)だけです。LED点滅サンプルソフトの、SH7262_LED.c と、cmt_func.c にレジスタ初期設定などを追加して、とりあえずボーレートを小さく設定して、CN6の6番に信号が出るかをテストします。パソコンのCOMポートの最小のボーレートは、110となるので、アナログテスターでも信号が出ているかを確認できます。シリアルポートは、TxD3と、RxD3を使います。この信号は、CN2にも出ています。
LED点滅ソフトの、SH7262_LED.c を改造
LED点滅ソフトの、cmt_func.c を改造。LED点滅の変化を出した後、1文字、0x40(’@’)を送信します。ターミナルから文字を送ると、エコーバックしますが、SH−2AではFIFOがあるので、すばやく16文字まで送信しても、あとから受信文字を返します。
/*=== インクルード ===*/
#include "iodefine.h"
/*=== グローバル変数 ===*/
extern int g_led_onoff; //LED点灯フラグ 0=OFF 1=ON
/*=== プロトタイプ宣言 ===*/
void led_on(); //LED ON 関数
void led_off(); //LED OFF 関数
// 以下の行を追加
#define SCFSR3 ((volatile short *)0xFFFE9810) // シリアルステータスレジスタ
#define SCFTDR3 ((volatile char *)0xFFFE980C) // 送信FIFO
#define SCFRDR3 ((volatile char *)0xFFFE9814) // 受信FIFO
// ここまで
/*=== CMT0初期化関数 ===*/
void io_init_cmt0(void)
{
/*--- FRQCR設定 内部クロック比 I:B:P = 144MHz:48MHz:24MHz ---*/
CPG.FRQCR.WORD = 0x1104;
/*--- STBCR7設定 CMTクロック供給開始 ---*/
CPG.STBCR7.BIT.MSTP72 = 0;
/*--- CMSTR設定 CMCNT0カウント停止 ---*/
CMT.CMSTR.BIT.STR0 = 0;
/*--- CMCNT0設定 0クリア ---*/
CMT.CMCNT0.WORD = 0x0000;
/*--- CMCSR0設定 CMI発生許可 クロック設定[Pφ/512] ---*/
CMT.CMCSR0.WORD = 0x0043;
/*--- CMCOR0設定 ---*/
CMT.CMCOR0.WORD = 0x8954;
/*--- CMSTR設定 CMCNT0カウント開始 ---*/
CMT.CMSTR.BIT.STR0 = 0x1;
}
/*=== CMI0処理関数 ===*/
void int_cmt_cmi0(void)
{
int rdata;
int rstat;
/*--- CMF 0クリア ---*/
CMT.CMCSR0.BIT.CMF = 0;
/*--- LED反転 ---*/
g_led_onoff ^= 1;
if(g_led_onoff == 0){
led_on();
}
else{
led_off();
}
// 以下の行を追加。LEDが点滅するタイミングで、CN6の6ピンにシリアル信号を出す。
rstat = *SCFSR3;// SCFSR3
if(rstat & 0x2)// SCFSR3
{
rdata = *SCFRDR3;// 受信データを読む
*SCFSR3 = rstat & 0xFFFC;
*SCFTDR3 = rdata;// SCFTDR3 に受信データを送信
*SCFSR3 &= 0xFFDF;
}
else
{
*SCFTDR3 = 0x40;// SCIF3 に0x40 '@'を送信
*SCFSR3 &= 0xFFDF;
}
// ここまで
}
RS232Cでパソコンと接続する、簡易RS232C変換回路。使っているデジタルトランジスタは、DTC143EKA、もしくは、FA1A4M(こちらはTrのOFFが2.1μ秒ほどかかるので、パソコンによっては正しく通信できないこともある。)。また、出力TXのプルアップ抵抗は、2.2kΩぐらいの方が出力を高くでき、信頼性が高くなります。
動作確認できたRS232Cポートで操作できるモニタを移植
TxD3 と、RxD3 で、パソコンと通信できたら、RS232Cの入出力部分をBIOSとして独立させた、以下の3個の関数を用意します。
パソコンのターミナルソフトに1文字を送信する。void putcon(char c)
パソコンのターミナルソフトから送られる1文字を受信するまで待つ。int getcon(void)
パソコンのターミナルソフトから送られる1文字を受信したかをチェックする。int statcon(void)
以下は作成したモニタ用BIOS
#define SCFTDR3 ((volatile unsigned char *)0xFFFE980C) // 送信FIFO
#define SCFRDR3 ((volatile unsigned char *)0xFFFE9814) // 受信FIFO
#define SCFSR3 ((volatile unsigned short *)(0xFFFE9810)) // シリアルステータスレジスタ_3
// モニタ用RS232CのBIOS
// 1文字送信
void putcon(int c)
{
while(1)
{
if(*SCFSR3 & 0x20)
break;
}
*SCFTDR3 = (char)c;
*SCFSR3 &= 0xFFDF;
}
// 1文字受信するまで待つ
int getcon(void)
{
unsigned int read;
while(1)
{
if(*SCFSR3 & 0x2)
break;
}
read = *SCFRDR3;
*SCFSR3 &= 0xFFFD;
return read;
}
// 1文字受信したかのチェック
//モニタを実行中、処理を中断したい場合、処理のループ内で呼び出す。
// 1 をリターンすると、getcon() で受信文字を確かめ、中断か、否かを判定。
int statcon(void)
{
int stat;
stat = *SCFSR3;
*SCFSR3 = stat & 0x0063;
if(stat & 2)
return 1;
return 0;
}
また、LED点滅サンプルソフトでは、タイマー割り込みを使っていますが、タイマーはそのまま使い、割り込みだけ発生しないように改造し、モニタ本体の mainmoni を呼び出します。割り込み処理関数 cmt_func.c は、そのままにしておきます。
改造した SH7262_LED.c
/***********************************************************************/
/* */
/* FILE :SH7262_LED.c */
/* DATE :Tue, Mar 09, 2010 */
/* DESCRIPTION :Main Program */
/* CPU TYPE :SH72623 */
/* */
/* This file is generated by Renesas Project Generator (Ver.4.16). */
/* */
/***********************************************************************/
/*=== インクルード ===*/
#include "iodefine.h"
#include
//#include "typedefine.h"
#ifdef __cplusplus
//#include // Remove the comment when you use ios
//_SINT ios_base::Init::init_cnt; // Remove the comment when you use ios
#endif
void main(void);
#ifdef __cplusplus
extern "C" {
void abort(void);
}
#endif
/*=== プロトタイプ宣言 ===*/
/*--- cmt_func.c ---*/
void io_init_cmt0(void); //CMT0初期化関数
void int_cmt_cmi0(void); //CMI0処理関数
/*--- led_func.c ---*/
void led_init(void); //LED初期化関数
/*=== グローバル変数 ===*/
int g_led_onoff; //LED点灯フラグ 0=OFF 1=ON
// ここから追加
#define STBCR4 ((volatile unsigned char *)(0xFFFE040C)) // スタンバイコントロールレジスタ4
#define PFCR1 ((volatile unsigned short *)(0xFFFE38AC)) // ポートF コントロールレジスタ1
#define PFCR0 ((volatile unsigned short *)(0xFFFE38AE)) // ポートF コントロールレジスタ0
#define PFIOR0 ((volatile unsigned short *)(0xFFFE38B2)) // ポートF・IO レジスタ0
#define SCSMR3 ((volatile unsigned short *)(0xFFFE9800)) // シリアルモードレジスタ
#define SCBRR3 ((volatile unsigned char *)(0xFFFE9804)) // ビットレートレジスタ_3
#define SCSCR3 ((volatile unsigned short *)(0xFFFE9808)) // シリアルコントロールレジスタ_3
#define SCFSR3 ((volatile unsigned short *)(0xFFFE9810)) // シリアルステータスレジスタ_3
#define SCFCR3 ((volatile unsigned short *)(0xFFFE9818)) // FIFO コントロールレジスタ_3
#define SCEMR3 ((volatile unsigned short *)(0xFFFE9828)) // シリアル拡張モードレジスタ_3
#define SCFTDR3 ((volatile unsigned char *)0xFFFE980C) // 送信FIFO
#define SCFRDR3 ((volatile unsigned char *)0xFFFE9814) // 受信FIFO
#define CMCNT0 ((volatile unsigned short *)(0xFFFEC004)) // カウンタ。1カウントで、21.33 μ秒
int mainmoni (int);
// ここまで
//
/*=== メイン関数 ===*/
void main(void)
{
/*--- LEDポート初期化 ---*/
g_led_onoff = 0;
led_init();
/*--- CMT0初期化 カウント開始 ---*/
io_init_cmt0();
// ここから追加
/* ポート設定(RXD3(PF3))*/
*PFCR0 = (*PFCR0 & 0x0FFF)|0x4000;
*PFCR1 = (*PFCR1 & 0xFFF8) | 0x4;
// モジュールストップ44 スタンバイ解除
// bit4 0:FIFO 内蔵シリアルコミュニケーションユニットチャネル3 は動作
*STBCR4 = (*STBCR4 & 0xEF); // SCIF3動作
// *PFIOR0 = (*PFIOR0 | 0x10);// TxD3 output この設定は不要
*SCSMR3 = 0x0000;// SCSMR3 1stop, none,8bit,clock 1/64
*SCFCR3 = 0x0006;// SCFCR3 FIFO CTL clear
*SCFSR3 &= 0x0;// SCFSR
*SCSMR3 = 0x0000;// SCSMR3 1stop, none,8bit,clock 1/64
*SCBRR3 = 0x0C;// SCBRR3 115200 bps
*SCEMR3 = 0x0080;// SCEMR3 0x80
*SCFCR3 = 0x0000;// SCFCR3 FIFO CTL
*SCSCR3 = 0x30;// SCSCR3 Tx Rx
// ここまで
/*--- 割り込み優先レベル設定 ---*/
// INTC.IPR10.BIT._CMT0 = 0x1;
// 割り込みを発生させないので、cmt_func.c の、int_cmt_cmi0() は実行されない。
// set_imask( 0 );
/*--- ループ ---*/
while(1)
{
// if(statcon())
// putcon(getcon());
mainmoni (0);
}
}
#ifdef __cplusplus
void abort(void)
{
}
#endif
モニタ自体は、かなり大きく monitor.c とファイル名を変更 して、プロジェクトに追加し、ビルドして実行すれば、ターミナルには、以下のように表示されます。図では、プロンプトの後、0x1C002600番地以降のメモリ128バイトを、d コマンドで表示しています。
注意
この回路図にはありませんが、SDカードで使うSPIポートは、オンボードのブート用SROM(U5)と共用になっているため、SDカードを操作する場合は、SROMのチップセレクトを、ブート後は切り離しておきます。半田ジャンパーのJP16をカットしておき、JPP3をオープンにすることで切り離せます。
SH2Aと、SDカードとの接続は、以下のようになります。ライトプロテクトや、カード挿入の検出は、まだ接続していません。SDカードソケットは、ヒロセの、DM1シリーズの、DM1AA-SF-PEJ と思われます。このソケットでは、カード挿入検出ピンがソケットの横に出ていて、小さく、しかもケースと非常に近いため、半田付けには慎重さが必要です。(実際、同じルネサスの RX62NマイコンにSDカードを接続する とき、カード挿入検出ピン( DETECT )が、内部ケース部分とショートしてしまい、COMピンを、GNDにすることができなくなってしまいました)
今回は、半田付けの困難な、DETECT ピンと、DSカードの8番ピン(DAT1)に、あらかじめ接続線を付けてユニバーサル基板に実装しました。他のピンは、2.50mmピッチに並んでいるので、ユニバーサル基板の穴の近くに並びます。ただしこのようにするには、ソケットの裏のプラスチックの突起がちょうどスルーホールに入るように、穴を大きく(直径1.5mmぐらいのドリル)しておきます。
モニタのコマンドにSDカードを操作するコマンドを追加して、単にSDカードの読み書きにとどまらず、いろいろなことができるようにします。予定している操作機能は、以下のようなものです。
SDカードの初期化。コマンドは、Si(enter)--CMD0,CMD8, ... さらに、CSD を読み出して、SDHC か否かなどを調査する。
SDカードを指定セクタから指定メモリに、指定セクタ数だけ読む。コマンド例。Sr2000,1c010000,1(enter)--0x2000 セクタから、0x1c010000 番地に、1 セクタ読み出す。
上記コマンドで、マルチセクタリード、CMD23 + CMD18 で実行。コマンド例。SR2000,1c010000,10,10(enter)--0x2000 セクタから、0x1c010000 番地に、10 セクタ読み出す。
SDカードの指定セクタから指定メモリのデータを、指定セクタ数だけ書く。コマンド例。Sw5000,1c010000,10(enter)--5000(hex) セクタから、0x1c010000 番地からのデータを、0x10 セクタ書く。
CRCチェックの有効、無効を指定する。encrc(enter)--有効、 dscrc(enter)--無効。
SPIの転送クロックを指定する。ボーレート設定レジスタを変更してスピードを変える。clkspeed 0(enter)--付録基板での最速、24MHz になる。
CRC7や、CRC16を計算する。crc7 1c008100,f(enter)--メモリの 0x1c008100 番地から、0xF バイトのCRC7を計算して表示する。
CMDx をSPIで送って、レスポンスを表示する。CMD0,CMD1,CMD8,CMD9,CMD10,CMD17,CMD18,CMD23,CMD24,CMD58,CMD41(=ACMD41) など
各コマンドの実行時間を測定して、後で確かめる。最大約1.2秒まで。これは、SH7262 内臓カウンタが16ビットの制限による。T(enter)
以上の機能を入れるため、先に紹介した、monitor.c を、4個のファイルに分割します。旧monitor.c は、新monitor.c と、monitor.h と、mmcbios.c と、sh7262.h になります。それぞれmonitor.c monitor.h mmcbios.c sh7262.h です。これらをプロジェクトに追加してコンパイルします。
注意。追記 ここに示したソースは、2011.8.1 に修正したものです。インターフェイス誌2010年5月号の130ページで解説されているように、シリアル・フラッシュROMのアップデートを行うと、SH7262のスタンバイ制御レジスタのほとんどが、スタンバイ状態に戻されるため、以前のプログラムではSDカードを操作できなくなってしまうのです。スタンバイレジスタ、STBCR5も、0xFFになってしまいます。購入したままの基板では、STBCR5は、0x10となっており、すでにSPIポート0は動作可能状態になっているため、設定を変更することなく動作していました。アップデート後のシリアルフラッシュメモリでブートした状態で、SDカードプログラムを走らせるには、STBCR5の、D1ビットを0にする必要があります。このため、上記、mmcbios.c と、sh7262.h に、STBCR5のD1を0にする命令を追加しました。
修正前のファイルsh7262_old.h mmcbios_old.c
以上の操作ができるモニタを移植して、操作したスクリーンショットです。この例では、8GBの microSD カードを操作しています。
この例では、Si で初期化、その後、 CMD10 を送ってレスポンスを表示しています。
CID = 00 FF FE 13 4B 47 53 44 30 38 47 00 61 28 1F 32 00 AC 75 3E 15 FF FF
CID = 00 は、レスポンス00の後、送られたデータをそのまま表示しています。FE の次からが、CIDデータ列です。15バイトの後、CRC7、続いてCRC16が、2バイトになっています。これらを確認するため、crc7 と、 crc16 で、計算して確認しています。
CID data address=1C006120
は、CIDを読み取った先頭アドレスを表示しているので、FEの次の 13 のアドレスは、0x1C006123 となるので、crc7, crc16 コマンドの引数でこのアドレスを指示し、バイト数を指示して計算しています。レスポンスの値と一致していることがわかります。
SH2A-Bug>Sr4000,1c020000,10
次にSDカードの0x4000セクタから0x10セクタを、メモリの0x1C020000番地以降に読み出して、その実行時間を後で表示しています。16セクタ読むのに、18msほどかかっているのがわかります。8KBを、約15msで読むので、553kB/秒、平均ビットレート4.42Mビット/秒となります。SPIのクロックを24MHzにしているので、18%ぐらいの速さです。SPIでのソフト転送では優秀な方です。
SH2A-Bug>SR4000,1c020000,10,10
次は、マルチセクタリードのコマンドで同じ操作をして、14.8msであることを表示しています。若干早くなっているのがわかります。引数が1個増えていますが、CMD23 で与えるセクタ数を指定するためです。
SH2A-Bug>d1c020000
最後に、セクタ指定して読み出したSDカードのデータを表示しています。このSDカードでは、ここが、FAT32のディレクトリであることがわかります。0x4000セクタから読み出していますが、メーカーの異なる同じ8GBのSDカードでも、ここにディレクトリ情報があるとは限りません。
基板が動かない????。USBデバイスを認識しない
一週間ほど動かさないで、再び動かそうとすると、Hewの起動画面で、デバッグ用シリアルポートでSH−2A基板が認識されなくなっていた。何度やっても同じで、Windowsを再起動してもだめだった。デバイスマネージャには、不明なデバイスと出るだけ。ドライバを再インストールしても、だめ。うーん、これはどうしたことか。「CQ SH−2A デバイス 認識しない」 で検索。すると、CQのサイトに、このような記述が・・・ そこで、別の基板で試すと、2枚がだめで、1枚だけ認識した。
おいおいおい、なんてことだ。ま、2千円ほどで買った基板だから、しようがないか。USBが動かないと、このままではなにもできない。USB内臓マイコンで、最初の動作を、ブート後USBポートでのデバッグになっている場合、パソコン側でUSBがブロックされてしまうと、身動きできない。
実は、USBデバッガは、以前からあまり信用していなかったので、(フェイルセイフの観点から、信頼性に劣る)SH−2Aの別のブートデバイスで、RS232C経由のデバッグを作ろうと思います。無論、Hewでの操作ではなく、デバッグ機能は低いけれど、簡易モニタでの操作となります。C言語のソースレベルデバッグなど、もうとっくの昔に卒業してしまっているので、Hewでなくても不自由はしない。
オンボードSROMを無効にして、外部の他のデバイスからブートする改造
付録基板は、オンボードのSROMからブートするようになっており、ブート後、HewのデバッガとUSBで通信するようになっていますが、SROMのチップセレクトを無効にすることができ、外部に並列にSROMを装着して、これのチップセレクトを有効にすると、そこからブートさせることができます。とはいうものの、USBを認識しなくなった基板では、外部のSROMにプログラムを書くことすらできません。他のデバイスからブートする方法として、以下の方法が考えられます。すでにUSBを認識できなくなった2枚のボードを復旧するには、この方法しかないようです。(JTAGデバッガーを持ってないし、安価になったとは言え、1万円を投資する気はない)
外部16ビットパラレルバスに接続した、フラッシュメモリ(またはROMエミュレータ)からブートする。ブートモードを0にする基板改造が必要。 外部に並列にSROMを付け、オンボードのチップセレクトを無効にする。半田ジャンパーJP16をカットし、JPP3をオープンにしておく。
NANDフラッシュメモリからブートする。
以上3種類があるようですが、書いてない4番目は、SROMを低速で動作させるだけで、方式は2と同じとなります。しかし、いづれもROMにどうやって最初にプログラムを書くかという問題が付きまといます。ROMエミュレータや、SROMエミュレータがあればいいのですが、このためだけに購入、または製作する気はないので、とりあえず動作している1枚の基板を使って、外部に並列に追加したSROMに別のプログラムを書いて、チップセレクトを入れ替えて起動できるような改造をします。この改造した状態が、以下の写真です。
SROMは2個追加して、2種類のブートが選択できるように、チップセレクトを有効にするジャンパーピンをそれぞれに設けています。この写真では、オンボードのJPP3をオープンにし、追加したSROMの左側を有効にしています。無論、Hewで操作できるように、最初は、オンボードのJPP3だけショートしておいてHewを立ち上げ、その後、書き換えたいSROMのジャンパーピンだけショートします。追加するSROMは、オンボードと同じく、M25P05にしたいところですが、手持ちが無かったので、M25P20になっています。その為、CQ出版のサイトからダウンロードできるSROM書き換えユーティリティーソフト( SPIwriterAll )は正常には動きませんでした。
追加したSROMの回路図です。SDカードで使ってる信号とほとんど共用ですので、SDカードを操作する場合は、チップセレクトのジャンパーを外しておきます。しかし、これでは不便なので、SROMのCSピンへは、SH2AのSPI0で操作するSSL00ではなく、別のピンで操作する方法に変更予定です。→ SDカードのCSがLowの時、SROMのCSを無効( High )にする。
CQ出版のSH2A特設ページには、いろいろと有用なソフトがあって、ソースコードもありますが、このサイトから、SROMに書かれているブートローダのソースと、SROMのアップデータファイル( バイナリファイルで、名称は、SPIROM.BIN )を参考に、SROMの前半部分、0x2000以降にUSBモニタの代わりに、簡易モニタを入れてブートできるようにします。SROMの後半部分に書けば、Hewのデバッガと選択的にブートできるのですが、NMIピンのLow、Highで切り替える方法では、NMIが使えなくなるので、前半0x2000〜0x7FFFに書きます。
SH7262にあらかじめ組み込まれているブートローダは、SROMの0〜0x1FFFまでなので、8kBしか使えませんから、ブートローダはそのままで、その後に書きます。同じセクタ内なので、ブートローダを含む1セクタ32kBを読み出して、新しいモニタを、0x2000以降に上書きしてSROMに書く手順とします。オンボードのSROMを書き換えると、USBモニタをブートできなくなるので、新しく追加したSROMで行います。
SH7262のモード1のブート手順は、内臓されたブートプログラム( ルネサスでは非公開 )が、SROMの0番地から0x2000バイトを、内部高速メモリの0xFFF80000番地以降にロードし、0xFFF80000から実行するようになっています。ブートローダーは、ロード先のアドレス、実行アドレス、実行の前に設定するスタックポインタの値の3個を、以下の場所から読み出しています。
SROMの先頭から0x2000:4バイト:ロード後、プログラムカウンタに設定する値。このアドレス値から実行する。
SROMの先頭から0x2004:4バイト:実行前に設定する、スタックポインタの値。
SROMの先頭から0x2020:4バイト:ロード先のメモリアドレスの先頭番地
以上の値を設定したプログラムデータを、0x2000番地以降に書いておけば、ローダーが読み出して実行してくれますが、ローダー部分を含めたユーザープログラムを、SROMに書くソフトが必要になってきます。そこで、次のようなSROMリードライト操作ができるモニタを作成しました。そして、このモニタをブートできるようにします。
SH2A-Bug>rrx,y (enter) SROMの x 番地から、y バイトをヘキサ表示する。
SH2A-Bug>rrmx,y,z (enter) SROMの x 番地から、z バイトを、メモリの y 番地以降に、z バイト読み出す。
SH2A-Bug>rs (enter) SROMのステータスレジスタを読み出して表示する。
SH2A-Bug>rs (enter) SROMのステータスレジスタを読み出して表示する。
SH2A-Bug>rsw (enter) ライトイネーブルフラグ( WEL )を1にする。
SH2A-Bug>rex (enter) アドレス、x のページを消去する。あらかじめ、WELフラグを1にしておく。
SH2A-Bug>rwx,y,z (enter) SROMの x 番地以降に、メモリの y 番地以降の z バイトを書く。あらかじめ、WELフラグを1にしておく。
モニタには、パソコンからモトローラSレコード形式のヘキサファイルを受信して、メモリに書くローダー機能や、逆にメモリのデータを、Sレコードでパソコンに送信する機能もあります。またこの機能には、Sレコードの実アドレスに数値を加算したアドレスにロードしたり、送信したりできるので、高速RAM領域のアドレス、0xFFF8xxxx で実行できるSレコードファイルを、大容量メモリの0x1C00xxxxなどにロードできます。
こちらが、これらの機能を追加したモニタの、Hewプロジェクトファイル一式です→ ISample4_SROM.lzh
上記、無い場合は、こちら→ ISample4_SROM.lzh
この中の、release フォルダにある、SH7262_LEDboot.mot が、SROMのブートローダー付きの、SROMに書くデータです。
また、CQ出版のURLからダウンロードできる、SROMのアップデータには、SROMに書くバイナリファイル、SPIROM.BIN がありますが、これをSレコード形式に変換したファイル、spirom.mot と、SROMのローダー部分だけ抜き出した、spirom_loader.mot も置いています。いずれも、先頭アドレスが0xFFF87000になっています。ISample4_SROM.lzh で作成するユーザープログラム ( release ) は、0xFFF89000番地からロードするようにしているので、このようなアドレス設定になっています。SPIROM.BIN を、spirom.mot に変換したツールは、こちらにあります→ hexutils013
SH7262_LEDboot.mot は、Hewで作成した、SH7262_LED.mot を、spirom_loader.mot の後にエディタで追加して作成したものです。
HewによるUSBデバッガが使える状態から、SH7262_LEDboot.mot をSROMに書く手順は以下です。SROMに書く場合は、書き換えたいSROMのチップセレクトだけ有効にしておきます。
付録基板に追加した、SIO3ポートにパソコンのRS232Cケーブルを接続し、ターミナルソフトで監視する。
Hewで、ISample4_SROM.lzh を解凍したプロジェクトを開く。
Hewで、Degugモードを選択して、デバッグ(D)タブの下の方の、ダウンロード(W) で、すでに出来上がっている、プログラムデータをダウンロードする。
Hewの、デバッグ(D)タブの、リセット後実行(E)を選択する。
ターミナルには、
Custom Monitor SROM 2011.8.6
SH2A-Bug>
と表示される。
パソコンから、SH7262_LEDboot.mot を受信して、0x1C010000番地以降にロードするため、次のコマンドを与えます。
SH2A-Bug>l1c089000 ( enter ) これは、Sレコードのアドレス情報に、0x1C089000を加算したアドレスにロードする指示。
0x1C089000 + 0xFFF87000 = 0x1C010000 となり、0xFFF87000 番地のデータは、0x1C010000 にロードされます。
ターミナルから、SH7262_LEDboot.mot を送信します。テラタームでは、バイナリ指定にしておきます
全部受信すると、
start loading address = 1C010000
END. bytes loaded = 0000444C ( これは受信した全バイト数。モニタのバージョンにより、この数値と異なる場合があります )
と、SH2Aが応答します。
SH2A-Bug>rsw ( enter ) で、WELフラグを1にします。
SH2A-Bug>rs ( enter ) で、WELフラグを確認します。
02 02 と応答します。
SH2A-Bug>res ( enter ) で、イレーズセクタコマンドを出します。s の右に何も無いので、0セクタとなっています。セクタ1なら、res1
SH2A-Bug>rr0,f ( enter ) で、先頭のデータをダンプして、消されているか確認します。
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF
と、応答するので、次にライトします。
SH2A-Bug>rw0,1c010000,5000 ( enter ) で、SROMの先頭0番地以降に、0x1C010000 番地から、0x5000 バイトを、書きます。
SH2A-Bug>rw0,1c010000,5000................................................................................
と応答します。ドット1個で、256バイト書いたことを示しています。途中、書き込み終了の応答が無い場合、タイムアウトのエラーが出ます。
SH2A-Bug>rr0,7f ( enter ) で、先頭部分をダンプしてみます。SH7262_LEDboot.mot と一致しているはずです。
SH2A-Bug>rr0,7f
DF 05 D0 04 40 2B 00 09 44 2E 60 42 74 04 6F 42
40 2B 00 09 FF F8 00 1C FF F8 20 00 7F FC D1 42
41 4B 04 6A 0E F1 E8 00 7E FF 24 E9 D1 3F 41 0B
44 6A 07 E0 08 00 05 6A 34 71 90 00 01 00 80 00
25 E9 24 18 45 6A 32 2A 72 01 65 F3 62 2D 22 28
D2 37 8F 1E E6 04 04 00 80 20 42 4B 06 6A 65 F2
25 58 26 E9 8D 03 46 6A 60 53 88 FF 8B 03 05 00
3C 00 45 28 2F 52 02 80 20 00 06 00 80 00 35
22
SH2A-Bug>
以上の操作のスクリーンショットです。
テラタームで、送信ファイルを選択しているところ。バイナリ(B)にチェックを入れておきます。
テラタームで、送信しているところ。
一連の操作の図
SDカードのCSがLowの時、SROMのCSを無効( High )にする。
SDカードを操作するときも、同じSPIポートを使うので、SROMのチップセレクトが接続されていると、SDカードへのコマンド送信のとき、SROMのチップセレクトもLowになり、たまたまSROMのコマンドフォーマットに合致したバイト列だと、それへの応答をしてしまいます。このとき、SDカードの信号とショートしてしまいます。SDカードの操作をしているとき、たまにSDカードの初期化が失敗することがあり、その原因を調べていると、SROMの応答信号とショートしているらしい信号波形が見つかり、以下のような回路を追加しました。
無論、SROMのチップセレクトを禁止できるのは、外部に追加したSROMだけで、オンボードのSROMは禁止できないので、SDカードを操作するときは、外部に追加したSROMからブートして使うようにしました。いままで、オンボードのSROMが有効のまま、SDカードをいろいろ操作してきましたが、SROMが何ともなかったのは不思議なくらいです。( SDカードの操作で、たまにエラーは起こっていた)
SH用GCCクロス開発環境 ( Cygwin ) を作成し、これでソフト開発。gcc はコードサイズが小さい
RXマイコンでは作成しましたが、今度はSH用に作成してみます。使っている Cygwinは、1.7.7( $ uname -r でバージョンを確認できる ) のものですが、最新のものでもOKでしょう。クロス開発環境を作成する Cygwn のセットアップの仕方は、こちらと同じです。→ RXマイコン用GCC開発環境を作る
クロス開発環境のセットアップは、RXマイコンとほとんど同じです。違いは、コンフィギュアーのスクリプトで、ターゲットのCPUの指定を、rx-g460-elf から、sh-g460-elf に代えるだけです。
用意したソースは、binutils-2.21.tar.bz2 gcc-4.6.0.tar.bz2 newlib-1.18.0.tar.gz です。newlib だけは、redhat からです。
これらを、/usr/local フォルダにコピーしておき、以下を実行します。
#------------- 解凍
cd /usr/local
bzip2 -dc binutils-2.21.tar.bz2 | tar xvf - >tarbin221.log 2>&1
tar zxvf newlib-1.18.0.tar.gz >tarn1180.log 2>&1
bzip2 -dc gcc-4.6.0.tar.bz2 | tar xvf - >targc460.log 2>&1
#------------ configure binutils
cd /usr/local/binutils-2.21
mkdir buildsh
cd buildsh
../configure --target=sh-g460-elf --prefix=/usr/local/sh-g460-elf --disable-nls \
>confb.log 2>&1
#------------- make and install
make >makeb.log 2>&1
make install >makebi.log 2>&1
#------------ cd dir
cd /usr/local
cd gcc-4.6.0
mkdir buildsh
cd buildsh
#------------- set path
export PATH=/usr/local/sh-g460-elf/bin:$PATH
#------------- configure
../configure --target=sh-g460-elf --prefix=/usr/local/sh-g460-elf \
--with-gmp --with-mpfr --with-mpc \
--with-gnu-as --with-gnu-ld --with-newlib \
--with-headers=/usr/local/newlib-1.18.0/newlib/libc/include \
--enable-languages=c,c++ >confshg460.log 2>&1
#------------- make and install
make >makeshg460.log 2>&1
make install >makeshg460i.log 2>&1
#------------- add newlib
cd /usr/local/newlib-1.18.0
mkdir buildsh
cd buildsh
../configure --prefix=/usr/local/sh-g460-elf \
--target=sh-g460-elf \
>confb.log 2>&1
#------------- make and install
make >maken.log 2>&1
make install >makeni.log 2>&1
#------------- tar and zip toolchain
cd /usr/local/sh-g460-elf
tar zcvf ../sh-g460-elf.tar.gz ./ >../tarshg460.log 2>&1
これらのコンパイルは、RXのように1時間ほどでは終わらず、かなり時間がかかり、Corei5の3.3GHzで、2 時間半ほどかかりました。
tar.gz でまとめたものはこちら。→ sh-g460-elf.tar.gz 90MBほどあります。無い場合は日を改めてね。ときどきサーバーを止めます。
解凍して、sh-g460-elf フォルダを /usr/local フォルダにコピーして、
export PATH=/usr/local/sh-g460-elf/bin:$PATH でパスを通すと使えます。
makefile の例です。ここで紹介したSDカードを操作するモニタを、GCCで開発できるものです。
#/*
# Copyright Bitcraft Co.Ltd 2011.6
# All rights reserved.
#*/
CC = sh-g460-elf-gcc
LD = sh-g460-elf-ld
OBJCOPY = sh-g460-elf-objcopy
AS = sh-g460-elf-as
STRIP = sh-g460-elf-strip
# -finput-charset=cp932 -fexec-charset=cp932 はSJISコメント// 行の右端が"能"、文字列で、"表示"などの対策
CFLAGS = -m2a -Os -finput-charset=cp932 -fexec-charset=cp932
LDFLAGS_RAM = -Tspr7262.x -nostartfiles
LDFLAGS_ROM = -Tspr7262r.x -nostartfiles
# C library
LDLIBS = /usr/local/sh-g460-elf/lib/gcc/sh-g460-elf/4.6.0/m2a/libgcc.a
all: spr7262.mot spr7262r.mot monitor.s monitor.lst
# RAM
spr7262.mot : crt0.o intprg.o monitor.o mmcbios.o makefile spr7262.x sh7262.h
$(LD) $(LDFLAGS_RAM) -Map=spr7262.map -o spr7262.elf crt0.o intprg.o monitor.o mmcbios.o $(LIBC) $(LDLIBS)
$(OBJCOPY) -O srec -R .stack spr7262.elf spr7262.mot
# rm spr7262.elf
# ROM
spr7262r.mot : crt0.o intprg.o monitor.o mmcbios.o makefile spr7262r.x sh7262.h
$(LD) $(LDFLAGS_ROM) -Map=spr7262r.map -o spr7262r.elf crt0.o intprg.o monitor.o mmcbios.o $(LIBC) $(LDLIBS)
$(OBJCOPY) -O srec -R .stack spr7262r.elf spr7262r.mot
# rm spr7262r.elf
# FLASH ROM
monitor.o : monitor.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -c $(CFLAGS) -o monitor.o monitor.c
monitor.s : monitor.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -S $(CFLAGS) -o monitor.s monitor.c
mmcbios.o : mmcbios.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -c $(CFLAGS) -o mmcbios.o mmcbios.c
mmcbios.s : mmcbios.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -S $(CFLAGS) -o mmcbios.s mmcbios.c
intprg.o : intprg.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -c $(CFLAGS) -o intprg.o intprg.c
intprg.s : intprg.c makefile spr7262.x sh7262.h spr7262r.x
$(CC) -S $(CFLAGS) -o intprg.s intprg.c
#
monitor.lst : monitor.s makefile sh7262.h
$(AS) -isa=sh2a -o monitors.o -ahls=monitor.lst monitor.s
crt0.o : crt0.s makefile sh7262.h
$(AS) -isa=sh2a -o crt0.o -ahls=crt0.lst crt0.s
この makefile で扱うSDカード操作プログラムの Cygwin GCC sh-g460-elf.tar.gz 用の全ソースはこちら → sh7262mmc.lzh
解凍して、Cygwin の 適当なディレクトリにコピーします。例。Cygwin/home/anonymous/sh7262mmc
ここには、0xFFF89000から(CQ出版のSROMのブートローダ対応)ロードされて実行可能なROMファイルと、0x1C000000からロードして実行可能なRAM用ファイルを作成する、リンカースクリプトを含んでいます。
ソースを改造して、再構築するには、cd /home/anonymous(例)/sh7262mmc で、make ( enter ) で、ROM用 spr7262r.mot、RAM用の実行ファイル spr7262.mot ができます。SROMのブートローダーで、電源ONで実行させるには、spr7262r_boot.mot の 先頭から、0xFFF88FFF までがブートローダーなので、これを、spr7262r.mot の前方に追加して、SROMの0番地から書けば、電源ONで、spr7262r.mot が走ります。ただ、このプログラムには、SROMの書き換え機能を含んでいません。SDカードを操作するソフトです。
このプログラムの元になった、Hewで作成するプロジェクトファイル一式がこちら → Interface_Sample5a.lzh
中身を見ると判りますが、GCCで作成すると、1割強短くなっています。Hexファイルを、モニタでロードしてみて、比較したスクリーンショットです。
上3行が、Hewで作成したRAM用実行プログラムの長さ。(アドレスでの長さではなく、ロードしたバイト数)
5行目から7行目が、GCC( sh-g460-elf.tar.gz )で作成したRAM用実行プログラムの長さ。(アドレスでの長さではなく、ロードしたバイト数)
いづれも、Sレコードからメモリに書いた長さなので、( 最終にロードされるアドレス − 先頭アドレス ) ではありません。実際、Hewで作成したものは、リンカーのセクション指示で、アドレスが不連続になっていますから、0x1C004F6E が最終というわけではありません。
なお、Hewでのコンパイルオプションは、コードサイズを小さくするのを最優先としており、GCCも同じです。GCCでのオプションは、-Os となっています。
ちなみに、実行スピードでは、Hewが早いようです。特に、Dhry Stone V2.1 ベンチマークでは、Hewの方が早いらしい。というのは、Dhry Stone では文字列の比較ルーチンがあり、Hewでは、SH2の特別な命令を使って、このあたりを早く実行するからだと思われます。SH7262では試していませんが、以前、SH2で比較したことがあり、Hewがかなり早かった記憶があります。1.2〜1.3倍。
Dhrystone 2.1 で、186,780 Dhrystones per Second
Dhrystone 2.1 は、20年以上も使われているベンチマークソフトですが、ICベンダーのコンパイラでは、たとえば、文字列比較( strcmp )などを、高速に実行するため、特殊な命令を使ったライブラリを使うので、単純な比較はできません。そこで、strcpy , strcmp などを、組み込みライブラリを使わず、自前で作成したもので、Dhrystones per Second を出してみます。Dhrystone 2.1 では、時間を計測する、time() 関数が必要なので、SH7262内蔵のタイマーカウンタを使います。
ところが、モニタで使用しているカウンタは、16ビットまでなので、長時間の測定ができません。そこで、16ビットタイマーを2個使って、カスケード接続して、32ビットカウンタで測定します。使うタイマーは、マルチファンクションタイマの、TCNT_2 と TCNT_1 です。この2個は、カスケード接続ができますが、TCNT_2 のプリスケーラの選択が減って、PΦ/512 が無く、PΦ/64 を使うことになります。PΦは、24MHzなので、1クロックが、2.66666μsec になります。これでカスケード接続の32ビットのカウントを行って、時間を計測します。それぞれのカウンタ値は、別アドレスになっているので、2箇所読んで、ソフトで結合しますが、カウンタのLSB側 TCNT_2 読んだときがオーバーフロー直前で、上位MSB TCNT_1 を後で読んだときには、TCNT_1 が更新してしまう場合が起こります。この場合は本来の値より、0xFFFF多くなってしまいます。これを避けるには、TCNT_2 を読んだときに、0xFFFFなら、0xFFFFでなくなるまで待って、TCNT_1 を読むようにします。では、TCNT_2 が0xFFFEならどうなのかということですが、CPUが早いので、割り込みを使っていなければ、 TCNT_1 を読むときまでオーバーフローすることはありません。
以下は、Dhrystone 2.1 を、100万回実行したときのスクリーンショットです。
下の方の、Time HEX = 51B51A は、32ビットカウンタから読んだ差を、マイクロ秒に換算した32ビットのヘキサ表示の値です。100万回で約5.3秒かかっています。18万6千というのは早いのか遅いのか、ピンときませんが、パソコンのCore2 2.2GHzで、約770万になるので、この場合1/41の速さになります。
ちなみに、インターフェイス誌2009年5月号の付録基板、ARM の LPC2388(72MHz)では、6万2千500でした。ここで使っているSH2Aは、付録基板のARMの、2倍のクロック(144MHz)ですが、Dhrystone 2.1 では、3倍ほど になっています。無論、同じソースで、コンパイラもGCCを使って、オプティマイズも(−O2)での比較です。SH7262は、最高で、2命令/1クロックなので、この辺で差が出ているものと思います。さらに、SH4(SH7750。SH4としてはかなり古い)の240MHzでは、約35万になります。144MHz換算では、21万となり、クロックを考慮すると、SH7750が勝っています。SH4も、2命令/1クロックですが、さすがSH4って感じです。
上記のスクリーンショットで使ったDhrystone 2.1 の Cygwin ソース一式。 この中の、spr7262.mot を、アドレス情報通りに SH7262の0xFFF80000番地からロードし、0xFFF80500から実行します。その後、
SH2A-Bug>Df4240 ( enter ) で、
Dhrystone Benchmark, Version 2.1 (Language: C)
Program compiled without 'register' attribute
Program compiled with optimizing option (-O2)
Please give the number of runs through the benchmark: ここで、( enter ) のみを押すと、
Dhrystone 2.1 を100万回実行して、約5秒後に結果を出します
spr7262.mot での回数指定は、SH2A-Bug>Df4240 と、0xf4240 ( 1,000,000 ) で指定しています。実行結果の計算は、整数で行っているので、最大で約100万回です。'D' は、 Dhrystone を実行するコマンドです。
上記のソースの元にしたのは、
Windows(VC++ 6.0、2005 など)でコンパイルできる Dhrystone 2.1 の ソースです。実行ファイルは、dhry21.exe 。 ソースは、どこからダウンロードしたか不明です。コンパイル時にたくさんの warning が出ますが無視。パソコンでは100,000,000回実行します。(1億回 )
工事中
ホーム に戻る
SEO