dsPIC33AKシリーズ⑭QEIモジュールの使い方

dsPIC33Aシリーズ

概要

今回は、QEI(Quadrature Encoder Interface)モジュールの使い方をご紹介します。
QEIモジュールは主にモータ制御など、回転を検出するアプリケーションで使用されます。モータに直結したエンコーダによって、機械的な位置、回転方向、回転速度などを検出します。

QEIモジュールの特徴

・4つの入力端子: 2つの位相信号、インデックス・パルス、ホーム・パルス
・入力のプログラマブル・デジタル・ノイズ・フィルター
・カウンタ・パルスとカウント方向を提供する直交デコーダ
・x4カウント分解能
・位置カウンターをリセットするインデックス・パルス
・汎用32ビット・タイマ/カウンタ・モード
・QEIまたはカウンタ・イベントによって生成される割り込み
・32ビット速度カウンタ
・32ビット位置カウンタ
・32ビットインデックスパルスカウンタ
・32ビット間隔タイマ
・32ビット位置初期化/捕捉/比較ハイワードレジスタ
・32ビット位置初期化/捕捉/比較下位ワード・レジスタ
・4X直交カウント・モード
・外部アップ/ダウン・カウント・モード
・外部ゲート・カウント・モード
・外部ゲート・タイマ・モード
・インターバル・タイマ・モード


エンコーダが出力するA相/B相の信号をQEIモジュールに入力します。このとき、入力エッジと逆相の信号レベルに応じてカウンタがアップまたはダウンします。さらに、Z相が入力されると、このカウンタがゼロにリセットされ、回転角度などを検出することが可能になります。

(fig.0-1)直交エンコーダ信号(データシート 70005539B – p.907より抜粋)

今回は基本的な使い方を紹介します。

関連記事

記事リンク
第1回dsPIC33AKシリーズについてdsPIC33Aシリーズに関して – ぴくおの電子工作的な何かWP (electricpico.com)
第2回開発ボード、コンフィグレーション設定、クロック設定についてdsPIC33AKシリーズ②開発ボード,コンフィグレーション設定,クロック設定について – ぴくおの電子工作的な何かWP (electricpico.com)
第3回CPU性能についてdsPIC33AKシリーズ③CPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第4回FPU性能についてdsPIC33AKシリーズ④FPU性能について – ぴくおの電子工作的な何かWP (electricpico.com)
第5回DSPについてdsPIC33AKシリーズ⑤DSPについて – ぴくおの電子工作的な何かWP (electricpico.com)
第6回タイマー1割り込みの使い方dsPIC33AKシリーズ⑥Timer1割り込みの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第7回PMUの使い方dsPIC33AKシリーズ⑦PMUの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第8回高速ADCの使い方dsPIC33AKシリーズ⑧高速ADCの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第9回高速OPAMPの使い方dsPIC33AKシリーズ⑨高速OPAMPの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第10回DMAモジュールの使い方dsPIC33AKシリーズ⑩DMAモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第11回WDTモジュールの使い方dsPIC33AKシリーズ⑪WDTモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第12回DMTモジュールの使い方dsPIC33AKシリーズ⑫DMTモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第13回I/Oインテグリティモニタモジュールの使い方dsPIC33AKシリーズ⑬I/Oインテグリティモニターモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
第14回(本記事)QEIモジュールの使い方dsPIC33AKシリーズ⑭QEIモジュールの使い方 – ぴくおの電子工作的な何かWP (electricpico.com)
(fig.1-1)各関連記事リンク

開発環境

開発環境を以下に示します。
今回はどちらのCPUボードでも動作いたします。

項目リンク
ベースボードdsPIC33A CURIOSITY PLATFORM
DEVELOPMENT BOARD
dsPIC33A Curiosity Platform Development Board User’s Guide (microchip.com)
CPUボード(EV68M17A)EV68M17A – dsPIC33AK128MC106 Motor Control DIMdsPIC33AK128MC106 Motor Control Dual In-Line Module (DIM) Information Sheet (microchip.com)
CPUボード(EV02G02A)dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM)dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | Microchip Technology
統合開発環境MPLAB X IDE v6.20MPLAB® X IDE | Microchip Technology
コンパイラMPLAB XC DSC v3.10MPLAB® XC DSC Compiler | Microchip Technology
(fig.2-1)本記事の動作確認環境
(fig.2-2)動作環境

QEIモジュールブロック図

以下にQEIモジュールのブロック図を示します。
外部エンコーダの場合、通常A相はQEIAxに、B相はQEIBxに、Z相はQEINDXxに接続します。
ペリフェラルのバススピードは’Standard’のため、最大100MHzの信号をキャプチャ可能です。

