So-net無料ブログ作成

MC9S08SH4 のギャング出力で作るPWM [HCS08]このエントリーを含むはてなブックマーク#

2630227

MC9S08SH4 のギャング出力でPWMは使えるか?で判明したように、ギャング出力にハードウェアPWMを接続することはできませんでした。 しかたないので、ソフトウェアでPWMを実現します。

PWMの周波数をどのくらい高くすればいいか

今回のPWMの最終使用目的は、LEDではなく、DC-DCコンバータです。 一般にDC-DCコンバータの駆動周波数は可聴周波数よりも十分に大きくする必要があります。 これは、もし可聴周波数領域で駆動するとコイルなどの振動が耳障りな音として聞こえてくるからです。

また、周波数が低くなるとDC-DCコンバータのコイルのインダクタンスを大きくする必要があります。 インダクタンスを大きくすると、コイルが大きくなり、コイルの巻き数が増加して抵抗成分も増加し、いいことがありません。

そのため、できる限り周波数を高くしたPWMを設計する必要があります。 目安としては、インバータ式蛍光灯で使われている20kHzから50kHzというところでしょう。

MCUの駆動周波数

今回使用する MCU MC9S08SH4 は、最大バスクロックが 20MHz とされています。 これまで、良く使ってきた MC9S08QG8 の最大バスクロックが 10MHz だったので、二倍高速に動作することがわかります。 そのため、ソフトウェア PWM の周波数も従来の MCU に比べて二倍にすることができます。 今回は、この最大バスクロック20MHzで動作させることにします。

PWMの周波数を 20kHz から 50kHz と決めました。 そのため、 PWM 波形一周期に入るバスクロックは、 400サイクル から 1000サイクルということになります。 ここでは、「キリのいい」 512サイクルとします。 時間にして 25.6µ秒、周波数にして 約39kHzです。

成功の鍵は、割り込み処理にあり

ソフトウェアは、512サイクルごとにパルスを発生させなくてはなりません。 このイベントをハードウェア・タイマを使用して発行できたとしても、それをソフトウェアがきちんと受け止めなくてはタイミングが合わなくなります。 また、PWMパルスを発生させる裏では、電流や電圧を監視するA/Dコンバータ、PWMのデューティーを決定するための制御プログラムなどが動作します。 そのため、PWM出力をメイン・ルーチンに組み込むわけにもいきません。

このような事情から、PWMの処理は、割り込みによって行い、割り込み処理ルーチンの所要時間をできる限り削減することで対応することにしました。

初代割り込み処理ルーチン

最初に作成した割り込み処理ルーチンは、こんなものです。

word    duty;           // Duty value.

ISR(pwm_overflow_isr) {
  TPM2C0V = duty;       // Set next duty ratio.
  TPM2SC_TOF = 0;       // Clear overflow flag.
  GPort_SetVal();       // Assert GPORT
}

ISR(pwm_channel_isr)
{
  GPort_ClrVal();       // Negate GPORT
  TPM2C0SC_CH0F = 0;    // Clear channel flag.
}

タイマのオーバフロー周期をPWM周期の 25.6µ秒に設定し、オーバフロー割り込みの発生ごとにギャング出力をセットします。 このとき、同時に16ビットのアウトプット・コンペアにデューティ比を設定します。

アウトプット・コンペア割り込みが発生したら、ギャング出力をクリアします。

たった、これだけの処理なのですが、コンパイルの結果をみると意外に時間がかかっていることがわかります。

   36:  ISR(pwm_overflow_isr) {
  0000 8b       [2]             PSHH  
   39:    TPM2C0V = duty;       // Set next duty ratio.
  0001 320000   [5]             LDHX  duty
  0004 3500     [5]             STHX  _TPM2C0V
   41:    TPM2SC_TOF = 0;       // Clear overflow flag.
  0006 1f00     [5]             BCLR  7,_TPM2SC
   42:    GPort_SetVal();       // Assert GPORT
  0008 1000     [5]             BSET  0,_PTCD
   43:  }
  000a 8a       [3]             PULH  
  000b 80       [9]             RTI   
   44:  
   46:  ISR(pwm_channel_isr)
   47:  {
  0000 8b       [2]             PSHH  
   48:    GPort_ClrVal();       // Negate GPORT
  0001 1100     [5]             BCLR  0,_PTCD
   49:    TPM2C0SC_CH0F = 0;    // Clear channel flag.
  0003 1f00     [5]             BCLR  7,_TPM2C0SC
   50:  }
  0005 8a       [3]             PULH  
  0006 80       [9]             RTI   

行番号がバラバラですが、お気になさらず。 "pwm_overflow_isr"では、割り込み受付を含めておよそ54サイクル必要で、"pwm_channel_isr"では、割り込み受付を含めておよそ44サイクル必要です。 割り込みが連続して発生したとしても、ギャング出力に出力される最小パルス幅は、およそ34サイクルなので、理論上の最小デューティー比は6.6%ということになります。

変数はゼロページに置くべし

HCS08には、ゼロページという概念があります。 ゼロページ、すなわち$0000から$00FFまでの範囲のメモリ・アクセスは高速に実行されます。 そこで、変数"duty"をゼロページに配置します。

#pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE
word    duty;           // Duty value.
#pragma DATA_SEG DEFAULT

