RH850F1KHで自動生成コードをベースでCANドライバーを作る2

前記事では北斗電子さんHSBRH850F1KH176をターゲットにRH850自動コード生成をベースとし、RH850/U2A 用のCANドライバサンプルコードを、RH850F1KH用に基本部分を移植しました。次にCAN送信をテストしていきます。今回は企画元がFD未対応なので、CAN2.0のみの使用です。


CAN受信側のハードは、PEAK CAN-USB FDバージョン を用います。代理店さんから購入予定でしたが、ebayで新品放出品があり入手しました。正規ルート以外はコピー品も多いようなので要注意です。ドイツから直接購入は出来ないようです。過去職場でCAN2.0版を導入しましたが、筐体が黒になり安っぽさが消えたように見えます。Kavaer PCeボートも保有していますが、今回、新しく試しています。

配線はpin1とpin4を逆にしないよう注意です。HSBRH850F1KH176 のCANコネクタはpin番号がシルクに書いないようです。JST製なのでpin番がハウジングに書いてあったと思いましたが見当たらず。付属のケーブルは線が細くはんだ付して直ぐ切れそうリスキーです。太い線で作り直した方がよさげです。CANも絶縁になっていないので回路検討としてはCANトランシーバから先は別で組んだ方が良いかも。

CAN受信側のソフトはオープンソースのBUSMATER を用います。CAN DBを定義でき、CANシグナルに分けてサンプリングとログができます。CANLayzer の CAN DB のコンバートも可。しかし数年間、UPDATEがありません。のでCAN-FDには未対応です。過去職場でも紹介し導入し、割と評判が良かったですが、世間的には知名度が低いのでしょうか? (リリース当時ETASさんもアピールしていましたが) にしてもKavaer CAN King ( 全然Kingじゃない )は使い物にならないと思うのですが…


マニュアル 「表 24.125 通信速度の設定例」の表内の「(数値)」が、CANクロックの分周ですが、そのまま設定するとBUSエラーになります。通信速度の計算式をみると、そこから -1 が必要です。CANクロック:fCAN40MHz1Mbpsの場合、r_rh850_can_cfg.c の設定は以下のようになります。Tq数( 1bitの分解能、通信相手によっては調整要す )は取急ぎ粗目に 8 としています。

