🔆

RustとRP2040マイコンでPWMを出力してみた(組み込み開発、PWM入門)

2025/03/13に公開

はじめに

多くのマイコンには、PWM(pulse width modulation:パルス幅変調)という波形を出力する機能があります。

https://ja.wikipedia.org/wiki/パルス幅変調

このPWMは、デューティー比とと言われるON/OFFの比率を変化させることで平均的な電圧値を下げることができ、デジタル出力をアナログ出力の様に扱うことができます。これを利用すれば擬似的な正弦波を出力することもできます。以下、ディーティ比の数式です。

{\displaystyle D={\frac {\tau }{T}}\ }

{\displaystyle \tau }は信号(関数)がゼロでない期間、{\displaystyle \mathrm {T} }は信号(関数)の期間


https://ja.wikipedia.org/wiki/デューティ比

RP2040マイコンにも、このPWMの出力回路が備わっています。今回は、RP2040が搭載されていて手軽にRust組み込み開発ができる開発ボードのBaker link. DevでPWMを出力をしてみました。

RP2040のPWM回路について

コードの話に入る前に、PWM回路の説明をいたします。以下、公式のPDF(リンク)から抜粋したPWMスライス回路の図です。RP2040は、この図の回路と同じものが計8つ備わっています。

各スライス回路は 2つのPWM信号を出力できます(入力信号の周波数またはデューティサイクルを測定したりもできます)。つまり、8×2=16のPWM信号を出力することができます。また全てのGPIOピンは、PWM出力可能でGPIOと16のPWM信号は以下のように対応しています。PWM Channelは、コード中で指定する数字になります。

リンクより

使用するハードウェア

プロジェクトを作成

  1. Baker link. Envを起動し、プロジェクト名を入力、createをクリック、プロジェクト保存先のフォルダを選択してください。

プロジェクトを作成

  1. Baker link. Envを起動し、プロジェクト名を入力、createをクリック、プロジェクト保存先のフォルダを選択してください。

  2. Visual Studio Code起動後は、左下のコンテナで再度開くをクリックしてください。しばらくすると、Dockerの環境がビルドされ、環境構築が完了します!

  3. Visual Studio Code起動後は、左下のコンテナで再度開くをクリックしてください。しばらくすると、Dockerの環境がビルドされ、環境構築が完了します!

コーディング(コードを書く)

  1. src/main.rsを次のコードに書き換えてください。
    これは、緑のLEDの光を徐々に強く、徐々に弱くを繰り返すコードです。
#![no_std]
#![no_main]

use defmt::*;
use defmt_rtt as _;
use panic_probe as _;
use rp2040_hal as hal;

use hal::pac;

use embedded_hal::delay::DelayNs;
use embedded_hal::pwm::SetDutyCycle;

#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;

const LOW: u16 = 0;

const HIGH: u16 = 25000;

const XTAL_FREQ_HZ: u32 = 12_000_000u32;

#[rp2040_hal::entry]
fn main() -> ! {
    info!("Program start!");
    let mut pac = pac::Peripherals::take().unwrap();

    let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

    let clocks = hal::clocks::init_clocks_and_plls(
        XTAL_FREQ_HZ,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .ok()
    .unwrap();

    let mut timer = rp2040_hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);

    let sio = hal::Sio::new(pac.SIO);

    let pins = hal::gpio::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);

    let pwm = &mut pwm_slices.pwm3;
    pwm.set_ph_correct();
    pwm.enable();

    let channel = &mut pwm.channel_a;
    channel.output_to(pins.gpio22);

    loop {
        for i in LOW..HIGH {
            timer.delay_us(8);
            channel.set_duty_cycle(i).unwrap();
        }

        for i in (LOW..HIGH).rev() {
            timer.delay_us(8);
            channel.set_duty_cycle(i).unwrap();
        }

        timer.delay_ms(500);
        debug!("Looping...");
    }
}

ハードウェアの準備

難しいジャンパー線等の配線は不要です!USBでPCとBaker link. Devを接続してください。

プログラムをRUN

  1. コーディングが終わったら、Baker link. EnvのRunをクリックしてください。するとバックグラウンドで、probe-rsのDAP Serverが起動します。

  2. Visual Studio CodeでF5キーを押してください。すると、以下のようなアイコンが表示されます。

  3. もう一度、F5キーを押すと、プログラムが動作します。

すると緑のLEDが点灯します!

最後に

以上の手順で、RustでPWMを出力することができました。今回はLEDを光らせただけですが、モーターなど他にも多くの場面でPWMは使えるので試してみてください!

今回のプログラム

https://github.com/Baker-Tanaka/rp2040_pwm

Discussion