CCWO Embedded Space

CCWOの日々の開発を発信するブログ

Renesas RX621 Timer割り込み

Timer割り込みとは、メインのプログラム実行から周期的(タイマー的)に割り込みプログラムを実行する機能です。
このため、プログラムを周期的に行いたい時や何かイベントが発生した時に実行したい時に割り込みは使用されます。
今回は周期的にプログラムを実行するTimer割り込みについて説明していきます。
(イベント: AD変換完了、通信においてデータ受信or送信、インプットキャプチャ(状態変化)等があげられます。)
それでは、CMT(コンペアマッチタイマー)機能を用いて、Timer割り込みの設定をしていきたいと思います。
まず、e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからCMT.c
新規→ヘッダ・ファイルからCMT.h
を作成します。
ソースコードの追加はプロジェクトファイルのsrcフォルダに直接作成することでも可能です。
つぎに、hardware_setup.cにてCMT.hをインクルードし、HardwareSetup関数でCMT.cのCMT0_initialize関数とCMT1_initialize関数を呼びます。

CMT.h

#ifndef CMT_H_
#define CMT_H_

void CMT0_initialize(void);
void CMT1_initialize(void);

#endif /* CMT_H_ */

CMT.c

#include "iodefine.h"
#include "machine.h"
#include "vect.h"
#include "CMT.h"

#pragma interrupt (timer0(vect=VECT(CMT0, CMI0)))
#pragma interrupt (timer1(vect=VECT(CMT1, CMI1)))

void CMT0_initialize(void);
void CMT1_initialize(void);

void timer0(void){
	static unsigned char timer0cnt;

	if(timer0cnt == 10){
		PORTA.DR.BIT.B2 ^= 1;
		timer0cnt = 0;
	}
	timer0cnt++;
}

void timer1(void){
	static unsigned char timer1cnt;

	if(timer1cnt == 10){
		PORTA.DR.BIT.B3 ^= 1;
		timer1cnt = 0;
	}
	timer1cnt++;
}

void CMT0_initialize(void)
{
	// CMT0 5ms
	MSTP(CMT0) = 0;			// Wake up CMT0
	CMT0.CMCR.BIT.CMIE = 1;	// Enable interrupt
	CMT0.CMCR.BIT.CKS = 0;	        // PCLK/8
	CMT0.CMCOR = 29999;	        // Time interval 5ms
	IPR(CMT0, CMI0) = 3;	        // Interrupt level 3
	IEN(CMT0, CMI0) = 1;	        // Enable CMT0 interrupt
	CMT.CMSTR0.BIT.STR0 = 1;     // CMT0 counter start
	
}

void CMT1_initialize(void)
{
	// CMT1 10ms
	MSTP(CMT1) = 0;			// Wake up CMT1
	CMT1.CMCR.BIT.CMIE = 1;	// Enable interrupt
	CMT1.CMCR.BIT.CKS = 0;		// PCLK/8
	CMT1.CMCOR = 59999;		// Time interval 10ms
	IPR(CMT1, CMI1) = 4;		// Interrupt level 4
	IEN(CMT1, CMI1) = 1;		// Enable CMT1 interrupt
	CMT.CMSTR0.BIT.STR1 = 1;	// Counter start	
}

つぎに、vect.hの

// CMT0 CMI0
#pragma interrupt (Excep_CMT0_CMI0(vect=28))
void Excep_CMT0_CMI0(void);

// CMT1 CMI1
#pragma interrupt (Excep_CMT1_CMI1(vect=29))
void Excep_CMT1_CMI1(void);

をすべてコメントアウトします。
この状態でビルドを行い、LEDが点滅すれば成功です。

それではCMTの設定を見ていきます。今回はCMT0,CMT1の設定の違いはタイマークリア値のみなので、CMT0について説明していきます。

  1. モジュールスタート(消費電力低減機能の解除)
  2. ピンの設定
  3. CMTの設定
  4. ユーザ関数の定義

1.モジュールスタート(消費電力低減機能の解除)

MSTP(CMT1) = 0;	// Wake up CMT1

消費電力低減機能を解除します。RX631のようにアクセスロックはないので、そのまま解除します。
MSTPCTRレジスタがiodefine.hでMSTP(****)というようにデファインされているのでこれを使用します。

2.ピンの設定
今回CMTと連動するピンはないので設定はありません。

3.CMT0の設定
f:id:CCWO:20160822173537p:plain
データシートp.1133の図22.3とその説明を参考にします。

CMT0.CMCR.BIT.CMIE = 1;	// Enable interrupt
CMT0.CMCR.BIT.CKS = 0;	        // PCLK/8
CMT0.CMCOR = 29999;	        // Time interval 5ms
IPR(CMT0, CMI0) = 3;	        // Interrupt level 3
IEN(CMT0, CMI0) = 1;	        // Enable CMT0 interrupt
CMT.CMSTR0.BIT.STR0 = 1;     // CMT0 counter start

CMT0のTimer割り込みの設定は
CMCRレジスタの
CMIE: 1→割り込みを許可
CKS: 0→タイマカウント周期をPCLK/8
CMT0レジスタの
CMCOR: 29999→タイマクリアカウントを29999に設定し、5ms周期でタイマカウントがクリアされるようにする
CMTSTR0レジスタの
STR0: 1→CMT0のカウントをスタートする。
となり、割り込みの設定は

IPR(CMT0, CMI0) = 3;	        // Interrupt level 3
IEN(CMT0, CMI0) = 1;	        // Enable CMT0 interrupt

とします。RX621はICUにより、すべての割り込みが管理されています。
ICUのIENレジスタに各割り込みに対しての、許可ビットが存在し、IPRレジスタに各割り込みに対しての、割り込み優先度を設定するビットが存在します。
そしてこのIENレジスタとIPRレジスタは各割り込み毎にIPR(割り込み名)、IEN(割り込み名)というようにiodefine.hでマクロされていますのでこれを使用します。
これで割り込みを含め、Timer割り込みの設定が完了しました。

4.ユーザ関数の定義

#include "vect.h"

#pragma interrupt (timer0(vect=VECT(CMT0, CMI0)))
#pragma interrupt (timer1(vect=VECT(CMT1, CMI1)))

各割り込みで呼ばれる割り込み関数はvect.hですべて定義されています。
そのため、vect.hのCMT0とCMT1のコンペアマッチで発生する割り込み(コンペアマッチ割り込み)の該当部分をコメントアウトし、CMT.hでTimer割り込みすべてを完結できるようにします。
ここで

#pragma interrupt ((割り込み関数名)(vect=(割り込みベクタ番号)))

というように定義することで、ベクタ番号とベクタ番号に対応し割り込み発生時に呼ばれる関数を定義することができます。
ベクタ番号とは各割り込みに対して呼ばれる関数にすで番号が振られており、それをベクタ番号といい、VECT(割り込み名)でiodefine.hでマクロされているのでこれを使用します。
今回はCMT0のコンペアマッチ割り込みの関数としてtimer0を、CMT1のコンペアマッチ割り込みの関数としてtimer1を作成しました。
ここでtimer0関数は5ms毎に呼ばれ10回目でLEDを点滅させるので50msおきにLEDを点滅させます。
同様にtimer1関数は10ms毎に呼ばれ10回目でLEDを点滅させるので100msおきにLEDを点滅させます。
Timer割り込みの設定はこれで完了です。多重割り込み等は
embedded-blog.ccwo.net
を参照して下さい。

20160822の記事

Renesas RX621 UART

UARTを用いて、RX621のデバッグをします。
SIM I/Oを用いて今回はpritnfをSCI1にリダイレクト出来るようにします。
(printfを自身で作成するのもアリかと思います。)
回路はRX621→SCI1→FT231XS→COM(パソコン)となります。
embedded-blog.ccwo.net
手順はRX631と同様になるため、さくさく説明していきます!
まず、lowsrc.c、lowsrc.hとSCI.c、SCI.hという名前で次のファイルをプロジェクトに追加します。
(lowsrc.c、lowsrc.hは上記RX631のUARTの記事を参照)
e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからlowsrc.c
新規→ヘッダ・ファイルからlowsrc.h
新規→ソース・ファイルからSCI.c
新規→ヘッダ・ファイルからSCI.h
を作成します。
ソースコードの追加はプロジェクトファイルのsrcフォルダに直接作成することでも可能です。
つぎに、hardware_setup.cにてSCI.hをインクルードし、HardwareSetup関数でSCI.cのSCI1_initialize関数を呼びます。

SCI.h

#ifndef SCI_H_
#define SCI_H_

void SCI1_initialize(void);

#endif /* SCI_H_ */

SCI.c

#include "iodefine.h"
#include "machine.h"
#include "SCI.h"

void SCI1_initialize(void){
	MSTP(SCI1) = 0;		// Wake up SCI1
	PORT3.ICR.BIT.B0 = 1;	// Enable P30 receive buffer
	SCI1.SCR.BIT.TIE = 0;	// Disable TXI
	SCI1.SCR.BIT.RIE = 0;	// Disable RXI, ERI
	SCI1.SCR.BIT.TE = 0;		// Disable TX
	SCI1.SCR.BIT.RE = 0;		// Disable RX
	SCI1.SCR.BIT.MPIE = 0;	// Normal Mode
	SCI1.SCR.BIT.TEIE = 0;	// Disable TEIE
	SCI1.SCR.BIT.CKE = 0;	// SCK is port
	SCI1.SMR.BIT.CM = 0;	// Asynchronous communication method
	SCI1.SMR.BIT.CHR = 0;	// 8bit
	SCI1.SMR.BIT.PM = 0;	// None parity
	SCI1.SMR.BIT.STOP = 0;	// None stop bit
	SCI1.SMR.BIT.MP = 0;	// Disable multiple processor
	SCI1.SMR.BIT.CKS = 0;	// PCLK
	SCI1.BRR = 12;			// 115200bps
        nop();
	SCI1.SCR.BIT.TE = 1;		// Enable TX
	SCI1.SCR.BIT.RE = 1;		// Enable RX
}

void charput(char c)
{
	while(SCI1.SSR.BIT.TEND == 0);
	SCI1.TDR = c;
	SCI1.SSR.BIT.TEND = 0;
}

char charget(void){
	char data;

	data = SCI1.RDR;
	SCI1.SSR.BIT.RDRF = 0;

	return data;
}

