GR-ROSE+e2studio + FIT を使用したUSBサンプルプログラムが動作しない

お世話になっております。マイコン初心者のコミーです。

現在、GR-ROSE と e2studio + FIT を使用しPC(Teraterm)とUSB通信しようとチャレンジしています。

補足:E2Liteエミュレータを接続+GR-ROSEのUSBとPCを接続して使用しています。

手順書「 Renesas e2studio スマート・コンフィグレータ Application Examples:CMT,A/D,SCI,DMA,USB(アプリケーションノート)

R20AN0469JS0120 Rev.1.20

2019.06.20 」

をApplocation Example1~4までは順調に動作させることができましたが、USBのサンプル:Applocation Example5のみ動作させることができません。

*不具合動作1:COMポートは認識はするが(2分ほど)時間がかかる(デバック実行してから)

*不具合動作2:COMポート認識後、Teraterm で接続できるようになり、遅い反応ですが文字は打てます。

        ただし、GR-ROSEからのリアクションは一切なしです。

コードはそのまま(Applocation Example5)のPDFからコピーして使用しました。

変更したのはクロックの設定とデバックの設定だけです。(CTM0とLED点灯用のPORTは(Applocation Example1)にて設定)

原因に心当たりがありましたら、ご教示いただければと思います。

<クロック設定>

SCKCR2にチェック / 48(USBクロックUCLK)になるように設定

<デバック設定>

EXTAL周波数:12 / 動作周波数:120 / 接続タイプ:FINE / エミュレータから電源を供給する:いいえ

下記追加情報です。

<デバイス選択ウィンドウ>