これだけで、オーバフロー処理が1サイクル高速になります。

   36:  ISR(pwm_overflow_isr) {
  0000 8b       [2]             PSHH  
   39:    TPM2C0V = duty;       // Set next duty ratio.
  0001 5500     [4]             LDHX  duty
  0003 3500     [5]             STHX  _TPM2C0V
   41:    TPM2SC_TOF = 0;       // Clear overflow flag.
  0005 1f00     [5]             BCLR  7,_TPM2SC
   42:    GPort_SetVal();       // Assert GPORT
  0007 1000     [5]             BSET  0,_PTCD
   43:  }
  0009 8a       [3]             PULH  
  000a 80       [9]             RTI   

まあ、わずかに1サイクルではありますが。

Hレジスタの退避は、必要か?

"pwm_channel_isr"では、割り込み処理ルーチン内でHレジスタが使われないにも係わらずスタックに退避されています。 これはムダなので退避させないようにします。

#pragma TRAP_PROC SAVE_NO_REGS
ISR(pwm_channel_isr)
{
  GPort_ClrVal();       // Negate GPORT
  TPM2C0SC_CH0F = 0;    // Clear channel flag.
}

関数の前に"#pragma"宣言を置くと、Hレジスタの退避が省略されます。

   45:  #pragma TRAP_PROC SAVE_NO_REGS
   46:  ISR(pwm_channel_isr)
   47:  {
   48:    GPort_ClrVal();       // Negate GPORT
  0000 1100     [5]             BCLR  0,_PTCD
   49:    TPM2C0SC_CH0F = 0;    // Clear channel flag.
  0002 1f00     [5]             BCLR  7,_TPM2C0SC
   50:  }
  0004 80       [9]             RTI   

同様に"pwm_overflow_isr"でもHレジスタの退避を省略したいところですが、こちらの処理ルーチンでは、16ビットレジスタへのアクセスのためにHレジスタが使用されています。 そこで、タイマのプリスケーラを2倍に設定することでデューティー比変数"duty"を8ビットとし、上位8ビットには、常に0を書き込むことにします。 これで、Hレジスタを退避する必要がなくなりました。

#pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE
byte    duty;           // Duty value.
#pragma DATA_SEG DEFAULT

#pragma TRAP_PROC SAVE_NO_REGS
ISR(pwm_overflow_isr) {
  TPM2C0VH = 0;
  TPM2C0VL = duty;      // Set next duty ratio.
  TPM2SC_TOF = 0;       // Clear overflow flag.
  GPort_SetVal();       // Assert GPORT
}

この部分、デューティ比設定レジスタは、下位8ビットのデータだけを設定するだけでいいんじゃないかと思っていました。 ところが、 MC9S08SH4 のタイマでは16ビット分設定しないとレジスタが変更されませんでした。 したがって、ムダではありますが、 "TPM2C0VH = 0;" という行を入れてあります。

   31:  #pragma DATA_SEG __SHORT_SEG MY_ZEROPAGE
   32:  byte    duty;           // Duty value.
   33:  #pragma DATA_SEG DEFAULT
   34:  
   35:  #pragma TRAP_PROC SAVE_NO_REGS
   36:  ISR(pwm_overflow_isr) {
   37:    TPM2C0VH = 0;
  0000 3f00     [5]             CLR   _TPM2C0V
   38:    TPM2C0VL = duty;      // Set next duty ratio.
  0002 4e0001   [6]             MOV   duty,_TPM2C0V:1
   41:    TPM2SC_TOF = 0;       // Clear overflow flag.
  0005 1f00     [5]             BCLR  7,_TPM2SC
   42:    GPort_SetVal();       // Assert GPORT
  0007 1000     [5]             BSET  0,_PTCD
   43:  }
  0009 80       [9]             RTI   

デューティー比レジスタを書き込む部分で多少てこずりましたが、3サイクル削減しました。 最初は34サイクルあった処理が、30サイクルまで減りました。 もうちょっと、がんばりたいけど、今のところはここまで。

設定値とデューティ比の確認

プログラムができたので、変数 "duty" に設定した値と実際のデューティー比を確認します。 デューティー比は、 2.2kΩ の抵抗と 0.1µF のマイラ・コンデンサで作った一次ローパスフィルタの出力電圧で代用しています。 電源電圧は、 5.1V でした。

dutyVOUT (V)ratio (%)
04.6591.2
11.76334.6
20.25024.9
:::
200.25024.9
210.27015.3
220.29005.7
230.31006.1
:::
1342.52049.4
1352.54049.8
1362.56050.2
1372.58050.6
:::
2374.5789.6
2384.5990.0
2394.6190.4
2404.6390.8
2414.6591.2
:::
2554.6591.2

この結果から、このPWMが正しくパルスを出すことができるのは、 "duty" の値が 20 から 241 までであり、そのときのデューティ比は、 4.9% から 91.2% の範囲になることがわかりました。

次は、コイルを作ります。

2009-03-19 追記

変数をゼロページに配置するための #pragma の記述方法が間違っておりましたので、訂正しました。

参考文献

HCS08 Unleashed: Designer's Guide to the HCS08 Microcontrollers

HCS08 Unleashed: Designer's Guide to the HCS08 Microcontrollers

  • 作者: Fabio Pereira
  • 出版社/メーカー: Booksurge Llc
  • 発売日: 2007/11/13
  • メディア: ペーパーバック

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。