次に、reset_program.c内の

//#ifdef __cplusplus				// Use SIM I/O
//extern "C" {
//#endif
//extern void _INIT_IOLIB(void);
//extern void _CLOSEALL(void);
//#ifdef __cplusplus
//}
//#endif

とreset_program.cのPowerON_Reset_PC関数内の

//_INIT_IOLIB();
//_CLOSEALL();

のコメントアウトを外します。

これで準備は完了しました。
main文にて、printf関数を用いてデバッグを行います。

#include "iodefine.h"
#include "machine.h"
#include <stdio.h>

void main(void)
{
	static unsigned int i;
	while(1){
		printf("Hello RX World!\n");
		for(i = 0; i < 65000; i++) nop();
	}
}

これでTeraTerm等でCOM接続をし、Hello RX World!と表示されれば成功です。
ただ、printfを高速で連続に呼び出すと、送信バッファが溜まってしまいますので、空関数nopを使ってdelayをとっています。
nop関数を使うためにはmachine.hをインクルードする必要があります。

それでは、SCI1の設定手順を見ていきます。

  1. モジュールスタート(消費電力低減機能の解除)
  2. ピンの設定
  3. SCI1の設定
  4. ユーザ関数の定義

1.モジュールスタート

MSTP(SCI1) = 0;		// Wake up SCI1

消費電力低減機能を解除します。RX631のようにアクセスロックはないので、そのまま解除します。
MSTPCTRレジスタがiodefine.hでMSTP(****)というようにデファインされているのでこれを使用します。

2.ピンの設定

PORT3.ICR.BIT.B0 = 1;	// Enable P30 receive buffer

P30の受信バッファを有効にします。RX631とくらべて、ピンひとつずつに周辺機能を割り当てる機能は一部にしか用意されておらず、モジュール開始と同時に切り替わる仕様であると思います。

3.SCI1の設定
f:id:CCWO:20160822170603p:plain
データシート図29.7を参考に、レジスタを設定していきます。

SCI1.SCR.BIT.TIE = 0;	// Disable TXI
SCI1.SCR.BIT.RIE = 0;	// Disable RXI, ERI
SCI1.SCR.BIT.TE = 0;		// Disable TX
SCI1.SCR.BIT.RE = 0;		// Disable RX
SCI1.SCR.BIT.MPIE = 0;	// Normal Mode
SCI1.SCR.BIT.TEIE = 0;	// Disable TEIE
SCI1.SCR.BIT.CKE = 0;	// SCK is port
SCI1.SMR.BIT.CM = 0;	// Asynchronous communication method
SCI1.SMR.BIT.CHR = 0;	// 8bit
SCI1.SMR.BIT.PM = 0;	// None parity
SCI1.SMR.BIT.STOP = 0;	// None stop bit
SCI1.SMR.BIT.MP = 0;	// Disable multiple processor
SCI1.SMR.BIT.CKS = 0;	// PCLK
SCI1.BRR = 12;			// 115200bps
nop();
SCI1.SCR.BIT.TE = 1;		// Enable TX
SCI1.SCR.BIT.RE = 1;		// Enable RX

ほぼ初期化手順通りで大丈夫です。

4.ユーザ関数の定義
今回はprintfにリダイレクトするため、SCI1でcharget,charputを定義しています。
他のSCIを用いてprintfをする場合はSCIの番号を変えれば可能です。

これでSCIの設定は完了です。

Renesas RX621 I/O

次にI/Oピンの設定をします。
出力ピンにPA2,PA3,PA4,PA5
入力ピンにPD0,PD1,PD2,PD3
を設定します。

hardware_setup.cにて以下のようにPin_initialzie関数を作成し、HardwareSetup関数にて呼び出します。

#include "iodefine.h"

void Clock_initialize(void);
void Pin_initialize(void);

void HardwareSetup(void)
{
	Clock_initialize();
	Pin_initialize();
}

void Clock_initialize(void)
{
	SYSTEM.SCKCR.BIT.ICK = 0x0;	// ICLK: XTAL*8
	SYSTEM.SCKCR.BIT.PCK = 0x1;	// PCLK: XTAL*4
	SYSTEM.SCKCR.BIT.BCK = 0x2;	// BCLK: XTAL*2
}

void Pin_initialize(void)
{
	PORTD.DDR.BIT.B0 = 0;	// BUTTON3
	PORTD.DDR.BIT.B1 = 0;	// BUTTON2
	PORTD.DDR.BIT.B2 = 0;	// BUTTON1
	PORTD.DDR.BIT.B3 = 0;	// BUTTON0
	PORTA.DDR.BIT.B2 = 1;	// LED0
	PORTA.DDR.BIT.B3 = 1;	// LED1
	PORTA.DDR.BIT.B4 = 1;	// LED2
	PORTA.DDR.BIT.B5 = 1;	// LED3
}

DDRレジスタにて、入力出力方向を設定します。0: 入力,1: 出力となります。
今回のようにHardwareSetup関数で一度だけ呼ばれる場合はビット単位でアクセスしても問題はありませんが、高速で何度も呼ばれる場合には、レジスタ単位でのアクセスを推奨します。
これでピンの入出力設定が完了したので、BUTTON0~3ボタンの入力に応じて、LEDがそれぞれ点灯するようにmain文にて処理します。

main

#include "iodefine.h"

void main(void)
{
	while(1){
		if(!PORTD.PORT.BIT.B3)	PORTA.DR.BIT.B2 = 1;
		else PORTA.DR.BIT.B2 = 0;
		if(!PORTD.PORT.BIT.B2)	PORTA.DR.BIT.B3 = 1;
		else PORTA.DR.BIT.B3 = 0;
		if(!PORTD.PORT.BIT.B1)	PORTA.DR.BIT.B4 = 1;
		else PORTA.DR.BIT.B4 = 0;
		if(!PORTD.PORT.BIT.B0)	PORTA.DR.BIT.B5 = 1;
		else PORTA.DR.BIT.B5 = 0;
	}
}

ボタンの入力情報はPORTレジスタに収納されます。
また、出力するためにはDRレジスタを設定します。1: High, 0: Lowを出力となります。
今、ボタンは10kΩの抵抗でプルアップされているため、通常時はHighであり、押されているときはLowになります。
なので、if文条件式にてPORTレジスタの負論理をとり、ボタンがHighのときにLEDの出力はLowになるようにしました。
ただ、if文にてこの操作をするのはあまり効率的とは言えないので、レジスタ間を直接操作するほうが効率的かと思われます。
その際には

#define PORTA.DR.BIT.B2 LED0
#define PORTD.PORT.BIT.B3 BUTTON0

とデファイン等しておくと可読性が上がるかと思います。

20160822の記事

Renesas RX621 クロック

RX621のクロック設定は非常に簡単になっております。
hardware_setup.cにて以下のようにClock_initialzie関数を作成し、HardwareSetup関数にて呼び出します。

hardware_setup.c

#include "iodefine.h"

void Clock_initialize(void);

void HardwareSetup(void)
{
	Clock_initialize();
}

void Clock_initialize(void)
{
	SYSTEM.SCKCR.BIT.ICK = 0x0;	// ICLK: XTAL*8
	SYSTEM.SCKCR.BIT.PCK = 0x1;	// PCLK: XTAL*4
	SYSTEM.SCKCR.BIT.BCK = 0x2;	// BCLK: XTAL*2
}

となります。
SCKCRレジスタにてICLK、PCLK、BCLKのクロックを入力クロックから何倍PLLするか設定するだけです。
ただし、ビット単位でアクセスする場合はこの順でないと初期化できないので注意!レジスタ単位でアクセスする場合は問題ありません。

Renesas RX621 下準備<プロジェクトファイルの確認>

生成されるプロジェクトファイルは以下の通りになります。
RX631と同様のプロジェクトファイルが自動で生成されます。
embedded-blog.ccwo.net

  • dbsct.c(セクションの初期化処理用テーブル)
  • hardware_setup.c(ハードウェア初期化ルーチン)
  • interrupt_handlers.c(ベクタ関数の定義)
  • iodefine.h(レジスタ一覧)
  • reset_program.c(リセット直後に呼ばれる関数)
  • main.c(プロジェクト名.c)(main関数)
  • sbrk.c(ヒープ領域:低水準インターフェースルーチン→通常は不要→消しても問題なし)
  • sbrk.h(ヒープ領域:低水準インターフェースルーチン→通常は不要→消しても問題なし)
  • stacksct.h(スタックサイズの設定)
  • typedefine.h(型定義ヘッダ)
  • vect.h(ベクタ関数のヘッダ)
  • vector_table.c(固定ベクタテーブル)

となっております。
大きく分けて三種類のファイルが生成されます。

  • スタック・ヒープ領域
  • 割り込みベクタテーブル
  • 実行ファイル

(ハードウェア記述ファイルiodefine.h)
マイコンリセット後に呼ばれる順番として、

  1. reset_program.c→PowerON_Reset_PC関数
  2. PowerON_Reset_PC関数内→スタック・ヒープの設定
  3. PowerON_Reset_PC関数内→HardwareSetup関数(hardware_setup.c)
  4. PowerON_Reset_PC関数内→main関数

となっています。
なので、main関数が呼ばれる前に、HardwareSetup関数等でハードウェアの初期化を完了し、main関数に実際の処理を書いていく手順となります。

20160822の記事

Renesas RX621 下準備<プロジェクトの作成>

e2 studioとRenesas Flash Programmer(以下RFP)のプロジェクトの作成をし、作成プロジェクトファイルの確認と書き込みを行いたいと思います。
RX631とほぼ同じなので、
e2 studioのプロジェクトの作成はこちらを
embedded-blog.ccwo.net
RFPのプロジェクトの作成はこちらを
embedded-blog.ccwo.net
プロジェクトファイル確認と書き込みはこちらを
embedded-blog.ccwo.net
を参考にしつつさくさく進めたいと思います。