GR-ROSE用ボード定義ファイル(BDF)も使用し選択しました。

  • コミーさん、こんにちは。NoMaYです。

    > ちなみにGR-ROSEと外部への接続は4)のケーブルのみですがよいのでしょうか?

    ルネサスさんのGR-ROSEのウェブページを見ると、USBバスパワーで動作するようですので、それで良いと思います。(すみません、私は実物を持っていません。) デバッグ時と単体動作時で挙動が異なることは気にはなりますけれども、、、

    > FITモジュール [ r_usb_pcdc ] のサンプル(スマートコンフィグレータからインポート)したもの。
    ...
    > このサンプルは動作(E2Liteでのデバック動作)しました

    今の予感としては、以下のアプリケーションノートのUSB(PCDC)の練習課題は今のFITモジュールではもう動作しない、という顛末の可能性があるような気がしてきたのですけれども、、、

    Renesas e² studio スマート・コンフィグレータ アプリケーションサンプル:CMT, A/D, SCI, DMA, USB編
    www.renesas.com/jp/ja/document/apn/renesas-e-studio-smart-configurator-application-examples-cmt-ad-sci-dma-usb

    私の手持ちのボードにはRXスマートコンフィグレータの生成コードでUSB PCDCを試せるものがないのですが、あれば以下の点を確認してみたいところです。

    (1) 2019年当時のFITモジュールをかき集めて置き換えて練習課題を試す → 動作するような予感

    それに対して、

    (0) 現在の状況: 2022年入手のFITモジュールを使用して練習課題を試す → 動作しない

  • NoMayさんアドバイスありがとうございます。kommyです。

    GR-ROSEをお持ちでないのに考察していただきありがとうございます。

    >このアプリケーションノートのUSB(PCDC)の練習課題は今の>FITモジュールではもう動作しない

    残念ながら↑の可能性大なのでしょうか。スマートコンフィグレータで使いやすくなっているとは言え、少し躓いただけで、私のように内部を本当に理解していない人間では原因がつかめないことがよくわかりました。

    ユーザーマニュアルを少しづつ見ながら理解を深めていきたいと思います。

  • コミーさん、こんにちは。NoMaYです。

    くだんのアプリケーションノート上では、LチカもUART通信もUSB通信も表面上は同じレベルのことに見えるでしょうけれども、10年前、20年前、といった時代にはイメージ的には、1倍、4倍、16倍といった感じの歴然とレベルの異なるスキルでしたよ。そして、今でもUSB通信なんて普通に躓く人達があちらこちらにいるはずだと思いますよ。ただ、皆さん、プロの(それで生計を立てている)ソフトウェア開発者さんやハードウェア開発者さんですので、遅かれ早かれ自己解決されてしまうのでしょうけれども。もちろん、組織というか組織の人脈というか、そういった面からの支援もありますでしょうし。それゆえ、逆に、果たしていつ頃から動作しなくなったのだろうかが分からない、ということもあったりするということでもあるのでしょうが。

    あと、今回のような(推測ですが)使っているライブラリのバージョンにまつわる話は、ちょっと凝ったArduinoシールドのサンプルプログラムがArduino本体をバージョンアップしたら動かなくなった、という普通に見聞きする話と同類かなと思うのです。(と推測しています。) こちらは、売る側も買う側もコミュニティも、初心者ユーザが大半を占めていることを前提としていると思いますので、動作しなくなったといった話はわりと早く上がってきたりするものなのではないかなぁ、とも思ったりしました。

    今、以下のように推測していますけれども、APIがこういう振る舞いだと、あのプログラムでは動作するはずがないかなぁ、と、、、

    > [追記]
    > 画面コピーの2枚目と3枚目から推測すると、R_USB_GetEvent(&ctrl)が何らかの理由で何十回と即リターンしてしまっているのかな。本来なら、然るべきUSBイベントの発生に応じて、僅かな回数しかリターンしない筈、であるのに。
    > [追記2]
    > 待て待て待て、自分よ、それではスーパーループにならないよね、、、何か変な気がするのだけれども、、、本来なら、然るべきUSBイベントの発生に応じて、僅かな回数しかリターンしない筈、であるのに。
    > [追記3]
    > ひょっとしたら、FIT PCDCジュールの挙動が昔とは違っているのかなぁ、、、
    > 昔(2019年) (推測)
    > ・USB_STS_CONFIGUREDになるまでR_USB_GetEvent(&ctrl)は返ってこない?
    > 今(2022年) (推測)
    > ・USB_STS_CONFIGUREDになる前にもR_USB_GetEvent(&ctrl)はUSB_STS_NONEで何度も何度も返ってくる?

    サンプルプログラムの記述

        R_USB_Open(&ctrl, &cfg); /* Initializes the USB module */
        /* Loop back between PC Terminal and USB MCU */
        while (1)
        {
            switch (R_USB_GetEvent(&ctrl))
            {
            case USB_STS_CONFIGURED :
                break;
            case USB_STS_WRITE_COMPLETE :
                /* Read the input from PC terminal*/
                R_USB_Read(&ctrl, g_buf, 1);
                break;
            case USB_STS_READ_COMPLETE :
                /* Clear start message flag*/
                flag_start = 0;
                略
                /* Print message at PC terminal */
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
                /* Change blinking rate */
                CMT0.CMCOR = (uint16_t)(5000 * interval_level);
                break;
            default :
                break;
            }
            /* USB_STS_CONFIGUREDの前にR_USB_Write()してしまっているのでは?かつ、怒涛の勢いで? */
            /* USB_STS_CONFIGUREDの後も怒涛の勢いは衰えずにR_USB_Write()してしまっているのでは? */

            if (flag_start == 1)
            {
                /* Print start message until the 1st input from PC host is received */
                sprintf(print_str, "Press space bar twice to start ...\r ");
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
            }
        }

     
    こんな感じでないと動作しないような、、、と思ったけれども、これだと"Press space bar twice to start ...\r "を取りこぼすケースがあるはずですので駄目だな、と思い直しました。(USB接続後にTeraTermで仮想COMポートをオープンした場合など。)

        R_USB_Open(&ctrl, &cfg); /* Initializes the USB module */
        /* Loop back between PC Terminal and USB MCU */
        while (1)
        {
            switch (R_USB_GetEvent(&ctrl))
            {
            case USB_STS_CONFIGURED :
                /* Print start message until the 1st input from PC host is received */
                sprintf(print_str, "Press space bar twice to start ...\r ");
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
                break;
            case USB_STS_WRITE_COMPLETE :
                /* Read the input from PC terminal*/
                R_USB_Read(&ctrl, g_buf, 1);
                break;
            case USB_STS_READ_COMPLETE :
                略
                /* Print message at PC terminal */
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
                /* Change blinking rate */
                CMT0.CMCOR = (uint16_t)(5000 * interval_level);
                break;
            default :
                break;
            }
        }

      
    ですので、、、

        R_USB_Open(&ctrl, &cfg); /* Initializes the USB module */
        /* Loop back between PC Terminal and USB MCU */
        while (1)
        {
            switch (R_USB_GetEvent(&ctrl))
            {
            case USB_STS_CONFIGURED :
                /* CONFIGUREDフラグを立てる処理を追加する */
                break;
            case USB_STS_WRITE_COMPLETE :
                /* Read the input from PC terminal*/
                R_USB_Read(&ctrl, g_buf, 1);
                break;
            case USB_STS_READ_COMPLETE :
                /* Clear start message flag*/
                flag_start = 0;
                略
                /* Print message at PC terminal */
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
                /* Change blinking rate */
                CMT0.CMCOR = (uint16_t)(5000 * interval_level);
                break;
            default :
                break;
            }
            /* 上記CONFIGUREDフラグが立つまで以下をスキップする処理を追加する */
            if (flag_start == 1)
            {
                /* 1秒待つ(送信間隔を空ける)処理を追加する */
                /* Print start message until the 1st input from PC host is received */
                sprintf(print_str, "Press space bar twice to start ...\r ");
                slength = strlen(print_str);
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
            }
        }

     
    とか、かなぁ、、、と思ったけれども、R_USB_Write()とUSB_STS_WRITE_COMPLETE、R_USB_Read()とUSB_STS_READ_COMPLETE、それぞれ対応関係の整合性が取れてないので駄目だな、と思い直しました。

    これは数時間考えないと書けないかもなぁ、、、

  • こんにちは。NoMaYです。

    あぁっ、良く見ると`\n`で無くて`\r`ですね。

    Press space bar twice to start ...\r 

     

  • こんにちは。NoMaYです。

    そういえば、仮想COMポートとなると、Windowsのバージョンの違いによる動作の違いも気になりますね。

  • NoMayさんありがとうございます。

    とりあえず、すぐに展開できるWinsows情報を添付します。

  • コミーさん、こんにちは。NoMaYです。

    繰り返しになりますけれども、もともとはRSK-RX65N 2MBを対象にしたガイドですがGR-ROSEでも同じ筈だけど、と思っているわけなのですが、USB仮想COMポートともなると、なぜ今アプリケーションノートのようにやっても動作しないのか、要因を探るのは容易では無いことですね。(Windowsのバージョンの違いに加えて、TeraTermのバージョンの違いも懸案事項ですね。)

    他方で、徐々にソース内容が分かってくると、そもそも何か今イチな処理になっているようなことにも気付いてきました。このスレッドへのリプライとしてどういうものが良いのか悩ましいのですが、ちょっとソースを書き換えてみることにしました。たまたまですが、先ほどArduinoを話題にしましたので、ふと思い付いてsetup()とloop()を使ってみました。このソースではどうでしょうか?(なお、TeraTermの受信の改行設定ですが、AUTOでは無くてCR+LFにしてみて下さい。)

    [追記]

    以前に頂いたプロジェクトファイル一式の差し替え版を作ってみました。自分に都合の良いようにプロジェクト設定を少し弄っていますが、以下のzipファイルの中で肝心なファイルは以下のCファイル1つだけです。(なお、動作するかどうかは未知数ですけれども。)

    GR_ROSE_USB_sample_NG__modified_by_NoMaY_20220509.zip

    [ここまで追記]

    Smart_Configurator_Example_USB.c

    ...略...

    void setup(void);
    void loop(void);
    void main(void);

    void main(void)
    {
        setup();
        for(;;)
        {
            loop();
        }
    }

    usb_ctrl_t ctrl;
    usb_cfg_t cfg;

    void setup(void)
    {
        /* Start CMT0 counter operation */
        R_Config_CMT0_Start();

        R_USB_PinSet_USB0_PERI();       /* USB MCU pin setting */

        ctrl.module = USB_IP0;          /* USB0 module */
        ctrl.type = USB_PCDC;           /* Peripheral Communication Device Class*/
        cfg.usb_speed = USB_FS;         /* USB_HS/USB_FS */
        cfg.usb_mode = USB_PERI;
        cfg.p_usb_reg = (usb_descriptor_t *)&usb_descriptor;
        R_USB_Open(&ctrl, &cfg);        /* Initializes the USB module */

        while(USB_STS_CONFIGURED != R_USB_GetEvent(&ctrl))
        {
            nop();
        }

        /* Print start message (until the 1st input from PC host is received) */
        sprintf(print_str, "Press space bar twice(?) to start ...\r ");
        slength = strlen(print_str);
        /* Call the non blocking USB WRITE API to print the message */
        R_USB_Write(&ctrl, (uint8_t *)print_str, slength);

        /* Read the input from PC terminal */
        /* Call the non blocking USB READ API to get an input */
        R_USB_Read(&ctrl, g_buf, 1);
    }

    void loop(void)
    {
        /* Loop back between PC Terminal and USB MCU */
        switch (R_USB_GetEvent(&ctrl))
        {
        case USB_STS_WRITE_COMPLETE :
            if(1 == flag_start)
            {
                /* Wait for a while */
                R_BSP_SoftwareDelay(1000, BSP_DELAY_MILLISECS);
                /* Print start message until the 1st input from PC host is received */
                sprintf(print_str, "Press space bar twice(?) to start ...\r ");
                slength = strlen(print_str);
                /* Call the non blocking USB WRITE API to print the message */
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
            }
            break;

        case USB_STS_READ_COMPLETE :
            /* Clear start message flag */
            flag_start = 0;
            /* Instruction to slow down blinking rate is received */
            if (('a' == *g_buf)|| ('A' == *g_buf))
            {
                /* Get new blink interval level. Maximum level is 9. */
                if (interval_level < 10)
                {/* Notify the character received and inform next action */
                    sprintf(print_str, "\r\n Character 'a' or 'A' is received. LED2 will blink at slower rate.\r\n");
                    interval_level++;
                }
                else
                {
                    sprintf(print_str, "\r\n This is minimum. Please press 'b' or 'B' to blink faster. \r\n");
                }
            }
            else if (('b' == *g_buf)|| ('B' == *g_buf))
            {
                /* Get new blink interval level. Minimum level is 1 */
                if (interval_level > 1)
                {
                    /* Instruction to increase blinking rate is received */
                    sprintf(print_str, "\r\n Character 'b' or 'B' is received. LED2 will blink at faster rate.\r\n");
                    interval_level--;
                }
                else
                {
                    sprintf(print_str, "\r\n This is maximum. Please press 'a' or 'A' to blink slower. \r\n");
                }
            }
            else
            {
                sprintf(print_str, "\r\n Press keyboard to control the blinking rate of LED2 (not case sensitive)\n\r\n a ----> Slower\n\r\n b ----> Faster\n\r\n");
            }
            /* Print message at PC terminal */
            slength = strlen(print_str);
            /* Call the non blocking USB WRITE API to print the message */
            R_USB_Write(&ctrl, (uint8_t *)print_str, slength);
            /* ↑細かいことを言うとビジーチェックが無いですが、、、(前の送信完了前に送信するリスクがありますが、、、) */

            /* Change blinking rate */
            CMT0.CMCOR = (uint16_t)(5000 * interval_level);

            /* Read the input from PC terminal */
            /* Call the non blocking USB READ API to get an input */
            R_USB_Read(&ctrl, g_buf, 1);
            break;

        default :
            break;
        }
    }

     
    [追記] 2022/05/10

    上のコードが動作するかどうか分からない内に更なる書き換えを提示するのは良くないかも知れませんけれども、、、

    Smart_Configurator_Example_USB.c

    ...略...

    void setup(void);
    void loop(void);
    void main(void);

    void main(void)
    {
        setup();
        for(;;)
        {
            loop();
        }
    }

    usb_ctrl_t ctrl;
    usb_cfg_t cfg;
    bool is_send_busy;
    bool is_recv_ready;
    uint32_t count_100ms;

    void setup(void)
    {
        /* Start CMT0 counter operation */
        R_Config_CMT0_Start();

        R_USB_PinSet_USB0_PERI();       /* USB MCU pin setting */

        ctrl.module = USB_IP0;          /* USB0 module */
        ctrl.type = USB_PCDC;           /* Peripheral Communication Device Class*/
        cfg.usb_speed = USB_FS;         /* USB_HS/USB_FS */
        cfg.usb_mode = USB_PERI;
        cfg.p_usb_reg = (usb_descriptor_t *)&usb_descriptor;
        R_USB_Open(&ctrl, &cfg);        /* Initializes the USB module */

        while(USB_STS_CONFIGURED != R_USB_GetEvent(&ctrl))
        {
            nop();
        }

        /* Print start message (until the 1st input from PC host is received) */
        sprintf(print_str, "Press space bar twice(?) to start ...\r ");
        slength = strlen(print_str);
        /* Call the non blocking USB WRITE API to print the message */
        is_send_busy = true;
        R_USB_Write(&ctrl, (uint8_t *)print_str, slength);

        /* Read the input from PC terminal */
        /* Call the non blocking USB READ API to get an input */
        is_recv_ready = false;
        R_USB_Read(&ctrl, g_buf, 1);

        /* Reset the tick count */
        count_100ms = 0;
    }

    void loop(void)
    {
        /* Loop back between PC Terminal and USB MCU */

        /* Wait for a while then increment the tick count */
        R_BSP_SoftwareDelay(100, BSP_DELAY_MILLISECS);
        count_100ms++;

        usb_status_t event;

        while(USB_STS_NONE != (event = R_USB_GetEvent(&ctrl)))
        {
            switch(event)
            {
            case USB_STS_WRITE_COMPLETE:
                is_send_busy = false;
                break;
            case USB_STS_READ_COMPLETE:
                is_recv_ready = true;
                break;
            default:
                /* Ignore the class request */
                break;
            }
        }

        if(false == is_send_busy)
        {
            if(false == is_recv_ready)
            {
                if((1 == flag_start) && (10 <= count_100ms))
                {
                    /* Print start message until the 1st input from PC host is received */
                    sprintf(print_str, "Press space bar twice(?) to start ...\r ");
                    slength = strlen(print_str);
                    /* Call the non blocking USB WRITE API to print the message */
                    is_send_busy = true;
                    R_USB_Write(&ctrl, (uint8_t *)print_str, slength);

                    /* Reset the tick count */
                    count_100ms = 0;
                }
            }
            else
            {
                /* Clear start message flag */
                flag_start = 0;
                /* Instruction to slow down blinking rate is received */
                if (('a' == *g_buf)|| ('A' == *g_buf))
                {
                    /* Get new blink interval level. Maximum level is 9. */
                    if (interval_level < 10)
                    {/* Notify the character received and inform next action */
                        sprintf(print_str, "\r\n Character 'a' or 'A' is received. LED2 will blink at slower rate.\r\n");
                        interval_level++;
                    }
                    else
                    {
                        sprintf(print_str, "\r\n This is minimum. Please press 'b' or 'B' to blink faster. \r\n");
                    }
                }
                else if (('b' == *g_buf)|| ('B' == *g_buf))
                {
                    /* Get new blink interval level. Minimum level is 1 */
                    if (interval_level > 1)
                    {
                        /* Instruction to increase blinking rate is received */
                        sprintf(print_str, "\r\n Character 'b' or 'B' is received. LED2 will blink at faster rate.\r\n");
                        interval_level--;
                    }
                    else
                    {
                        sprintf(print_str, "\r\n This is maximum. Please press 'a' or 'A' to blink slower. \r\n");
                    }
                }
                else
                {
                    sprintf(print_str, "\r\n Press keyboard to control the blinking rate of LED2 (not case sensitive)\n\r\n a ----> Slower\n\r\n b ----> Faster\n\r\n");
                }
                /* Print message at PC terminal */
                slength = strlen(print_str);
                /* Call the non blocking USB WRITE API to print the message */
                is_send_busy = true;
                R_USB_Write(&ctrl, (uint8_t *)print_str, slength);

                /* Change blinking rate */
                CMT0.CMCOR = (uint16_t)(5000 * interval_level);

                /* Read the input from PC terminal */
                /* Call the non blocking USB READ API to get an input */
                is_recv_ready = false;
                R_USB_Read(&ctrl, g_buf, 1);
            }
        }
    }

     

  • コミーさん、こんにちは。NoMaYです。

    その後どうでしょうか?どういう状況でしょうか?こちらから提示したソースの書き換えにて動作するようにはなったですか?それとも、動作するようにはならなかったですか?

  • NoMayさんありがとうございます。このページに2ページ目があることに気づきませんでした。

    すごいです!インポートしてビルド・デバックして動きました。

    a ,b をキーボードに打ち込むとタイマーで点滅している速さがちゃんと変わります!

    (中身の確認はいっさいできていませんが、まずは報告させていただきます!)

  • コミーさん、こんにちは。NoMaYです。

    リプライありがとうございます。動作しましたか。そうなりますと、やはり考えられるのは、アプリケーションノートが作成されて動作確認された2019年当時と(可能性の大きそうな要因としてですが)以下の何れか若しくは複数が今では挙動が変わってしまっていることにより、アプリケーションノートのUSB(PCDC)の練習課題のソースコードはもう動作しない、ということだろうなぁ、と思われるのです。(この後の、アプリケーションノートのソースコードをどのように修正/改版するか、といったことなどが、ルネサスさんのお仕事でしょうかね、、、)

    可能性の大きそうな要因

    ・FITのPCDCモジュール/USB共通モジュールのバージョンが上がっている
    ・Windowsのバージョンが上がっている
    ・TeraTermのバージョンが上がっている

    [追記]

    可能性の小さそうな要因

    ・CC-RXのバージョンが上がっている