ATtiny13A-CTCモードでソフトウェアPWMを生成できない


8

ATtiny13Aを使ってリモコンのRGB LEDライトを作ろうとしています。

私はATtiny85がこの目的により適していることを知っており、最終的にコード全体に適合できない可能性があることを知っていますが、今のところ私の主な関心事はCTCモードで割り込みを使用してソフトウェアPWMを生成することです。

私は(と高速PWM以外の他のモードで動作することができないOCR0AようにTOP、私が使用していたIR受信コードは、それがCTCを使用して生成する38 kHzの周波数を必要とするため、基本的に同じものです)OCR0A=122

だから私は(そしてインターネットでこれが言及されているのを見たことがあります)、ソフトウェアPWMを生成するために割り込みOutput Compare AOutput Compare B割り込みを使用しようとしています。

OCR0AIRコードでも使用されるは、周波数を決定しますが、これは気にしません。そしてOCR0B、LEDの色を変更するために使用するPWMのデューティサイクルを決定します。

OCR0B値をから0に変更することで、デューティサイクルが0〜100%のPWMが得られると期待していますOCR0A。これは何が起こるべきかについての私の理解です:

波形

しかし実際に起こっていることはこれです(これはProteus ISISシミュレーションからです):

以下を見るとわかるように、約25%〜75%のデューティサイクルを取得できますが、〜0-25%および〜75-100%の場合、波形はスタックし、変化しません。

黄色の線:ハードウェアPWM

REDライン:固定デューティサイクルのソフトウェアPWM

緑のライン:デューティサイクルが変化するソフトウェアPWM

オシロスコープの結果

そして、これが私のコードです:

#ifndef        F_CPU
    #define        F_CPU        (9600000UL) // 9.6 MHz
#endif

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int main(void)
{
    cli();

    TCCR0A = 0x00;                        // Init to zero
    TCCR0B = 0x00;

    TCCR0A |= (1<<WGM01);                 // CTC mode
    TCCR0A |= (1<<COM0A0);                // Toggle OC0A on compare match (50% PWM on PINB0)
                                          // => YELLOW line on oscilloscope

    TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B);  // Compare match A and compare match B interrupt enabled

    TCCR0B |= (1<<CS00);                  // Prescalar 1

    sei();

    DDRB = 0xFF;                          // All ports output


    while (1)
    {
        OCR0A = 122;                      // This is the value I'll be using in my main program
        for(int i=0; i<OCR0A; i++)
        {
            OCR0B = i;                    // Should change the duty cycle
            _delay_ms(2);
        }
    }
}


ISR(TIM0_COMPA_vect){
    PORTB ^= (1<<PINB3);                  // Toggle PINB3 on compare match (50% <SOFTWARE> PWM on PINB3)
                                          // =>RED line on oscilloscope
    PORTB &= ~(1<<PINB4);                 // PINB4 LOW
                                          // =>GREEN line on oscilloscope
}

ISR(TIM0_COMPB_vect){
    PORTB |= (1<<PINB4);                  // PINB4 HIGH
}

ハードウェアPWMを使用できない理由を教えてください。あなたが与えている理由は何の意味もありません。ハードウェアを使用しない唯一の理由は、SPIインターフェイスまたは外部割り込みが必要な場合です。
メープル、

@Maple RGB LEDを制御しようとしているので、各色に1つずつ、合計3つのPWM信号が必要です。OCR0A私は持っているので、IRコードで使用されますOCR0B。3つの非PWMピンでソフトウェアPWMを生成するためにそれを使用しようとしています。
Pouria P

38kHzソフトウェアPWMは機能しません。これはMCUには速すぎます。
JimmyB 2018

1
ISRを38kHzで実行できます(そうしている場合もあります)。ただし、50%以外のデューティサイクルでは、より高い周波数が必要になります。例:25%@ 38kHzの場合、38kHz / 25%= 152kHzの時間枠内で2つの連続した割り込みを処理できる必要があります。これにより、ISRに約63 CPUクロックサイクル(9600kHz / 152kHz)しか残りません。10%のデューティサイクルでは、ISR用に25 CPUクロックが1つ残っています。
JimmyB 2018

3
目的のPWM周波数を指定していません。輝度を制御するために、38kHzの近くにいる必要はありません。100Hzで十分かもしれません。38kHz(IR)周波数をソフトウェアPWMの最小デューティサイクルとして使用し、PWMをその倍数、たとえば256として実装することをお勧めします。これにより、最小デューティサイクルは1/256(1つの38kHzクロック周期)となり、最高(100%未満)は(255/256)で、255 38kHzクロック周期に相当します。これにより、(38000/256)〜148Hzで8ビットPWMが得られます。
JimmyB 2018

回答:


8

最小限のソフトウェアPWMは次のようになります。

volatile uint16_t dutyCycle;


uint8_t currentPwmCount;

ISR(TIM0_COMPA_vect){
  const uint8_t cnt = currentPwmCount + 1; // will overflow from 255 to 0
  currentPwmCount = cnt;
  if ( cnt <= dutyCyle ) {
    // Output 0 to pin
  } else {
    // Output 1 to pin
  }
}