e2 studioのプロジェクトを作成していきます。
ファイル→新規→C Project
・選択したタイプのプロジェクトを作成します。
f:id:CCWO:20160822143008p:plain
プロジェクトの種類:
Executable (Renesas) Sample Project
ツールチェイン:
Renesas RXC Toolchain
を選択します。
・ターゲット固有の設定の選択
f:id:CCWO:20160822143250p:plain
ターゲットの選択: R5F56218BxDP(今回使用するのはR5F56218BDFP)
上記以外はデフォルト
・コード生成とFITの設定
デフォルト
・追加CPUのオプション
デフォルトを推奨(任意で変更)
・グローバル・オプション設定
デフォルト
・標準ヘッダー・ファイル
f:id:CCWO:20160822143439p:plain
ライブラリー構成: C(C99)
任意のヘッダー・ファイルの選択
・各種スタック領域を設定し、サポート・ファイルを追加
f:id:CCWO:20160822143710p:plain
ユーザー・スタック・サイズ: 2000
ハードウェア設定関数の生成: C/C++ Source File
これでプロジェクトの作成を「終了」します。プロジェクの要約がホップアップするので「OK」を押します。
e2 studioの設定はこれで終了します。ctrl+Bもしくは左上トンカチマークを押しビルドします。(初回は標準ライブラリーのビルドのため、少々長くなります。)

RFPのプロジェクトを作成していきます。
RFPを開きます。
f:id:CCWO:20160822144418p:plain
画像中の青色になっているワークスペースRXで右クリックをし、プロジェクトの追加を選択します。
・新しいワークスペースの作成
f:id:CCWO:20160822144653p:plain
使用するターゲット・マイクロコントローラ: グループ→RX 製品名: Generic Boot Device
プロジェクト名: 任意のプロジェクト名
に設定します。
・通信方式
f:id:CCWO:20160822144855p:plain
今回はCOMを使用するので、使用ツールはRXが接続されているCOM番号を選びます。
・Genericデバイス問い合わせ
f:id:CCWO:20160822144948p:plain
すべてに緑チェックが付いたらOKを押します。
・クロック供給
f:id:CCWO:20160822150747p:plain
入力クロック: 12MHz(入力メインクロックを入力します。)
CKP: 4
・通信速度
f:id:CCWO:20160822145139p:plain
「デフォルト値を使用する」のチェックを外し、115200bpsを選択します。
設定できましたら、「完了」を選択し、プロジェクトの作成を終了します。

つぎに、RFPで作成したプロジェクトにプログラム・ファイルを追加します。
f:id:CCWO:20160822150914p:plain
画像中の青色になっているプロジェクト***で右クリックをし、プログラム・ファイルの追加をします。
~/(e2 studioプロジェクト名)/HardwareDebug/(e2 studioプロジェクト名).mot
を選択し、プログラム・ファイルを追加します。
この状態で一度鉛筆マークもしくは(e2 studioプロジェクト名).motの上で右クリックをし書き込みを選択し書き込みましょう。
(書き込み等に失敗する場合はマイコンを一度リセットし、画像左上緑色ボタンで接続を一度解除し、再接続し書き込みましょう。)

これでe2 studioとRFPのプロジェクト作成が完了しました。

Renesas RX621 はじめに

RX631の初期設定みたいなことをしましたが、RX621のほうもやっていきたいと思います。
RX631に比べれると非常に簡単なので、RX631の記事も参考にしつつさくさくやりたいと思います。
使用するマイコンは秋月電子通商でも購入可能な
RX621マイコン R5F56218BDFP: マイコン関連 秋月電子通商-電子部品・ネット通販
です。秋月電子通商では評価ボードも販売しているので利用するといいかもしれません。
RX621マイコンボード: マイコン関連 秋月電子通商-電子部品・ネット通販

ではさっそく、
準備するものと、やることはRX631とほぼ変わらず、
準備するもの

  • e2 studio
  • Rnesas Flash Programmer
  • RX621データシート
  • RX621評価基板等
  • C言語、レジスタの知識、MCUの知識

です。

やること

  • 下準備<プロジェクの作成>
  • 下準備<プロジェクトファイルの確認>
  • クロック
  • I/O
  • UART
  • Timer割り込み
  • PWM
  • MTU2(エンコーダ)
  • 12bitADC
  • RTC

について書いて行きたいと思います。
それではよろしくお願いします。

20160822の記事

Renesas RX631 余談<1>

f:id:CCWO:20160822194413p:plain
ここまででRX631開発は

  • プロジェクトの作成
  • クロック
  • I/O
  • UART
  • Timer割り込み
  • PWM
  • エンコーダ
  • 12bitADC

と扱えるようになり、 hardware_setup.cのHardwareSeup関数は

void HardwareSetup(void)
{
	Clock_initialize();
	Pin_initialize();
	SCI1_initialize();
	CMT0_initialize();
	CMT1_initialize();
	MTU2_initialize();
	S12AD_initialize();
}

このようになっていることと思います。基本的にはモジュール(周辺機能)単位でinitialize関数を作っています。また、ユーザ関数や割り込み等が必要な場合には別でファイルを作っています。
これで、あらかたの機能は使えるようになったので、これから「マイコンで何かをしよう!」の下地には最低限なっているのかな~っと思っています。
これ以外の機能が必要になった場合でも、手順はほとんど変わることはないかと思います。
1.消費電力低減機能の解除
→ほぼ必ず必要。
2.ピンの設定
→ピンとともに使う周辺機能であれば必ず必要。
3.周辺機能の設定
→必須。
4.ユーザ関数の設定
→割り込み関数、周辺機能を使いやすくするための関数(例えば、PWMを%から変換して出力や、エンコーダを回転数に変換等)、このほかにも今回は扱わなかったCAN、SPI、I2C等では通信の関数が必ず必要となります。
自分も何度も壁にぶちあたったりしていますが、気負わずに、しっかりデータシートや当ブログのようなサイトを参考にゆっくり、確実に、精度よくやっていくことがいいかと思います。
番外編として
・RX631,621の最小構成回路
を予定しています。(通信もできたら・・・)

Renesas RX631 12bitADC

アナログ電圧の計測等で必要不可欠な12bitADCの設定を行います。
12bitADC=12bit Analog Digital Converterの略でアナログ電圧を12bitのディジタル信号に変換することを指します。
これにより、アナログ電圧をディジタル信号つまりビットに変換し、取り扱うことができ、アナログ電圧を出力するセンサー等の値をマイコンにより処理することでき大変便利です。
RX631(R5F5631FDDFP)では12bitAD変換が全14chあるのですべてを動作させたいと思います。
以下の手順で設定していきます。
1.消費電力低減機能の解除
2.ピンの設定
3.S12ADの設定
4.ユーザ関数の定義

はじめに
1.消費電力低減機能の解除
2.ピンの設定
を一度にみていきましょう。
まず、S12AD.cとS12AD.hという名前で次のファイルをプロジェクトに追加します。
e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからS12AD.c
新規→ヘッダ・ファイルからS12AD.h
を作成します。
ソースコードの追加はプロジェクトファイルのsrcフォルダに直接作成することでも可能です。
つぎに、hardware_setup.cにてS12AD.hをインクルードし、HardwareSetup関数でS12AD.cのS12AD_initialize関数を呼びます。
S12AD.h

#ifndef S12AD_H_
#define S12AD_H_

extern unsigned short ADC12[14];

void S12AD_initialize(void);

#endif /* S12AD_H_ */

S12AD.c

#include "iodefine.h"
#include "machine.h"
#include "vect.h"
#include "S12AD.h"

#pragma interrupt (S12AD_interrupt(vect=VECT(S12AD, S12ADI0)))

unsigned short ADC12[14] = {0};

void s12ad_initialize(void){
	SYSTEM.PRCR.WORD = 0xA502;		// Release Protect
	MSTP(S12AD) = 0;				// Wake up S12AD
	SYSTEM.PRCR.WORD = 0xA500;		// Protect
	// Set MPC
	PORT4.PMR.BIT.B0 = 1;			// Set P40-7: Peripheral
	PORT4.PMR.BIT.B1 = 1;
	PORT4.PMR.BIT.B2 = 1;
	PORT4.PMR.BIT.B3 = 1;
	PORT4.PMR.BIT.B4 = 1;
	PORT4.PMR.BIT.B5 = 1;
	PORT4.PMR.BIT.B6 = 1;
	PORT4.PMR.BIT.B7 = 1;
	PORTD.PMR.BIT.B0 = 1;			// Set PD0-5: Peripheral
	PORTD.PMR.BIT.B1 = 1;
	PORTD.PMR.BIT.B2 = 1;
	PORTD.PMR.BIT.B3 = 1;
	PORTD.PMR.BIT.B4 = 1;
	PORTD.PMR.BIT.B5 = 1;
	MPC.PWPR.BIT.B0WI = 0;			// Release protect
	MPC.PWPR.BIT.PFSWE = 1;
	MPC.P40PFS.BIT.ASEL = 1;		// Set P40-7: Analog Input
	MPC.P41PFS.BIT.ASEL = 1;
	MPC.P42PFS.BIT.ASEL = 1;
	MPC.P43PFS.BIT.ASEL = 1;
	MPC.P44PFS.BIT.ASEL = 1;
	MPC.P45PFS.BIT.ASEL = 1;
	MPC.P46PFS.BIT.ASEL = 1;
	MPC.P47PFS.BIT.ASEL = 1;
	MPC.PD0PFS.BIT.ASEL = 1;		// Set PD0-5: Analog Input
	MPC.PD1PFS.BIT.ASEL = 1;
	MPC.PD2PFS.BIT.ASEL = 1;
	MPC.PD3PFS.BIT.ASEL = 1;
	MPC.PD4PFS.BIT.ASEL = 1;
	MPC.PD5PFS.BIT.ASEL = 1;
	MPC.PWPR.BIT.PFSWE = 0;			// Protect
	MPC.PWPR.BIT.B0WI = 1;
	// S12AD Settings software trigger
	S12AD.ADCSR.BIT.CKS = 0;		// PCLK/8
	S12AD.ADCSR.BIT.ADIE = 1;		// Enable S12ADI0
	S12AD.ADCSR.BIT.ADCS = 1;		// Continuous scanning
	S12AD.ADCSR.BIT.ADST = 0;		// Stop S12AD
	S12AD.ADANS0.WORD = 0xFFFF;		// S12ADC: AN000-015
	S12AD.ADADS0.WORD = 0x0000;		// Disable ADD result Mode
	S12AD.ADCER.BIT.ACE = 1;		// Auto clearing
	S12AD.ADCER.BIT.ADRFMT = 0;		// Right -justified
	S12AD.ADSSTR01.BIT.SST1 = 60;	// 10us
	S12AD.ADCSR.BIT.ADST = 1;		// Enable S12AD

	IEN(S12AD, S12ADI0) = 1;
	IPR(S12AD, S12ADI0) = 8;
}

