Raspberry Pi PicoとMOSFET ③ PWMのAPI
PicoからPWM出力をします。PWMはどのGPIOからでも出力できます。ここでは、GPIO2、GPIO3、GPIO4、GPIO5の4本を最初に利用します。
●PWMの周波数
Picoは125MHzのクロックで動いています。このクロックを2種類の分周機構で低い周波数のPWM信号を得られるように作られています。下記の二つは縦続接続されているので、どちらか一方を使ってもよいし、両方を使って細かな周波数を得ることもできます。
- wrap(16ビット) pwm_set_wrap(slice_num, 99); // 1/100
- 固定小数点形式で指定する分周ユニット
uint8_t div = 1;
uint8_t fract = 4;
pwm_set_clkdiv_int_frac(slice_num, div, fract); // 1/1.25
上記以外に、
float div = 3;
pwm_config_set_clkdiv(&config, div);
構成オブジェクトをつかって分周できますが、使いかたがよくわかりません。
このファンクションは、PWMの出力以外に、パルスのカウントもできます。
●PWMディバイダ・モードの設定内容
enum pwm_clkdiv_mode { PWM_DIV_FREE_RUNNING = 0, PWM_DIV_B_HIGH = 1, PWM_DIV_B_RISING = 2, PWM_DIV_B_FALLING = 3 }
●pwmファンクション
スライス PWM出力の論理番号。 フェーズ 位相。位相補正で使われる。 チャネル すべてのGPIOピンは、PWM出力に使えるが、次のようにチャネルが割り付けられている。一つのチャネルにはAとBがある。8チャネルしかないので、GPIO16以降は、再度0から。なお、23、25、25、29はピンが存在しない。
構成オブジェクト 初期値=(システム・クロック速度でフリー・ランニング、位相補正なし、0xffffでのwrapする、標準極性、チャネルAおよびB)? |
ファンクション | 要約 |
---|---|
static uint pwm_gpio_to_slice_num (uint gpio) | 指定されたGPIOに接続されているPWMスライスが返る |
static uint pwm_gpio_to_channel (uint gpio) | 指定されたGPIOに接続されているPWMチャネルが返る |
static void pwm_config_set_phase_correct (pwm_config *c, bool phase_correct) | 位相制御をtrueに設定すると、wrapポイントに達したときにゼロにラップバックする代わりに、PWMがカウント・ダウンを開始する(下の図参照)。位相補正モードを有効にすると、出力周波数が半分になる |
static void pwm_config_set_clkdiv (pwm_config *c, float div) | PWM構成でクロック分周器を設定する |
static void pwm_config_set_clkdiv_int (pwm_config *c, uint div) | PWMクロック分周器をPWM構成に設定する |
static void pwm_config_set_clkdiv_mode (pwm_config *c, enum pwm_clkdiv_mode mode) | PWM構成でPWMカウント・モードを設定する |
static void pwm_config_set_output_polarity (pwm_config *c, bool a, bool b) | PWM構成で出力極性を設定する |
static void pwm_config_set_wrap (pwm_config *c, uint16_t wrap) | PWM構成でPWMカウンタwrap値を設定する。 0に戻る前にカウンタが到達する最大値を設定。TOPとも呼ばれる |
static void pwm_init (uint slice_num, pwm_config *c, bool start) | 構成オブジェクトからの設定を使用してPWMを初期化する |
static pwm_config pwm_get_default_config (void) | PWM構成(システム・クロック速度でフリー・ランニング、位相補正なし、0xffffでのラッピング、標準極性、チャネルAおよびB)のデフォルト値のセットを取得する |
static void pwm_set_wrap (uint slice_num, uint16_t wrap) | PWMカウンタwrap値を設定する。 0に戻る前にカウンタが到達する最大値を設定。TOPとも呼ばれる |
static void pwm_set_chan_level (uint slice_num, uint chan, uint16_t level) |
チャネルAまたはチャネルBのいずれかのPWMカウンタ比較値の値を設定する。
カウンタ比較レジスタは、ハードウェアでダブル・バッファリングされている。これは、PWMが実行されているときに、カウンタ比較値は、次にPWMスライスがラップするまで(または、位相補正モードでは、次回スライスが0に達したとき)。PWMが実行されていない場合、書き込みはすぐにラッチされる。
chan 更新するチャネル。Aの場合は0、Bの場合は1
|
static void pwm_set_both_levels (uint slice_num, uint16_t level_a, uint16_t level_b) |
PWMカウンタの比較値AとBの値を設定する。
カウンタ比較レジスタは、ハードウェアでダブル・バッファリングされている。これは、PWMが実行されているときに、カウンタ比較値は、次にPWMスライスがラップするまで(または、位相補正モードでは、次回スライスが0に達したとき)。PWMが実行されていない場合、書き込みはすぐにラッチされる。
カウンタが設定値に達すると、AもしくはB出力がディアサートされる
|
static void pwm_set_gpio_level (uint gpio, uint16_t level) |
GPIOに関連付けられたスライスとチャネルのPWMレベルを設定するヘルパ関数。
特定のGPIOの正しいスライス(0から7)とチャネル(AまたはB)を検索し、対応するカウンタ比較フィールドを更新。
このPWMスライスは、すでに構成され、実行に設定されている必要がある。また、複数のGPIOがにマッピングされることに注意。
同じスライスとチャネル(GPIOの差が16の場合)。
カウンタ比較レジスタは、ハードウェアでダブル・バッファリングされている。これは、PWMが実行されているときに、カウンタ比較値は、次にPWMスライスがラップするまで(または、位相補正モードでは、次回スライスが0に達したとき)。PWMが実行されていない場合、書き込みはすぐにラッチされる
|
static uint16_t pwm_get_counter (uint slice_num) | PWMカウンタの現在の値を取得する |
static void pwm_set_counter (uint slice_num, uint16_t c) | PWMカウンタの値を設定する |
static void pwm_advance_count (uint slice_num) | カウンタを実行するフェーズを1カウント進める |
static void pwm_retard_count (uint slice_num) | 実行中のカウンタのフェーズを1カウント遅らせる |
static void pwm_set_clkdiv_int_frac (uint slice_num, uint8_t integer, uint8_t fract) | 8(integer整数):4(fract小数値)を使用してPWMクロック分周器を設定する |
static void pwm_set_clkdiv (uint slice_num, float divider) |
クロック分周器を設定する。カウンタの増分は、ゲーティングを考慮して、sysclockをこの値で割った値になる。 divider 1.f ⇐ value < 256.f |
static void pwm_set_output_polarity (uint slice_num, bool a, bool b) | PWM出力の極性を設定する。trueで反転 |
static void pwm_set_clkdiv_mode (uint slice_num, enum pwm_clkdiv_mode mode) | PWM分周器モードを設定する |
static void pwm_set_phase_correct (uint slice_num, bool phase_correct) |
位相制御をtrueに設定すると、wrapポイントに達したときにゼロにwrapバックせずに、PWMがカウントダウンを開始する。位相補正モードを有効にすると、出力周波数が半分になる
|
static void pwm_set_enabled (uint slice_num, bool enabled) | PWMを有効/無効にする。trueは指定されたPWMを有効にし、falseは無効にする |
static void pwm_set_mask_enabled (uint32_t mask) | 複数のPWMスライスを同時に有効/無効にする |
static void pwm_set_irq_enabled (uint slice_num, bool enabled) | PWMインスタンス割り込みを有効にする |
static void pwm_set_irq_mask_enabled (uint32_t slice_mask, bool enabled) | 複数のPWMインスタンス割り込みを有効にする |
static void pwm_clear_irq (uint slice_num) | 単一のPWMチャネル割り込みをクリアする |
static uint32_t pwm_get_irq_status_mask (void) | 現在設定されているすべてのPWM割り込みのビット・マスクを取得する |
static void pwm_force_irq (uint slice_num) | PWM割り込みを強制する |
●wrapを使ってみる
pico/worksフォルダにpwmフォルダを作ります。なかに、CMakeLists.txtとpwm.cを入れます。コンパイルの方法などは、下記の連載を参照してください。
連載 Raspberry Pi Picoでプログラミング
pico/worksフォルダのCMakeLists.txtの内容です。
cmake_minimum_required(VERSION 3.12)
# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)
project(pico_examples C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})
# Initialize the SDK
pico_sdk_init()
# Add blink example
add_subdirectory(cmake)
add_subdirectory(blink)
add_subdirectory(serial)
add_subdirectory(clock)
add_subdirectory(i2cscanner)
add_subdirectory(lps25hb)
add_subdirectory(tmp117)
add_subdirectory(aht20)
add_subdirectory(mcp3008)
add_subdirectory(mcp3208)
add_subdirectory(pwm)
pico/works/pwmフォルダのCMakeLists.txtの内容です。
add_executable(pwm
pwm.c
)
# Pull in our pico_stdlib which pulls in commonly used features
target_link_libraries(pwm pico_stdlib hardware_pwm)
# create map/bin/hex file etc.
pico_add_extra_outputs(pwm)
●pwm.cの内容
GPIO機能を選択するファンクションでGP2/GP3端子をPWM用にします。
gpio_set_function(2, GPIO_FUNC_PWM);
gpio_set_function(3, GPIO_FUNC_PWM);
スライスはチャネルの低いほうのGPxの番号xをあてるようです。
uint slice_num = pwm_gpio_to_slice_num(2);
wrapを125にしました。0から数えるので、124を記入しています。上記のファンクションの説明では、0からTOPが1周期です。TOPは初期値では0xffffが設定されているようです。この関数の解説では、「0に戻る前にカウンタが到達する最大値を設定」となっているので、0xffffより小さな数値のように思えます。
しかし、この関数では、wrapのカウント数ぶん分周するという動作をします。システム・クロックは125MHzですから、125で割ると1MHzです。オシロスコープの計測でも1MHzになっていました。
pwm_set_wrap(slice_num, 124);
pwm_set_chan_level(slice_num, PWM_CHAN_A, 12);
は、赤色の波形で、12/125=約10%のデューティになります。
pwm_set_chan_level(slice_num, PWM_CHAN_B, 63);
は、黄色の波形で、63/125=約50%のデューティになります。
pwm.cのソースです。
#include "pico/stdlib.h"
#include <stdio.h>
#include "hardware/pwm.h"
int main() {
stdio_init_all();
printf("\nHello, PWM GP2/3\n");
gpio_set_function(2, GPIO_FUNC_PWM);
gpio_set_function(3, GPIO_FUNC_PWM);
// Find out which PWM slice is connected to GPIO 0 (it's slice 0)
uint slice_num = pwm_gpio_to_slice_num(2);
// Set period of 10 cycles (0 to 3 inclusive)
pwm_set_wrap(slice_num, 124);
// Set channel A output high for one cycle before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_A, 12);
// Set initial B output high for three cycles before dropping
pwm_set_chan_level(slice_num, PWM_CHAN_B, 63);
// Set the PWM running
pwm_set_enabled(slice_num, true);
return 0;
}