マイコンカーラリーで1ms毎の高速データログを目指す

マイコンカーラリーの走行データ記録

マイコンカーラリー競技で速度アップするためのパラメータ調整には走行中のラインセンサの状態、速度、ステアリング角度などをチェックすることが欠かせません。

マイコンカーラリーではMicroSDカードに走行データを記録するライブラリが提供されており、MicroSDカード用のボードを追加したり、MicroSDカードコネクタが付いたドライブボードを使って走行データ分析のために活躍しています。

ボード搭載MicroSDカードの速度限界と出来れば実現したい速度

このライブラリによるMicroSDカードへの記録は50000bpsの通信速度でおこなわれているので62文字/10msが限界となっています。
MicroSDカードとの通信に使えるハード的な速度はまだ余裕があるはずですがデータのフォーマット処理とFat形式でMicroSDへ書き込むプログラムの速度を考えれば20MHzのR8Cではこのあたりが限界なのでしょう。

マイコンカーラリーでは1mSのサイクルタイムで制御しているので出来れば1mS毎のデータを記録しておきたいところです。

そのために使える手段としてプログラム書き込みコネクタに接続されているUART0の最高通信速度1250000bpsでデータを出力してそのデータを別のボードでMicroSDに記録するという方法があります。

通信速度1250000bpsならば125文字/mSのデータが出力できますので理論的には1mS毎のデータを記録可能です。
残る問題はプログラム処理時間にそれだけのデータを送る余裕があるか否かです。

現状のプログラム実行時間測定

1mS毎にデータ送信するプログラムを組み込めるかどうかを検討するために、まず現在のプログラム実行時間を調べてみました。
測定手法は調べたい処理の最初にR8C/38ボード上のLEDを点灯するコード

p4_5 = 1;

を挿入し、処理の最後にLEDを消灯するコード

p4_5 = 0;

を挿入してプログラムを実行し、LEDの端子にオシロのプローブを当てて実測波形で該当部分の時間を測るという単純な方法です。

割り込み関数で消費される時間

intTRB(): 1mS毎の割り込み関数で制御のベースになっています。
実測時間 : 約100uS ~ 150uS  microSD書き込み時も大きな変化なし

printf関数を使ったデータ出力時間

まず通信速度1250000bpsに設定してprintf関数を使ったデータ送信に必要な時間を測定してみました。
4桁の16進数+カンマを8組(42文字)出力する例で2mS近く時間がかかっていました、これは単純にprintf関数の実行時間ですが通信速度と送信文字数を考慮すると送信割り込み関数の消費時間もこの時間に含まれています。
いずれにしてもこれでは1mS毎のデータ出力には使えそうもありません。

シンプルなフォーマット関数を考える必要あり。

送信割り込み _uart0_trans() (vect=17) の実測時間
15uS ~ 100uS

write() 関数の実測消費時間
約10u

送信割り込みを使っているので速いと思っていましたが、実測では一文字出力するのに50uS以上の時間がかかっています、1250000bpsの通信速度では 割り込みを使わないほうが5倍速いことになります 8-O

DTCを使ったUART0送信

R8C/38はDMAの代わりにDTCという機能があります、この機能を使って送信する方法を試してみました。

参考サイト
https://www.renesas.com/ja-jp/doc/products/mpumcu/apn/004/rjj05b1533_r8cap.pdf

https://www.renesas.com/ja-jp/software/D1016391.html

上はUART0の同期送受信のサンプルプログラムです。
これを参考にして下の送信プログラムを作ってみました、printf関数からも使えるようになっていますがprintfのオーバーヘッドに注意する必要があります。
バッファが一杯になるか改行があるとバッファのデータをDTCを使って送信します、DTC送信中は次のDTC送信要求は無視されますから送信が終わってから次の送信を始めなければなりません。
例えばタイマ割り込み関数の中でデータを送信する用途に向いています。

ライブラリに含まれているprintfではオーバーヘッドが大きすぎるので専用のフォーマット関数を使わないと1mS毎のデータ送信は無理があります。

/*======================================*/
/* インクルード */
/*======================================*/
#include <stdio.h>
#include "sfr_r838a.h" /* R8C/38A SFRの定義ファイル */
#include "printf_uart0.h" /* printf関連処理 */
/*======================================*/
/* シンボル定義 */
/*======================================*/
#define TX_BUF_SIZE 128 //64 /* 送信バッファサイズ */