(fig.3-1)QEIブロック図(データシート 70005539B – p.909より抜粋)

QEIレジスタ

以下にQEIレジスタとその説明を示します。

レジスタ名(xは1)ビット名説明
QEIxCONQEIENモジュールの有効/無効化
QEISIDLIdleモードでの動作設定
PIMODポジションカウンタ初期化モード
IMVインデックスマッチ判定
INTDIVタイマープリスケーラ
CNTPOLカウンタアップダウン設定
GATEN外部ゲート有効化
CCMカウンタ制御モード
QEIxIOCHCAPENホームイベントによるキャプチャ有効化
QCAPENインデックスマッチイベントによるキャプチャ有効化
FLTRENデジタルフィルタ有効化
QFDIVブデジタルフィルタ分周設定
OUTFNC出力機能設定
SWPABA/B入力入れ替え設定
HOMPOLHome入力極性ビット
IDXPOLIndex入力極性ビット
QEBPOLB入力極性ビット
QEAPOLA入力極性ビット
HOMEHOME入力ステータス
INDEXIndex入力ステータス
QEBB入力ステータス
QEAA入力ステータス
QEIxSTATPCHEQIRQPOSCNTとQEIGECの比較結果
PCHEQIENPOSCNTとQEIGECの比較結果による割り込み有効化
PCLEQIRQPOSCNTとQEILECの比較結果
PCLEQIENPOSCNTとQEILECの比較結果による割り込み有効化
POSOVIRQPOSCNTオーバーフローステータス
POSOVIENPOSCNTオーバーフロー割り込み有効化
PCIIRQPOSCNT初期化プロセス終了ステータス
PCIIENPOSCNT初期化プロセス終了ステータス割り込み
VELOVIRQVELCNTオーバーフローステータス
VELOVIENVELCNTオーバーフロー割り込み有効化
HOMIRQHOMEイベントステータスビット
HOMIENHOMEイベント割り込み有効化
IDXIRQIndexイベントステータスビット
IDXIENIndexイベント割り込み有効化
POSxCNTPOSCNTポジションカウンタ
POSxHLDPOSHLDポジションカウンタホールドレジスタ
VELxCNTVELCNTベロシティカウンタ
VELxHLDVELHLDベロシティカウンタホールドレジスタ
INTxTMRINTTMRインターバルタイマレジスタ
INTxHLDINTHLDインターバルタイマホールドレジスタ
INDXxCNTINDXCNTIndexカウンタレジスタ
INDXxHLDNDXHLDIndexカウンタホールドレジスタ
QEIxICQEIIC初期化/キャプチャレジスタ
QEIxGECQEIGEC比較レジスタ(以上)
QEIxLECQEILEC比較レジスタ(以下)
(fig.4-1)QEIレジスタ

動作確認

今回は、A/B/Z相を出力するエンコーダが手元に無かったため、内部でダミー信号を生成し、それを観測することにしました。以下のブロック図のように構成しています。

SCCP1の割り込み間隔は、ポテンショメータで調整します。その割り込み内で、A/B/Zパルスを生成します。なお、A/B相は1回転あたり400パルスと仮定しています。

(fig.5-1)動作確認ブロック図

ソースコード

インクルードファイル

コンフィグレーションファイル、クロック設定ファイルは以下のファイルをインクルードしてください。

■コンフィグレーションファイル (config.h)

■クロック設定ソースファイル(Clock_Driver.c)

■クロックヘッダーファイル(clock_driver.h)

ソースコード全体

QEI1GEC レジスタが書き込んだ後にゼロクリアされてしまう現象が発生しましたので、メインルーチン内で常時書き込みを行うようにしています。

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "peripheral_init.h"
#include "BoardSupportPackage.h"
#include <dsp.h>

#define SPEED_MAX 100000
#define ENC_PPR   1600
int32_t s4g_PotData;
int32_t s4g_MV_Speed;
int32_t s4g_Direction;
int32_t s4g_Pos_AB;
volatile int32_t s4g_Pos_Z;

const uint32_t s4g_Lat[4] = {0x00,0x0400,0x440,0x040};

