SSPv1.3.0利用でwhileから抜けない?最適化?

お世話になっております。Sugachanceです。

Synergyを利用されている方、SSPをご利用の方教えてください。

環境:e2studio Version: 5.4.0.018

SSP:v1.3.0

ターゲットボード:SK-S7G2 Starter Kit

 

にて、A/D変換のプロプログラムを作成したいと思い、

A0(A/Dのch0)に可変抵抗を接続、アプリケーションノートR30AN0256JJ0101を参考に、

A/D変換を実行しA/D変換のscan end 割り込みのコールバック関数から

A/D変換値に応じてLEDが光る関数を呼び出して実行するプログラムは作成できました。

アプリケーションノート同様、再スタートはコールバック関数内です。

 

これを、A/D変換完了割り込み部では

A/D変換値を格納し、変換完了のフラグを立てるまでにして、

外部からリスタートするようにしたいと思ったのですが、

フラグが立つにもかかわらず、whileから抜けてくれません。

そこで様子を確認しようと、whileの中身に

単純なインクリメント処理を入れたところ、whileを抜けてくれるようになりました。

 

whileの()の中身って、C言語であれば継続条件でいいんですよね?

 

コンパイル時に最適化?されてwhile部分が無効化されてしまったのでしょうか?

CC-RLで通る書き方ではダメということがあるのでしょうか?

 

全く動かないという投稿を書いているうちに、動くようになったので直近の問題としては解決といえば解決なのですが

原因を知りたいので、何かございましたらよろしくお願いいたします。

単純に何か忘れているだけの気がしますが・・・

 

以下、hal_entry.cの内容

/* HAL-only entry function */
#include "hal_data.h"
#include "my_NN_math.h"
bsp_leds_t leds;
unsigned char adc_end_flag;
adc_data_size_t val_adc0;

unsigned int a = 0;

void adc_get(unsigned int ch);
void adc2led(adc_data_size_t val);

void hal_entry(void)
{
    /* TODO: add your own code here */
    R_BSP_LedsGet(&leds);//ボードのLED情報取得

    /* If this board has no LEDs then trap here */
    if (0 == leds.led_count)
    {
        while(1); // There are no LEDs on this board
    }


    adc_get(0);
    while(1){
        while(adc_end_flag!=1){/*a++;*/};//A/D終了待ち :while(adc_end_flag!=1);だとここで抜けてくれない
        adc2led( val_adc0 );
        adc_get(0);
    }
}

 void adc2led(adc_data_size_t val)

{
    if(val > 800){
        g_ioport.p_api->pinWrite(leds.p_leds[0], IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(leds.p_leds[1], IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(leds.p_leds[2], IOPORT_LEVEL_HIGH);
    }
    else if(val > 200){
        g_ioport.p_api->pinWrite(leds.p_leds[0], IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(leds.p_leds[1], IOPORT_LEVEL_LOW);
        g_ioport.p_api->pinWrite(leds.p_leds[2], IOPORT_LEVEL_HIGH);
    }
    else{
        g_ioport.p_api->pinWrite(leds.p_leds[0], IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(leds.p_leds[1], IOPORT_LEVEL_HIGH);
        g_ioport.p_api->pinWrite(leds.p_leds[2], IOPORT_LEVEL_LOW);
    }
}

void adc_get(unsigned int ch)
{
    if(ch == 0)
    {
        adc_end_flag = 0;
        g_adc0.p_api->open(g_adc0.p_ctrl, g_adc0.p_cfg);
        g_adc0.p_api->scanCfg(g_adc0.p_ctrl, g_adc0.p_channel_cfg);
        g_adc0.p_api->scanStart(g_adc0.p_ctrl);
     }
}


void callback_ADC0(adc_callback_args_t * p_args)
{
    //J26-1:ADC0の処理
    if( p_args->event == ADC_EVENT_SCAN_COMPLETE )
    {
        g_adc0.p_api->read( g_adc0.p_ctrl, ADC_REG_CHANNEL_0, &val_adc0 );
        adc_end_flag = 1;//自作完了フラグ
       //adc2led( val_adc0 );//アプリケーションノートの動作
       //g_adc0.p_api->scanStart(g_adc0.p_ctrl);//アプリケーションノートの動作
    }
}

  • わわいです
    実行しているコード中で変更されない変数は、「内容が変更しない」ものとして、最適化されます。
    最初から変更されないとわかっている変数は、whieのループ回るごとにわざわざその値を読む、というのは無駄なだけですんで、コンパイラは、最初に一回値を読んでおいて、その値を使いまわそう、とします。
    その結果、そのwhileループは無限ループとなってしまうというわけですねー

    んで、これを(自分の思うように)動かしたいときは、その変数の宣言に volatile を入れます
    コンパイラは、volatile付きで宣言された変数は最適化しないようにするので、whileループ回るごとにその変数の値を読み込み直してくれるようになるので、(自分の思うように)きちんと動いてくれるようになります

    ちなみに、これは一般的なCコンパイラであればどれでもこういう最適化を行いますねー

  • わわい様

    ありがとうございます。
    やはりそうでしたか。volatileで動きました。


    CC-RLで最適化されないのは・・・
    オプション設定があったかな・・・
  • わわいです
    コンパイラの設定のところに最適化の項目があります
    これを「なし」にすると前述のvolatileをつけなくとも動いたりなんかしますね
    とにかく、割り込みとメインルーチン両方で使う変数にはvolatileをつけておきましょう。
    まー、不要なところまでつけてしまうと最適化が効かなくなったりするので痛し痒しですが。

    一通りプログラムが動くようになったら、この最適化をいろいろ変えてみて動作がおかしくならないか見てみましょう。
    これで思わぬバグを見つけたりなんかすることもありますねー