Padaukマイコン内蔵の11bitPWM機能を利用して、任意のデューティのPWM波形を生成することができました。
内蔵PWM
8bitと11bit
PFS123には、Timer2とTimer3を使用した2つの8bit PWM生成回路と、専用の3ch 11bit PWM生成回路が内蔵されています。
Timerを使用したPWMの場合、PWMの周波数は設定したクロック源の周波数の1/256となります。
PWM専用の11bitPWM生成回路の場合は、カウントの最大値を設定できるため、任意の周波数に設定することができます。
今回は、100kHzの周波数のPWMを生成したいので、11bitPWM生成回路でPWMを生成してみまたいと思います。
接続
11bit PWMのブロック図は上の図のようになっています。PFS123には3chの11bitPWM生成回路が内蔵されていて、それぞれ出力できるピンが異なります。
今回はPA3にPWMを出力したいので、3ch目の11bitPWM生成回路を使用します。
まずは左上のクロック源の設定です。IHRCは一番速いクロック源となります。PFS123の場合は16MHzです。今回はIHRCを使用します。
3ch目のPWM生成回路には、分周機能やコンパレータ出力でANDする機能、PWM波形を反転する機能があります(図の中央下から右下)。これらの機能は、今回は使用しません。
最後に一番右下の部分で、生成されたPWM波形をどこのピンに出力するかを設定することができます。これをPA3にします。
プログラム
最低限のプログラム
#include <pdk/device.h>
#include <stdint.h>
#include "auto_sysclock.h"
#include "delay.h"
#define PWM_OUT 3
#define PWM_MAX 320
void main() {
PDK_USE_FACTORY_IHRCR_16MHZ();
PDK_USE_FACTORY_BGTR();
AUTO_INIT_SYSCLOCK();
CLKMD &= ~CLKMD_ENABLE_WATCHDOG; // Disenable WDT
PAC |= ( 1 << PWM_OUT);
PWMGCUBL = (uint8_t)(PWM_MAX << 5);
PWMGCUBH = (uint8_t)(PWM_MAX >> 3);
PWMG2DTL = 0;
PWMG2DTH = 0;
PWMGCLK = (uint8_t)(PWMGCLK_PWMG_ENABLE | PWMGCLK_CLK_IHRC);
PWMG2C = (uint8_t)(PWMG2C_OUT_PA3);
ROP = ROP_PWM_16MHZ;
while(1)
{
for( int16_t pwm = 0; pwm<PWM_MAX; pwm++)
{
PWMG2DTL = (uint8_t)(pwm << 5);
PWMG2DTH = (uint8_t)(pwm >> 3);
_delay_ms(10);
}
}
}
上記が、最低限の11bitPWM生成プログラムです。
14行目でPA3ピンを出力に設定します。
15,16行目でカウンタの最大値を設定します。PWMの周波数はクロック源×2/カウンタの最大値となります。クロック源は今回はIHRC=16MHz、カウンタの最大値を320とすると、PWMの周波数は100kHzとなります。
17,18行目でPWMの閾値を設定します。11bitなので2つのレジスタに値を書き込むのですが、Lowバイトから先に書き込み、次にHighバイトを書き込みます。この順番で書き込むと、Highバイトを書き込んが瞬間に、LowバイトとHighバイトが同時に比較器にセットされます。
19行目はクロック源を設定します。PWMGCLKレジスタはライトオンリーのレジスタなので、1バイト分をまとめて書き込む必要があります。PWMGCLK_PWMG_ENABLE を書き込んでから、PWMGCLK_CLK_IHRCをORするといったことはできません。
20行目はどこのピンに出力するかを設定します。今回はPA3です。
以上の設定をすればPWM波形が生成されます。
これはPA3の波形です。デューティが0から100%まで変化する波形が出力されます。
スイッチでデューティを設定できるようにする
続いて、スイッチを操作して任意のデューティのPWMを生成できるようにします。現在の閾値がわかるように、先日作った5bitバイナリ表示器を接続します。
表示器に関して詳しくはこちらをご覧ください。