プログラムdutyCycleが目的の値に設定され、ISRが対応するPWM信号を出力します。0から256までの値を許容するdutyCyclea です。256はすべての可能な値よりも大きいため、完全な100%のデューティサイクルを提供します。uint16_tcurrentPwmCount

あなたは0%(または100%)を必要としない場合は、使用して、いくつかのサイクルをオフに剃ることができますuint8_tので、どちらかという01/256のデューティ・サイクルでの結果とは255100%であるか、00%と255255のデューティ・サイクルであります/ 256。

38kHz ISRにはまだ時間がありません。小さなインラインアセンブラを使用すると、ISRのサイクル数を1/3から1/2に削減できます。代替方法:PWMコードを他のすべてのタイマーオーバーフローでのみ実行し、PWM周波数を半分にします。

複数のPWMチャネルがあり、PMWしているピンがすべて同じであるPORT場合、すべてのピンの状態を変数に収集し、最後に1つのステップでポートに出力することができます。ポート、およびマスク付き、または新しい状態のポートへの書き込みが、ピン/チャネルごとに1 回ではなく1回です。

例:

volatile uint8_t dutyCycleRed;
volatile uint8_t dutyCycleGreen;
volatile uint8_t dutyCycleBlue;

#define PIN_RED (0) // Example: Red on Pin 0
#define PIN_GREEN (4) // Green on pin 4
#define PIN_BLUE (7) // Blue on pin 7

#define BIT_RED (1<<PIN_RED)
#define BIT_GREEN (1<<PIN_GREEN)
#define BIT_BLUE (1<<PIN_BLUE)

#define RGB_PORT_MASK ((uint8_t)(~(BIT_RED | BIT_GREEN | BIT_BLUE)))

uint8_t currentPwmCount;

ISR(TIM0_COMPA_vect){
  uint8_t cnt = currentPwmCount + 1;
  if ( cnt > 254 ) {
    /* Let the counter overflow from 254 -> 0, so that 255 is never reached
       -> duty cycle 255 = 100% */
    cnt = 0;
  }
  currentPwmCount = cnt;
  uint8_t output = 0;
  if ( cnt < dutyCycleRed ) {
    output |= BIT_RED;
  }
  if ( cnt < dutyCycleGreen ) {
    output |= BIT_GREEN;
  }
  if ( cnt < dutyCycleBlue ) {
    output |= BIT_BLUE;
  }

  PORTx = (PORTx & RGB_PORT_MASK) | output;
}

このコードは、デューティサイクルを1ピンの論理出力にマップします。LEDに「負論理」(ピンがローのときにLEDがオン)がある場合、単にに変更if (cnt < dutyCycle...)するだけでPWM信号の極性を反転できますif (cnt >= dutyCycle...)


すごいね。あなたが私に言われたことの私の理解が正しいかどうか疑問に思っていました。今、この非常に有益な答えと例とすべてがあります。再度、感謝します。
Pouria P

もう1つだけ、これを正しく理解しました。他のすべてのタイマーオーバーフローでPWMを実行する場合if、割り込みルーチンに入れて、1回おきにPWMコードのみを実行します。これを行うことにより、私のPWMコードに時間がかかりすぎて次のオーバーフロー割り込みが見逃された場合、次の割り込みが何もしなかったので、私のプログラムは問題ありません。それはあなたが意味したことですか?
Pouria P

はい、これは私が意味したことです。ISRは、最初に割り込みを見逃さないように十分に高速でなければなりませんが、たとえそうであっても、1つのISRでCPU時間の90%を費やすことも適切ではない可能性があるため、「複雑なロジックは他のすべての割り込みに割り込んで、他のタスクにより多くの時間を残します。
JimmyB 2018

2

@JimmyBがコメントしたように、PWM周波数が高すぎます。

割り込みの合計レイテンシはPWMサイクルの4分の1のようです。

重複する場合、2番目の割り込みがキューに入れられ、最初の割り込みが終了した後に実行されるため、合計レイテンシによってデューティサイクルが固定されます。

最小PWMデューティサイクルは、PWM周期の合計割り込み遅延パーセンテージによって与えられます。同じロジックが最大PWMデューティサイクルに適用されます。

グラフを見ると、最小デューティサイクルは約25%であり、合計レイテンシは〜1 /(38000 * 4)= 6.7 µsでなければなりません。

結果として、最小PWM周期は256 * 6.7 µs = 1715 µsおよび最大周波数583 Hzです。

高い頻度で可能なパッチに関するいくつかのより多くの説明:

何も実行できない場合、割り込みには2つのブラインドウィンドウがあり、コンテキストが保存および回復されると、割り込みを終了します。あなたのコードはかなりシンプルなので、これはレイテンシのかなりの部分を占めると思います。

低い値をスキップするソリューションには、少なくとも割り込みから出て次の割り込みに入るまでの待ち時間があるため、最小デューティサイクルは期待どおりにはなりません。

これがPWMステップ以上である限り、PWMデューティサイクルはより高い値から始まります。あなたが今持っているものからほんの少しの改善。

割り込みでプロセッサ時間の25%をすでに使用しているので、50%以上を使用しないでください。2番目の割り込みはそのままにして、比較フラグ用にプールしてください。128までの値を使用する場合、デューティサイクルは最大50%になりますが、アセンブラで最適化できる2つの命令のレイテンシがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.