2

現在、DCF77 ライブラリ(ソース コードは GitHub にあります) を Arduino (AVR ベース) から Arduino Due (ARM Cortex M3) に移植しています。

ライブラリには、正確な 1 ミリ秒のタイミングが必要です。明らかな候補は、syssticks の使用です。便利なことに、Arduino Due は 1 kHz のシステムスティック用にすでにセットアップされています。

ただし、私の (AVR) DCF77 ライブラリは、DCF77 にロックするとタイミングを調整できます。これは、タイマーのリロード値を次のように操作することによって行われます。

void isr_handler() {
    cumulated_phase_deviation += adjust_pp16m;
    // 1 / 250 / 64000 = 1 / 16 000 000
    if (cumulated_phase_deviation >= 64000) {
        cumulated_phase_deviation -= 64000;
        // cumulated drift exceeds 1 timer step (4 microseconds)
        // drop one timer step to realign
        OCR2A = 248;
    } else if (cumulated_phase_deviation <= -64000) {
        // cumulated drift exceeds 1 timer step (4 microseconds)
        // insert one timer step to realign
        cumulated_phase_deviation += 64000;
        OCR2A = 250;
    } else {
        // 249 + 1 == 250 == 250 000 / 1000 =  (16 000 000 / 64) / 1000
        OCR2A = 249;
    }

    DCF77_Clock_Controller::process_1_kHz_tick_data(the_input_provider());
}

これをARMプロセッサに移植したい。ARM インフォメーション センターで、次のドキュメントを見つけました。

SysTick の構成

...

SysTick を設定するには、SysTick イベント間に必要な間隔で SysTick Reload Value レジスタをロードする必要があります。タイマー割り込みまたは COUNTFLAG ビット (SysTick Control and Status レジスタ内) は、1 から 0 への遷移でアクティブになるため、n+1 クロック ティックごとにアクティブになります。100 の期間が必要な場合は、SysTick Reload Value レジスタに 99 を書き込む必要があります。SysTick Reload Value レジスタは、1 ~ 0x00FFFFFF の値をサポートします。

SysTick を使用して 1ms などの時間間隔でイベントを生成する場合は、SysTick キャリブレーション値レジスタを使用して、リロード レジスタの値をスケーリングできます。SysTick キャリブレーション値レジスタは、TENMS フィールド (ビット 0 ~ 23) に 10ms の期間のパルス数を含む読み取り専用レジスタです。このレジスタには SKEW ビット (30) もあり、クロック周波数の変動が小さいため、TENMS セクションの 10ms のキャリブレーションが正確に 10ms ではないことを示すために使用されます。ビット 31 は、基準クロックが提供されているかどうかを示すために使用されます。

...

残念ながら、SysTick->LOAD と SysTick->CALIB がどのように接続されているかについては何も見つかりませんでした。つまり、システムスティックを抑制または加速したい場合、LOAD または CALIB 値を操作する必要がありますか? また、これらのレジスタにどの値を入力する必要がありますか?

インターネットで検索しても、これ以上のヒントは見つかりませんでした。多分私は間違った場所を探しています。これらの質問に対するより詳細なリファレンスはどこにありますか? それとも、いくつかの良い例でさえありますか?

4

2 に答える 2

2

AtMega328 のデータシートCortex-M3 TRMと比較すると、顕著な点は、タイマーが逆方向に動作することです。AVR では、値をロードしてタイマーがカウントアップするOCR2Aのを待っていますが、M3 ではTCNT2に遅延値をロードすると、システムはでこの値から 0 までSYST_RVRカウントダウンSYST_CVRます。

キャリブレーションの大きな違いは、比較値が 0 に固定されており、リロード値のみを調整できるためです。比較値を直接調整する場合と比較して、レイテンシが長くなる可能性があります (カウンタのリロードが割り込みと同時に発生すると仮定すると、生成されます)。

の読み取り専用値SYST_CALIB(実際に存在する場合、実装定義でオプション) は、SYSTICK ティックを実際の壁時計時間に関連付けるためだけのものです。タイマーを最初に初期化するときは、希望する期間に適切なリロード値を設定するため、「この多くの参照クロック ティックが 10 ミリ秒で発生する (おそらく)」というレジスタ フィールドがあると、値をハードコードするのではなく、実行時にポータブルな方法で計算する可能性がいくらか提供されます。デバイスごとに変更する必要がある場合があります。

ただし、この場合、さらに正確な外部クロックを同期することで、これが重要でなくなるだけでなく、ファームウェアによってタイマーが既に構成されていることが重要ですSYST_RVRしたがって、どんな値が入っていても1KHz に十分近い値を表していると仮定して、そこから作業を進めることができSysTick->LOAD++ます。SysTick->LOAD--エラーがいずれかの方向に大きくなりすぎる場合。


もう少し深く掘り下げると、SAM3X データシートは、その SoC の特定の M3 実装では、SYSTICK が 10.5 MHz の基準クロックを持っていることを示しているため、SYST_CALIBレジスタは 10 ミリ秒で 105000 ティックの値を与える必要があります。そうでないことを除いて、どうやら Atmel は、明確に名前が付けられた TENMS フィールドに1msのティックカウント、10500 を代わりに与えることが本当に賢いと考えたようです。素晴らしい。

于 2015-01-11T13:00:14.640 に答える