Shujima Blog

Apple製品,技術系の話をするブログ

STM32 NUCLEO-F746ZG Zephyr PWM出してみた(自分用メモ1)

自分用memo

やってること

STM32 Nucleo-F746ZGボードでPWM出力可能な全ピン32ヶ所からPWMを出す。

Version

cd ~/zephyrproject/zephyr
cat VERSION
VERSION_MAJOR = 2
VERSION_MINOR = 7
PATCHLEVEL = 99
VERSION_TWEAK = 0
EXTRAVERSION =

なので、Zephyr 2.7.99

Zephyr 3系だと動かない可能性高し

west --version v0.12.0 python --version Python 3.7.6

プロジェクトの作成

appを作っていく。お好きなエディタでいくつかのファイルを作成・記述していく。

最小構成のディレクトリ

最小構成は以下の通り

参考: https://docs.zephyrproject.org/latest/application/index.html#overview

<home>/app
├── CMakeLists.txt
├── prj.conf
└── src
    └── main.c

今回はappの名前をprj_f746とした。

ボード定義はzephyrに最初から含まれているnucleo_f746zgのものを利用する。

ただし、今回作成するPWMのアプリケーションに必要なタイマーの記述が、元のボード定義に不足していたため、新たにapp.overlayファイルを追加する必要がある。

<home>/app
├── CMakeLists.txt
├── prj.conf
├── app.overlay
└── src
    └── main.c

CMakeLists.txt

prj_f746ディレクトリ直下にCMakeLists.txtを作成

引用: https://docs.zephyrproject.org/latest/application/index.html#creating-an-application

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr)
project(prj_f746)

target_sources(app PRIVATE src/main.c)

prj.conf

prj_f746ディレクトリ直下にprj.confを作成

標準だとGPIOしか有効になっていないので、PWMなどのおしゃれな機能を使おうとしても動かない。なお動かなくてもビルドエラーは出ない(n敗)。

以下を記述する。

CONFIG_PWM=y

src/main.c

PWMを全部出してみた。 ただし、nucleoに乗ってる青色LED(LD2, PB7)は動作チェック用に点滅(1Hz)動作にしてある。

この点滅動作含めコードのほとんどはblinkyのサンプルから流用している。

zephyr/samples/basic/blinky at main · zephyrproject-rtos/zephyr · GitHub

#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <drivers/pwm.h>

#include <stdio.h>


//#include <dt-bindings/pwm/pwm.h>

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   1000

/* The devicetree node identifier for the "led2" alias. */

#define LED2_NODE DT_ALIAS(led2)

#if DT_NODE_HAS_STATUS(LED2_NODE, okay)
#define LED2   DT_GPIO_LABEL(LED2_NODE, gpios)
#define PIN    DT_GPIO_PIN(LED2_NODE, gpios)
#define FLAGS  DT_GPIO_FLAGS(LED2_NODE, gpios)
#else
/* A build error here means your board isn't set up to blink an LED. */
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED2   ""
#define PIN    0
#define FLAGS  0
#endif

void main(void)
{
    
    const struct device *pwm[15];
    const struct device *gpio_b; //B_14
    
    bool led_on = true;
    int ret;
    char labelname[20];

    const char pwm_enbl[15][4] =
    {
        {0,0,0,0}, //0
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {0,0,0,0},
        {0,0,0,0},
        {1,1,1,1},
        {1,1,0,0},
        {1,0,0,0},
        {1,0,0,0},
        {1,1,0,0},
        {1,0,0,0},
        {1,0,0,0}
    };


    gpio_b = device_get_binding("GPIOB");
    if (gpio_b == NULL) {
        return;
    }

    

    for(int8_t i = 1; i <= 14; i++ )
    {
        if(i >= 1 && i <= 5 || i >= 8 && i <= 14)
            sprintf(labelname, "PWM_%d", i);
            pwm[i] = device_get_binding(labelname);
    }

    for(int8_t i = 1; i <= 14; i++ )
    {
        for(int8_t j = 1; j <= 4; j++ )
        {
            if(pwm_enbl[i][j-1] == 1)
                pwm_pin_set_usec(pwm[i], j, 200, 100, PWM_POLARITY_NORMAL);   
        }
    }

    ret = gpio_pin_configure(gpio_b, 7, GPIO_OUTPUT_ACTIVE | FLAGS);

    while (1) {
        gpio_pin_set(gpio_b, 7, (int)led_on);
        led_on = !led_on;
        k_msleep(SLEEP_TIME_MS);
    }


}

app.overlay

dtsファイルの内容を補足する。

拡張子は.overlayだが、書式はdtsそのもの。

ファイル名は「app」まで含めて決められているため変えてはいけない(変える場合がCMakeListに記載する必要がある)

https://docs.zephyrproject.org/latest/guides/dts/howtos.html#set-devicetree-overlays https://docs.zephyrproject.org/latest/guides/dts/intro.html

元になったと思われるArm Linuxのoverlayファイル(.dtso)では、先頭に

/dts-v1/;
/plugin/;

を記述する必要があるっぽい(参考:デバイスツリー Overlay について調べてみた - Qiita)が、Zephyrではむしろあっちゃダメっぽかった。