void S12AD_interrupt(void){
	ADC12[0] = S12AD.ADDR0;
	ADC12[1] = S12AD.ADDR1;
	ADC12[2] = S12AD.ADDR2;
	ADC12[3] = S12AD.ADDR3;
	ADC12[4] = S12AD.ADDR4;
	ADC12[5] = S12AD.ADDR5;
	ADC12[6] = S12AD.ADDR6;
	ADC12[7] = S12AD.ADDR7;
	ADC12[8] = S12AD.ADDR8;
	ADC12[9] = S12AD.ADDR9;
	ADC12[10] = S12AD.ADDR10;
	ADC12[11] = S12AD.ADDR11;
	ADC12[12] = S12AD.ADDR12;
	ADC12[13] = S12AD.ADDR13;
}

まず、消費電力低減機能の解除を見ていきます。

SYSTEM.PRCR.WORD = 0xA502;		// Release Protect
MSTP(S12AD) = 0;				// Wake up S12AD
SYSTEM.PRCR.WORD = 0xA500;		// Protect

これまでと同様に、消費電力低減機能のアクセスロックを解除し、消費電力低減機能を解除し、再度ロックします。
つぎにピンの設定を見てきましょう。

// Set MPC
PORT4.PMR.BIT.B0 = 1;			// Set P40-7: Peripheral
PORT4.PMR.BIT.B1 = 1;
PORT4.PMR.BIT.B2 = 1;
PORT4.PMR.BIT.B3 = 1;
PORT4.PMR.BIT.B4 = 1;
PORT4.PMR.BIT.B5 = 1;
PORT4.PMR.BIT.B6 = 1;
PORT4.PMR.BIT.B7 = 1;
PORTD.PMR.BIT.B0 = 1;			// Set PD0-5: Peripheral
PORTD.PMR.BIT.B1 = 1;
PORTD.PMR.BIT.B2 = 1;
PORTD.PMR.BIT.B3 = 1;
PORTD.PMR.BIT.B4 = 1;
PORTD.PMR.BIT.B5 = 1;
MPC.PWPR.BIT.B0WI = 0;			// Release protect
MPC.PWPR.BIT.PFSWE = 1;
MPC.P40PFS.BIT.ASEL = 1;		// Set P40-7: Analog Input
MPC.P41PFS.BIT.ASEL = 1;
MPC.P42PFS.BIT.ASEL = 1;
MPC.P43PFS.BIT.ASEL = 1;
MPC.P44PFS.BIT.ASEL = 1;
MPC.P45PFS.BIT.ASEL = 1;
MPC.P46PFS.BIT.ASEL = 1;
MPC.P47PFS.BIT.ASEL = 1;
MPC.PD0PFS.BIT.ASEL = 1;		// Set PD0-5: Analog Input
MPC.PD1PFS.BIT.ASEL = 1;
MPC.PD2PFS.BIT.ASEL = 1;
MPC.PD3PFS.BIT.ASEL = 1;
MPC.PD4PFS.BIT.ASEL = 1;
MPC.PD5PFS.BIT.ASEL = 1;
MPC.PWPR.BIT.PFSWE = 0;		// Protect
MPC.PWPR.BIT.B0WI = 1;

SCI同様にMPCのアクセスロックを解除し、ピンに周辺機能を割り当て、再度ロックし、下準備を完了します。
今回は14個のピンを一度に設定するのでかなり長くなっています。個別に設定しているのはあとで変更しやすくするためです。
固定であるならば、一括でレジスタを設定してもよいでしょう。

3.S12ADの設定
S12ADはデータシートに初期化手順が示されているわけではないので、今回は連続スキャンモードを参考に設定していきます。
しかし、ここで余談ですが、RXに限らずマイコンのAD変換の設定はおおまかに
・AD変換クロックの設定(モジュールの動作周波数の設定)
・トリガ、割り込みの設定(AD変換のトリガの設定)
・AD変換chの設定(何個AD変換を使用するの設定)
・加算、フィルタの設定(精度を上げたりするための設定)
・データ型の設定(右詰め、左詰め(Little,Big Endian=Byte-order)の設定)
・サンプリング周期の設定(AD変換には一般的にある程度の時間を要さないと構造的に精度が出ないためサンプリング時間の設定をする。)
RX631もほぼ例に漏れることなく設定していく。

// S12AD Settings software trigger
// AD変換クロックの設定
S12AD.ADCSR.BIT.CKS = 0;		// PCLK/8
// 割り込みの設定
S12AD.ADCSR.BIT.ADIE = 1;		// Enable S12ADI0
S12AD.ADCSR.BIT.ADCS = 1;		// Continuous scanning=連続スキャンモード
S12AD.ADCSR.BIT.ADST = 0;		// Stop S12AD=AD変換の設定をするため一旦モジュールをストップ
// AD変換chの設定
S12AD.ADANS0.WORD = 0xFFFF;		// S12ADC: AN000-015
// 加算、フィルタの設定
S12AD.ADADS0.WORD = 0x0000;		// Disable ADD result Mode
S12AD.ADCER.BIT.ACE = 1;		// Auto clearing
// データ型の設定
S12AD.ADCER.BIT.ADRFMT = 0;		// Right -justified
// サンプリング周期の設定
S12AD.ADSSTR01.BIT.SST1 = 60;	// 10us
S12AD.ADCSR.BIT.ADST = 1;		// Enable S12AD=AD変換開始

このように、一般的なマイコンと同様(かなり高機能な部類)にして設定が可能である。
最後に、タイマー割り込みで設定したときと同様に割り込みの設定をする。

IEN(S12AD, S12ADI0) = 1;
IPR(S12AD, S12ADI0) = 8;

同様にvect.hの

// S12AD S12ADI0
#pragma interrupt (Excep_S12AD_S12ADI0(vect=102))
void Excep_S12AD_S12ADI0(void);

をすべてコメントアウトします。
これでAD変換の設定は完了しました。

4.ユーザ関数の定義
割り込みベクタテーブルの設定と関数の設定をします。

#include "vect.h"

#pragma interrupt (S12AD_interrupt(vect=VECT(S12AD, S12ADI0)))

void S12AD_interrupt(void){
	ADC12[0] = S12AD.ADDR0;
	ADC12[1] = S12AD.ADDR1;
	ADC12[2] = S12AD.ADDR2;
	ADC12[3] = S12AD.ADDR3;
	ADC12[4] = S12AD.ADDR4;
	ADC12[5] = S12AD.ADDR5;
	ADC12[6] = S12AD.ADDR6;
	ADC12[7] = S12AD.ADDR7;
	ADC12[8] = S12AD.ADDR8;
	ADC12[9] = S12AD.ADDR9;
	ADC12[10] = S12AD.ADDR10;
	ADC12[11] = S12AD.ADDR11;
	ADC12[12] = S12AD.ADDR12;
	ADC12[13] = S12AD.ADDR13;
}

上記はタイマー割り込みと設定したときと同様で、S12AD_interrupt関数をベクタテーブル番号VECT(S12AD,S12ADI0)で呼ばれるようにpragmaにて定義し、
割り込み処理関数ではグローバル変数で用意したADC12配列にひとつずつ収納していく形になっています。

これで設定は完了しました。
最後にmain文にて

#include <stdio.h>
#include "iodefine.h"
#include "machine.h"
#include "S12AD.h"

void main(void)
{
	int i;
	while(1){
		for(i = 0; i < 14; i++){
			printf("S12AD[%d]:%4d\n", i, ADC12[i]);
		};
	}
}

という感じでデバッグしてみましょう。TeraTerm等ではおそらくランダムな値が出てくると思います。(Hi-Z状態のため、値が震えてる。)
これで12bitADCは完了です!

20160818の記事

Renesas RX631 エンコーダ

モータ制御等に必要不可欠なエンコーダを計測していきたいと思います。
エンコーダとは、光とスリットによって、回転方向と回転量を計測することができるセンサーです。
広くモータの回転量の制御や回転量の変化を利用し移動量の計測に使用されます。
以下の手順で設定していきます。エンコーダはMTU2(マルチファンクションタイマパルスユニット2)を用います。
1.消費電力低減機能の解除
2.ピンの設定
3.MTU2の設定
4.ユーザ関数の設定(今回、関数は定義しないので省略)

はじめに
1.消費電力低減機能の解除
2.ピンの設定
を一度にみていきましょう。
PWMの設定時に作成したMTU2_initialize関数に続けて位相係数の設定をしていきます。

MTU2_initialize関数

void MTU2_initialize(void){
        // MTU1,MTU2
	SYSTEM.PRCR.WORD = 0xA502;		// Release Protect
	MSTP(MTU1) = 0;					// Wake up MTU1
	MSTP(MTU2) = 0;					// Wake up MTU2
	SYSTEM.PRCR.WORD = 0xA500;		// Protect

	// Set MPC
	PORT1.PMR.BIT.B4 = 1;		// Set P14: Peripheral
	PORT1.PMR.BIT.B5 = 1;		// Set P15: Peripheral
	PORTC.PMR.BIT.B4 = 1;		// Set PC4: Peripheral
	PORTC.PMR.BIT.B5 = 1;		// Set PC5: Peripheral
	MPC.PWPR.BIT.B0WI = 0;		// Release protect
	MPC.PWPR.BIT.PFSWE = 1;
	MPC.P14PFS.BIT.PSEL = 2;	// Set P14: MTCLKA
	MPC.P15PFS.BIT.PSEL = 2;	// Set P15: MTCLKB
	MPC.PC4PFS.BIT.PSEL = 2;	// Set PC4: MTCLKC
	MPC.PC4PFS.BIT.PSEL = 2;	// Set PC5: MTCLKD
	MPC.PWPR.BIT.PFSWE = 0;	// Protect
	MPC.PWPR.BIT.B0WI = 1;

	// MTU1, MTU2 Encoder Settings 位相係数モード1
	MTU1.TMDR.BIT.MD = 4;		// MTU1 位相係数モード1
	MTU2.TMDR.BIT.MD = 4;		// MTU2 位相係数モード1
	MTU1.TCNT = 0x0000;		// Clear MTU1 count
	MTU2.TCNT = 0x0000;		// Clear MTU2 count
	MTU.TSTR.BIT.CST1 = 1;		// Start MTU1 count
	MTU.TSTR.BIT.CST2 = 1;		// Start MTU2 count

        // MTU4(設定省略)
}

