トホホな疑問(39) ラズパイPico、C/C++SDKからのPWM出力でトホホが2つ

Joseph Halfmoon

何度か使ってラズパイPicoのC/C++SDKの使い方も分かって来たぞ、という感触。今回はPWM出力をさらっと確かめるつもりで作業開始。しかし「さらっと」などと不埒なことを考えると「トホホ」が待っているのです。gpio.hは見つかるのにpwm.hが見つからない?なぜ、ビルドできないじゃん?解決して実機で走らせたら今度はLEDが光らない?トホホ。

※「トホホな疑問」投稿順Indexはこちら

(末尾に実験で使ったサンプルコード全文を掲げました。)

ラズパイPicoのC/C++のプロジェクト生成には、以前の投稿で書きました Raspberry Pi Pico Project Generator というツールを使わせていただいております。これ使えば CMakeLists.txt は自動でOKと安心しきっておったのですが。

gpio.h はインクルードできるのに pwm.h のインクルードができない

3チャネルのPWMを使って、RGB三色LEDを光らせるサンプルプログラムはほんの数分で書けました。ま、簡単だし。ビルドすれば即動くっしょ、という乗りでビルド。しかし、make中のエラーで落ちます。見れば、PWMを使うためのヘッダ pwm.hが見つからないと言っています。見つからなければコンパイルできないのは当然、でも何で?

SDKのパスの傘下にはちゃんとpwm.hが存在しています。ちょっと込み入った深いところにあるのだけれど。でも、同様な位置にあるgpio.hはインクルードできているみたい。この差は何?

振り返って見ると、ビルドする前にVS Codeのエディタ画面でも不穏な波線が出てました。こんな感じ。波線位置にカーソルあわせればファイルが見当たらない、と。

includeFileErrorVS Codeは、何が見えて何が見えないのか、把握した上で補完してくれているのでしょう。こころみに以下のように

#include "hardware/"

の / を打った瞬間、補完機能が働いて以下のようにリストが現れます。その中に gpio.h は勿論、以前使った timer.h とか uart.h などがちゃんと登場します。こいつら別に何か指定した記憶が無いのに現れます。しかし、pwm.h は登場しません。

noPWMHそのくせ、regsの下のレジスタ定義のヘッダの中には PWM関係のレジスタアクセス用のpwm.hが見えていたり(includeする pwm.h よりも下位のヘッダでより深い位置にある)します。なんで?

トホホなときは原典に立ち戻ると。原典は以下ですね(最新版は6月末の1.6でした。6月だけでも2回更新。私がダウンロードしてあったのは少し古かったです。こまめに更新した方がよさそうです。)

raspberry-pi-pico-c-sdk.pdf

上記の文書の ”2.2. Every Library is an INTERFACE” から1か所引用させていただきます。

pico_stdlib provides all the basic functionality needed to get a simple application running and toggling GPIOs and printing to a UART,

ほえほえ、pico_stdlibを含めることで、gpioとか、uartとかも暗黙のうちに含まれてきていたのね。それで見えていたのか。逆に言えば、pico_stdlibには pwm は含まれていないので、明示的に入れてあげないとならないのね。

GUIで生成した CMakeLists.txt に手動で hardware_pwm を追加いたしました。こんな感じ。

CMakeListsそしたらビルド出来ましたです。VS Code上も波線消えました。トホホ。そんなことかい。ビルドできたので実機動作の確認へ。

実機動作の確認

実機動作の意図は簡単です。GPIOの以下の端子をRGB-LEDの3端子に割り当て、それぞれの端子をPWM駆動してやり、「いろいろな色」を光らせようという目論見です。

    • R — GPIO4
    • G — GPIO3
    • B — GPIO2

アイキャッチ画像をご覧いただくとわかりますが、上記の3端子に加えてGPIO2のとなりのGND端子を使うと「ちょうどブレッドボード上でラズパイPico」に「直結」できるLEDモジュールが手持ちにあったのです。配線無、モジュール差し込むだけ。お手軽さに浮かれてデータシートも確認せずに差し込みました。ただ、よく考えるとこのモジュールはArduino用だったのです(5V IO電圧。)

走らせてみると、「ちゃんと」LEDが点灯し、色も変化します。OKと思ったら色が変です。赤と緑は見えているのに青がないです。なにかソフトの書き方間違えた?とも考えましたが、ハード側の理由っぽいです。PWM波形の確認を兼ねてオシロで当たれば、RGB3色ともPWM波形出ていました。ようやく使っているLEDのデータシート見たところ、青と緑のVfはミニマムでも3.3Vでした。モジュール上電流制限抵抗の1kΩが直列に入っています。3.3V IOのラズパイPico端子に直結したのでは青と緑はスペック割れているはず。それでも緑は元気に光るのですが、青はダメみたい。

しかたないので、この3色LEDモジュールをあきらめ、3.3V IOでも大丈夫そうなR, G, B3個のLEDで汚くジャンパ線でつないだものがこちら。LEDs

 

ちゃんとR, G, Bの3色光っております。しかし、Lチカで躓くとはトホホ。。。

トホホな疑問(38) PicoDAC、カラーコード、よく確かめたつもりだったんだけど へ戻る

トホホな疑問(40) ATSAMD51、Port Event制御1個しかうごかないんですけど へ進む

C/C++ SDKからPWM出力をするサンプルプログラム
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/pwm.h"

// Color LED pins (analogOUT)
#define LED_R (4)
#define LED_G (3)
#define LED_B (2)
// PWM settings
#define MAX_COUNT (255)

uint pwm_slice1;
uint pwm_slice2;

void setLEDs(uint16_t R, uint16_t G, uint16_t B) {
    pwm_set_chan_level(pwm_slice1, PWM_CHAN_A, B);
    pwm_set_chan_level(pwm_slice1, PWM_CHAN_B, G);
    pwm_set_chan_level(pwm_slice2, PWM_CHAN_A, R);
}

int main()
{
    stdio_init_all();

    gpio_set_function(LED_R, GPIO_FUNC_PWM);
    gpio_set_function(LED_G, GPIO_FUNC_PWM);
    gpio_set_function(LED_B, GPIO_FUNC_PWM);

    pwm_slice1 = pwm_gpio_to_slice_num(LED_B);
    pwm_slice2 = pwm_gpio_to_slice_num(LED_R);
    pwm_set_wrap(pwm_slice1, MAX_COUNT);
    pwm_set_wrap(pwm_slice2, MAX_COUNT);
    setLEDs(0, 0, 0);
    pwm_set_enabled(pwm_slice1, true);
    pwm_set_enabled(pwm_slice2, true);

    setLEDs(255, 0, 0);
    sleep_ms(3000);
    setLEDs(0, 255, 0);
    sleep_ms(3000);
    setLEDs(0, 0, 255);
    sleep_ms(3000);

    for (uint16_t rIdx = 0; rIdx <= MAX_COUNT; rIdx++ ) {
        for (uint16_t gIdx = 0; gIdx <= MAX_COUNT; gIdx++ ) {
            for (uint16_t bIdx = 0; bIdx <= MAX_COUNT; bIdx++ ) {
                setLEDs(rIdx, gIdx, bIdx);
                sleep_ms(1);
            }
        }
    }

    setLEDs(0, 0, 0);
    puts("End of Execution.");
    return 0;
}