&timers1 {
    st,prescaler = <0>;
    status = "okay";

    pwm1: pwm {
        status = "okay";
        pinctrl-0 = <&tim1_ch1_pe9 &tim1_ch2_pe11 &tim1_ch3_pe13 &tim1_ch4_pe14>;
        pinctrl-names = "default";
    };
};


&timers2 {
    st,prescaler = <0>;
    status = "okay";

    pwm2: pwm {
        status = "okay";
        pinctrl-0 = <&tim2_ch1_pa15 &tim2_ch2_pb3 &tim2_ch3_pb10 &tim2_ch4_pb11>;
        pinctrl-names = "default";
    };
};

&timers3 {
    st,prescaler = <0>;
    status = "okay";

    pwm3: pwm {
        status = "okay";
        pinctrl-0 = <&tim3_ch1_pb4 &tim3_ch2_pb5 &tim3_ch3_pb0 &tim3_ch4_pb1>;
        pinctrl-names = "default";
    };
};

&timers4 {
    st,prescaler = <0>;
    status = "okay";

    pwm4: pwm {
        status = "okay";
        pinctrl-0 = <&tim4_ch1_pb6 &tim4_ch2_pd13 &tim4_ch3_pb8 &tim4_ch4_pb9>;
        pinctrl-names = "default";
    };
};

&timers5 {
    st,prescaler = <0>;
    status = "okay";

    pwm5: pwm {
        status = "okay";
        pinctrl-0 = <&tim5_ch1_pa0 &tim5_ch2_pa1 &tim5_ch3_pa2 &tim5_ch4_pa3>;
        pinctrl-names = "default";
    };
};

&timers8 {
    st,prescaler = <0>;
    status = "okay";

    pwm8: pwm {
        status = "okay";
        pinctrl-0 = <&tim8_ch1_pc6 &tim8_ch2_pc7 &tim8_ch3_pc8 &tim8_ch4_pc9>;
        pinctrl-names = "default";
    };
};

&timers9 {
    st,prescaler = <0>;
    status = "okay";

    pwm9: pwm {
        status = "okay";
        pinctrl-0 = <&tim9_ch1_pe5 &tim9_ch2_pe6>;
        pinctrl-names = "default";
    };
};

&timers10 {
    st,prescaler = <0>;
    status = "okay";

    pwm10: pwm {
        status = "okay";
        pinctrl-0 = <&tim10_ch1_pf6>;
        pinctrl-names = "default";
    };
};

&timers11 {
    st,prescaler = <0>;
    status = "okay";

    pwm11: pwm {
        status = "okay";
        pinctrl-0 = <&tim11_ch1_pf7>;
        pinctrl-names = "default";
    };
};

&timers12 {
    st,prescaler = <0>;
    status = "okay";

    pwm12: pwm {
        status = "okay";
        pinctrl-0 = <&tim12_ch1_pb14 &tim12_ch2_pb15>;
        pinctrl-names = "default";
    };
};

&timers13 {
    st,prescaler = <0>;
    status = "okay";

    pwm13: pwm {
        status = "okay";
        pinctrl-0 = <&tim13_ch1_pf8>;
        pinctrl-names = "default";
    };
};

&timers14 {
    st,prescaler = <0>;
    status = "okay";

    pwm14: pwm {
        status = "okay";
        pinctrl-0 = <&tim14_ch1_pf9>;
        pinctrl-names = "default";
    };
};

ビルドコマンド

west build -b nucleo_f746zg

実行コマンド

Nucleoを接続して

west flash

で自動的に書き込み・実行される。

青色LEDが点滅しだし、PWMが出るポートからPWMが出始める。

続き?

www.shujima.work

その他調べてわかったことメモ

プロジェクトフォルダの構造

https://docs.zephyrproject.org/latest/application/index.html

Zephyrにアプリケーションを追加する - みつきんのメモ

my_custom_board_defconfig
my_custom_board.dts
my_custom_board.yaml
board.cmake
board.h
CMakeLists.txt
doc/
dts_fixup.h
Kconfig.board
Kconfig.defconfig
pinmux.c
support/

Kconfig

prj.conf or <boardname>_defconfigファイル

defconfig

  • zephyr/
    • boards/
      • arm/
        • nucleo_f746zg/
          • nucleo_f746zg_defconfig

https://docs.zephyrproject.org/latest/guides/build/kconfig/setting.html#setting-configuration-values

Device Tree

デバイスツリーについて調べてみた - Qiita

[Linux][kernel] Device Tree についてのまとめ - Qiita

デバイスツリーのディレクトリ構成

  • zephyr/
    • boards/
      • arm/
        • nucleo_f746zg
          • nucleo_f746zg.dts
            • nucleoボードのデバイスツリー。f7のdtsiをincludeしている。
    • dts/
      • arm/
        • st
          • f7
            • stm32f7.dtsi
            • stm32f746.dtsi
              • 745を呼び出しているだけ
            • stm32f745.dtsi
              • i2c4
              • spi6
              • can2
              • mac(ethernet)

用語

当ブログをご利用いただく際には免責事項をお読みください。