(toppers-users 3063) [H8]E_CTX reported by `isig_tim()' in line 63 of `../jsp/systask/timer.c'. 頻発

中村和博 norichan1108 @ gmail.com
2010年 2月 12日 (金) 22:21:08 JST


はじめまして、中村といいます。

今回、事情によりH8/3069とToppers/JSPを使用して装置を組むこととなりました。
装置としてはグラフィックLCDとシリアル通信デバイスをつないで、画面情報を
表示するという簡単なアプリケーションです。
表示周りの動作が確認でき、デバイスとのシリアル通信もいくらかはできているの
ですが、シリアル通信中にフリーズしたり、E_CTXとなりisig_tim()がエラーを
返したりしてしまいなかなかうまくいきません。

E_CTX reported by `isig_tim()' in line 63 of `../jsp/systask/timer.c'.

実は装置そのものは月曜までに最低限の動作を仕上げなければならないこともあり、
このままToppers/JSPを使うのか、作り直すかを判断しなければならない時期に
さしかかっています。もし、H8ポートでの上記の現象について何か情報がありま
したらご教授いただけませんでしょうか。


それから、ざっとH8のハードウェアマニュアルを斜め見したところ、
t_cpu_lock()で呼ばれているdisintの実装でORCでCCRのI,UIフラグをセットした
直後にcpulockフラグを設定していますが、ORC実行中に割り込みを受けた場合、
H8はORCの次の命令を実行してから割り込み先に分岐するようです。
そうなると、CPUロック状態で割り込みに入ってしまう可能性があります。
なので、disintのORCの後にNOPなりの無効な処理を入れたほうが良いように思えます。

--引用ここから--
5.5.2 割り込みの受け付けを禁止している命令
割り込みを禁止している命令には、LDC、ANDC、ORC、XORC 命令があります。
割り込み要求が発生すると、割り込みコントローラが優先順位を判定した後、CPUに対
して割り込みを要求します。そのとき、CPUが割り込みを禁止している命令を実行してい
る場合は、その命令の実行を終了した後、必ず次の命令を実行します。
--引用ここまで--


なお、上記の修正(NOP追加)は手元で実際に試して見ましたが今回の現象の改善にはな
りませんでした。他の原因があるのかと思います。


環境:
ubuntu 8.04TLS(on VMWare)
gcc-3.4.3 非パッチ(with-newlib disable-nls)
binutils-1.15 (disable-nld)
newlib-1.13.0
make 3.81

汚いソースですがシリアル部分のソースです。
LCDやキー入力関連タスクをすべて殺した状態でも再現します。

oid rfid_task_main( VP_INT exinf )
{
  UB		buf[RECV_BUF_LEN];
  ER		result;
  RFID_MSG*	msg;
  int		i;
  int		cnt;
  int		l;
  T_SERIAL_RPOR	sts;

  if ((result = serial_opn_por(USER_PORTID)) == E_OK)
    {
      /* ポート制御フラグの設定 */
      syscall(serial_ctl_por(USER_PORTID, 0));

      /* ダミーを送信して、コマンドが正常に受け付けられるようにする */
      for (i=0; i<2; i++)
	{
	  /* ダミーCRを送信 */
	  syslog(LOG_NOTICE, "Send:CR");
	  result = serial_wri_dat(USER_PORTID, DUMMY, sizeof(DUMMY)-1);

	  syslog(LOG_NOTICE,"result:%d",result);

	  if (result != sizeof(DUMMY)-1)
	    {
	      syslog(LOG_EMERG, "error serial_wri_dat() code=%d", result);
	    }
	
	  /* 100ms待機 */
	  syscall(dly_tsk(100));

	  /* バッファの内容を読み出し */
	  memset(buf, 0, sizeof(buf));
	  for (i=0;; i++)
	    {
	      result = serial_rea_dat(USER_PORTID, &buf[i], 1);
	      if (result == 1)
		{
		  if (buf[i] == '\r') break;
		}
	      else
		{
		  syslog(LOG_EMERG, "error serial_rea_dat() code=%d", result);
		}
	    }
	  syslog(LOG_NOTICE, "Recv:%s", buf);
	}

      /* コマンドモードへ設定 */
      syslog(LOG_NOTICE, "Send: %s", CMD_MODE);
      result = serial_wri_dat(USER_PORTID, CMD_MODE, sizeof(CMD_MODE)-1);
      if (result != sizeof(CMD_MODE)-1)
	{
	  syslog(LOG_EMERG, "error serial_wri_dat() code=%d", result);
	}
      syslog(LOG_NOTICE, "Send-");

      /* 応答受信 */
      memset(buf, 0, sizeof(buf));
      for (i=0;; i++)
	{
	  result = serial_rea_dat(USER_PORTID, &buf[i], 1);
	  if (result == 1)
	    {
	      if (buf[i] == '\r') break;
	    }
	  else
	    {
	      syslog(LOG_EMERG, "error serial_rea_dat() code=%d", result);
	    }
	}
      syslog(LOG_NOTICE, "Recv:%s", buf);

      /* Mifareモードへ設定 */
      syslog(LOG_NOTICE, "Send: %s", MIFARE_MODE);
      result = serial_wri_dat(USER_PORTID, MIFARE_MODE, sizeof(MIFARE_MODE)-1);
      if (result != sizeof(MIFARE_MODE)-1)
	{
	  syslog(LOG_EMERG, "error serial_wri_dat() code=%d", result);
	}
      syslog(LOG_NOTICE, "Send-");

      /* 応答受信 */
      memset(buf, 0, sizeof(buf));
      for (i=0;; i++)
	{
	  result = serial_rea_dat(USER_PORTID, &buf[i], 1);
	  if (result == 1)
	    {
	      if (buf[i] == '\r') break;
	    }
	  else
	    {
	      syslog(LOG_EMERG, "error serial_rea_dat() code=%d", result);
	    }	
	}
      syslog(LOG_NOTICE, "Recv:%s", buf);

      for (;;)
	{
	  /* スキャンコマンドの送信 */
	  syslog(LOG_NOTICE, "Send: %s", MIFARE_SCAN);
	  result = serial_wri_dat(USER_PORTID, MIFARE_SCAN, sizeof(MIFARE_SCAN)-1);
	  if (result != sizeof(MIFARE_SCAN)-1)
	    {
	      syslog(LOG_EMERG, "error serial_wri_dat() code=%d", result);
	    }

	  syslog(LOG_NOTICE, "Send-");
	  /* 応答受信 */
	  memset(buf, 0, sizeof(buf));
	  for (i=0;; i++)
	    {
	      result = serial_rea_dat(USER_PORTID, &buf[i], 1);
	      if (result == 1)
		{
		  if (buf[i] == '\r') break;
		}
	      else
		{
		  syslog(LOG_EMERG, "error serial_rea_dat() code=%d", result);
		}	
	    }
	  buf[i] = 0;
	  syslog(LOG_NOTICE, "Recv:%s", buf);

	  /* 0.5秒間停止 */
	  syscall(dly_tsk(500));
	}
    }
}