PR 記事には広告が含まれています
スポンサーリンク
Translate

PadaukマイコンPFS123で11bitPWM波形が生成できました

スポンサーリンク

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 続きはこちら

 

Padaukマイコンライターキット | kohacraftのshop
Padaukマイコンにドラッグ&ドロップで書き込めるライターキットです
Padaukマイコン PFS123(PFS173) | kohacraftのshop
ローエンドPadaukマイコンの中で最も高機能なマイコン10個入りです