tinyAVRマイコンのタイマーAとtakeOverTCA0()
Arduino IDE環境でのtinyAVRマイコン、
AVR0系、1系、2系とさまざまなのがありますが、
そのタイマーAは、本来16bitのタイマーなのですが、
2つの8bitタイマーで使うように初期化されています。
PWM操作(8bitのanlogWrite出力)が目的
16bitタイマーで使うときは標準動作、
8bitタイマーだと分割動作と呼ばれています。
標準と分割とでレジスタの機能が異なっている部分が
あるので、実態は同じ制御レジスタなのに
「TCA0.SINGLE.xxxx」と「TCA0.SPLIT.xxxx」
と名前を変えて呼ばれます。
問題なのが、タイマーAを16bitで使いたいとき。
分割動作で初期設定されたのを標準に戻すわけです。
データシートを見ますと、こんな記述が見つかります。
(クリックで拡大↓)![]()
これ、リセットするのにArduino IDE環境では
「takeOverTCA0()」を使うことになっています。
「megaTinyCore」の例題スケッチを探すとsetup()の
中でこの関数を一回だけ呼び、その後16bitの標準
動作の設定を行っているのがわかります。
takeOverTCA0()が何をしているかというと、
こんなソースが"wireing_analog.c"の中に
入っています。
void takeOverTCA0() {
TCA0.SPLIT.CTRLA = 0; // Stop TCA0 (1)
__PeripheralControl &= ~TIMERA0;
// Mark timer as user controlled (2)
TCA0.SPLIT.CTRLESET =
TCA_SPLIT_CMD_RESET_gc | 0x03;
// Reset TCA0 (3)
}
(1)はタイマーAの停止処理
これは標準でも分割も同じ。
(2)は__PeripheralControlはPWM出力可能か
どうかを保持している変数。
タイマーAを止めてたらPWM出力できないぞ
を返すために使われてる(みたい)
(3)が分割モードでのリセット処理。
一連の流れでタイマーAがリセットされるという
仕掛けです。
私の場合、takeOverTCA0()を知ったのはつい
こないだのこと。
これを使わずにどうしてたかというと、まず参考になるのが
・ATtiny1614:タイマレジスタの初期設定を見る
これで、タイマーAを含むタイマー関連の初期状態が
想像できます。
ATtiny402の初期状態をあらためて見ると、
ATtiny402 : timer Disable
TCA0.CTRLA 09
TCA0.CTRLB 00
TCA0.CTRLD 01
TCA0.EVCTRL 00
TCA0.INTCTRL 02
TCA0.PER FEFE
TCA0.PERB FFFF
PORTMUX.CTRLC 01
そして、ATtiny3224で裸の32bit周波数カウンタ #2
では、このようにレジスタ名SPLITは使わず、
SINGLEのまま16bitモードに。
TCA0.SINGLE.INTCTRL= 0; // 割り込み禁止
TCA0.SINGLE.CTRLA = 0; // TCA0 停止
TCA0.SINGLE.CTRLD = 0; // TCA0 8bit分割停止 16bitに
↓
16bitモードの設定
ATtiny402マイコン サンプル:RCサーボモータテスター
では、
// タイマーA0, 分割モードで初期化されるので16bitモードに
TCA0.SPLIT.CTRLA = 0; // タイマー停止
TCA0.SPLIT.INTCTRL = 0; // 割り込みなしに
PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに
TCA0.SINGLE.CTRLD = 0; // TCA0を16bitモードに
↓
16bitモードの設定
手順はいろいろありますが、
・まずタイマーを止めて
・リセット
これがtakeOverTCA0()の手順。
あるいは、
・タイマーを止めて
・割り込みをなしに
・16bitモードに
これでも大丈夫。
で、takeOverTCA0()でちょっと問題か?っと
思ったのが「PORTMUX.CTRLC」の設定。
8bit PWMでの出力を4ch使えるように「ポート多重器」
を使って、WO0をPA7に割り当てています。
これで、
WO0 PA7 (代替ピン)
WO1 PA1
WO2 PA2
WO3 PA3 (WO0/WO3共用)
と4つのPWM出力が使えるのです。
しかし、16bit PWMモードではWO0、1、2の3つの
出力しか使えません。
その中のWO0が代替ピンのままになっています。
こうなってると分かっているのであれば
良いのですが、takeOverTCA0()では
ほったらかし。
16bit PWMの処理で、PA3がWO0出力になる
つもりのスケッチが、代替ピンのPA7に出て
しまいます。
完全に初期状態にというと、
「 PORTMUX.CTRLC = 0; // TCAポート多重切り替えなしに」
の1行が必要です。
※追記:ATtiny402、レジスタを表示してから
takeOverTCA0()を実行して、もう一度レジスタ表示。
ATtiny402
TCA0.CTRLA 09
TCA0.CTRLB 00
TCA0.CTRLD 01 ←8bit 分割モード
TCA0.EVCTRL 00
TCA0.INTCTRL 02
TCA0.PER FEFE
TCA0.PERB FFFF
PORTMUX.CTRLC 01 ←TCA00代替ポートが有効
takeOverTCA0実行
TCA0.CTRLA 00 ←初期値に
TCA0.CTRLB 00
TCA0.CTRLD 00
TCA0.EVCTRL 00
TCA0.INTCTRL 00
TCA0.PER FFFF
TCA0.PERB FFFF
PORTMUX.CTRLC 01 ←代替ポート指定は残る
※追記 analogWriteを実行するとどうなるか
レジスタ値出力後、
analogWrite(1, 1); // PA7 3pin
analogWrite(2, 2); // PA1 4pin
analogWrite(3, 3); // PA2 5pin
analogWrite(4, 254); // PA3 7pin
とanalogWrite で4つのPWMパルスを出力。
その後のレジスタ値の変化です。
ATtiny402 : 20MHz
analogWrite 前 後
-------------------------------
TCA0.CTRLA 0B 0B
TCA0.CTRLB 00 17 ←
TCA0.CTRLD 01 01
TCA0.EVCTRL 00 00
TCA0.INTCTRL 02 02
TCA0.PER FEFE FEFE
TCA0.PERB FFFF FFFF
TCA0.CMP0 0000 FE01 ←
TCA0.CMP1 0000 0002 ←
TCA0.CMP2 0000 0003 ←
PORTMUX.CTRLC 01 01
8bit分割モードで処理されたようすが見えてます。
ATtiny402でのanalogWrite、数値範囲は「0~255」。
0で全L。255で全Hなんで、128にしてもデューティ50%ジャスト
にはなりません。
50%よりちょっと大きめのデューティになります。
127だとちょっと小さめになり、analogWriteではジャスト
50%のデューティは出てきません。



















最近のコメント