まず、SCI、Timer割り込み同様に、消費電力低減機能のアクセスロックを解除し、消費電力低減機能を解除し、再度ロックします。
つぎに、SCI同様にMPCのアクセスロックを解除し、ピンに周辺機能を割り当て、再度ロックし、下準備を完了します。

3.MTU2の設定
MTU2の設定をします。
f:id:CCWO:20160819165528p:plain
データシートp.837の図23.29を参考に設定します。
ここで、MTU2の中には、MTU0~6のユニットがあり、今回は位相係数モードが使用できるMTU1,2を用います。
まず、MTU1とMTU2を位相係数モード1に設定し、MTUのカウントをクリアし、MTUのカウントをスタートさせます。
これでMTUの設定は完了です!
また、4.ユーザ関数の定義ですが今回関数等は設定しないので省略します。
次にmain文にて

#include <stdio.h>
#include "iodefine.h"
#include "machine.h"

void main(void)
{
	while(1){
		printf("MTU1:%6d\tMTU2:%6d\n", MTU1.TCNT, MTU2.TCNT);
	}
}

エンコーダを接続し、TeraTerm等でデバッグできれば成功です!
エンコーダの値が収納されるTCNTレジスタは16ビットのレジスタであることには頭に入れておきましょう。
ここで、可読性をあげるために、

#define MTU1.TCNT ENCODER0
#define MTU2.TCNT ENCODER1

としておくのもよいでしょう。

20160818の記事

Renesas RX631 PWM

モーター制御等さまざまな分野で必要不可欠なPWMを出力していきます。
PE2をMTIOC4Aに設定し、1kHzのPWMを出力していきます。
以下の手順で設定していきます。
1.消費電力低減機能の解除
2.ピンの設定
3.MTU2の設定
4.ユーザ関数の定義(今回、関数は定義しないので省略)

はじめに
1.消費電力低減機能の解除
2.ピンの設定
を一度にみていきましょう。
hardware_setup.cにて以下のMTU2_initialize関数を作成し、HardwareSetup関数で呼びましょう。

MTU2_initialize関数

void MTU2_initialize(void){
	// MTU4
	SYSTEM.PRCR.WORD = 0xA502;		// Release Protect
	MSTP(MTU4) = 0;					// Wake up MTU4
	SYSTEM.PRCR.WORD = 0xA500;		// Protect
	// Set MPC
	PORTE.PMR.BIT.B2 = 1;			// Set PE2: Peripheral
	MPC.PWPR.BIT.B0WI = 0;			// Release protect
	MPC.PWPR.BIT.PFSWE = 1;
	MPC.PE2PFS.BIT.PSEL = 1;		// Set PE2: MTIOC4A
	MPC.PWPR.BIT.PFSWE = 0;			// Protect
	MPC.PWPR.BIT.B0WI = 1;
	// PWM Settings
	MTU.TOER.BIT.OE4A = 1;			// Enable MTIOC4A Output
	MTU4.TCR.BIT.TPSC = 4;			// PCLK/256
	MTU4.TCR.BIT.CKEG = 0;			// Count rising edge
	MTU4.TCR.BIT.CCLR = 1;			// Clear TCNT count when compare match TGRA
	MTU4.TMDR.BIT.MD = 2;			// MTU4 PWMモード1
	MTU4.TMDR.BIT.BFA = 0;			// TGRA, TGRC normal mode
	MTU4.TMDR.BIT.BFB = 0;			// TGRB, TGRD normal mode
	MTU4.TIORH.BIT.IOA = 6;			// Compare Output High
	MTU4.TIORH.BIT.IOB = 7;			// Compare Output Low
	MTU4.TGRA = 29999;				// 1kHz
	MTU4.TGRB = 14999;				// Duty 50%
	MTU4.TCNT = 0;					// Clear MTU4 count
	MTU.TSTR.BIT.CST4 = 1;			// Start MTU4 count
}

まず、SCI、Timer割り込み同様に、消費電力低減機能のアクセスロックを解除し、消費電力低減機能を解除し、再度ロックします。
つぎに、SCI同様にMPCのアクセスロックを解除し、ピンに周辺機能を割り当て、再度ロックし、下準備を完了します。

3.MTU2の設定
f:id:CCWO:20160819232643p:plain
f:id:CCWO:20160819232915p:plain
データシートp.834の図23.25と図23.26を参考に設定します。
ここで、MTU2の中にはMTU0~6のユニットがあり、今回はMTU4をPWMモード1で使用します。
まず、PWMモードの設定手順例を参考に設定していきます。
・カウンタクロックの設定
→使用するクロックの分周比を設定します。
・カウンタクリアの要因の選択
→カウンタクロックがクリアされるソースを選択します。TGRAまたはTGRB。
・PWMモードの設定
→PWMモード1に設定します。
・波形出力レベルの選択
→どのように波形を出すか設定します。今回は初期HIGHに設定し、TGRBのコンペアマッチでLOW出力に、TGRAのコンペアマッチでHIGH出力。
・TGRの設定
→実際に値を設定し、PWM周波数とDuty比を設定します。今回はTGRB操作することでDuty比、TGRAを操作することでPWM周波数を設定します。ただし常にTGRA>TGRBを満たす。
・カウント動作開始
→実際にカウントスタートさせ動作を開始します。
(ただし、今回MTIOC4Aは初期状態では出力が禁止されているため、TOERレジスタのOE4Aビットを1にし、出力を許可しておきます。)

4.ユーザ関数の定義
今回は用意しないため省略します。

これでPWMの設定は完了しました。実際に書き込みオシロスコープ等でPE2の波形を観測し、PWMが出ていれば成功です!
PWM波形の一例を載せておきます。
f:id:CCWO:20160819234732j:plain

20160818の記事

RX631開発 Timer割り込み

マイコンにおいて必要不可欠なタイマー割り込みの設定をします。
10msと5msのタイマー割り込みを設定してLEDを点滅させてみましょう。
タイマー割り込みとは、文字通り現在行っているプログラムにタイマー的(周期的)に割り込んでプログラムを実行する機能です。
RX631マイコンや多くのマイコンは、シングルコアのCPUを持っています。そのため、一度に実行できるプログラムはただひとつのみです。(周辺機能はハードウェア的にレジスタに設定された動作を行っていますが、これはあくまで周辺機能なのでプログラムを実行しているCPUはプログラムをただひとつ実行していると表現しています。)
たとえばスイッチの入力を待つなどのプログラムを処理したい場合に、main文にてボタンの入力が来るのをずっと待っているプログラムを書くのは非常に非効率的です。(ボタンの入力を待つ以外の処理がなにもできなくなるため。)
そこで、割り込みを用いて、ボタンの入力がきたときだけ、実行する割り込みプログラムを別で用意しておくことができます。
ここではボタンの入力ではなく、周期的に呼ばれる割り込みプログラムを用意し、10msと5msおきに実行できるようにします。
まずはCMT.cとCMT.hを作成します。詳細は後述します。
CMT.h

#ifndef CMT_H_
#define CMT_H_

void CMT0_initialize(void);
void CMT1_initialize(void);

#endif /* CMT_H_ */

CMT.c

#include "iodefine.h"
#include "machine.h"
#include "vect.h"
#include "CMT.h"

#pragma interrupt (timer0(vect=VECT(CMT0, CMI0)))
#pragma interrupt (timer1(vect=VECT(CMT1, CMI1)))

void timer0(void){
	static unsigned char timer0cnt;

	if(timer0cnt == 10){
		PORTE.PODR.BIT.B1 ^= 1;
		timer0cnt = 0;
	}
	timer0cnt++;
}

void timer1(void){
	static unsigned char timer1cnt;

	if(timer1cnt == 10){
		PORTE.PODR.BIT.B0 ^= 1;
		timer1cnt = 0;
	}
	timer1cnt++;
}

void CMT0_initialize(void){
	// CMT0
	SYSTEM.PRCR.WORD = 0xA502;	// Release protect
	MSTP(CMT0) = 0;				// Wake up CMT0
	SYSTEM.PRCR.WORD = 0xA500;	// Protect
	CMT.CMSTR0.BIT.STR0 = 0;	// Disable CMT0 count
	CMT0.CMCR.BIT.CKS = 0;		// PCLK/8
	CMT0.CMCR.BIT.CMIE = 1;		// Enable CMIE
	CMT0.CMCNT = 0x0000;		// Clear Count
	CMT0.CMCOR = 29999;			// 5ms = (8/PCLK)*(CMCOR+1) >> CMCOR = ((5m*48M)/8)-1
	CMT.CMSTR0.BIT.STR0 = 1;	// Enable CMT0 count

	IEN(CMT0, CMI0) = 1;
	IPR(CMT0, CMI0) = 3;
}

void CMT1_initialize(void){
	// CMT1
	SYSTEM.PRCR.WORD = 0xA502;	// Release protect
	MSTP(CMT1) = 0;				// Wake up CMT1
	SYSTEM.PRCR.WORD = 0xA500;	// Protect
	CMT.CMSTR0.BIT.STR1 = 0;	// Disable CMT1 count
	CMT1.CMCR.BIT.CKS = 0;		// PCLK/128
	CMT1.CMCR.BIT.CMIE = 1;		// Enable CMIE
	CMT1.CMCNT = 0x0000;		// Clear Count
	CMT1.CMCOR = 59999;			// 10ms = (8/PCLK)*(CMCOR+1) >> CMCOR = ((10m*48M)/8)-1
	CMT.CMSTR0.BIT.STR1 = 1;	// Enable CMT1 count

	IEN(CMT1, CMI1) = 1;
	IPR(CMT1, CMI1) = 4;
}

つぎに、hardware_setup.cにてCMT.hをインクルードし、HardwareSetup関数でCMT.cのCMT0_initialize関数とCMT1_initialize関数を呼びます。
つぎに、vect.hの

