RX62Nでは,マイコンが立ち上がったとき自動的にHardwareSetup関数が呼び出されるようになっています.そのとき,マイコンの動作周波数や,周辺機能に与えられるクロックの周波数などを設定するプログラムを書きます.このプログラムは,以降行う演習ではすべて実行しますので,よく理解するようにしてください.なお,利便性を考え,下記プログラムを簡単に新規プロジェクトに追加できるようにしました.詳しくはこちらをご覧ください.
- マイコンの立ち上がりからmain関数が呼ばれるまで
RX62Nのプロジェクトを作成すると自動的にいくつかのファイルが生成されます.そのうちの一つ「resetprg.c」の中にあるPowerOn_Reset_PC関数を下に示します.大変難しい内容が書かれているように思われますが,大事な点は,34行目にあるmain関数を呼び出しているところです.RX62Nでは,main関数が呼ばれる前にPowerON_Reset_PC関数が呼ばれており,その中でmain関数を呼んでいるのです.
void PowerON_Reset_PC(void){ set_intb(__sectop("C$VECT")); #ifdef __ROZ // Initialize FPSW #define _ROUND 0x00000001 // Let FPSW RMbits=01 (round to zero) #else #define _ROUND 0x00000000 // Let FPSW RMbits=00 (round to nearest) #endif #ifdef __DOFF #define _DENOM 0x00000100 // Let FPSW DNbit=1 (denormal as zero) #else #define _DENOM 0x00000000 // Let FPSW DNbit=0 (denormal as is) #endif set_fpsw(FPSW_init | _ROUND | _DENOM); _INITSCT(); // _INIT_IOLIB(); // Use SIM I/O // errno=0; // Remove the comment when you use errno // srand((_UINT)1); // Remove the comment when you use rand() // _s1ptr=NULL; // Remove the comment when you use strtok() // HardwareSetup(); // Use Hardware Setup nop(); _CALL_INIT(); // Use global class object set_psw(PSW_init); // Set Ubit & Ibit for PSW // chg_pmusr(); // Remove the comment when you need to change PSW PMbit (SuperVisor->User) main(); // _CLOSEALL(); // Use SIM I/O ; ; _CALL_END(); // Use global class object brk(); }
さて,main関数よりも前の25行目に,「HardwareSetup関数」を呼び出す箇所がコメントアウトされています.このコメントアウトを外してHardwareSetup関数を呼ぶようにします.そうすれば,main関数よりも前に処理が行えます.そして,HardwareSetup関数内で動作周波数などを設定するようにします.25行目のコメントアウトを外し,HardwareSetup関数を呼ばれるようにした後,プロジェクトに「hwsetup.cpp」ファイルを追加します.下図のようにプロジェクト・ツリー上にある「ファイル」と書かれた個所で右クリックをし,追加⇒既存のファイルを追加を選択します.
次に,下のようにファイルの種類をC++ソース・ファイルに変更し,hwsetup.cppを選びます.これでHardwareSetup関数を含むhwsetup.cppがプロジェクトに追加されます. - HardwareSetup関数の改造
hwsetup.cppを開くとHardwareSetup関数を見ることができるはずです.初期状態では,関数内がすべてコメントアウトされているため,何も実行されません.これを下に示すプログラムにしてください.Frequencyクラスについては次章で説明します.
void HardwareSetup(void){ /* 周波数の初期設定 */ misc::Frequency::getInstance()->setDefaultFrequency(); }
- Frequencyクラスの作成
Frequencyクラスでは,周波数に関係する設定および周波数の参照が行えるようにプログラムを書きましょう.このクラスと関係のあるクラスをクラス図を下に示します.
Frequencyクラスは,シングルトンになっており,唯一のオブジェクトとなっております.このため,使用するにはgetInstance関数よりオブジェクトを取得し,そこから各メンバ関数を呼び出すようになっています.また,かなり多くのメンバ関数を持ったクラスとなっており,メンバ関数を分類すると,コンストラクタやデストラクタ,下に示すクロックのsetterおよびgetter,各種クロックをマイコンの端子から出力するか設定するためのものに分けられます.
・周辺機能クロック
・システムクロック
・バスクロック
・USBクロック
・サブクロック
さて,この中で最も重要なメンバ関数は「setDefaultFrequency関数」です.この関数を呼び出しますと,各クロックは次のように設定されます.
・周辺機能クロック(PCLK) : 48[MHz]
・システムクロック(ICLK) : 96[MHz]
・外部バスクロック(BCLK) : 96[MHz]
・SDRAMクロック(SDCLK) : 96[MHz](ただしこの周波数はBCLKと同じです)
・USBクロック(UCLK) : 48[MHz](ただしこの周波数は固定のため,setDefaultFrequency関数では特に何も書いていません)
加えてsetDefaultFrequency関数では,外部バスクロックおよびSDRAMクロックをマイコンの端子から出力しないようにし,RTC専用クロックを停止させています.以上のような設定をするとき,SYSTEM構造体で定義されたレジスタを使います.詳しくはRX62Nハードウェアマニュアル第8章2節をご覧ください.下にFrequency.cppを示します.
#include <iodefine.h> #include <stdio.h> #include "Frequency.hpp" namespace misc { const unsigned char Frequency::_SOURCE_CLK = 12; const unsigned char Frequency::_DEFAULT_PCLK = 48; const unsigned char Frequency::_DEFAULT_ICLK = 96; const unsigned char Frequency::_DEFAULT_BCLK = 96; const unsigned char Frequency::_UCLK = 48; const unsigned short Frequency::_SUBCLK = 32768; Frequency* Frequency::_singleton = NULL; void Frequency::_initialize(){ } Frequency* Frequency::getInstance(){ if(_singleton == NULL) { _singleton = new Frequency(); _singleton->_initialize(); } return _singleton; } Frequency::Frequency() : _peripheralClock(_DEFAULT_PCLK), _busClock(_DEFAULT_BCLK), _internalClock(_DEFAULT_ICLK), _peripheralClockMultiply(PCLK4), _busClockMultiply(BCLK8), _internalClockMultiply(ICLK8), _isOutputSubClock(false), _isOutputBusClockPin(false), _isOutputSdramClockPin(false), _isOutputSourceClockFromBusClockPin(true){ } Frequency::Frequency(const Frequency &src){ _peripheralClock = src._peripheralClock; _busClock = src._busClock; _internalClock = src._internalClock; _peripheralClockMultiply = src._peripheralClockMultiply; _busClockMultiply = src._busClockMultiply; _internalClockMultiply = src._internalClockMultiply; _isOutputSubClock = src._isOutputSubClock; _isOutputBusClockPin = src._isOutputBusClockPin; _isOutputSdramClockPin = src._isOutputSdramClockPin; _isOutputSourceClockFromBusClockPin = src._isOutputSourceClockFromBusClockPin; _singleton = src._singleton; } Frequency &Frequency::operator=(const Frequency &src){ _peripheralClock = src._peripheralClock; _busClock = src._busClock; _internalClock = src._internalClock; _peripheralClockMultiply = src._peripheralClockMultiply; _busClockMultiply = src._busClockMultiply; _internalClockMultiply = src._internalClockMultiply; _isOutputSubClock = src._isOutputSubClock; _isOutputBusClockPin = src._isOutputBusClockPin; _isOutputSdramClockPin = src._isOutputSdramClockPin; _isOutputSourceClockFromBusClockPin = src._isOutputSourceClockFromBusClockPin; _singleton = src._singleton; return *this; } Frequency::~Frequency(){ delete _singleton; } void Frequency::setDefaultFrequency(){ /* 周辺モジュールクロック:48[MHz] */ SYSTEM.SCKCR.BIT.PCK = 1; /* システムクロック:96[MHz] */ SYSTEM.SCKCR.BIT.ICK = 0; /* 外部バスクロック:96[MHz] */ SYSTEM.SCKCR.BIT.BCK = 0; /* 外部バスクロック出力ピンからの出力を停止させておく */ SYSTEM.SCKCR.BIT.PSTOP1 = 1; /* SDRAMクロック出力ピンからの出力を停止させておく */ SYSTEM.SCKCR.BIT.PSTOP0 = 1; /* RTC専用クロックを停止させておく */ SYSTEM.SUBOSCCR.BIT.SUBSTOP = 1; /* 外部バスクロック出力ピンからの出力を源クロックとしておく */ /* ただし,外部バスクロックを出力しないようになっているので */ /* 実質的に意味は無い */ SYSTEM.BCKCR.BIT.BCLKDIV = 0; } unsigned char Frequency::getPeripheralClock(){ return _peripheralClock; } unsigned char Frequency::getInternalClock(){ return _internalClock; } unsigned char Frequency::getBusClock(){ return _busClock; } unsigned char Frequency::getUsbClock(){ return _UCLK; } unsigned short Frequency::getSubClock(){ return _SUBCLK; } bool Frequency::isOutputSubClock(){ return _isOutputSubClock; } bool Frequency::isOutputBusClockPin(){ return _isOutputBusClockPin; } bool Frequency::isOutputSdramClockPin(){ return _isOutputSdramClockPin; } bool Frequency::isOutputSourceClockFromBusClockPin(){ return _isOutputSourceClockFromBusClockPin; } void Frequency::setPeripheralClock(PeripheralClock clock){ _peripheralClockMultiply = clock; SYSTEM.SCKCR.BIT.PCK = clock; _peripheralClock = (_SOURCE_CLK << (3-clock)); } void Frequency::setInternalClock(InternalClock clock){ _internalClockMultiply = clock; SYSTEM.SCKCR.BIT.ICK= clock; _internalClock = (_SOURCE_CLK << (3-clock)); } void Frequency::setBusClock(BusClock clock){ _busClockMultiply = clock; SYSTEM.SCKCR.BIT.BCK = clock; _busClock = (_SOURCE_CLK << (3-clock)); } void Frequency::setEnableOutputSubClock(bool is_output_sub_clock){ _isOutputSubClock = is_output_sub_clock; SYSTEM.SUBOSCCR.BIT.SUBSTOP = ((is_output_sub_clock == true) ? 0 : 1); } void Frequency::setEnableBusClockPin(bool is_output_bus_clock_pin){ _isOutputBusClockPin = is_output_bus_clock_pin; SYSTEM.SCKCR.BIT.PSTOP1 = ((is_output_bus_clock_pin == true) ? 0 : 1); } void Frequency::setEnableSdramClockPin(bool is_output_sdram_clock_pin){ _isOutputSdramClockPin = is_output_sdram_clock_pin; SYSTEM.SCKCR.BIT.PSTOP0 = ((is_output_sdram_clock_pin == true) ? 0 : 1); } void Frequency::setEnableSourceClockFromBusClockPin(bool is_output_source_clock_from_bus_clock_pin){ _isOutputSourceClockFromBusClockPin = is_output_source_clock_from_bus_clock_pin; SYSTEM.BCKCR.BIT.BCLKDIV = ((is_output_source_clock_from_bus_clock_pin == true) ? 0 : 1); } } // namespace misc
続いて,Frequency.hppを掲載します.#ifndef MISC_FREQUENCY_H #define MISC_FREQUENCY_H #include <iodefine.h> #include "PeripheralClock.hpp" #include "BusClock.hpp" #include "InternalClock.hpp" namespace misc { /** * 周波数の定義 * @author 芦田和毅 */ class Frequency { private: /** * 源周波数[MHz] */ static const unsigned char _SOURCE_CLK; /** * デフォルトの周辺モジュールクロック[MHz] */ static const unsigned char _DEFAULT_PCLK; /** * デフォルトの内部バスクロック[MHz] */ static const unsigned char _DEFAULT_ICLK; /** * デフォルトの外部バスクロック[MHz] */ static const unsigned char _DEFAULT_BCLK; /** * デフォルトのUSB専用クロック[MHz] */ static const unsigned char _UCLK; /** * RTC専用クロック[Hz] */ static const unsigned short _SUBCLK; /** * Singleton用インスタンス */ static Frequency* _singleton; /** * 周辺モジュールクロック[MHz] */ unsigned char _peripheralClock; /** * 外部バスクロック[MHz] */ unsigned char _busClock; /** * 内部バスクロック[MHz] */ unsigned char _internalClock; /** * サブクロックを出力するか */ bool _isOutputSubClock; /** * 外部バスクロックをBCLK端子から出力するか */ bool _isOutputBusClockPin; /** * 外部バスクロックをSDCLK端子から出力するか */ bool _isOutputSdramClockPin; /** * 外部バスクロックを出力するピンから源クロックを出力するか */ bool _isOutputSourceClockFromBusClockPin; /** * 源周波数に対して周辺機能クロックの周波数が何逓倍か */ PeripheralClock _peripheralClockMultiply; /** * 源周波数に対して外部バスクロックの周波数が何逓倍か */ BusClock _busClockMultiply; /** * 源周波数に対して内部バスクロックの周波数が何逓倍か */ InternalClock _internalClockMultiply; private: /** * 初期化する */ void _initialize(); /** * デフォルトコンストラクタ */ Frequency(); /** * コピーコンストラクタ * @param[in] src コピー元 */ Frequency(const Frequency &src); /** * 代入演算子 * @param[in] src コピー元 */ Frequency &operator=(const Frequency &src); public: /** * インスタンスを取得する<br> * Singletonのための関数 * @return Singleton化されたインスタンス */ static Frequency* getInstance(); /** * デストラクタ */ virtual ~Frequency(); /** * デフォルトの周波数を設定する */ void setDefaultFrequency(); /** * 周辺機能クロックの周波数を得る * @return 周辺機能クロックの周波数[MHz] */ unsigned char getPeripheralClock(); /** * 内部バスクロックの周波数を得る * @return 内部バスクロックの周波数 */ unsigned char getInternalClock(); /** * バスクロックの周波数を得る * @return バスクロックの周波数 */ unsigned char getBusClock(); /** * USB用クロックの周波数を得る * @return USB用クロックの周波数[MHz] */ unsigned char getUsbClock(); /** * RTC用クロックの周波数を得る * @return RTC用クロックの周波数[Hz] */ unsigned short getSubClock(); /** * サブクロックを出力するか得る * @return サブクロックを出力するか */ bool isOutputSubClock(); /** * 外部バスクロックをBCLK端子から出力するか得る * @return 外部バスクロックをBCLK端子から出力するか */ bool isOutputBusClockPin(); /** * 外部バスクロックをSDCLK端子から出力するか得る * @return 外部バスクロックをSDCLK端子から出力するか */ bool isOutputSdramClockPin(); /** * 外部バスクロックを出力するピンから源クロックを出力するか得る * @return 外部バスクロックを出力するピンから源クロックを出力するか */ bool isOutputSourceClockFromBusClockPin(); /** * 周辺機能用クロックの周波数を設定する * @param[in] clock 周辺機能用クロック */ void setPeripheralClock(PeripheralClock clock); /** * 内部バスクロックの周波数を設定する * @param[in] clock 内部バスクロック */ void setInternalClock(InternalClock clock); /** * 外部バスクロックの周波数を設定する * @param[in] clock 外部バスクロック */ void setBusClock(BusClock clock); /** * RTC用クロックを出力するか設定する * @param[in] is_output_sub_clock RTC用クロックを出力するか */ void setEnableOutputSubClock(bool is_output_sub_clock); /** * 外部バスクロック用ピンから出力をするか設定する * @param[in] is_output_bus_clock_pin 外部バスクロック用ピンから出力をするか */ void setEnableBusClockPin(bool is_output_bus_clock_pin); /** * SDRAM用ピンから出力をするか設定する * @param[in] is_output_sdram_clock_pin SDRAM用ピンから出力をするか */ void setEnableSdramClockPin(bool is_output_sdram_clock_pin); /** * 外部バスクロック用ピンから出力する信号を源クロックにするか設定する * @param[in] is_output_source_clock_from_bus_clock_pin 外部バスクロック用ピンから出力する信号を源クロックにするか */ void setEnableSourceClockFromBusClockPin(bool is_output_source_clock_from_bus_clock_pin); }; } // namespace misc #endif
#ifndef MISC_BUS_CLOCK_H #define MISC_BUS_CLOCK_H #include <iodefine.h> namespace misc { /** * 外部バスクロックの周波数を定義する列挙型 * @author 芦田和毅 */ typedef enum { /** * 源周波数を8逓倍したものを外部バスクロックの周波数とする */ BCLK8 = 0, /** * 源周波数を4逓倍したものを外部バスクロックの周波数とする */ BCLK4 = 1, /** * 源周波数を2逓倍したものを外部バスクロックの周波数とする */ BCLK2 = 2, /** * 源周波数を1逓倍したものを外部バスクロックの周波数とする */ BCLK1 = 3 } BusClock; } // namespace misc #endif
#ifndef MISC_INTERNAL_CLOCK_H #define MISC_INTERNAL_CLOCK_H #include <iodefine.h> namespace misc { /** * 内部バスクロックの周波数を定義する列挙型 * @author 芦田和毅 */ typedef enum { /** * 源周波数を8逓倍したものを内部バスクロックの周波数とする */ ICLK8 = 0, /** * 源周波数を4逓倍したものを内部バスクロックの周波数とする */ ICLK4 = 1, /** * 源周波数を2逓倍したものを内部バスクロックの周波数とする */ ICLK2 = 2, /** * 源周波数を1逓倍したものを内部バスクロックの周波数とする */ ICLK1 = 3 } InternalClock; } // namespace misc #endif
#ifndef MISC_PERIPHERAL_CLOCK_H #define MISC_PERIPHERAL_CLOCK_H #include <iodefine.h> namespace misc { /** * 周辺機能クロックの周波数を定義する列挙型 * @author 芦田和毅 */ typedef enum { /** * 源周波数を8逓倍したものを周辺クロックの周波数とする */ PCLK8 = 0, /** * 源周波数を4逓倍したものを周辺クロックの周波数とする */ PCLK4 = 1, /** * 源周波数を2逓倍したものを周辺クロックの周波数とする */ PCLK2 = 2, /** * 源周波数を1逓倍したものを周辺クロックの周波数とする */ PCLK1 = 3 } PeripheralClock; } // namespace misc #endif
以上,4個のヘッダファイルと1個のソースファイルができましたらすべてプロジェクトに追加してください.最後に,繰り返しになりますが,これらのヘッダおよびソースファイルはどのプロジェクトでも常に使われます.新しいプロジェクトを作成しましたら,上記プログラムを追加する方法をこちらに示しておきます.