/* printf,scanfに必要な変数 */
volatile FILE _iob[4]; // ダミー変数

/*======================================*/
/* グローバル変数の宣言 */
/*======================================*/
/* 送信バッファ */
static volatile char uart0_tx_buf[TX_BUF_SIZE];
static volatile char *tx_wp = uart0_tx_buf;
static volatile int tx_ct = 0;

/**********************************************************************************/
/* RAM
/**********************************************************************************/

#pragma ADDRESS dtc_fact_s0t 02C0BH /* DTC vector address of UART0 transfer interruption */
#pragma ADDRESS dtc_fact_s0r 02C0AH /* DTC vector address of UART0 receive interruption */

#pragma ADDRESS dtccr_dtcd0 02C40H /* Address of DTC control register in dtcd0 */
#pragma ADDRESS dtbls_dtcd0 02C41H /* Address of DTC block size register in dtcd0 */
#pragma ADDRESS dtcct_dtcd0 02C42H /* Address of DTC transfer count register in dtcd0 */
#pragma ADDRESS dtrld_dtcd0 02C43H /* Address of DTC transfer count reload register in dtcd0 */
#pragma ADDRESS dtsar_dtcd0 02C44H /* Address of DTC source address register in dtcd0 */
#pragma ADDRESS dtdar_dtcd0 02C46H /* Address of DTC destination address register in dtcd0 */

#pragma ADDRESS dtccr_dtcd1 02C48H /* Address of DTC control register in dtcd1 */
#pragma ADDRESS dtbls_dtcd1 02C49H /* Address of DTC block size register in dtcd1 */
#pragma ADDRESS dtcct_dtcd1 02C4AH /* Address of DTC transfer count register in dtcd1 */
#pragma ADDRESS dtrld_dtcd1 02C4BH /* Address of DTC transfer count reload register in dtcd1 */
#pragma ADDRESS dtsar_dtcd1 02C4CH /* Address of DTC source address register in dtcd1 */
#pragma ADDRESS dtdar_dtcd1 02C4EH /* Address of DTC destination address register in dtcd1 */

unsigned char dtc_fact_s0t; /* Control Data No. of UART0 transmit interruption */
unsigned char dtc_fact_s0r; /* Control Data No. of UART0 receive interruption */

unsigned char dtccr_dtcd0; /* DTC control register in dtcd0 */
unsigned char dtbls_dtcd0; /* DTC block size register in dtcd0 */
unsigned char dtcct_dtcd0; /* DTC transfer count register in dtcd0 */
unsigned char dtrld_dtcd0; /* DTC transfer count reload register in dtcd0 */
unsigned short dtsar_dtcd0; /* DTC source address register in dtcd0 */
unsigned short dtdar_dtcd0; /* DTC destination address register in dtcd0 */