// CMT0 CMI0
#pragma interrupt (Excep_CMT0_CMI0(vect=28))
void Excep_CMT0_CMI0(void);

// CMT1 CMI1
#pragma interrupt (Excep_CMT1_CMI1(vect=29))
void Excep_CMT1_CMI1(void);

をすべてコメントアウトします。
これでビルドし、書き込みましょう。LEDが点滅すれば成功です。

つぎに、タイマー割り込みの設定を説明します。
タイマー割り込みを行うためにはコンペアマッチタイマーというモジュール(周辺機能)を使用します。
今回、CMT0とCMT1を使用しますが、設定値の違いはタイマカウントのクリア値だけなので、CMT0について説明します。
以下の手順で設定します。
1.消費電力低減機能の解除
2.ピンの設定(今回は使用するモジュールとともに使うピンはないので不要。)
3.CMTの設定
4.ユーザー関数の定義(今回は割り込みのため、割り込み関数の定義となります。)

1.消費電力低減機能の解除

SYSTEM.PRCR.WORD = 0xA502;	// Release protect
MSTP(CMT0) = 0;				// Wake up CMT0
SYSTEM.PRCR.WORD = 0xA500;	// Protect

SCIの設定同様に、アクセスロックを解除し、消費電力低減機能を解除し、再度ロックします。

2.ピンの設定(略)

3.CMTの設定
f:id:CCWO:20160819160937p:plain
データシートp.1089の図28.2CMCNTカウンタの動作を参考に、設定します。

CMT.CMSTR0.BIT.STR0 = 0;	// Disable CMT0 count
CMT0.CMCR.BIT.CKS = 0;		// PCLK/8
CMT0.CMCR.BIT.CMIE = 1;		// Enable CMIE
CMT0.CMCNT = 0x0000;		// Clear Count
CMT0.CMCOR = 29999;			// 5ms = (8/PCLK)*(CMCOR+1) >> CMCOR = ((5m*48M)/8)-1
CMT.CMSTR0.BIT.STR0 = 1;	// Enable CMT0 count

まず、
・CMT0のカウントフラグをクリア(0にする)
・カウントアップ周波数の設定
・割り込みコントローラの設定
・CMT0のカウントをクリア(0にする)
・10msになるようにタイマーカウントをクリア値を設定
・タイマーカウントの開始
これでCMT0の設定は完了です。カウントが開始され、カウントが29999になったときにカウントがクリアされ、このとき割り込みプログラムが呼ばれ、またカウントアップを開始します。そして、この動作を継続します。

4.ユーザー関数の定義
割り込みプログラムを定義します。
ここでRX631にはICU(割り込みコントローラ)機能が存在し、割り込みはそこで一括して管理されています。
まずICUにて、各割り込みのEnable(利用可能)とPriority(優先順位)を設定します。MSTPと同様に、IERレジスタとIPRレジスタが各割り込みごとにiodefine.hでマクロされているのでこれを使用します。

IEN(CMT0 CMI0) = 1;    // Interrupt Enable
IPR(CMT0, CMI0) = 3;    // Interrupt Priority

IENにてCMT0の割り込みであるCMI0をEnableにし、割り込み優先レベル(小さい方が高レベル)を設定します。
各周辺機能の割り込みはデータシートp.387の表15.3割り込みベクタテーブルに一覧化されているので、参考にしましょう。
これで割り込みの設定が完了しました。
次に、ベクタテーブルの設定をします。

#include "iodefine.h"
#include "vect.h"

#pragma interrupt (timer0(vect=VECT(CMT0, CMI0)))
#pragma interrupt (timer1(vect=VECT(CMT1, CMI1)))

すべての割り込みはベクタテーブルで管理されており、RX631ではvect.hにて、割り込みで呼ばれるプログラムがすでに定義されています。
ここで、わかりやすいようにvect.hのCMI0,CMI1割り込み部分をコメントアウトし、CMT.cでタイマー割り込みのプログラムを完結できるように、vect.hをインクルードし、こちらで割り込み関数を定義します。
定義するためには

#pragma interrupt ((割り込み関数名)(vect=(ベクタ番号)))

で割り込み関数を定義します。
(関数名)に呼びたい関数名を定義し、ベクタ番号に呼ぶ呼び出す関数のベクタ番号を設定します。
ここでもIEN,IPRと同様に、ベクタ番号がiodefine.hでマクロされているのでこれを使用します。
これで割り込み関数の準備ができました。
また、多重割り込み(割り込み中の割り込み)を許可したい場合は(初期設定では不許可になっている。)

#pragma interrupt ((割り込み関数名)(vect=(ベクタ番号)),enable)

としたり、割り込み関数中で setpsw_i(); を呼ぶことで多重割り込みを許可できます。
これでタイマー割り込みが可能になったかと思います。以下割り込みも同様の手順のため省略します。
また、詳しい割り込みの動作については「RXショートセミナー」等の資料を参考にすると理解が深まると思います。

20160818の記事

Renesas RX631 UART

UARTを用いて、RX631のデバッグをします。
回路はRX631→SCI1→FT231XS→COM(パソコン)となります。
ここでは、printf(IOStream)を使うために、RenesasのSIM I/O(シミュレーション用のデバッグコンソール)を用いて、PCにシリアル転送を行います。
(自身でprintf関数を実装するのもいいかと思います。)
まず、lowsrc.cとlowsrc.hという名前で次のファイルをプロジェクトに追加します。(ソースコードは長いので後述。)(CS+のプロジェクトファイルから転用しました。)
e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからlowsrc.c
新規→ヘッダ・ファイルからlowsrc.h
を作成します。(ソースコードは長いので後述。)
ソースコードの追加はプロジェクトファイルのsrcフォルダに直接作成することでも可能です。
次に、reset_program.c内の

//#ifdef __cplusplus				// Use SIM I/O
//extern "C" {
//#endif
//extern void _INIT_IOLIB(void);
//extern void _CLOSEALL(void);
//#ifdef __cplusplus
//}
//#endif

とreset_program.cのPowerON_Reset_PC関数内の

//_INIT_IOLIB();
//_CLOSEALL();

のコメントアウトを外します。
つぎに、SCI1(UART)の設定をします。
ソースコードを追加するために、e2 stduio左側プロジェクトエクスプローラのプロジェクトフォルダ内のsrcフォルダを右クリックし,
新規→ソース・ファイルからSCI.c
新規→ヘッダ・ファイルからSCI.h
を作成します。(ソースコードは長いので後述。)
つぎに、hardware_setup.cにてSCI.hをインクルードし、HardwareSetup関数でSCI.cのSCI1_initialize関数を呼びます。
これで、デバッグの準備は出来ました!
main文にて

#include <stdio.h>
#include "iodefine.h"
#include "machine.h"

void main(void)
{
	unsigned int i;
	while(1){
		printf("Hello RX World!\n");
		for(i = 0; i < 65000; i++) nop();
	}
}

TeraTerm等を開き、COMを接続し、Hello RX World!が表示されれば成功です!連続でprintfをするのは処理が重いため、nop関数を用いてdelayをとっています。
これでターミナル等を用いてデバッグをすることが可能になりました。
COMの設定は
・ボーレート:115200
・データ:8bit
・パリティ:なし
・ストップビット:1bit
と一般的な設定になっています。
大まか設定としては、SCI1を使ってprintfにリダイレクト(charput,charget)しているということになるかとおもいます。

SCIの初期化の手順は
1.消費電力低減機能の解除
2.ピン設定
3.SCIの初期化
4.ユーザー関数の定義
の順でおこいます。

1.消費電力低減機能の解除
RX631シリーズには、RX621シリーズには実装されていなかった、消費電力低減機能が実装されています。
これはレジスタの初期状態ではすべての周辺機能が消費電力低減状態で起動しており、これを解除するまで任意の周辺機能を使用することが出来ません。
なので、まずはじめにSCI1の消費電力低減機能を解除します。

// SCI1
SYSTEM.PRCR.WORD = 0xA502;		// Release protect
MSTP(SCI1) = 0;					// Wake up SCI1
SYSTEM.PRCR.WORD = 0xA500;		// Protect

となります。MSTPCRレジスタに各モジュールの消費電力低減機能を解除するビットがあり、このビットがMSTP(***)というふうにiodefine.hでマクロされているので、これを使用します。
しかし、このMSTPCRレジスタにはアクセスロックがかかっているため、PRCRレジスタに0xA502を設定し、ロックを解除し、消費電力低減機能を解除した後は、再度ロックします。

2.ピン設定

// Set MPC
MPC.PWPR.BIT.B0WI = 0;			// Release protect
MPC.PWPR.BIT.PFSWE = 1;
MPC.P26PFS.BIT.PSEL = 0x0A;		// Set P26: TXD1
MPC.P30PFS.BIT.PSEL = 0x0A;		// Set P30: RXD1
MPC.PWPR.BIT.PFSWE = 0;		// Protect
MPC.PWPR.BIT.B0WI = 1;
PORT2.PMR.BIT.B6 = 1;			// P26: peripheral
PORT3.PMR.BIT.B0 = 1;			// P30: peripheral

次に、ピン設定をします。P26,P30をTXD1,RXD1に設定します。
MPC(マルチピンファンクション)レジスタにて各ピンに任意の周辺機能を付与することができます。
しかし、MPCレジスタはアクセスロックがかかっているため、PWPRレジスタを上コードのように設定し、アクセスロックを解除し、ピンに周辺機能の設定をし、再度ロックをします。
その後、PMR(ポートモードレジスタ)レジスタにてIOピンから周辺機能にピンの状態を変更し、ピンの設定を完了します。

3.SCIの初期化
RX63Nグループ、RX631グループ ユーザーズマニュアル ハードウェア編 Rev1.80(以下データシート)のp.1414の図35.8からSCIの初期化フローチャートの例(調歩同期式モード)を参考に、初期設定を行います。
f:id:CCWO:20160819153750p:plain

