このアプリケーションでは, LED を所望の周期で点滅させます.そのため,点滅周期の基本となるクロックの状態を調べておきます.
STM8S マイコン内部のペリフェラルに供給されるクロックは,マスタ・クロック(Master clock)と呼ばれ,いくつかのクロック源から選択することができます.
リセット直後は,高速内部 RC 発振器(High Speed Internal RC oscillator: HSI)が選択されます. HSI の発振周波数(fHSI)は, 16MHz とされています. HSI には,専用分周器があり,リセット後は 8 分周に設定されています.このため,リセット後のマスタ・クロック周波数(fMASTER)は, fHSI ÷ 8 = 2MHz となります.
タイマの分周比を決めようLED の点滅には, TIM3 の PWM(Pulse Width Modulation)出力機能をそのまま使います.すると, TIM3 のチャネル2に接続されている LED は,タイマ周期にしたがって点滅します.
点滅周期,すなわちタイマの周期は,1秒とします. fMASTER が 2MHz でしたから,タイマで必要な分周比は, 200万 ということになります.16ビットのタイマ・カウンタを目一杯使うため,タイマ・カウンタの周期を62500とし,プリスケーラを32分周に設定して,全体の分周比を 200万 としました.
ソース・コードを書こう
アプリケーションの方針で決めたように,タイマ TIM3 のチャネル2から, PWM 波形を出力させるだけで,アプリケーションはできそうです.そこで,マイコンのレジスタにひたすら値を書き込むプログラムを作成しました.
//**************************************
//
// main.c :
//
// Copyright (c) 2010 noritan.org
//
//**************************************
//======================================
// Type declaration
//======================================
typedef unsigned char byte;
typedef unsigned int word;
//======================================
// Register map definition.
//======================================
volatile byte TIM3_CR1 @ 0x005320;
volatile byte TIM3_CCMR2 @ 0x005326;
volatile byte TIM3_CCER1 @ 0x005327;
volatile byte TIM3_PSCR @ 0x00532A;
volatile byte TIM3_ARRH @ 0x00532B;
volatile byte TIM3_ARRL @ 0x00532C;
volatile byte TIM3_CCR2H @ 0x00532F;
volatile byte TIM3_CCR2L @ 0x005330;
//======================================
// Constant declaration
//======================================
#define PERIOD (62500) // timer counter period
#define DUTY (PERIOD/2) // PWM duty value
//======================================
// Main procedure
//======================================
main()
{
TIM3_PSCR = 5; // 1/32 prescaler
TIM3_ARRH = (PERIOD-1) >> 8; // set period MSB
TIM3_ARRL = (PERIOD-1); // set period LSB
TIM3_CCMR2 = 0b01100000; // Set TIM3CH2 as PWM
TIM3_CCER1 = 0b00110000; // Enable TIM3CH2 output
TIM3_CCR2H = DUTY >> 8; // Set PWM duty MSB
TIM3_CCR2L = DUTY; // Set PWM duty MSB
TIM3_CR1 = 0b00000001; // Start timer
while (1); // loop forever
}
まあ,これでも動作することはするのですが,まったくエレガントではありません.レジスタの宣言ぐらいは,再利用できるようにヘッダ・ファイルにまとめて欲しいものです.というわけで,ほかの方法を探します.
このプログラムは,最初の頃,
TIM3_CCRH/TIM3_CCRLレジスタを単なる16ビットのレジスタとして定義し,16ビットの変数で書き込んでいました.ところが,どうもうまく働きませんでした.原因は,16ビットのレジスタをアクセスする場合,MSBバイトをアクセスしてからLSBバイトをアクセスするという順にアクセスしなくてはならないという制約によるものです.16ビットのレジスタとして宣言した場合,16ビットのXレジスタによるアクセスを行うプログラムが生成されましたが,これでは,順序が保証されなかったようです.
しかたがないので,8ビットずつのアクセスを行うプログラムを書きました.こういった経緯から,冗長なプログラムになってしまいましたが,これもエレガントではない理由のひとつになっています.
次回は,エレガントなプログラムを作成するための準備をします.

