ラズピコ PWM出力を使ってみる

  • 2023.01.29
  • PWM
ラズピコ PWM出力を使ってみる

皆さん こんにちは。

今回は PWM出力を使ってみます。

PWMとは

PWMとは、Pulse Width Modulation の略で、日本語ではパルス幅変調といいます。
GPIOからパルスを出力する機能です。
パルス幅を変えることでモーターを制御したり、LEDの明るさ調節を行ったりすることができます。

今回はラズピコに載っている緑色のLED(D2)をPWM出力で制御して明るさを調節してみます。

詳細については RP2040データシート の4.5項をご覧ください。

PWMのチャンネル

全てのGPIOでPWMを使うことができます。
LED(D2)がつながっているGPIOは25番ですからチャンネルは 4B を使うことになります。
以下の表はRP2040データシートの 4.5.2 で確認することができます。

プロジェクトの作成

以下の設定でプロジェクトを作成します。

Project Name: picoPwm
Console Options の Console over UART をチェックする
IDE Options の Create VSCode project をチェックする
Debugger: は PicoProbe を選択する

VSCodeを起動する

起動後、何かファイルが開いてたら File – Close Folder で閉じた後、File – Open Folder から picoPwm のフォルダーを辿って選択します。

こちらの環境では C:\Users\m3925\Documents\Pico\pico-project-generator\picoPwm です。

m3925の部分は皆さんのユーザー名に置き換えてください。

vscode関連の json ファイルは前回作成済のプロジェクトのものをドラッグ&ドロップでコピー&ペーストすると楽です。

ソースコードを書く

picoPwm.c を以下の通りに編集します。

#include <stdio.h>
#include "hardware/pwm.h"
#include "pico/stdlib.h"

#define PWM_GPIO 25
#define WRAP_MAX 65535

int main() {
    stdio_init_all();
    puts("Hello, PWM!");

    gpio_set_function(PWM_GPIO, GPIO_FUNC_PWM);
    uint slice_num = pwm_gpio_to_slice_num(PWM_GPIO);

    pwm_config cfg = pwm_get_default_config();
    // プリスケーラーの初期値 (1) をあえて設定する
    pwm_config_set_clkdiv_int(&cfg, 1);

    pwm_init(slice_num, &cfg, false);

    pwm_set_wrap(slice_num, WRAP_MAX);
    int period_of_high = WRAP_MAX;
    pwm_set_chan_level(slice_num, PWM_CHAN_B, period_of_high);
    pwm_set_enabled(slice_num, true);
    bool dir_negative = true;

    while (true) {
        sleep_ms(5);
        pwm_set_enabled(slice_num, false);
        if (dir_negative) {
            period_of_high -= 100;
            if (period_of_high < 100) {
                period_of_high = 100;
                dir_negative = false;
            }
        } else {
            period_of_high += 100;
            if (WRAP_MAX < period_of_high) {
                period_of_high = WRAP_MAX;
                dir_negative = true;
            }
        }
        pwm_set_chan_level(slice_num, PWM_CHAN_B, period_of_high);
        pwm_set_enabled(slice_num, true);
    }

    return 0;
}

PC側の準備

I2C通信の動作確認用として Tera Term を使います。
API関数がうまく動作したか否かなどの結果をUARTのputs()やprintf()でログ出力するようにしてみました。

Tera Termをお持ちでない方は こちら からダウンロードしてお使いください。

インストール後、 Tera Term を起動し、シリアルポートでPicoprobeのCOMポートを選択します。

もしCOMポートが複数ある場合には、Picoprobe以外の通信ケーブルをはずしてデバイスマネージャーでCOMポート番号を確認しておきます。

起動後、設定メニューのシリアルポートから以下の設定を行います。

スピート : 115200
データ : 8 bit
パリティ : なし
ストップビット : 1
フロー制御 : none

(設定値からスピードだけ変更すれば良いはずです)

と言っても今回は puts("Hello, PWM!"); するだけでした。
お手数おかけしました。

今回使ったPWMのAPI

pwm_gpio_to_slice_num()

GPIO番号からスライス番号を取得します。

第1引数:GPIO番号を指定します。
戻り値:スライス番号
 GPIO25を指定した場合、チャンネル4Bの "4" が戻ります。


pwm_set_wrap()

PWMのカウンターがゼロに戻る前に到達する最大値を設定します。

第1引数:スライス番号を指定します。
第2引数:最大値を指定します。
 カウンターは16ビットなので設定する値は最大で 65535 になります。


pwm_set_chan_level()

PWM出力がHighレベルである期間を指定します。

第1引数:スライス番号を指定します。
第2引数:チャンネル記号(PWM_CHAN_A or PWM_CHAN_B)を指定します。
 今回は上で説明した通り PWM_CHAN_B を指定します。
第3引数:Highレベルの期間を指定します。
 ここでpwm_set_wrap()で指定した値の半分を指定すると duty比が 50% になります。
 


pwm_set_enabled()

PWM出力の有効、無効を設定します。

第1引数:スライス番号を指定します。
第2引数:有効(true)、無効(false)を指定します。


pwm_get_default_config()

PWMの初期設定値を取得します。

戻り値: pwm_config構造体


pwm_config_set_clkdiv_int()

プリスケーラーの整数部に値を設定します。

第1引数:pwm_config構造体へのポインタ
第2引数:プリスケーラーの値(0-255)
 初期値は 1 です。
 以下の式から fPWM を変更することができます。ただし CSR の PH_CORRECT = 0, DIV_FRASC = 0 (それぞれ初期値)としています。

fPWM = fsys / (TOP + 1) * DIV_INT [Hz]

 ここで TOP は pwm_set_wrap() の設定値です。
周期を変更してみたい方は、こちらで試してみてください。

波形では確認していないのですが、ここで fsys = 125MHz だと思われます。


pwm_init()

PWMを初期化します。

第1引数:スライス番号
第2引数:pwm_config構造体へのポインタ
第3引数:trueで初期化後にPWMを開始します。

なお、プリスケーラーを使わない(初期値 1 で良い)場合、以下のコードは不要です。

pwm_config cfg = pwm_get_default_config();
pwm_config_set_clkdiv_int(&cfg, 1);
pwm_init(slice_num, &cfg, false);

動作させてみる

それでは F5キーを押してプログラムを動作させてみます。
LEDの明るさが変われば成功です。

うまく明るさ調節できましたか。
お疲れさまでした。

PWMカテゴリの最新記事