// SCI1 Settings
SCI1.SCR.BIT.TEIE = 0;			// Disable TEIE
SCI1.SCR.BIT.MPIE = 0;			// Normal Mode
SCI1.SCR.BIT.RE = 0;			// Disable RX
SCI1.SCR.BIT.TE = 0;			// Disable TX
SCI1.SCR.BIT.RIE = 0;			// Disable RXI, ERI
SCI1.SCR.BIT.TIE = 0;			// Disable TXI
SCI1.SCR.BIT.CKE = 0;			// built in baud rate
SCI1.SMR.BIT.CKS = 0;			// PCLK
SCI1.SMR.BIT.MP= 0;				// Disable multiple processor
SCI1.SMR.BIT.STOP = 0;			// 1 stop bit
SCI1.SMR.BIT.PM = 0;			// none parity
SCI1.SMR.BIT.CHR = 0;			// 8bit data length
SCI1.SMR.BIT.CM = 0;			// 調歩同期式
SCI1.BRR = 12;					// 115200bps
SCI1.SCR.BIT.RE = 1;			// Enable RX
SCI1.SCR.BIT.TE = 1;			// Enable TX

ここはデータシート通りかと思います。

4.ユーザー関数の定義
ここではprintfでリダイレクされてくる、cahrputとchargetを定義しておきます。
これでSCIの初期設定は完了です。

以下使用ソースコード
SCI.h

#ifndef SCI_H_
#define SCI_H_

void SCI1_initialize(void);

#endif /* SCI_H_ */

SCI.c

#include "iodefine.h"
#include "machine.h"
#include "SCI.h"

void SCI1_initialize(void){
	// SCI1
	SYSTEM.PRCR.WORD = 0xA502;		// Release protect
	MSTP(SCI1) = 0;					// Wake up SCI1
	SYSTEM.PRCR.WORD = 0xA500;		// Protect
	// Set MPC
	MPC.PWPR.BIT.B0WI = 0;			// Release protect
	MPC.PWPR.BIT.PFSWE = 1;
	MPC.P26PFS.BIT.PSEL = 0x0A;		// Set P26: TXD1
	MPC.P30PFS.BIT.PSEL = 0x0A;		// Set P30: RXD1
	MPC.PWPR.BIT.PFSWE = 0;			// Protect
	MPC.PWPR.BIT.B0WI = 1;
	PORT2.PMR.BIT.B6 = 1;			// P26: peripheral
	PORT3.PMR.BIT.B0 = 1;			// P30: peripheral
	// SCI1 Settings
	SCI1.SCR.BIT.TEIE = 0;			// Disable TEIE
	SCI1.SCR.BIT.MPIE = 0;			// Normal Mode
	SCI1.SCR.BIT.RE = 0;			// Disable RX
	SCI1.SCR.BIT.TE = 0;			// Disable TX
	SCI1.SCR.BIT.RIE = 0;			// Disable RXI, ERI
	SCI1.SCR.BIT.TIE = 0;			// Disable TXI
	SCI1.SCR.BIT.CKE = 0;			// built in baud rate
	SCI1.SMR.BIT.CKS = 0;			// PCLK
	SCI1.SMR.BIT.MP= 0;				// Disable multiple processor
	SCI1.SMR.BIT.STOP = 0;			// 1 stop bit
	SCI1.SMR.BIT.PM = 0;			// none parity
	SCI1.SMR.BIT.CHR = 0;			// 8bit data length
	SCI1.SMR.BIT.CM = 0;			// 調歩同期式
	SCI1.BRR = 12;					// 115200bps
	SCI1.SCR.BIT.RE = 1;			// Enable RX
	SCI1.SCR.BIT.TE = 1;			// Enable TX
}


void charput(char c)
{
	while(SCI1.SSR.BIT.TEND == 0);
	SCI1.TDR = c;
	SCI1.SSR.BIT.TEND = 0;
}

char charget(void){
	char data;

	data = SCI1.RDR;
	ICU.IR[VECT_SCI1_RXI1].BIT.IR = 0;

	return data;
}

lowsrc.h

/*Number of I/O Stream*/
#define IOSTREAM 3

lowsrc.c

#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include "lowsrc.h"

/* file number */
#define STDIN  0                    /* Standard input (console)        */
#define STDOUT 1                    /* Standard output (console)       */
#define STDERR 2                    /* Standard error output (console) */

#define FLMIN  0                    /* Minimum file number     */
#define _MOPENR	0x1
#define _MOPENW	0x2
#define _MOPENA	0x4
#define _MTRUNC	0x8
#define _MCREAT	0x10
#define _MBIN	0x20
#define _MEXCL	0x40
#define _MALBUF	0x40
#define _MALFIL	0x80
#define _MEOF	0x100
#define _MERR	0x200
#define _MLBF	0x400
#define _MNBF	0x800
#define _MREAD	0x1000
#define _MWRITE	0x2000
#define _MBYTE	0x4000
#define _MWIDE	0x8000
/* File Flags */
#define O_RDONLY 0x0001 /* Read only                                       */
#define O_WRONLY 0x0002 /* Write only                                      */
#define O_RDWR   0x0004 /* Both read and Write                             */
#define O_CREAT  0x0008 /* A file is created if it is not existed          */
#define O_TRUNC  0x0010 /* The file size is changed to 0 if it is existed. */
#define O_APPEND 0x0020 /* The position is set for next reading/writing    */
                        /* 0: Top of the file 1: End of file               */

/* Special character code */
#define CR 0x0d                     /* Carriage return */
#define LF 0x0a                     /* Line feed       */

extern const long _nfiles;     /* The number of files for input/output files */
char flmod[IOSTREAM];          /* The location for the mode of opened file.  */

unsigned char sml_buf[IOSTREAM];

#define FPATH_STDIN     "C:\\stdin"
#define FPATH_STDOUT    "C:\\stdout"
#define FPATH_STDERR    "C:\\stderr"

/* Output one character to standard output */
extern void charput(unsigned char);
/* Input one character from standard input */
extern unsigned char charget(void);

#include <stdio.h>
FILE *_Files[IOSTREAM]; // structure for FILE
char *env_list[] = {            // Array for environment variables(**environ)
    "ENV1=temp01",
    "ENV2=temp02",
    "ENV9=end",
    '\0'                        // Terminal for environment variables
};

char **environ = env_list;

/****************************************************************************/
/* _INIT_IOLIB                                                              */
/*  Initialize C library Functions, if necessary.                           */
/*  Define USES_SIMIO on Assembler Option.                                  */
/****************************************************************************/
void _INIT_IOLIB( void )
{
    /* A file for standard input/output is opened or created. Each FILE     */
    /* structure members are initialized by the library. Each _Buf member   */
    /* in it is re-set the end of buffer pointer.                           */

    /* Initializations of File Stream Table                                 */
    _Files[0] = stdin;
    _Files[1] = stdout;
    _Files[2] = stderr;

    /* Standard Input File                                                  */
    if( freopen( FPATH_STDIN, "r", stdin ) == NULL )
        stdin->_Mode = 0xffff;  /* Not allow the access if it fails to open */
    stdin->_Mode  = _MOPENR;            /* Read only attribute              */
    stdin->_Mode |= _MNBF;              /* Non-buffering for data           */
    stdin->_Bend = stdin->_Buf + 1;  /* Re-set pointer to the end of buffer */

    /* Standard Output File                                                 */
    if( freopen( FPATH_STDOUT, "w", stdout ) == NULL ) 
        stdout->_Mode = 0xffff; /* Not allow the access if it fails to open */
    stdout->_Mode |= _MNBF;             /* Non-buffering for data           */
    stdout->_Bend = stdout->_Buf + 1;/* Re-set pointer to the end of buffer */
    
    /* Standard Error File                                                  */
    if( freopen( FPATH_STDERR, "w", stderr ) == NULL )
        stderr->_Mode = 0xffff; /* Not allow the access if it fails to open */
    stderr->_Mode |= _MNBF;             /* Non-buffering for data           */
    stderr->_Bend = stderr->_Buf + 1;/* Re-set pointer to the end of buffer */
}

/****************************************************************************/
/* _CLOSEALL                                                                */
/****************************************************************************/
void _CLOSEALL( void )
{
    long i;

    for( i=0; i < _nfiles; i++ )
    {
        /* Checks if the file is opened or not                               */
        if( _Files[i]->_Mode & (_MOPENR | _MOPENW | _MOPENA ) )
        fclose( _Files[i] );    /* Closes the file                           */
    }
}

/**************************************************************************/
/*       open:file open                                                   */
/*          Return value:File number (Pass)                               */
/*                       -1          (Failure)                            */
/**************************************************************************/
long open(const char *name,                  /* File name                 */
     long  mode,                             /* Open mode                 */
     long  flg)                              /* Open flag                 */
{


    if( strcmp( name, FPATH_STDIN ) == 0 )      /* Standard Input file?   */
    {
        if( ( mode & O_RDONLY ) == 0 ) return -1;
        flmod[STDIN] = mode;
        return STDIN;
    }
    else if( strcmp( name, FPATH_STDOUT ) == 0 )/* Standard Output file?  */
    {
        if( ( mode & O_WRONLY ) == 0 ) return -1;
        flmod[STDOUT] = mode;
        return STDOUT;
    }
    else if(strcmp(name, FPATH_STDERR ) == 0 )  /* Standard Error file?   */
    {
        if( ( mode & O_WRONLY ) == 0 ) return -1;
        flmod[STDERR] = mode;
        return STDERR;
    }
    else return -1;                             /*Others                  */
}

long close( long fileno )
{
    return 1;
}

/**************************************************************************/
/* write:Data write                                                       */
/*  Return value:Number of write characters (Pass)                        */
/*               -1                         (Failure)                     */
/**************************************************************************/
long write(long  fileno,             /* File number                       */
      const unsigned char *buf,       /* The address of destination buffer */
      long  count)                   /* The number of chacter to write    */
{
    long    i;                          /* A variable for counter         */
    unsigned char    c;                 /* An output character            */

    /* Checking the mode of file , output each character                  */
    /* Checking the attribute for Write-Only, Read-Only or Read-Write     */
    if(flmod[fileno]&O_WRONLY || flmod[fileno]&O_RDWR)
    {
        if( fileno == STDIN ) return -1;            /* Standard Input     */
        else if( (fileno == STDOUT) || (fileno == STDERR) ) 
			                                    /* Standard Error/output   */
        {
            for( i = count; i > 0; --i )
            {
                c = *buf++;
                charput(c);
            }
            return count;        /*Return the number of written characters */
        }
        else return -1;                  /* Incorrect file number          */
    }
    else return -1;                      /* An error                       */
}