#include <pdk/device.h>
#include <stdint.h>
#include "auto_sysclock.h"
#include "delay.h"
#define PWM_OUT 3
#define PWM_MAX 320
#define PWM_ADD 4
#define TEST_PIN 4
#define TEST_PIN_OFF() PA &= ~(1 << TEST_PIN)
#define TEST_PIN_ON() PA |= (1 << TEST_PIN)
#define UP_PIN 7
#define DOWN_PIN 6
#define UP_STATUS() ( ( PB & (1 << UP_PIN) ) != 0 )
#define DOWN_STATUS() ( ( PB & (1 << DOWN_PIN) ) != 0 )
#define PRESS 0
#define UNPRESS 1
void main() {
PDK_USE_FACTORY_IHRCR_16MHZ();
PDK_USE_FACTORY_BGTR();
AUTO_INIT_SYSCLOCK();
CLKMD &= ~CLKMD_ENABLE_WATCHDOG; // Disenable WDT
//for PWM
PAC |= ( 1 << PWM_OUT);
PAC |= ( 1 << TEST_PIN);
PWMGCUBL = (uint8_t)(PWM_MAX << 5); PWMGCUBH = (uint8_t)(PWM_MAX >> 3);
PWMG2DTL = 0;
PWMG2DTH = 0;
PWMGCLK = (uint8_t)(PWMGCLK_PWMG_ENABLE | PWMGCLK_CLK_IHRC);
PWMG2C = (uint8_t)(PWMG2C_OUT_PA3);
ROP = ROP_PWM_16MHZ;
//for bottom switch input
PBC &= ~(1 << UP_PIN);
PBPH |= (1 << UP_PIN);
PBDIER |= (1 << UP_PIN);
PBC &= ~(1 << DOWN_PIN);
PBPH |= (1 << DOWN_PIN);
PBDIER |= (1 << DOWN_PIN);
//for BIN out
PBC |= 0x1F;
PB &= ~( 0x1F );
int16_t pwm = 0;
uint8_t UP_press = UP_STATUS();
uint8_t DOWN_press = DOWN_STATUS();
while(1)
{
//for UP
if( UP_press == UNPRESS & UP_STATUS() == PRESS)
{
pwm+= PWM_ADD;
PWMG2DTL = (uint8_t)(pwm << 5);
PWMG2DTH = (uint8_t)(pwm >> 3);
if( pwm > PWM_MAX)
{
pwm = PWM_MAX;
}
UP_press = PRESS;
_delay_ms(30);
}else if( UP_press == PRESS & UP_STATUS() == UNPRESS)
{
UP_press = UNPRESS;
_delay_ms(30);
}
//for DOWN
if( DOWN_press == UNPRESS & DOWN_STATUS() == PRESS)
{
pwm-= PWM_ADD;
PWMG2DTL = (uint8_t)(pwm << 5);
PWMG2DTH = (uint8_t)(pwm >> 3);
if( pwm < 0 )
{
pwm = 0;
}
DOWN_press = PRESS;
_delay_ms(30);
}else if( DOWN_press == PRESS & DOWN_STATUS() == UNPRESS)
{
DOWN_press = UNPRESS;
_delay_ms(30);
}
//out BIN
PB = ( PB & 0xE0 )|( pwm/PWM_ADD ) & 0x1F;
}
}
スイッチでPWMの閾値を上下できるようにプログラムを修正しました。スイッチが押されるごとに、PWMの閾値が+4または-4され、最小から最大まで80段階のPWMが生成されます。
35から40行目でスイッチ用にIOを入力に設定しプルアップを有効にしています。
52行目はUPボタンが押されたかを検出しています。押された場合にはpwmの値を+4して30ms待ちます。30ms待つのはスイッチのチャタリング(瞬間的にON,OFFを繰り返す現象)が落ち着くのを待つためです。
63行目はUPボタンが離されたことを検出しています。この場合には何も処理をせず30ms待ちます。
70行目以降はDOWNボタンについて同様な処理をしています。
88行目は表示器にpwmの値を表示されるため、バイナリーを出力します。
上の図は閾値が10と30の時のPWMの波形です。10の場合のデューティは10/80=12.5%です。オシロスコープでの測定とほぼ合っています。30の場合は37.5%です。これもオシロスコープでの測定と合っています。
11bitPWM波形が生成された
Padauk内蔵の11bitPWM生成回路を利用して、100kHzで任意のデューティを出力できるプログラムが完成しました。
2025.1.21 続きはこちら










コメント