const can_ch_cfg_t  g_can_ch_cfg[ USED_UNIT_NUM ][ MAX_CH_NUM_U0 ] = {
// ========================== U n i t 0 設 定 ==========================
{
	// ------------------------ C h 0 設 定 ---------------------------
    {
    ・・・中略・・・
     /* ---- Normal Baudrate ----
       パラメータ( 分周比, SEG1 Bit-Timing, SEG2 Bit-Timing, Jump幅)
  	 */
    	CAN_CFG_N_BAUDRATE(
			// 1Mbps 分周比 = 40Mhz ÷ ( 1MHz × Tq数:8 ) = 5 より-1
   			4U, CAN_NTSEG1_5TQ, CAN_NTSEG2_2TQ, CAN_NSJW_1TQ
		),
    	/* ---- Data Baudrate ---- */
    	CAN_CFG_D_BAUDRATE(
			// 1Mbps 分周比 = 40Mhz ÷ ( 1MHz × Tq数:8 ) = 5 より-1
			// 取急ぎCAN2.0では Normal Baudrate と同じでよい模様。
   			4U, CAN_NTSEG1_5TQ, CAN_NTSEG2_2TQ, CAN_NSJW_1TQ
		),

設定値まとめを以下に示します。なお一般的に乗用車両は500kbps、働く車やレクレーションVehicleは250kbpsですが、レースや車両評価で使う場合は1Mbpsが多いようです。

項目
通信速度1Mbps
fCAN クロック40Mz
クロック分周5
Tq数8
SEG1 Bit Timing5
SEG2 Bit Timing2
Bitズ レジャンプ幅1

CANクロック::fCANは、設定にもよりますが下図の部分でよいようです。


RH850では送信は3つの方法があります。その中で送信Buffer が一番シンプルな手段です。使用する APIは R_CAN_TransmitByTxBuf (orgは略しすぎなので改名してます) です。送信Buffer 数は以下のようになっています。

項目
1 Channelあたり送信Buffer数36
1 Unitあたり送信Buffer SFR数255

CAN Channel と 送信Buffer の割当てがイマイチ分かりにくいです。単純に 「 Channel番号 × 36 + CH毎に使うBuffer番号」 でいいようです。OrignalのAPIは 送信Buffer 番号は絶対値なので、ch毎の相対にした方が使いやすいでしよう。以下コードを追加しました。

#define CAN_CH_TO_TX_BUF( ch, num )			( ch * MAX_TX_BUF_OF_CH	+ num )
・・・中略・・・
	// 送信Buffer番号を算出
	txbuf_idx = CAN_CH_TO_TX_BUF( ch_idx, txbuf_idx )

以下呼出しコード例です。基板確認のため、Ch 0、Ch 1両方試します。

	Can_RtnType ret;
	can_frame_t	frame;

	frame.ID	= 0x700;
	frame.DLC	= 8;
	frame.IDE	= 0;	  // 標準frame
	frame.TMFDF = 0;	// CAN2.0
	frame.RTR	= 0;
	frame.DB[ 0 ]	= 0x30;
	frame.DB[ 1 ]	= 0x31;
	frame.DB[ 2 ]	= 0x32;
	frame.DB[ 3 ]	= 0x33;
	frame.DB[ 4 ]	= 0x34;
	frame.DB[ 5 ]	= 0x35;
	frame.DB[ 6 ]	= 0x36;
	frame.DB[ 7 ]	= 0x37;

	ret =  R_CAN_TransmitByTxBuf(	0,	// i : CAN Unit
								  0, 	    // i : CAN Ch番号
									0, 	    // i : 送信Bfffer番号
									&frame	// i : CAN Frame
	);
	
  frame.ID	= 0x701;
	frame.DLC	= 8;
	frame.IDE	= 0;	// 標準frame
	frame.TMFDF = 0;	// CAN2.0
	frame.RTR	= 0;
	frame.DB[ 0 ]	= 0x40;
	frame.DB[ 1 ]	= 0x41;
	frame.DB[ 2 ]	= 0x42;
	frame.DB[ 3 ]	= 0x43;
	frame.DB[ 4 ]	= 0x44;
	frame.DB[ 5 ]	= 0x45;
	frame.DB[ 6 ]	= 0x46;
	frame.DB[ 7 ]	= 0x47;

	ret =  R_CAN_TransmitByTxBuf(	0,	// i : CAN Unit
								 	1, 	    // i : CAN Ch番号
									0, 	    // i : 送信Bfffer番号
									&frame	// i : CAN Frame
	);

BUSMASTERでの受信結果は以下のとおりです。送信できない場合、あまり不確定要素はないため、配線ミスかBaudrate間違いの可能性が高いです。

なお送信前に、送信中かエラー中かの判定もないので追加したほうがいいでしょう。API: R_CAN_CheckTxBufResult でも代用できるかもしれません。

	{
		volatile uint32_t sts;

		sts = RCFDCnCFDCmSTS( ch_idx );
		if ( ( sts & CAN_COM_STS_BIT_ON ) == 0) {   // Ch通信可=不可
			return CAN_RTN_TX_ERROR ;
		}

		if ( ( sts & CAN_BUSOFF_STS_BIT_ON ) != 0) {  // Ch BUS-OFF
			return CAN_RTN_TX_ERROR ;
		}

		if ( ( sts & CAN_TRM_STS_BIT_ON ) != 0) {  	// Ch送信STATUS=送信中
			return CAN_RTN_TX_ERROR ;
		}
	}


送信完了割込みは、エラー割込みや送信前のSFRチェックを行えば特に不要です。割込が多発すると、組込みでは貴重な処理能力を食います。今のところは余裕があるため検出しておきました。弊方での実装例は以下のとおりです。実装先は自動コード生成された r_smc_intprg. c です。

/* CAN0 TRANSMIT INTERRUPT */
#if defined (__CCRH__)
#pragma interrupt IntCAN0Tx(enable=false, channel=26, fpu=true, callt=false)
#elif defined (__ghs__)
#pragma ghs interrupt
#elif defined (__ICCRH850__)
#pragma type_attribute=__interrupt
#else
#error Unknown Compiler
#endif
void IntCAN0Tx(void)
{
/* Start user code for IntCAN0Tx. Do not edit comment generated here */
	R_CAN_DispatchEevent( 0 /*unit*/, 0 /* ch.*/, CAN_EVENT_SEND_COMPLATE );
/* End user code. Do not edit comment generated here */
}

弊方では上記の R_CAN_DispatchEevent の中で、登録ずみcallbackを呼んでいます。例がなくとも想像がつくでしょう。r_rh850_can_cfg.c の設定も少し変更します。以下の 0xFFFFU の部分、送信Buffer の32個に対して1bitづつ有効無効を指定します。取急ぎ全部有効にしておきます。

const can_ch_cfg_t  g_can_ch_cfg[ USED_UNIT_NUM ][ MAX_CH_NUM_U0 ] = {
// ========================== U n i t 0 設 定 ==========================
{
	// ------------------------ C h 0 設 定 ---------------------------
    {
 ・・・中略・・・   
        /* ---- Tx/Rx FIFO buffer ---- */
        0x00000000UL,
     	  0x00000000UL,
        0x00000000UL,
        /* ---- Tx queue ---- */
        0x00000000UL,
        /* ---- 送信Buffer割込許可 RCFDCnCFDTMIECm ---- */
        0xFFFFU		// LSBより 1bit 1Buffer で割当て
    }

割込みが発生しない、割込みが発生後、RESETする場合は、割込み設定が正しくできていない可能性が高いです。前記事をよく確認します。

以上で送信まで試せました。受信編へ続きます。


SFRは多すぎてウオッチするのに時間がかかります。CS+ にもあるかもしりませんが、e2Studioでとても役に立った機能を記録しておきます。

① 選択されたレジスターを使うと、確認したいSFR値だけをまとめておける。

② 上記①の抽出のため、SFR一覧の目視検索に時間がかがる。SFRiodefine.hの定義名なので、マニュアル記載名が検索キーにならないところ、アドレスでも検索できる。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です