long read( long fileno, unsigned char *buf, long count )
{
	   long i;

       /* Checking the file mode with the file number, each character is input and stored the buffer */

       if((flmod[fileno]&_MOPENR) || (flmod[fileno]&O_RDWR)){
             for(i = count; i > 0; i--){
                   *buf = charget();
                   if(*buf==CR){              /* Replace the new line character */
                         *buf = LF;
                   }
                   buf++;
             }
             return count;
       }
       else {
             return -1;
       }
}

long lseek( long fileno, long offset, long base )
{
    return -1L;
}

#ifdef _REENTRANT
// For Reentrant Library (generated lbgrx with -reent option)
#define MALLOC_SEM   1  /* Semaphore No. for malloc */
#define STRTOK_SEM   2  /* Semaphore No. for strtok */
#define FILE_TBL_SEM 3  /* Semaphore No. for fopen  */
#define MBRLEN_SEM   4  /* Semaphore No. for mbrlen */
#define FPSWREG_SEM  5  /* Semaphore No. for FPSW register */
#define FILES_SEM    6  /* Semaphore No. for _Files */
#define SEMSIZE     26  /* FILES_SEM + _nfiles (assumed _nfiles=20) */

#define TRUE 1
#define FALSE 0
#define OK 1
#define NG 0
extern long *errno_addr(void);
extern long wait_sem(long);
extern long signal_sem(long);
static long sem_errno;
static int force_fail_signal_sem = FALSE;
static int semaphore[SEMSIZE];

/******************************************************************************/
/*                  errno_addr: Acquisition of errno address                  */
/*                        Return value: errno address                         */
/******************************************************************************/
long *errno_addr(void)
{
    /* Return the errno address of the current task */
    return (&sem_errno);
}

/******************************************************************************/
/*           wait_sem: Defines the specified numbers of semaphores            */
/*                       Return value: OK(=1) (Normal)                        */
/*                                     NG(=0) (Error)                         */
/******************************************************************************/
long wait_sem(long semnum) /* Semaphore ID */
{
    if((0 < semnum) && (semnum < SEMSIZE)) {
        if(semaphore[semnum] == FALSE) {
            semaphore[semnum] = TRUE;
            return(OK);
        }
    }
    return(NG);
}

/******************************************************************************/
/*          signal_sem: Releases the specified numbers of semaphores          */
/*                       Return value: OK(=1) (Normal)                        */
/*                                     NG(=0) (Error)                         */
/******************************************************************************/
long signal_sem(long semnum) /* Semaphore ID */
{
    if(!force_fail_signal_sem) {
        if((0 <= semnum) && (semnum < SEMSIZE)) {
            if( semaphore[semnum] == TRUE ) {
                semaphore[semnum] = FALSE;
                return(OK);
            }
        }
    }
    return(NG);
}
#endif

20160818の記事

Renesas RX631 I/O

つぎにI/Oの設定をしていきたいと思います。
(先にクロックの設定http://ccwo.hatenablog.jp/entry/2016/08/18/012106を行って下さい。)
I/O(Input/Output)とは、マイコンの入出力ピンのことを指します。
まずは出力設定をします。ピンよりHighを出力し、LEDを点灯させたいと思います。
Highを出力するピンは、PE1,PE0,PD7,PD6の4つを用います。
f:id:CCWO:20160818003210p:plain
回路図は上図のようになります。電流制限抵抗に1kΩを用いてLEDを駆動します。
ではこの4つのピンを設定していきましょう。
まず、hardware_setup.cにPin_initializeという関数を作り、以下のようにレジスタを設定します。

void Pin_initialize(void){
	PORTE.PDR.BIT.B1 = 1;	// LED0
	PORTE.PDR.BIT.B0 = 1;	// LED1
	PORTD.PDR.BIT.B7 = 1;	// LED2
	PORTD.PDR.BIT.B6 = 1;	// LED3
}

PORTレジスタのPDRを用いてピンを個別に出力設定に変更します。
今回のように一度しか呼ばないような場合はビット単位でレジスタにアクセスしても問題はないかと思いますが、高速で複数回呼ばれるような場合はレジスタ単位でレジスタにアクセスしましょう。
そして、この関数をHardwareSetup関数内で呼びます。

void HardwareSetup(void)
{
	Clock_initialize();
	Pin_initialize();
}

続いてメイン文にて、

#include "iodefine.h"

void main(void)
{
	PORTE.PODR.BIT.B1 = 1;    // LED0
	PORTE.PODR.BIT.B0 = 1;    // LED1
	PORTD.PODR.BIT.B7 = 1;    // LED2
	PORTD.PODR.BIT.B6 = 1;    // LED3
}

これで出力の設定ができました。
f:id:CCWO:20160818005752j:plain
LEDが4つ点灯しました。

つぎに、入力設定をします。
ピンにタクトスイッチをつなげボタンの入力を見たいと思います。
ボタンを入力するピンは、P25,P24,P23,P22の4つを用います。
f:id:CCWO:20160818010323p:plain
10kΩのプルアップ抵抗を用いて各ピンをプルアップしています。このため、ピンにはボタンが押されていないときにはHighが入力され、ボタンが押されているときはLowが入力されます。
ではさきほどの設定につづけてピンの設定をしていきます。

void Pin_initialize(void){
	PORTE.PDR.BIT.B1 = 1;	// LED0
	PORTE.PDR.BIT.B0 = 1;	// LED1
	PORTD.PDR.BIT.B7 = 1;	// LED2
	PORTD.PDR.BIT.B6 = 1;	// LED3
	PORT2.PDR.BIT.B5 = 0;	// BUTTON0
	PORT2.PDR.BIT.B4 = 0;	// BUTTON1
	PORT2.PDR.BIT.B3 = 0;	// BUTTON2
	PORT2.PDR.BIT.B2 = 0;	// BUTTON3	
}

メイン文ではまず、ボタンが押されたらLEDが光るように処理してみましょう。

#include "iodefine.h"

void main(void)
{
	while(1){
		if(!PORT2.PIDR.BIT.B2) PORTE.PODR.BIT.B1 = 1;
		else PORTE.PODR.BIT.B1 = 0;
		if(!PORT2.PIDR.BIT.B3) PORTE.PODR.BIT.B0 = 1;
		else PORTE.PODR.BIT.B0 = 0;
		if(!PORT2.PIDR.BIT.B4) PORTD.PODR.BIT.B7 = 1;
		else PORTD.PODR.BIT.B7 = 0;
		if(!PORT2.PIDR.BIT.B5) PORTD.PODR.BIT.B6 = 1;
		else PORTD.PODR.BIT.B6 = 0;
	}
}

これで入力の設定ができました。
ボタンに合わせてLEDが点灯すれば成功です!
現状ではif文を用いて処理していますが、レジスタ間を直接操作する方法のほうが効率的かと思います。
また、このままではLEDやボタンが扱いにくいので、

#define PORTE.PODR.BIT.B1 LED0
#define PORT2.PIDR.BIT.B2 BUTTON0

などでデファインや変数に入れておくなどすると操作が簡単かと思います。

20160818の記事

Renesas RX631 クロック

ここではクロックの設定をしていきます。
ただ、RX631のクロック設定は非常に難しく、Renesas公式HPにて公開されている「RXショートセミナー」という資料を参考に、クロック設定を行いたいと思います。
といっても、参考資料を少し改変したものなります。
hardware_setup.cにClock_initialize関数を作ります。

#include "iodefine.h"
#include "machine.h"

void Clock_initialize(void);

void HardwareSetup(void)
{
    Clock_initialize();
}

void Clock_initialize(void){
    int i;
    SYSTEM.PRCR.WORD = 0xA503; // Release protect
    SYSTEM.MOSCWTCR.BYTE = 0x0D; // 131072cyc wait stability term
    // Enable main clock
    SYSTEM.MOSCCR.BYTE = 0x00;
    while(SYSTEM.MOSCCR.BYTE == 0x01);
    SYSTEM.PLLCR.WORD = 0x0F00; // 12Mhz/1*16=192Mhz
    SYSTEM.PLLCR2.BYTE = 0x00; // Wake up PLL circuit
    SYSTEM.PLLWTCR.BYTE = 0x0E; // 2097152cyc wait stability term
    for( i = 0; i <636; i++ ) nop(); // wait 22.1053ms 22.1053ms*143.75khz(LOCO)/5cyc=636 nop()=5cyc
    // FCLK :192/4=48Mhz
    // ICLK: 192/2=96Mhz
    // BCLK: 192/64=3Mhz & disable
    // PCLKA: 192/2=96Mhz
    // PCLKB: 192/4=48Mhz
    // IECLK: 192/4=48Mhz
    // UCLK: 192/4=48Mhz

    // Enable PLL circuit
    SYSTEM.SCKCR.LONG = 0x21C61211;
    SYSTEM.SCKCR2.WORD = 0x0032;
    SYSTEM.SCKCR3.WORD = 0x0400;

    // Stop Unused Clock Source
    SYSTEM.LOCOCR.BYTE = 0x01; // Stop LOCO
    SYSTEM.SOSCCR.BYTE = 0x01; // Stop sub clock source
    while( SYSTEM.SOSCCR.BYTE != 0x01) // wait writing
    ;
    RTC.RCR3.BYTE = 0x0C; // Disable clock in
    while( RTC.RCR3.BYTE != 0x0C ) // wait writing
    ;
    SYSTEM.PRCR.WORD = 0xA500; // Protect
}

ここで、machine.hはClock_initialize関数内のnop関数を呼ぶために必要なヘッダファイルです。
nop関数は1clockを使った空命令になります。
また、サブクロックは停止させています。

  • FCLK :192/4=48Mhz
  • ICLK: 192/2=96Mhz
  • BCLK: 192/64=3Mhz & disable
  • PCLKA: 192/2=96Mhz
  • PCLKB: 192/4=48Mhz
  • IECLK: 192/4=48Mhz
  • UCLK: 192/4=48Mhz

12MHzの水晶発振子をメインクロックに入力し、周辺モジュールを上記クロックでクロック設定しました。
クロック設定はこれで完了です。RX621に比べ非常にややこしなくなっており、現状自分で書くのは不可能だったので、資料を参考にしました。

20160818の記事