初めまして。
RL78/F14、CS+でA/D変換とCANを使うコードを書きました。
A/D変換はソフトウエア・トリガ・モード(スキャン・モード,ワンショット変換モード)です。
通常は割り込みが4回入るのですが、同じタイミングでCANの受信割り込みが入ると前述のA/D完了割り込みが2回または3回しか入ってきません。
A/D変換の変数及び各関数は以下のようなものです。
//--------------------------------------------
#include "r_cg_macrodriver.h"#include "r_cg_adc.h"#include "r_cg_userdefine.h"//--------------------------------------------
ushort * ad_buff_address; /* ADConvert buffer address */
void R_ADC_Create(void){ADCEN = 1U; /* supply AD clock */ADM0 = _00_AD_ADM0_INITIALVALUE; /* disable AD conversion and clear ADM0 register */ADMK = 1U; /* disable INTAD interrupt */ADIF = 0U; /* clear INTAD interrupt flag */ADPR1 = 1U; /* Set INTAD level2 priority */ADPR0 = 0U;ADPC = 0x0FU;PM9 |= 0x0FU; /* Set ANI0 - ANI13 pin as analog input */PM8 |= 0xFFU;PM3 |= 0x18U;ADM0 = _10_AD_CONVERSION_CLOCK_16 | _00_AD_TIME_MODE_NORMAL_1 | _40_AD_OPERMODE_SCAN; // スキャンモードADM1 = _00_AD_TRIGGER_SOFTWARE | _20_AD_CONVMODE_ONESELECT; // ソフトウェアトリガ ワンショット変換ADM2 = _40_AD_POSITIVE_AVREFP | _20_AD_NEGATIVE_AVREFM | _00_AD_AREA_MODE_1 | _00_AD_RESOLUTION_10BIT; // 10bit分解能 AVREFP/AVREFMから供給ADUL = _FF_AD_ADUL_VALUE;ADLL = _00_AD_ADLL_VALUE;ADS = _02_AD_INPUT_CHANNEL_2_5;ADCE = 1U; /* enable AD comparator */}//--------------------------------------------void R_ADC_Start(void){ADIF = 0U; /* clear INTAD interrupt flag */ADMK = 0U; /* enable INTAD interrupt */ADCS = 1U; /* enable AD conversion */}//--------------------------------------------void R_ADC_Get_Result(ushort * const buffer){*buffer = (ushort)(ADCR >> 6U);}//--------------------------------------------void R_ADS_Set(ushort * const buff,int pin){ ad_buff_address = buff;ADS = pin; /* enable AD comparator */}//--------------------------------------------static void __near r_adc_interrupt(void){P1_bit.no7 =1;R_ADC_Get_Result(ad_buff_address);ad_buff_address++; /* 次の格納先指定 */P1_bit.no7 =0;}//--------ここからメイン側の変数、各関数------void hdwinit(void){DI();R_Systeminit();}//--------------------------------------------void R_Systeminit(void){//ポート設定などのコードは省略R_ADC_Create(); // AD変換設定R_CAN_Create(); // CAN設定}//--------------------------------------------void ConvAD(ushort *pAddr, int ch){R_ADS_Set(pAddr,ch); // チャンネル設定R_ADC_Start(); // A/D変換開始while(ADCS){}}//-------------------------------------------- main(){ static ushort AiBuff[12]; while (1U) { //A/D変換以外のコードは省略 if( msec20 == 1) {//20msec毎にフラグ=1 msec20=0; GetAD( &AiBuff[0], 2 ); // A/D変換処理(変換開始CH指定) GetAD( &AiBuff[4], 6 ); // A/D変換処理(変換開始CH指定) GetAD( &AiBuff[8], 10 ); // A/D変換処理(変換開始CH指定) }}
添付の画像「normal」「error」ともに青色:CH1は上述「r_adc_interrupt」関数内のP1_bit.no7をオシロスコープで観測した波形水色:CH2はCANの割り込み内でP1_bit.no6をオシロスコープで観測した波形です。正常時はAD割り込みが4回入る(normal)のに対し、CAN受信割り込みと同タイミングの場合(error)、2回しかINTADが入らないのですが・・・?割り込みのプライオリティはどちらもレベル2ですが、INTADをレベル0(高優先順位)にしても症状は変わりませんでした・・・。多重割り込みは避けたいのでIEフラグは操作していません。ので、割り込みは保留されると思っていたのですが、さにあらず。
みなさんのお知恵を拝借したく、よろしくお願いします。
sato@palさん、こんにちは。NoMaYと申します。これはそういうものだと思いますよ。A/Dスキャンモードに限らず、UART受信割り込みやSCIスレーブの通信割り込みもそうですが、それらのように一定間隔で割り込みが発生せざるを得ない状況であれば、それらの割り込みがすっぽ抜けるのを防ぐには、以下の2通りの対策のどちらかを取らざるを得ないと思うのです。(1) 他の割り込み区間やDI/EIによる割り込み禁止区間が、上記の割り込みの発生間隔以下になるようにする。(実際には、割り込み処理そのものの処理時間がありますので、上記の割り込みの発生間隔より、ずっと短くなくてはいけない筈だと思います。)(2) 多重割り込みを使い、他の割り込み区間でも、上記の割り込みを受け付けるようにする。
NoMaYさん、レスありがとうございます。
今回の件、前出の「error」波形ではAD変換の1回目と2回目と3回目が「保留」にされ、CANの割り込みからの復帰時には保留を解除されるAD割り込みが1個しか無いコトが原因でした。
仰るようにCANの割り込み処理時間を短くすることで解決しそうです。
ありがとうございます!
sato@palさん、こんにちは。NoMaYです。あと、対処法としては、RL78/F14ですのでDMAではなくDTCが搭載されていると思いますが、以下のスレッドのようにDTC転送を使うという手もあります。ADコンバータとDTC転送(ソフトウエアトリガ、スキャン、ワンショット変換)で他の端子のアナログデータを読み込むjapan.renesasrulz.com/cafe_rene/f/forum18/6237/ad-dtcRL78のDTCのchain転送を使って6chのanalog入力を(ほぼ)連続convertさせてみた(CC-RL/CSplus)japan.renesasrulz.com/cafe_rene/f/forum18/6259/rl78-dtc-chain-6ch-analog-convert-cc-rl-csplus