CAN通信の送信時に関して

お世話になります。

RX71MでCAN通信の環境構築をしようとしているものです。

今回CANの送信時にいくつかの疑問が生じてしまったので、お力添えいただいただけないかと投稿させていただきました。

 

まず、今回使用しているmain関数のPCへのCAN送信部分を以下に示させていただきます。

//送信処理(キーボード0-7がMB[0]-[7]に対応)
  xc=sciRead();
  s_mb=0xff;
  switch(xc)
  {
   case '0':
    s_mb=0;  //使用するメールボックス番号
    s_dlc=1; //送信バイト数
    break;
   case '1':
    s_mb=1;
    s_dlc=2;
    break;
   case '2':
    s_mb=2;
    s_dlc=3;
    break;
   case '3':
    s_mb=3;
    s_dlc=4;
    break;
   case '4':
    s_mb=4;
    s_dlc=5;
    break;
   case '5':
    s_mb=5;
    s_dlc=6;
    break;
   case '6':
    s_mb=6;
    s_dlc=7;
    break;
   case '7':
    s_mb=7;
    s_dlc=8;
    break;
#if (LED_PORT_NUM > 0)
   case 'z':
    //ボード識別向けLED点滅
    sciPrintBuf("LED blink test(for board identify).\n");
    led=LED1_PORT;
    for(l=0; l<3; l++)
    {
     LED1_PORT=1;
     for(x=0; x<1000000; x++) nop();
     LED1_PORT=0;
     for(x=0; x<1000000; x++) nop();
    }
    LED1_PORT=led;
    break;
#endif
   case 'c':
    for(l=0; l<CAN_CH; l++)
    {
     send_can_ch++;
     if(send_can_ch>=CAN_CH) send_can_ch=0;
     if(varid_can_ch[send_can_ch] == 1) break;
    }
    sciPrintBuf("CAN send channel -> CAN");
    sciWriteBuf(send_can_ch+0x30);
    sciPrintBuf("\n");
    break;
   default:
    break;
  }
  
  if(s_mb != 0xff)
  {
   switch(send_can_ch)
   {
    case 0:
#if (CAN0_VALID == 1)
     s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 1:
#if (CAN1_VALID == 1)
     s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 2:
#if (CAN2_VALID == 1)
     s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    default:
     break;
   }
   
   sciPrintBuf("CAN");
   sciWriteBuf(send_can_ch+0x30);
   sciPrintBuf(" data send,     MB=0x");
   sciPrintByteBuf(s_mb);
   sciPrintBuf(" ret=0x");
   sciPrintWordBuf(s_ret);
    
   if(s_ret==0)
   {
    sciPrintBuf(" id=MB    ");
    sciPrintBuf(" data=0x");
    for(j=0; j<s_dlc; j++)
    {
     if(j>=8) break;
     sciPrintByteBuf(s_data[j]);
    }
   }
   sciPrintBuf("\n");
  }

 

ざっくりいうと

もともと用意していたデータを用意していたメールボックスにいれ(送信処理前に行っています)

switch関数を用いてキーボードの0~7に対応するメールボックスの番号とデータ量を指定

・switch文を抜けた後に、s_retで送信関数を呼び出してPCへの送信を行う

というような流れになっていると理解しています。

送信用の関数は以下のようになっています。