unsigned char dtccr_dtcd1; /* DTC control register in dtcd1 */
unsigned char dtbls_dtcd1; /* DTC block size register in dtcd1 */
unsigned char dtcct_dtcd1; /* DTC transfer count register in dtcd1 */
unsigned char dtrld_dtcd1; /* DTC transfer count reload register in dtcd1 */
unsigned short dtsar_dtcd1; /* DTC source address register in dtcd1 */
unsigned short dtdar_dtcd1; /* DTC destination address register in dtcd1 */
/************************************************************************/
/* UART0の初期化、及びprintf関係をUART0に割り当て */
/* 引数  通信速度 */
/************************************************************************/
void init_uart0( long bps )
{
  int brg;

  stdin->_cnt = stdout->_cnt = stdaux->_cnt = stdprn->_cnt = 0;
  stdin->_flag = _IOREAD;
  stdout->_flag = _IOWRT;
  stdaux->_flag = _IORW;
  stdprn->_flag = _IOWRT;

  stdin->_mod = _TEXT;
  stdout->_mod = _TEXT;
  stdaux->_mod = _BIN;
  stdprn->_mod = _TEXT;

  stdin->_func_in = NULL;
  stdout->_func_in = NULL;
  stdaux->_func_in = NULL;
  stdprn->_func_in = NULL;

  stdin->_func_out = NULL;
  stdout->_func_out = write;
  stdaux->_func_out = write;
  stdprn->_func_out = NULL;

  brg = (1250000L*10 / bps+5)/10 - 1; /* 四捨五入処理をしている */
  /* UART0の設定 */
  u0sr = 0x05; /* P14=TXD0,P15=RXD0に設定 */
  u0c0 = 0x00; /* カウントソース=20MHz */
  u0c1 = 0x05; /* 送信、受信許可 */
  u0brg = brg; /* 通信速度 = brg */
  u0mr = 0x05; /* UART0 データ長8bit 1ストップビット */
  s0tic = 0x00; /* UART0 transmit interrupt disabled */

  /* Setting DTCD0 registers */
  dtc_fact_s0t = 0; /* Setting Control Data No. of UART0 transfer interruption to "No. 0" */
  dtccr_dtcd0 = 0x04; /* Setting DTC control register in DTCD0 at UART0 transfer interruption */
  /* Normal mode is selected */
  /* Source address is incremented */
  /* Destination address is fixed */
  /* Chain transfers is disabled */
  dtbls_dtcd0 = 1; /* Setting DTC block size register in DTCD0 */
  /* One-byte is set */
  dtcct_dtcd0 = TX_BUF_SIZE-1; /* Setting DTC transfer count register in DTCD0 */
  /* Transmit or receive data size minus one is set to transfer */
  dtrld_dtcd0 = 0; /* Setting DTC transfer count reload register in DTCD0 */
  /* Not used in normal mode */
  dtsar_dtcd0 = (unsigned short )&uart0_tx_buf[1];
  /* Setting DTC source address register in DTCD0 */
  /* DTC source address is set to the address of "uart0_tx_data[1]"*/
  dtdar_dtcd0 = (unsigned short)&u0tbl; /* Setting DTC destination register in DTCD0 */
  /* DTC destination address is set to the address of "u0tbl" register */

  /* Setting DTC activation enable registers */
  dtcen0 = 0x00; /* Activation disabled */
  dtcen1 = 0x00; /* Activation disabled */
  dtcen2 = 0x00; /* Activation disabled */
  dtcen3 = 0x00; /* Activation disabled */
  dtcen4 = 0x00; /* Activation disabled */
  dtcen5 = 0x00; /* Activation disabled */
  dtcen6 = 0x00; /* Activation disabled */
  dtctl = 0x00; /* Setting DTC activation control register */
  /* Non-maskable interrupts not generated is selected */
}

/************************************************************************/
/* 1文字出力 */
/* 引数  送信データ */
/************************************************************************/
void uart0_putch( char c )
{
  while( ti_u0c1 == 0 ) ;
  u0tbl = c;
}
/**********************************************************************
* printfで呼び出される関数 *
************************************************************************/
int write( int c )
{
  // p4_5 = 1;
  if( (c == '\n')||( TX_BUF_SIZE <= tx_ct ) ){
    if(dtcen14 == 1){ /* An activation disabled in UART0 transmission interrupt ? */
      tx_wp = &uart0_tx_buf[0];
      tx_ct = 0;
      return 0;
    }
    dtcct_dtcd0 = tx_ct-1; /* Setting DTC transfer count register in DTCD0 */
    /* Transmit or receive data size minus one is set to transfer */
    dtsar_dtcd0 = (unsigned short)&uart0_tx_buf[1];
    /* Setting DTC source address register in DTCD0 */
    /* DTC source address is set */
    dtcen14 = 1; /* Activation enabled in UART0 transmission interrupt */
    te_u0c1 = 1; /* Transmission enabled in UART0 */
    while(ti_u0c1 == 0); /* Wating for no data in U0TB register */
    u0tbl = uart0_tx_buf[0]; /* Set transmission first data */
    tx_ct = 0;
    tx_wp = uart0_tx_buf;
  }else{
    *tx_wp++ = c;
    tx_ct++;
  }
  //p4_5 = 0;
  return 1; // TRUE
}

/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれるダミー関数 */
/************************************************************************/
int _sget( void ) { return 0; }

/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれるダミー関数 */
/************************************************************************/
int _sput( int put_data ) { return put_data; }

/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれる1文字出力関数 */
/* 引数  出力文字 */
/* 戻り値 正常:1 以上:EOF */
/************************************************************************/
int _pput( int put_data ) { return put_data; }

/************************************************************************/
/* end of file */
/************************************************************************/