がれすたさんのDIY日記

電子回路、Python、組み込みシステム開発、自作エフェクターを語るblog

MIMXRT10xxのeFlexPWMを使ってPWM信号を出力する。

今回はどのマイコンでもよく使う機能の一つでもあるPWMについてやっていく。
MIMX系のマイコンではeFlexPWMというペリフェラルがそれにあたる。

特徴を解説したいところですが長すぎたのでRMのFeatures部分を貼っておくので読みたい人は該当部分を読んでください

f:id:gsmcustomeffects:20191215055621p:plain


テスト環境と留意事項

  • MCUXpresso IDE 11.1(2020,1/1時点で最新
  • MCUXpresso SDK 2.70(2020,1/1時点で最新)
  • MIMXRT1020-EVK(ここは使う環境によって変わる)

今回はNXP公式ボードのMIMXRT1020-EVKを使うことにする。
最近MCUXprressoSDKとIDEが最新版になりePWMのコンフィグツールが入ったので最新版を前提に進めていこうと思います。

eFlexPWM

モジュール自体の内部構造はこのようになっている。

f:id:gsmcustomeffects:20191215055940p:plain
PWM Submodule Block Diagram

ごく一般的な比較レジスタとカウンタの組み合わせ

クロックがIPG経由でもらえるのでかなり高速なPWMを生成可能
16bit分解能というスイッチング電源つくってくれと言わんばかりの機能。

生成できるPWMのタイプ以下の4つ

  • Center Aligned PWMs
  • Edge Aligned PWMs
  • Phase Shifted PWMs
  • Double Switching PWMs

f:id:gsmcustomeffects:20191215062935p:plain
PWM type

PWM 生成のながれ

f:id:gsmcustomeffects:20200104024216p:plain
PWM Generation Block Diagram(クリックで拡大)

eFlexPWMは主に上記のブロックで構成されている。
各機能を含めブロック詳細をこれから解説していく。

PWM Clocking

f:id:gsmcustomeffects:20200104025733p:plain
PWM Clocking(クリックで拡大)

モジュールのクロックはIPBUS_CLK(IPGクロックのこと) , EXT_CLK(外部クロック) , AUX_CLK(submodule0からのクロックを供給)の3つのクロックから選べる。
最後のAUX_CLKはsubmodule0をマスターとしてsubmodule1 , submodule2 , submodule3にクロックを共有できる機能。(submodule0は必ずIPBUS_CLK , EXT_CLKのどちらかから駆動する必要がある。

eFlexPWM Clock Blockの機能としては , Prescalerを内蔵しているので1~128で分周を設定できる。
ここで設定しないといけないのはクロックソースとPrescalerの2つであり、それにより16bit counterのクロック速度が決定する。

Register Reload Logic

f:id:gsmcustomeffects:20200104030858p:plain
Register Reload Logic(クリックで拡大)

eFlexPWM関連のレジスタはダブルバッファで構成されている。(動作中に片側は書き換え可能ということ
Register Reload Logic Blockは、ダブルバッファのリロードのタイミングを設定することができる。

まずMaster ReloadとLocal Reloadだが、Masterはsubmodule0から他のsubmodule1-3を同期してリロードしたい場合に使用する。
ややこしいので例を示すと

submodule0はLocal Reloadを使用
submodule1-3はMaster Reloadを設定

submodule0からのリロード信号でsubmodule1-3のリロードを実行という感じです。

次にLDOK(Load OK )についてだがMaster Control Register (MCTRL)LDOKビットのことでLoadOKのこと。
こいつがセットされるとダブルバッファレジスタのセットされた値を有効にする。
コンフィグツールとSDK使うならユーザーがケアする必要がないので詳しく知りたい方はRM(Reference Manual)のMaster Control Register (MCTRL)の項を読んでください。

Mod Compareは、Control Register (SM0CTRL - SM3CTRL)COMPMODEのことでこれもSDKのコンフィグツールで設定可能なのでユーザーはno careでいい

Half CompareはリロードをPWMのハーフでするかの設定。
Control Register (SM0CTRL - SM3CTRL)のHALFビットで設定可能。同様にしてFULLビットも設定可能。
これもSDKのコンフィグツールで設定可能なのでユーザーはno careでいい

Timer synchronization

f:id:gsmcustomeffects:20200104043708p:plain
Submodule Timer Synchronization(クリックで拡大)

Timer(counter) synchronizationはカウンタの初期化同期の機能を提供する。
LocalSync , Master Reload , Master Sync , PWM_EXT_Syncの4つから選べる。

LocalSyncはそのモジュール自体でPWM周波数などを制御する。
Master Reloadはsubmodule0のReload頻度に他のモジュールがロックされる。
Master Syncはsubmodule0のLocalSync信号がそのまま自身のcounter Init挙動になる。
PWM_EXT_Syncこれはチップ外の信号にcounter Init挙動を任せる。

FORCE_OUTのFRCENビットがセットされている場合は上記のどれがセットされていようがFORCE_OUT信号のアサート時にカウンターを初期化できる。
この機能はRM曰く

When PWM signals are commutated on an inverter controlling a brushless DC motor, it is necessary to restart the PWM cycle at the beginning of the commutation interval.
This action effectively resynchronizes the PWM waveform to the commutation timing.

とあるように転流タイミングでのPWM同期をとるためっぽい。

PWM Generation

f:id:gsmcustomeffects:20200104064228p:plain
PWM Generation(kurikkudekakudai )

VALn Register とコンパレータでH/L信号を作りPWMを生成する部分
このセクションもSDKコンフィグツールで

  • Center Aligned PWMs
  • Edge Aligned PWMs
  • Phase Shifted PWMs
  • Double Switching PWMs

選択することで勝手に設定されるのでユーザーはno careでいい
ちなみにDuty CycleとかPWM周波数もコンフィグで入力できる部分があるので楽に設定可能

Force Out Logic

f:id:gsmcustomeffects:20200104065733p:plain
Force Out Logic(クリックで拡大)

このモジュールは、直訳するなら強制出力。
ForceOut信号自体は8つから選択出来てその信号が有効になるとあらかじめ設定された出力に強制的に切り替わる
その時出力できるのが、PWM23(positive,negative)、OUT23、PWM_EXTAの4つ

OUT23はSoftware Controlled Output Register (SWCOUT)で設定でき常時1か0を出力する。

Deadtime Insertion Logic

f:id:gsmcustomeffects:20200104072900p:plain
Deadtime Insertion Logic(クリックで拡大)

ハーフブリッジとかフルブリッジとかで同時ON(ショート)を防ぐための機能
SDKコンフィグツールで時間入力する部分があるのでレジスタとかはno careでいい

Fault Protection

f:id:gsmcustomeffects:20200104074713p:plain
Fault Protection(クリックで拡大)

Fault保護機能のこと。
下のほうはデバッグ中PWM止めるか止めないかを選べる機能できちんと設定しておかないと勝手にPWMが止まることになる。

Faultピン(Fault0-3)の接続先だがこの辺の資料に外部回路の例が載っているのでまじめにやるならばACMP(Analog Comparator)とFaultピンをXBARでリンクするなりの工夫が必要。
それ以外はXBARの内部接続機能でHIGH,LOWどっちか固定を選べる。

https://www.ti.com/jp/lit/an/jaja502a/jaja502a.pdf

https://www.analog.com/media/jp/technical-documentation/application-notes/jan105.pdf

http://www.ti.com/jp/lit/ml/jajy091/jajy091.pdf

Output Logic

f:id:gsmcustomeffects:20200104233735p:plain
Output Logic(クリックで拡大)
PWMの極性設定ができる。

実際にやっていく

ここまででPWMモジュールのブロック図の中身をあらかた解説したので次はMCUXpressoSDK内臓のペリフェラルコンフィグツールを使ってPWM出力を行う。
まず新規プロジェクト作成でpwm , xbaraをインポートしてプロジェクトを作成する。

f:id:gsmcustomeffects:20200105003608p:plain
新規プロジェクト作成

クロックの設定

f:id:gsmcustomeffects:20200105005003p:plain
クロックの設定
クロックのルートはコアクロック付近からもらってきているのでだいぶ高速である。
そのため自分に合ったところに落とすために周辺にある分周器に印をつけておいた。

ピンの設定

f:id:gsmcustomeffects:20200105020516p:plain
ピンの設定

PWM1を使うこととして、引き出せるピンの都合上、submodule3を使うことにする

f:id:gsmcustomeffects:20200105021334p:plain
使用するピン

PWMペリフェラルの設定

MCUXpressoSDK ペリフェラルコンフィグツールでPWM1を選択して画面を開く

設定値はあくまで参考程度だと思ってください

f:id:gsmcustomeffects:20200105035003p:plain
peripheral設定(クリックで拡大)
f:id:gsmcustomeffects:20200105035941p:plain
peripheral設定(クリックで拡大)
f:id:gsmcustomeffects:20200105040427p:plain
peripheral設定(クリックで拡大)

メインコード

一応動作済みのコードを示す。

Duty変更時のディレイはSystickタイマーで作っています。
PWM_SetPwmLdok(PWM1_PERIPHERAL, (kPWM_Control_Module_3), true);
PWM_StartTimer(PWM1_PERIPHERAL, (kPWM_Control_Module_3));

の部分はコンフィグツールのバグでsubmodule0のコードしか吐いてくれないのでやむなくmainでLoadOKとタイマーセットをしてる感じです。

ループではPWM_UpdatePwmDutycycleでDutyを更新してLDOKを読んでレジスタをReloadしているだけなので簡単ですね。

#include <stdio.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "MIMXRT1021.h"
#include "fsl_debug_console.h"
#include "fsl_xbara.h"
/* TODO: insert other include files here. */

/* TODO: insert other definitions and declarations here. */

/*
 * @brief   Application entry point.
 */

uint32_t delayCount;

void SysTick_Handler(void)
{
    if(delayCount != 0x00)
    {
    	delayCount--;
    }
}

void Systick_delay(uint32_t ms){
	SysTick->LOAD  = (SystemCoreClock/1000 & SysTick_LOAD_RELOAD_Msk) - 1;
	delayCount = ms;
	while(delayCount!=0x00);
}
int main(void) {

  	/* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();
  	/* Init FSL debug console. */
    BOARD_InitDebugConsole();


    PRINTF("Hello World\n");
	SysTick_Config(SystemCoreClock/1000-1);
    PWM_SetPwmLdok(PWM1_PERIPHERAL, (kPWM_Control_Module_3), true);
    PWM_StartTimer(PWM1_PERIPHERAL, (kPWM_Control_Module_3));
    while(1) {
        for (int i = 0;  i <=90;  i=i+10) {
        	PWM_UpdatePwmDutycycle(PWM1_PERIPHERAL, kPWM_Module_3, kPWM_PwmA, kPWM_SignedCenterAligned, i);
        	PWM_SetPwmLdok(PWM1_PERIPHERAL, (kPWM_Control_Module_3), true);
        	Systick_delay(2000);
		}
        __asm volatile ("nop");
    }
    return 0 ;
}

動作時の波形はこのような感じです。

f:id:gsmcustomeffects:20200105041223p:plain
PWMの波形
f:id:gsmcustomeffects:20200105042636p:plain
PWMの波形

LEDの点灯密度もきれいに取れたので貼っておきます

f:id:gsmcustomeffects:20200105055900p:plain
PWMでLED点灯をしている図

PWM周波数が20kHz となっているので正しく波形が出ていることが確認できる。

参考資料

i.MX RT1020 Processor Reference Manual