int can0_send(unsigned char mb, unsigned char dlc, unsigned char *data)
{
 //CAN0 送信関数
 
 //戻り値
 // 0  : 正常終了
 // -1 : 引数チェックエラー
 // -2 : レジスタ値設定変更タイムアウト
 // -3 : メールボックスが受信に設定されている
 // -4 : メールボックス送信中
 
 //引数
 // mb    : メールボックス番号(0-31)
 // dlc   : 送信バイト数(1-8)
 // *data : 送信データ
 
 unsigned short i, loop;
 unsigned char reg8;
 
 if(mb>31) return -1;
 if((dlc == 0) || (dlc>8)) return -1;
 
 //メールボックスが受信モードに設定されているときはエラーとする
 if(CAN0.MCTL[mb].BIT.RX.RECREQ == 1)
 {
  return -3;
 }
 
 if(CAN0.MCTL[mb].BIT.TX.TRMACTIVE == 1)
 {
  //メールボックス送信中
  return -4;
 }
 
 //TRMREQ=0
 reg8 = CAN0.MCTL[mb].BYTE;
 reg8 &= ~0x80;
  CAN0.MCTL[mb].BYTE = reg8;
 
 loop=0;
 while(CAN0.MCTL[mb].BIT.TX.TRMREQ != 0)
 {
  loop++;
  if(loop > CAN_LOOP_TIMEOUT) return -2;
 }
 
 //SENTDATA=0
 reg8 = CAN0.MCTL[mb].BYTE;
 reg8 &= ~0x01;
 CAN0.MCTL[mb].BYTE = reg8;
 
 loop=0;
 while(CAN0.MCTL[mb].BIT.TX.SENTDATA != 0)
 {
  loop++;
  if(loop > CAN_LOOP_TIMEOUT) return -2;
 }
 
 //メールボックスにデータセット
 for(i=0; i<dlc; i++)
 {
  CAN0.MB[mb].DATA[i] = *data++;
 }
 
 CAN0.MB[mb].DLC = dlc;
 
 CAN0.MCTL[mb].BIT.TX.TRMREQ = 1;   //メールボックスを送信モードに設定
 
 return 0;
}

 

キーボードを押すと、それに対応したCAN通信先のPCで送られてきたデータに対する応答用の表示が確認できています。

ここでキーボード入力をしないとデータ送信ができないとなるとなにかと不便ではないかと考え、まずswitch文を用いないでデータの送信をやろうと考え以下のようしました。

//送信処理(キーボード0-7がMB[0]-[7]に対応)
  s_mb=0xff;
  s_mb=0;
  s_dlc=1;
  
  s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
  
  /*xc=sciRead();
  
  switch(xc)
  {
   case '0':
    s_mb=0;  //使用するメールボックス番号
    s_dlc=1; //送信バイト数
    break;
   case '1':
    s_mb=1;
    s_dlc=2;
    break;
   case '2':
    s_mb=2;
    s_dlc=3;
    break;
   case '3':
    s_mb=3;
    s_dlc=4;
    break;
   case '4':
    s_mb=4;
    s_dlc=5;
    break;
   case '5':
    s_mb=5;
    s_dlc=6;
    break;
   case '6':
    s_mb=6;
    s_dlc=7;
    break;
   case '7':
    s_mb=7;
    s_dlc=8;
    break;
#if (LED_PORT_NUM > 0)
   case 'z':
    //ボード識別向けLED点滅
    sciPrintBuf("LED blink test(for board identify).\n");
    led=LED1_PORT;
    for(l=0; l<3; l++)
    {
     LED1_PORT=1;
     for(x=0; x<1000000; x++) nop();
     LED1_PORT=0;
     for(x=0; x<1000000; x++) nop();
    }
    LED1_PORT=led;
    break;
#endif
   case 'c':
    for(l=0; l<CAN_CH; l++)
    {
     send_can_ch++;
     if(send_can_ch>=CAN_CH) send_can_ch=0;
     if(varid_can_ch[send_can_ch] == 1) break;
    }
    sciPrintBuf("CAN send channel -> CAN");
    sciWriteBuf(send_can_ch+0x30);
    sciPrintBuf("\n");
    break;
   default:
    break;
  }*/
  
  /*if(s_mb != 0xff)
  {
   switch(send_can_ch)
   {
    case 0:
#if (CAN0_VALID == 1)
     s_ret = can0_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 1:
#if (CAN1_VALID == 1)
     s_ret = can1_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    case 2:
#if (CAN2_VALID == 1)
     s_ret = can2_send(s_mb, s_dlc, &s_data[0]);
#endif
     break;
    default:
     break;
   }
   */
   sciPrintBuf("CAN");
   sciWriteBuf(send_can_ch+0x30);
   sciPrintBuf(" data send,     MB=0x");
   sciPrintByteBuf(s_mb);
   sciPrintBuf(" ret=0x");
   sciPrintWordBuf(s_ret);
    
   if(s_ret==0)
   {
    sciPrintBuf(" id=MB    ");
    sciPrintBuf(" data=0x");
    for(j=0; j<s_dlc; j++)
    {
     if(j>=8) break;
     sciPrintByteBuf(s_data[j]);
    }
   }
   sciPrintBuf("\n");
  //}

 

