Repository navigation
Timer_Template
EVSYS の 事象イベントのうち 単発ストローブのものは、そのまま GPIO に転送しても ふつう x1 CLK_PER のパルス信号なので、非常に観測しにくいことがある。無論 100 MHz 超級の十分な分解能を持つオシロスコープを使用すれば良いのだが、安価なロジックアナライザーや 単なる LED 点灯だと 1ms 以上の レベル信号に引き伸ばせなければ、観測自体がままならない。
感知精度が 20ns 程度あるリセットICがあると、IC・LED・同電流制限抵抗の 3点セットで要件が済むため簡単だ。部品点数は増えるが 555タイマーIC で回路を組むと可変抵抗でより柔軟な引き伸ばし遅延設定ができる。なので頻繁に出番があるならそういう小回路を工作しておくと便利である。555 に代えて AC(アナログ比較器)入出力のある ATtiny10 や ATtiny13 等の ミニマルMCU を使うのも、プログラマブルなものが作れて有利だろう。
MPU主クロックF_CPU=CLK_PERを OSC32K駆動に変更、さらに 64分周を掛ければ、MPU を 512 Hz の超低速スローモーション動作にすることができる。これは応用記述の変更をほとんどすることなしに、タイマーや CCL を組み合わせた複雑な波形生成のデバッグ検証を容易にする。ただし USART 等の外部通信機能の正常動作は期待できないので、条件に見合う場合しか活用できない。
/* F_CPU = 512 Hz */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLA, CLKCTRL_CLKSEL_OSC32K_gc);
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm);ある程度以上の間隔で繰り返されるパルス信号なら、それをトグル信号として出力を反転させるだけでも十分事足りるだろう。これは分周プリスケーラーと実質同じなので、様々な応用を考えることができる。しかし当然だが、事象イベント発生間隔が短い場合、LED駆動では視覚的には連続点灯と変わりなく見分けがつかない。
/* 割込トグル */
ISR(...) {
digitalWriteMacro(LED_BUILTIN, TOGGLE);
/* 要割込フラグクリア処理 */
}/* 偶数 CCL_LUT での トグル・ラッチ */
void init_unit (void) {
EVSYS_USERCCLLUT0A = EVSYS_USER_CHANNEL0_gc; /* -> LUT0_EVENTA */
/* TRUTH _ 2 1 _ */
/* 1:FDB 0 1 0 1 */
/* 0:TGL 0 0 1 1 */
CCL_TRUTH0 = CCL_TRUTH_1_bm | CCL_TRUTH_2_bm;
CCL_LUT0CTRLB = CCL_INSEL1_FEEDBACK_gc
| CCL_INSEL0_EVENTA_gc; /* 任意のトグル入力 */
CCL_LUT0CTRLA = CCL_ENABLE_bm | CCL_OUTEN_bm /* -> PA3 */
| CCL_FILTSEL_SYNCH_gc | CCL_EDGEDET_EN_gc;
CCL_CTRLA = CCL_ENABLE_bm;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}/* TCA を計数器+分周器とする */
void init_unit (void) {
EVSYS_USERTCA0CNTA = EVSYS_USER_CHANNEL0_gc;
TCA0_SINGLE_CMP0 = 0; /* 0=分周比2、1=分周比4... */
TCA0_SINGLE_EVCTRL = TCA_SINGLE_CNTAEI_bm | TCA_SINGLE_EVACTA_CNT_POSEDGE_gc;
TCA0_SINGLE_CTRLB = TCA_SINGLE_CMP0EN_bm /* -> PA0 */
| TCA_SINGLE_WGMODE_FRQ_gc;
TCA0_SINGLE_CTRLA = TCA_SINGLE_ENABLE_bm | TCA_SINGLE_CLKSEL_DIV1_gc;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}TCBn が余っている場合は、TCBn_WO 出力を単発計時で駆動することができる。コードの汎用性・移植性は高く、基本中の基本だろう。しかし用途が広く希少な TCBn を占有するのが、最大の弱点。
void setup_tcb0_single (void) {
EVSYS_USERTCB0CAPT = EVSYS_USER_CHANNEL0_gc; /* 単発ストローブで CAPT 開始 */
/* CAPT で CNT開始 → MAX に達すると自動停止 → CNT はゼロに戻る */
TCB0_CCMP = F_CPU / 1000L * 5; /* 5 ms 信号レベル維持 */
TCB0_EVCTRL = TCB_CAPTEI_bm;
TCB0_CTRLB = TCB_CCMPEN_bm | TCB_CNTMODE_SINGLE_gc; /* -> PA2 */
TCB0_CTRLA = TCB_ENABLE_bm | TCB_CLKSEL_DIV1_gc;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}TCAn が余っているという応用記述はそう多くはないが、TCBn とは異なる設計が必要だ。TCAn は始動すると継続動作が強制され、TCBn と違って 1周期で自動停止するという設定ができない。このため LUTn に出力波形を与え、FEEDBACK と 事象ストローブによる 1-bit ラッチで、最初の 1波形ぶんを切り出して CCLn_OUT に出力するよう構成することでこれを補う。事象ストローブは CCL_LUTn へ与えると同時に、TCAn の再起動(TCAn_CNT と TCAn_WOn 出力のプリセット)に使用する。
- 後述する
ADCnやACnを使ったディレイ生成法に比べると移植性が高いのは長所。持続時間も調整しやすい。TCAnがない AVR_EB/LA は除く。(TCEnを使用する) - 次例での 16-bit構成の
TCAnで生成可能な最長の波形出力時間は、F_CPU= 20 MHz のときに 209 ms となる。CLKSEL_DIV64とすればその 64倍に伸ばせる・・・が実用上の意義は低い。2 ms もあれば、必要電流の大きな高輝度 LED でも十分な明るさで光るからだ。 -
TCAnのWGMODE_FRQ波形出力は、再起動時にはLOW(0) で開始される。よってこれがHIGH(1) になったなら ラッチをプリセットして初期状態に戻す。 -
INSELn_FEEDBACKは、奇数番のLUTnでは 偶数番のCCLn_OUTを参照する。そのため次例では 偶数番のLUTnを必要とする。 -
LUTnのCLKSRCは、参照元にCLKPERかOSCHFしか選ぶことができない。その他では x1 CLK_PER 長の 単発ストローブ(の上昇端)を取りこぼす。同様の理由でFILTSELはDISABLEでなければならない。
void setup_ccl0_tca0_delay (void) {
/* EVSYS_CH0 ストローブは、TCA0 再起動と CCL_LUT0A 入力に分配 */
EVSYS_USERTCA0CNTB = EVSYS_USER_CHANNEL0_gc;
EVSYS_USERCCLLUT0A = EVSYS_USER_CHANNEL0_gc;
/* CCL_LUT0 でラッチ回路を構成する(5の条件で初期状態 0/1に戻す) */
/* TRUTH _ _ 2 3 4 _ 6 7 */
/* 2:FDB 0 0 0 0 1 1 1 1 */
/* 1:EVA 0 0 1 1 0 0 1 1 */
/* 0:TCA 0 1 0 1 0 1 0 1 */
CCL_TRUTH0 = CCL_TRUTH_2_bm
| CCL_TRUTH_3_bm
| CCL_TRUTH_4_bm
| CCL_TRUTH_6_bm
| CCL_TRUTH_7_bm;
CCL_LUT0CTRLC = CCL_INSEL2_FEEDBACK_gc;
CCL_LUT0CTRLB = CCL_INSEL1_EVENTA_gc
| CCL_INSEL0_TCA0_gc;
CCL_LUT0CTRLA = CCL_ENABLE_bm | CCL_OUTEN_bm; /* -> PIN_PA3 */
CCL_CTRLA = CCL_ENABLE_bm;
/* TCA0 で指定の時間の 交互切替 WO0 波形を生成しつづけ */
/* CNTB 事象を受け取ったら再起動する */
/* _________1ms______ 単位の 波形出力持続時間 */
TCA0_SINGLE_CMP0 = (F_CPU / 1000L / 64) * 2;
TCA0_SINGLE_EVCTRL = TCA_SINGLE_CNTBEI_bm | TCA_SINGLE_EVACTB_RESTART_POSEDGE_gc;
TCA0_SINGLE_CTRLB = TCA_SINGLE_WGMODE_FRQ_gc;
TCA0_SINGLE_CTRLA = TCA_SINGLE_ENABLE_bm | TCA_SINGLE_CLKSEL_DIV64_gc;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}偶数番の LUTn は、自身の帰還入力を使うと単体で RSラッチ回路(フリップフロップ)を仕立てることができる。そこで単発ストローブを このラッチの "セット"入力と ADCn の開始ストローブに、ADCn 完了ストローブを ラッチの "リセット"入力に送ることで、8000 x CLK_PER 程度までのレベル出力を作ることができる。ADCn に意味のある仕事をさせれば "ADCn 変換中だけ HIGH を維持するレベル信号" を同時に得ることができるし、ADCn 自体に用がないのなら、単なる遅延信号生成器に転用することができる。
-
ADCnは、属するファミリーによって全く設定方法が異なり、応用コードには相互移植性がない。これが一番の難点。 -
ADCnで達成できる遅延時間は、TIMEBASE あるいは INITDLY と SAMPDUR 値によってほとんど決まる。これは正味の CLK_PER 消費数であるが、F_CPU時間相対とするには計算・設定がしづらい。普通に書くと 350 us 程度までしか遅延させられない。OSC32Kによる超低速(スローモーション)動作向きか。 -
INSELn_FEEDBACKは、奇数番のLUTnでは 偶数番のCCLn_OUTを参照する。そのため次例では 偶数番のLUTnを必要とする。 -
LUTnのCLKSRCは、参照元にCLKPERかOSCHFしか選ぶことができない。その他では x1 CLK_PER 長の 単発ストローブ(の上昇端)を取りこぼす。同様の理由でFILTSELはDISABLEでなければならない。
/* for AVR_DD/DU */
void setup_ccl0_adc0_delay (void) {
/* EVSYS_CH0 ストローブは、ADC0 開始と CCL_LUT0A 入力に分配 */
EVSYS_USERADC0START = EVSYS_USER_CHANNEL0_gc;
EVSYS_USERCCLLUT0A = EVSYS_USER_CHANNEL0_gc;
/* EVSYS_CH1 は ADC0 完了を CCL_LUT0B 入力に転送 */
EVSYS_CHANNEL1 = EVSYS_CHANNEL_ADC0_RESRDY_gc;
EVSYS_USERCCLLUT0B = EVSYS_USER_CHANNEL1_gc;
/* CCL_LUT0 で ラッチ回路 を構成する */
/* TRUTH _ 4 1 5 */
/* 2:FDB 0 1 0 1 */
/* 1:EVB 0 0 0 0 */
/* 0:EVA 0 0 1 1 */
CCL_TRUTH0 = CCL_TRUTH_1_bm
| CCL_TRUTH_4_bm
| CCL_TRUTH_5_bm;
CCL_LUT0CTRLC = CCL_INSEL2_FEEDBACK_gc;
CCL_LUT0CTRLB = CCL_INSEL1_EVENTB_gc /* <- EVSYS_CH1 */
| CCL_INSEL0_EVENTA_gc; /* <- EVSYS_CH0 */
CCL_LUT0CTRLA = CCL_ENABLE_bm | CCL_OUTEN_bm; /* -> PIN_PA3 */
CCL_CTRLA = CCL_ENABLE_bm;
/* AVR_DU ファミリー用 ADC0 の場合 */
/* ここでは内蔵温度感知器を参照する */
CLKCTRL_MCLKTIMEBASE = 31;
ADC0_MUXPOS = ADC_MUXPOS_TEMPSENSE_gc;
ADC0_CTRLF = ADC_SAMPNUM_ACC64_gc;
ADC0_CTRLE = 255; /* TIMEBASE x SAMPDUR : 31 x 255 = 7905 x CLK_PER */
ADC0_CTRLC = ADC_REFSEL_2V048_gc;
ADC0_CTRLB = ADC_PRESC_DIV64_gc; /* (ACC) 64 x CLK_PER x 10 (bit) */
ADC0_CTRLA = ADC_ENABLE_bm;
ADC0_COMMAND = ADC_MODE_SINGLE_10BIT_gc | ADC_START_EVENT_TRIGGER_gc;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}一部の品種には
EVSYS_CHANNEL_ADC0_SAMPRDY_gc信号がある。これがレベル出力であったならCCLnを使わずにADCn単体で "ADC シングルショット・ディレイ" を作れるのだが、残念ながら x1 CLK_PER パルス なので、用を為さない。
555タイマーIC がそうであるように、外付けの抵抗とキャパシタによる RC直列回路を設け、それを MPU 搭載のアナログ比較器 AC0 をエラーアンプに用いて遅延回路を構成することを考える。
CCL のラッチ回路設定は ADC0 を使用した例と同等だが、次のような配慮が必要だ。
-
AINPnと、CCLn_OUTまたはEVOUTxが同時に設定できる GPIO とCCLnを探す。AVR_DD/DU を例に挙げると、PD3 + EVOUTDとPD6 + LUT2の組が該当する。 - 見つけた
AINPnに、電流制限抵抗とコンデンサを直列に取り付ける。(コンデンサが GND 側でなければならない) -
AINPnはアナログ入力許可/デジタル入力禁止にしつつ、CCLn_OUTの出力に選ぶ。直接選べなければEVOUTxを経由する。 - こうすると "CCLn_OUT = HIGH" ではコンデンサにゆっくりと充電されることになる。するとそれに遅れて、
ACn_OUTが変化する。
この構成の勘所は、AINPn をアナログ入力兼デジタル出力かつデジタル入力禁止にしていることだ。ふつうはこういう使い方をしないので気づきにくいが、データシートの "PORT 構成図" を参照すると、これが可能なことが理解できる。MPU によって "兼用端子" が見つけられない、あるいは回路設計上の都合で空きがない場合は、MPU の外で AINPn と CCLn_OUT を単に短絡させても良い。
"デジタル入力禁止" は重要。これを許すと "遅い電圧昇降傾斜" が デジタル入力素子のスリューレート定格制限を超えてしまい(グリッチ現象を招き)永久故障の原因になる。
-
CCLn_OUTは、観測端子(LED)と、AINPnに分配する。両者は兼用してもよい(LED と並列にコンデンサを配置し、電流制限抵抗を兼用する)が、時定数を計算で求めるのは煩雑になる。 -
CCLn_OUTは、さらに自身のINSEL2にFEEDBACKする。上記の分配をしている場合はEVSYS_CHnを経由しているので、奇数偶数いずれの LUTn でも可能だ。兼用かつEVSYS_CHn分配をしない場合は、偶数 LUTn が必要になる。(かわりにEVSYS_CHn消費がひとつ減る) -
ACnの設定は MPU によって差異がある。どの場合でもMUXPOS(AINPn) と比較するMUXNEGに与える参照電圧DACREFは、AINPnの到達最高電圧より僅かに低く設定すると最長の遅延時間が得られる。
この用例は MPU 内部で完結しない(外部に抵抗とコンデンサ、それに繋がる GPIO)かつ品種によって互換性のない ACn 設定という欠点があるが、ACn は比較的使われずに空いていることが多い周辺機能なので、タイマーや ADCn リソースの消費を嫌う場合は、有力な選択肢になり得る。
/* for AVR_DD/DU */
void setup_ccl2_ac0_delay (void) {
/* GPIO */
pinControlRegister(PIN_PD3) = PORT_ISC_INPUT_DISABLE_gc;
/* 信号分配 */
EVSYS_CHANNEL0 = EVSYS_CHANNEL_OFF_gc; /* <- STROBE */
EVSYS_CHANNEL1 = EVSYS_CHANNEL_CCL_LUT2_gc; /* <- PD3 */
EVSYS_USEREVSYSEVOUTD = EVSYS_USER_CHANNEL1_gc; /* -> PD2 */
EVSYS_USERCCLLUT2A = EVSYS_USER_CHANNEL0_gc; /* -> LUT2_IN0 */
EVSYS_USERCCLLUT2B = EVSYS_USER_CHANNEL1_gc; /* -> LUT2_IN2 */
/* AC0 で遅延回路を構成 */
/* PD2 - 470 ohm - 4.7 uF - GND : 時定数 2 ms */
VREF_ACREF = VREF_REFSEL_VDD_gc; /* DACREF へ VDD */
AC0_DACREF = 254; /* VDD x 係数:適宜調整(252〜254)*/
AC0_MUXCTRL = AC_MUXPOS_AINP0_gc /* <- PD2 から */
| AC_MUXNEG_DACREF_gc; /* <- DACREF から */
AC0_CTRLA = AC_ENABLE_bm /* -> LUT2_IN1 (PA7) */
| AC_POWER_PROFILE2_gc /* 電力特性選択:応答時間を犠牲に */
| AC_HYSMODE_LARGE_gc; /* ヒステリシス:最大 */
/* CCL_LUT2 で ラッチ回路 を構成する */
/* TRUTH _ 1 5 4 */
/* 2:FDB 0 0 1 1 */
/* 1:AC0 0 0 0 0 */
/* 0:EVA 0 1 1 0 */
CCL_TRUTH2 = CCL_TRUTH_1_bm
| CCL_TRUTH_4_bm
| CCL_TRUTH_5_bm;
CCL_LUT2CTRLC = CCL_INSEL2_EVENTB_gc; /* <- FEEDBACK */
CCL_LUT2CTRLB = CCL_INSEL1_AC0_gc /* <- AC0_OUT */
| CCL_INSEL0_EVENTA_gc; /* <- STROBE */
CCL_LUT2CTRLA = CCL_ENABLE_bm | CCL_OUTEN_bm; /* -> PD3 + PD2 */
CCL_CTRLA = CCL_ENABLE_bm;
}
void strobe (void) {
EVSYS_SWEVENTA = EVSYS_CH0_bm;
}Twitter(X): @askn37
BlueSky Social: @multix.jp
GitHub: https://github.com/askn37/
Product: https://askn37.github.io/
Copyright (c) 2026 askn (K.Sato) multix.jp
Released under the MIT license
https://opensource.org/licenses/mit-license.php
https://www.oshwa.org/
multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)