Z変換から導いた漸化式で正弦波を高速に生成

マイコン三角関数を計算するのは重い処理ですが、次の漸化式を用いると離散正弦波の数列を高速に生成することができます。漸化式なので生成を繰り返すと誤差が蓄積することに注意。

離散正弦波の数列 x(n) は
正弦波の周波数を f 、サンプリング周波数を k とすると
x(0) = 0
x(1) = sin( 2πf / k )
n≧2 のとき
x(n) = a x(n-1) - x(n-2)
ただし、a = 2 cos( 2πf / k )

下記のページに詳しい説明があります。

違う見方をすると、正弦波のZ変換からこの漸化式を導くこともできます。
(たぶん本質的には同じことです。)

実際に計算した結果のグラフです。

f:id:licheng:20201218114638p:plain

計算に用いたプログラムです。

#include <stdio.h>
#include <math.h>

const float PI = 3.14159265359;

// Z変換から導いた漸化式で離散正弦波の数列を生成するクラス
class ZtrSin
{
public:
    float xz1;  // x[n-1] : 前回値
    float xz2;  // x[n-2] : 前々回値
    float a;    // 漸化式の係数

public:
    // 初期化 (漸化式の初期値と係数の計算)
    // f : 正弦波の周波数[Hz]
    // k : サンプリング周波数[Hz]
    // phi : 初期位相[rad]
    ZtrSin(float f, float k, float phi)
    {
        xz2 = sinf(phi);
        xz1 = sinf(phi + 2 * PI * f / k);
        a = 2 * cos(2 * PI * f / k);
    }

    // 次の値を生成 (漸化式の計算)
    float get() {
        float x = a * xz1 - xz2;
        xz2 = xz1;
        xz1 = x;
        return x;
    }
};

int main(void)
{
    // f=10Hz, k=320Hz, phi=0の離散正弦波の数列を2周期ぶん出力 
    ZtrSin ztrsin(10, 320, 0);
    printf("%f\n", ztrsin.xz2);
    printf("%f\n", ztrsin.xz1);
    for (int n = 2; n <= 64; n++) {
        printf("%f\n", ztrsin.get());
    }

    return 0;
}

Arduino/がじぇるね用お役立ちライブラリ

Arduino/がじぇるね用のお役立ちライブラリをいろいろ作りました。

GR-CITRUS用ロータリーエンコーダライブラリ (位相計数)

GitHub - lipoyang/RotaryEncoder: Rotary Encoder Library for GR-CITRUS

Arduino用移植しやすい周期タイマ (割り込み処理)

GitHub - lipoyang/UniTimer: Universal Interval Timer for various Arduinos.

RS-422とRS-485

RS-422とRS-485の規格の本質的な差は、ドライバ(送信器)が電気的に常時出力かトライステート出力かである。

ドライバが常時出力であるRS-422では、ドライバどうしを結線することは許されない。そのため1本のバスは必ず片方向通信になる。これに対し、ドライバがトライステート出力であるRS-485では、ドライバどうしを結線することができる。そのため1本のバスで双方向通信が可能となる。2線か4線か、片方向か全二重か半二重か、一対一か一対多か多対多かの組み合わせは、このドライバの電気的仕様から決まることである。

RS-422 4線全二重 一対一 (point-to-point) (1)
2線片方向 一対多 (multi-drop) (2)

RS-485
2線半二重 一対一 (point-to-point) (3)
2線半二重 多対多 (multi-point) (4)
4線半二重 一対多 (multi-drop) (5)

(1)は一対一の全二重通信。RS-422の典型的な形であり、UART通信をそのまま差動伝送に変換した形である。
f:id:licheng:20201202111216p:plain

(2)は一対多であるが、複数ドライバの結線は許されないので複数レシーバのみの片方向通信である。「RS-422は一対多の通信が可能」というのはあくまで片方向通信の話だという点に注意。
f:id:licheng:20201202111241p:plain

(3)は一対一の半二重通信。これは次に述べる多対多の半二重通信の特殊な形(N=1)といえる。
f:id:licheng:20201202111255p:plain

(4)は多対多の半二重通信。RS-485の典型的な形である。この形は電気的には全てのノードが対等である。しかし、通信プロトコル上はどれか一つのノードがマスターとなって実質的には一対多の通信をおこなうことが多い。
f:id:licheng:20201202111307p:plain

(5)は一対多の全二重通信。前述のようにRS-485では(4)の形で一対多通信をおこなうことが多く、この形をとることは少ない。
f:id:licheng:20201202111317p:plain

また、言うまでもないが、多対多で全二重などということは理屈上ありえない。

RX65Nマイコンの割り込みベクタについて

RX65Nマイコンには「選択型割り込み」という仕組みがあり、一つの割り込みベクタに複数の割り込み要因が割り当てられているものがある。MTU割り込みなどがこれに割り当たっている。これは従来のRX63Nなどにはなかった仕組みであり、割り込み要因の数が増えすぎたために設けられたのであろう。

下記のアプリケーションノートにその使い方が説明されている。また、詳細は「RX65Nグループ、RX651グループ ユーザーズマニュアル ハードウェア編」の「15. 割り込みコントローラ(ICUB)」に記載されている。