int main() 
{
    /*-----------------------------------------------------------------------*/
    /*初期化*/
    /*-----------------------------------------------------------------------*/
        vdg_Clock_Set_Register();
		
	s4g_MV_Speed = 10000;
	s4g_Direction = 1;
    /*-----------------------------------------------------------------------*/
    /* ピン設定 */
    /*-----------------------------------------------------------------------*/
	ANSELAbits.ANSELA7 = 1u;
	ANSELB = 0x0000u;

	TRISBbits.TRISB10 = 0u;  //A相出力
	TRISBbits.TRISB6 = 0u;	//B相出力
	TRISCbits.TRISC8 = 0u;   //Z相出力
	RPOR9bits.RP40R = 45u;	//QEI Cpmp
		
	RPINR7bits.QEIA1R = 27u;		//A相入力
	RPINR7bits.QEIB1R = 23u;		//B相入力
	RPINR7bits.QEIINDX1R = 41u;	//Z相入力
		
    /*-----------------------------------------------------------------------*/
    /* ADC設定 */
    /*-----------------------------------------------------------------------*/
	AD1CH0CONbits.TRG1SRC = 1u;
	AD1CH0CONbits.TRG2SRC = 2u;			//次回以降のAD変換は即時再トリガー
	AD1CH0CONbits.PINSEL = 6u;                      //AD1AN6入力
	AD1CH0CONbits.MODE = ADC_MODE_INTEGRATION;	//積算モード
	AD1CH0CNT = 2048u;
		
	AD1CON = 0x00000000U;
	AD1CONbits.ON = 1u;   
	while(AD1CONbits.ADRDY == 0u)
	{
		;
	}
	AD1SWTRGbits.CH0TRG = 1u;
    /*-----------------------------------------------------------------------*/
    /* SCCP1設定 */
    /*-----------------------------------------------------------------------*/
	CCP1CON1 = 0x00000000u;
	CCP1CON1bits.T32 = 1u; //32bitモード
	CCP1CON2 = 0x00000000u;
	CCP1CON3 = 0x00000000u;
			
	CCP1PR = s4g_MV_Speed;
		
	IPC6bits.CCT1IP = 4u;
	IFS1bits.CCT1IF = 0u;
	IEC1bits.CCT1IE = 1u;
	CCP1CON1bits.ON = 1u;
		
    /*-----------------------------------------------------------------------*/
    /* QEI設定 */
    /*-----------------------------------------------------------------------*/
	QEI1CON = 0x00000000u;
	QEI1CONbits.PIMOD = 1u;   //Index入力でクリア

	QEI1IOC = 0x00000000u;
	QEI1IOCbits.OUTFNC = 3u; //POSCNT > QEI1GECとPOSCNT < QEI1LECでHigh
	QEI1IOCbits.QCAPEN = 1u;

	QEI1LEC = 50u;
	QEI1GEC = 1500u;
			
	QEI1CONbits.ON = 1u;
	INTCON1bits.GIE = 1u;
			
    /*-----------------------------------------------------------------------*/
    /* メインルーチン */
    /*-----------------------------------------------------------------------*/
	while(1)
	{
		QEI1GEC = 1500u;	//QEI1GECがなぜかゼロクリアされるので、常に書込み
			
		/***** ポテンションの値取得 ******/
		if (AD1STATbits.CH0RDY == 1u)
		{
			s4g_PotData = AD1CH0DATA;
			s4g_MV_Speed = 100000000/(0.04857 * (float)s4g_PotData -482)  ;
			AD1SWTRGbits.CH0TRG = 1u;
		}

	}
		
}
void __attribute__((interrupt, no_auto_psv)) _CCT1Interrupt(void)
{
    /*-----------------------------------------------------------------------*/
    /* ABパルス出力 */
    /*-----------------------------------------------------------------------*/
	s4g_Pos_AB += s4g_Direction;
	s4g_Pos_AB &= 3u;
	LATB = s4g_Lat[s4g_Pos_AB];

    /*-----------------------------------------------------------------------*/
    /* Zパルス出力 */
    /*-----------------------------------------------------------------------*/
	s4g_Pos_Z += s4g_Direction;

	if ((s4g_Pos_Z >= ENC_PPR ))
	{
	   s4g_Pos_Z = 0u;
	}
	else if ((s4g_Pos_Z < 0 ))
	{
	   s4g_Pos_Z = ENC_PPR - 1u;
	}

	if ((s4g_Pos_Z <= 4u ) && (s4g_Pos_Z >= 0))
	{
	   LATCbits.LATC8 = 1u;
	}
	else
	{
	   LATCbits.LATC8 = 0u;
	}
    /*-----------------------------------------------------------------------*/
    /* 割り込み間隔指定 */
    /*-----------------------------------------------------------------------*/
	CCP1PR = s4g_MV_Speed;

	IFS1bits.CCT1IF = 0u;
}

結果

下記のように、Z相出力の前100パルスと後50パルスで、QEIのコンペア出力がHighになっていることが確認できました。

(fig.7-1)CH0 A相出力 , CH1 B相出力 , CH2 Z相出力 , CH3 QEIComp出力

記事についての注意点

本記事は慎重に内容を検討し正確さに努めておりますが、内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント

タイトルとURLをコピーしました