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です。

    >実際に送信関数の中でー4を返すところにシリアル表示のプログラムを書き込んでみたところ、それこそとんでもない速度でシリアル表示がおこなわれていました。
    >つまり、main関数がとんでもない速度で回っていて、メールボックスの状態がずっとメールボックス送信中になっているので本来動くはずのプログラムに影響を与えて問題が生じているという解釈で大丈夫でしょうか?

    正直なところ私にはCANの知識が欠けているので断定口調は取れないですけれど(正直なところ最初はCC-RXの生成コードの話かと思ってソースを見始めたのでした)、改造後のプログラムで-4を返していることが確認出来たので、その可能性は随分と高くなったように思います。後は、次の2点が確認出来たら、そういうことになるのかな、と思います。

    (1) 改造前のもともとのプログラムでは-4を返すことが無い
    (2) 改造後のプログラムでmain関数のループの先頭あたりに待ち時間を加えると(-4を返すこと無く)期待した動作になる

    なお、もしFITのBSPモジュールを使っていれば、以下の時間待ち関数がありますので、これを上記の(2)で使うと手っ取り早く試すことが出来るかな、と思います。

    smc_gen/r_bsp/mcu/all/r_bsp_common.c

    /***********************************************************************************************************************
    * Function Name: R_BSP_SoftwareDelay
    * Description  : Delay the specified duration in units and return.
    * Arguments    : uint32_t delay  - the number of 'units' to delay
    *              : bsp_delay_units_t units - the 'base' for the units specified. Valid values are:
    *                  BSP_DELAY_MICROSECS, BSP_DELAY_MILLISECS, BSP_DELAY_SECS.
    *
    *                Accuracy is good, however the minimum possible delay depends on the current ICLK frequency
    *                and the overhead clock cycles required for this function to run.
    *                For example, given a 16 MHz ICLK and 180 clock cycles for this function, the minimum
    *                possible delay would be: 1/16000000 * 180 = 11.25 uS
    *
    * Return Value : true if delay executed.
    *                false if delay/units combination resulted in overflow or the delay cannot be achieved
    ***********************************************************************************************************************/
    bool R_BSP_SoftwareDelay(uint32_t delay, bsp_delay_units_t units)
    {
    ...省略...
    }

     

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

    >実際に送信関数の中でー4を返すところにシリアル表示のプログラムを書き込んでみたところ、それこそとんでもない速度でシリアル表示がおこなわれていました。
    >つまり、main関数がとんでもない速度で回っていて、メールボックスの状態がずっとメールボックス送信中になっているので本来動くはずのプログラムに影響を与えて問題が生じているという解釈で大丈夫でしょうか?

    正直なところ私にはCANの知識が欠けているので断定口調は取れないですけれど(正直なところ最初はCC-RXの生成コードの話かと思ってソースを見始めたのでした)、改造後のプログラムで-4を返していることが確認出来たので、その可能性は随分と高くなったように思います。後は、次の2点が確認出来たら、そういうことになるのかな、と思います。

    (1) 改造前のもともとのプログラムでは-4を返すことが無い
    (2) 改造後のプログラムでmain関数のループの先頭あたりに待ち時間を加えると(-4を返すこと無く)期待した動作になる

    なお、もしFITのBSPモジュールを使っていれば、以下の時間待ち関数がありますので、これを上記の(2)で使うと手っ取り早く試すことが出来るかな、と思います。

    smc_gen/r_bsp/mcu/all/r_bsp_common.c

    /***********************************************************************************************************************
    * Function Name: R_BSP_SoftwareDelay
    * Description  : Delay the specified duration in units and return.
    * Arguments    : uint32_t delay  - the number of 'units' to delay
    *              : bsp_delay_units_t units - the 'base' for the units specified. Valid values are:
    *                  BSP_DELAY_MICROSECS, BSP_DELAY_MILLISECS, BSP_DELAY_SECS.
    *
    *                Accuracy is good, however the minimum possible delay depends on the current ICLK frequency
    *                and the overhead clock cycles required for this function to run.
    *                For example, given a 16 MHz ICLK and 180 clock cycles for this function, the minimum
    *                possible delay would be: 1/16000000 * 180 = 11.25 uS
    *
    * Return Value : true if delay executed.
    *                false if delay/units combination resulted in overflow or the delay cannot be achieved
    ***********************************************************************************************************************/
    bool R_BSP_SoftwareDelay(uint32_t delay, bsp_delay_units_t units)
    {
    ...省略...
    }

     

Children
  • NoMaYさん

     

    こんにちは、makiです

    お返事が遅くなってしまい、すみません

     

    現状で(1)の部分は確認することができたので、(2)の部分の確認を進めていきたいと思います。

    なるほど、mainのループの最初に待ち時間を加えさせてやれば時間にゆとりが持てて期待した結果が出そうな気がします。

     

    NoMaYさんのおかげでどこで自分がつまづいているのか、何が大きな原因になっているのか再確認することができました。

    本当に助かりました。開発を進められそうです。ありがとうございます。