RX65Nの場合、CMT, TMR, TPU, RTC, MTU, CAN, USB, A/Dなど、おもにタイマ系の割り込みが選択型割り込みに割り当てられている。タイマ系は数が多くまた割り込みの種類も多いためだろうか。

例えば、MTU0のTGIA0 (TGRAのインプットキャプチャ/コンペアマッチ)の割り込みは、従来のRX63N等では下記のように設定していた。

MTU0.TIER.BIT.TGIEA = 1
IEN(MTU0, TGIA0) = 1;
IPR(MTU0, TGIA0) = 1;

RX65Nでは、MTU0の割り込みは選択型割り込みAに割り当てることになる。例えば割り込みベクタ番号208に割り当てたい場合は下記のように設定する。

MTU0.TIER.BIT.TGIEA = 1;
ICU.SLIAR208.BYTE   = 1; // MTU0のTGIAの割り込み要因番号
IEN(PERIA, INTA208) = 1;
IPR(PERIA, INTA208) = 1;

このように何の割り込みかコードを見ただけではわかりにくいので、適宜コメントを書いておいたほうがよいだろう。

11月まとめ

進捗

  • GR-CITRUS用ライブラリ開発 (ロータリーエンコーダ計測)
  • GR-ROSE用ライブラリ開発 (パルス幅計測、ESP8266ファーム書き換え、INIファイル読み書き)
  • 技術書典10(オンライン)の原稿執筆
  • ガンプラ製作 (せんとくんガンダム)

その他

f:id:licheng:20201130200426j:plain:w640

所感

9月・10月と低調だったが、少し持ち直したかんじ。

e2studioでmakeが見つかりません

e2studioにプロジェクトをインポートしてビルドしようとしたとき、「Program "make" not found in PATH」あるいは「PATH でプログラム "make" が見つかりません」というエラーが発生する場合がある。

[ERROR] No toolchain set or toolchain not integrated.」というメッセージがあるなら、プロジェクトで指定されたバージョンのツールチェーンがe2studioに統合されていないという意味。

f:id:licheng:20201126171403p:plain

その場合は、プロジェクトの「Properties」>「C/C++ Build」>「Settings」>「Toolchain」で使用するツールチェーンの種類とバージョンを選択しなおす。

f:id:licheng:20201126171414p:plain:w640

【参考】
https://ja-support.renesas.com/knowledgeBase/18367361

GR-ROSEのタイマリソース

GR-ROSEのArduinoライブラリで使用されるタイマリソースについてまとめる。Arduino環境でRXマイコンのタイマリソースを直接使用する場合、Arduinoライブラリとの競合に注意する。またGR-ROSEのArduinoライブラリはFreeRTOS上で動作していることにも要注意。

GR-SAKURA/GR-CITRUSについてはこちら ↓
GR-SAKURA/GR-CITRUSのタイマリソース - 滴了庵日録

(1) FreeRTOS

FreeRTOSのシステムタイマとして CMT0 が使用される。vTaskDelay関数やxTimerCreate関数などがこのシステムタイマに依存する。

(2) PWM出力

ServoクラスおよびanalogWrite関数で使用されるタイマリソースは以下の通り。詳細はisHardwarePWMPin関数, setPinModeHardwarePWM関数, setPinModeSoftwarePWM関数のソースを参照。

ピン番号 使用するタイマリソース 備考
3 TPU5
7 TPU0
9 MTU2
10 MTU1
13 MTU4
上記以外 TPU4 ソフトウェアPWM, 割り込み使用

また、tone関数はピン番号にかかわらずソフトウェアPWMであり、TPU4を使用する。

(3) PPG(プログラマブルパルス生成)

GR-ROSEのライブラリでは従来からあるPWM系のライブラリに加えて、PPGライブラリがある。PPGライブラリで使用されるタイマリソースは以下の通り。

ピン番号 使用するタイマリソース
1 MTU0
3 MTU1
5 MTU2
7 MTU3

(4) その他

ライブラリ 使用するタイマリソース 備考
delay関数 CMT0 ※1
millis関数
micros関数
delayMicroseconds関数
CMT1 ※2
SoftwareSerialクラス 未対応
MsTimer2クラス CMT0 ※3
WavMp3pクラス 未対応
attachIntervalTimerHandler関数 CMT0 ※3
attachCyclicHandler関数 未対応

※1: FreeRTOSのvTaskDelay関数を使っている。
※2: これらはFreeRTOSとは別個のタイマを使用している。
※3: FreeRTOSのxTimerCreate関数を使っている。

タイマリソース別まとめ

MTU0 PPG
MTU1 ハードウェアPWM, PPG
MTU2 ハードウェアPWM, PPG
MTU3 PPG
MTU4 ハードウェアPWM
MTU5~8 未使用
TPU0 ハードウェアPWM
TPU1 未使用
TPU2 未使用
TPU3 未使用
TPU4 ソフトウェアPWM
TPU5 ハードウェアPWM
CMT0 システムタイマ(FreeRTOS)
CMT1 millis関数, micros関数, delayMicroseconds関数
CMT2〜3 未使用
TMR0〜1 未使用

ハードウェアPWM: ServoクラスおよびanalogWrite関数
ソフトウェアPWM: ServoクラスおよびanalogWrite関数, tone関数