最初にメールボックスの番号とデータ量を指定し、送信関数を呼び出してしてswitch文をコメントアウトしました。

しかし、ここで以前のような表示がCAN通信先のPCで見られなくなり、一回分だけ表示ができる時とできない場合があったりします。

ここで疑問なのですが、

・switch文のcase0と私が書いたコードは同義ではないのでしょうか

・そもそもmain自体がwhile(1)でまわっている(まわしています)のに一回分しか送信されないことはどこか私が書いたコードに問題があるのでしょうか

 

初歩的なプログラムの疑問ですみません、どなたかお力添えいただけないでしょうか。

よろしくお願い致します。

 

 

Parents
  • makiさん、こんにちは。NoMaYです。

    sciRead()というのは、PCから文字が到着するまで、その関数内でずっと待っているのではないですか?つまり、もともとのプログラムというのは、PCを操作している人がキー操作する時間のオーダー(秒~数十秒程)の速さでmain関数が回っていたのではありませか?他方、改造したプログラムは、それこそとんでもない速さでmain関数が回っている筈ですが、その違いが影響していないでしょうか?

    例えば、can0_send()に以下のコメントがありますが、送信関数が-4を返していたりしませんか?

     //CAN0 送信関数
     
     //戻り値
     // 0  : 正常終了
     // -1 : 引数チェックエラー
     // -2 : レジスタ値設定変更タイムアウト
     // -3 : メールボックスが受信に設定されている
     // -4 : メールボックス送信中

     

Reply
  • makiさん、こんにちは。NoMaYです。

    sciRead()というのは、PCから文字が到着するまで、その関数内でずっと待っているのではないですか?つまり、もともとのプログラムというのは、PCを操作している人がキー操作する時間のオーダー(秒~数十秒程)の速さでmain関数が回っていたのではありませか?他方、改造したプログラムは、それこそとんでもない速さでmain関数が回っている筈ですが、その違いが影響していないでしょうか?

    例えば、can0_send()に以下のコメントがありますが、送信関数が-4を返していたりしませんか?

     //CAN0 送信関数
     
     //戻り値
     // 0  : 正常終了
     // -1 : 引数チェックエラー
     // -2 : レジスタ値設定変更タイムアウト
     // -3 : メールボックスが受信に設定されている
     // -4 : メールボックス送信中

     

Children
  • NoMaYさん、こんにちは、makiです。

    お返事ありがとうございます。

    >SciRead()というのは、PCから文字が到着するまで、その関数内でずっと待っているのではないですか?つまり、もともとのプログラムというのは、>PCを操作している人がキー操作する時間のオーダー(秒~数十秒程)の速さでmain関数が回っていたのではありませか?他方、改造したプログラム

    >は、それこそとんでもない速さでmain関数が回っている筈ですが、その違いが影響していないでしょうか?

    確かに、その点を考慮していませんでした。

    ただ単にswitch文を消しただけなので、その可能性が高いような気がします。

     

    例えば、can0_send()に以下のコメントがありますが、送信関数が-4を返していたりしませんか?

    実際に送信関数の中でー4を返すところにシリアル表示のプログラムを書き込んでみたところ、それこそとんでもない速度でシリアル表示がおこなわれていました。

    つまり、main関数がとんでもない速度で回っていて、メールボックスの状態がずっとメールボックス送信中になっているので本来動くはずのプログラムに影響を与えて問題が生じているという解釈で大丈夫でしょうか?