web-dev-qa-db-ja.com

STM32F4タイマー-周期とプリスケールの計算、および1 msの遅延の生成

_STM32F407VGT6_とCubeMXを使用しています。
それで私は汎用タイマーから始めていて、プリスケールと期間の値で立ち往生しています。

基本的に、n(n = 1,2,3 ..)msごとにタイマー割り込みを生成し、いくつかのタスクを実行したいと思います。
周期とプリスケールの値を計算する式には多くのバリエーションがあります

式の一部のバージョンは次のとおりです。

TIMupdateFreq(HZ)= Clock /((PSC-1)*(Period-1))
更新イベント= TIM clk /((PSC + 1)*(ARR + 1)*(RCR + 1))
プリスケーラ=(((((ClockSpeed)/((period)/(1/frequency)))+ 0.5)-1)

質問に来ると、コアクロックは_168 MHz_で実行されていますが、タイマーが_APB1 Bus_で実行されている_84 MHz_に接続されていることがわかります。

私は1ミリ秒の遅延を生成するコードを試してみました(著者によると)その値をプリスケールと期間に使用した後、1ミリ秒の遅延を生成するコード(直感-スコープなし)も生成しました。

コードでは、41999のプリスケール値と1999の期間を使用しています。

そう、
PSC-41999
ARR-1999
これを2番目の式に適用

Update Event = TIM clk/((PSC+1)*(ARR+1)*(RCR+1))

Update Event = 84000000/(42000*2000) = 1(これは1msの遅延ですか?)

わかりましたので、今、この_PSC = 41999_と_Period = 1999_がどのように選択されているかを理解しようとしていますか?それは純粋に仮定に基づいていますか? 1.5または2.3または4.9で正確なタイミングのようなものを言いたい場合、プリスケールと周期を計算する方法は?

[〜#〜]編集[〜#〜]

さらに、_PSC=41999 and Period =999_を使用した場合、更新イベントの値は2です。

Update Event = 84000000/(42000*1000) = 2

しかし、私の遅延は毎秒2回です。つまり、500ms

また、_PSC=39999 and Period =4199_を使用する場合、更新イベントの値は0.5です。

Update Event = 84000000/(40000*4200) = 0.5

と私の遅延2ミリ秒。

前もって感謝します

4
Ehsan Habib

TIMupdateFreq(HZ)= Clock /((PSC-1)*(Period-1))

これは明らかに間違っています。カウンターは0からレジスター値(両端を含む)まで進み、レジスター値よりも常に1サイクル多く、1サイクルではありません。

更新イベント= TIM clk /((PSC + 1)*(ARR + 1)*(RCR + 1))

これの方が優れていますが、汎用タイマーにはRCRレジスタがありません。 _RCR=0_を想定し、数式から*(RCR+1)を省略できます。

プリスケーラ=((((ClockSpeed)/((period)/(1/frequency)))+ 0.5)-1)

これは、整数解が不可能な場合に結果を丸めようとします。後で詳しく説明します。

Update Event = 84000000/(42000*2000) = 1(これは1msの遅延ですか?)

いいえ、これは1秒(1秒)の遅延、つまり1 Hzの周波数です。

この_PSC = 41999_および_Period = 1999_の選択方法

簡単な式を考えてみましょう。

_Updatefrequency = TIM clk/((PSC+1)*(ARR+1))
_

それを再配置する

_(PSC+1)*(ARR+1) = TIMclk/Updatefrequency
_

すると、右側には既知の値がありますが、左側には2つの未知数があります。簡単な解決策は、それらの1つを設定することです。 PSCから_0_へ、およびARRから右側の値-1へ。

残念ながらほとんどのタイマーは16ビットのレジスターしか持っていないので、これは_TIMclk/Updatefrequency > 65535_の場合は機能しません。 PSCARRはどちらも0〜65535の範囲内でなければなりません。これらを満たす分解を見つける必要があります制約。

例を見てみましょう。2.3秒の遅延が必要です。 2.3sは周波数ではなく周期なので、式にその逆数を入れる必要があることに注意してください。

_(PSC+1) * (ARR+1) = 84000000 / (1 / 2.3) = 84000000 * 2.3 = 193200000_

幸いなことに、最後にはゼロがたくさんあります。たとえば、プリスケーラとして_10000_(_PSC=9999_)、およびARRは_19320-1 = 19319_になります。望ましい比率がナイスラウンド数でない場合は、 整数因数分解 に頼るか、小さなプログラムを記述してすべての可能な除数(for(i=0;i<65536;i++) ...)を探す必要があります。

また、正確な整数解がまったくない場合もあります。その場合は、可能なすべてのプリスケーラー値をループして、どれが最小のエラーを与えるかを確認できます。

Update Event = 84000000/(42000*1000) = 2

しかし、私の遅延は毎秒2回です。つまり、500ms

寸法に注意してください。式で周波数を使用しており、84 MHzの入力周波数をいくつかの値で除算し、2 Hzを結果。 2 Hzの周波数は、毎秒2つのイベントを意味するため、イベントは実際に500ミリ秒離れています。

「バリエーション」はありません。数式は1つだけ存在します:

Period = (PSC+1)*(ARR+1) / TmerClockFreq秒単位Period = 1000 * (PSC+1)*(ARR+1) / TmerClockFreqミリ秒単位

したがって、必要な期間にできるだけ近い時間を提供するARRとPSCを見つける必要があります。

2
P__J__

ここでもっと包括的な答えを投げると思いました。 84MHzクロックの場合、多数プリスケーラーと周期の組み合わせが機能します。以下はほんの一部です。

  PSC    ARR            F         ERROR EXACT
   1  41999  1000.000000  0.0000000000   YES
   2  27999  1000.000000  0.0000000000   YES
   3  20999  1000.000000  0.0000000000   YES
   4  16799  1000.000000  0.0000000000   YES
   5  13999  1000.000000  0.0000000000   YES
   6  11999  1000.000000  0.0000000000   YES
   7  10499  1000.000000  0.0000000000   YES
   9   8399  1000.000000  0.0000000000   YES
  11   6999  1000.000000  0.0000000000   YES
  13   5999  1000.000000  0.0000000000   YES
  14   5599  1000.000000  0.0000000000   YES
  15   5249  1000.000000  0.0000000000   YES
  19   4199  1000.000000  0.0000000000   YES

これらをどうやって思いつくのですか? MikroElektronicaのような市販のツールでさえ、正確な(または不正確な)組み合わせは1つしかありません。それらをすべて見つける方法は?私は単にpythonプログラムを記述してすべてを計算します。それぞれを正確に分類するか、不正確なものの相対誤差を記録します。プログラムの上部で許容誤差を変更することにより、必要に応じて、計算を「締める」または「緩める」。

プログラム全体を次に示します。

import numpy as np
import pandas as pd

TARGET_F = 1000  # In Hz so 50.0 is 0.020 seconds period and 0.25 is 4 seconds period
CLOCK_MCU = 84000000
TOLERANCE = 0.0001

# -----------------------------------------------------


def abs_error(num1, num2):
    return abs((num1 - num2) / num1)


def hertz(clock, prescaler, period):
    f = clock / (prescaler * period)
    return f


def perfect_divisors():
    exacts = []
    for psc in range(1, 65536):
        arr = CLOCK_MCU / (TARGET_F * psc)
        if CLOCK_MCU % psc == 0:
            if arr <= 65536:
                exacts.append(psc)
    return exacts


def add_exact_period(prescaler):
    entries = []
    arr = CLOCK_MCU / (TARGET_F * prescaler)
    if arr == int(arr):
        entry = [prescaler, arr, TARGET_F, 0.0]
        entries.append(entry)
    return entries


def possible_prescaler_value():
    possibles = []
    for psc in range(1, 65536):
        if psc in exact_prescalers:
            continue
        h1 = hertz(CLOCK_MCU, psc, 1)
        h2 = hertz(CLOCK_MCU, psc, 65536)
        if h1 >= TARGET_F >= h2:
            possibles.append(psc)
    return possibles


def close_divisor(psc, tolerance):
    arr = CLOCK_MCU / (TARGET_F * psc)
    error = abs_error(int(arr), arr)
    if error < tolerance and arr < 65536.0:
        h = hertz(CLOCK_MCU, psc, int(arr))
        return psc, int(arr), h, error
    else:
        return None


#  ------------------------------------------------------------------------

# Make a dataframe to hold results as we compute them
df = pd.DataFrame(columns=['PSC', 'ARR', 'F', 'ERROR'], dtype=np.double)

# Get exact prescalars first.
exact_prescalers = perfect_divisors()
exact_values = []
for index in range(len(exact_prescalers)):
    rows = add_exact_period(exact_prescalers[index])
    for rowindex in range(len(rows)):
        df = df.append(pd.DataFrame(np.array(rows[rowindex]).reshape(1, 4), columns=df.columns))

# Get possible prescalers.
poss_prescalers = possible_prescaler_value()
close_prescalers = []
for index in range(len(poss_prescalers)):
    value = close_divisor(poss_prescalers[index], TOLERANCE)
    if value is not None:
        close_prescalers.append((value[0], value[1], value[2], value[3]))
df = df.append(pd.DataFrame(np.array(close_prescalers).reshape(len(close_prescalers), 4), columns=df.columns))

#  Adjust PSC and ARR values by -1 to reflect the way you'd code them.
df['PSC'] = df['PSC'] - 1
df['ARR'] = df['ARR'] - 1

#  Sort first by errors (zeroes and lowest errors at top of list, and
#  then by prescaler value (ascending).
df = df.sort_values(['ERROR', 'PSC'])

# Make and populate column indicating if combination is exact.
df['EXACT'] = pd.Series("?", index=df.index)
df['EXACT'] = np.where(df['ERROR'] == 0.0, "YES", "NO")

#  Format for output.
df['PSC'] = df['PSC'].map('{:.0f}'.format)
df['ARR'] = df['ARR'].map('{:.0f}'.format)
df['F'] = df['F'].map('{:.6f}'.format)
df['ERROR'] = df['ERROR'].map('{:.10f}'.format)

output = df.to_string()
print(output)
print()
print('these are the ', df.shape[0], ' total combination meeting your tolerance requirement')
exit(0)

このプログラムを使用すると、誰もが自信を持ってこれらの値を計算することができます。お役に立てば幸いです。

1
TomServo