STM8SDiscovary
mugen2010では、STMicoElectoronicsの
STM8SDiscovaryを使うことを考えていました。
このマイコン基板は安価かつソフトウエアと
ハードウエアのデバッガがUSBで使えるのが
魅力です。
大阪に移動するとき、荷物は極力減らしたいので
USBでファームウエアをダウンロードできるのは
ケーブルの用意だけで都合がよかったのです。
開発環境のダウンロードとインストールが面倒
なので、放置状態でした。2012年の大型連休を
利用して、環境を整備しました。
移動メカテストの環境として使えるかを調べたい
ので、重い腰を上げて作業にかかります。
ダウンロードに3時間、インストールに40分
ライブラリの環境整備に20分ほどかかって
環境が完成しました。
ボード上のLEDを点滅させるファームウエアを
入れた後、通信やモータ制御のためのI/Oボード
を半田付けです。
通信には、RS232Cを利用しますが、MAX232Cの
手持ちがなかったので、74HC04を使った簡易
インタフェースを入れました。
このインタフェースボードの回路図は以下です。
動作テストに、2つのLEDを接続して、点滅周期を
2秒、3秒にしてみました。単純な処理ですが
タイマー割込みとRTOS(Real Time Operating System)を
使ってみます。RTOSには、USO2を使います。
Raisonance CとSTMicroのライブラリを利用して
作成したファームウエアのソースコードは、以下。
#include "stm8s.h"
#define OFF 0
#define ON OFF+1
#define NO 0
#define YES NO+1
#define CLKF 16000000
#define ARR4 256
/* define data type */
typedef unsigned char UBYTE ;
typedef signed char SBYTE ;
typedef unsigned short UWORD ;
typedef signed short SWORD ;
typedef unsigned long ULONG ;
typedef struct {
void (*tsk)(void);
UWORD wcount ;
} TCBP ;
#define TSK_ID_MAX 4
#define TSK_ID0 0
#define TSK_ID1 1
#define TSK_ID2 2
#define TSK_ID3 3
TCBP tcb[TSK_ID_MAX];
#define TTS_SUSPEND 0
#define TTS_WAIT TTS_SUSPEND+1
#define TTS_READY TTS_SUSPEND+2
UWORD ready ;
UWORD suspend;
UWORD waitq ;
UBYTE run_tsk;
UBYTE os_cnt ;
#define TSK0_INTERVAL 5
#define TSK1_INTERVAL 200
#define TSK2_INTERVAL 300
#define TSK3_INTERVAL 100
/*------------------*/
/* system call body */
/*------------------*/
void init_os(void)
{
ready = 0 ;
suspend = 0 ;
waitq = 0 ;
}
void cre_tsk(UBYTE tid,void (*tsk)(void))
{
tcb[tid].tsk = tsk;
tcb[tid].wcount = 0;
}
void sta_tsk(UBYTE tid,UBYTE sta)
{
UWORD tmp ;
tmp = (1 << tid);
if ( sta == TTS_READY ) { ready |= tmp; }
if ( sta == TTS_SUSPEND ) { suspend |= tmp; }
if ( sta == TTS_WAIT ) { waitq |= tmp; }
}
void rsm_tsk(UBYTE tid)
{
UWORD tmp ;
tmp = (1 << tid);
ready |= tmp;
suspend &= ~tmp;
waitq &= ~tmp;
}
void sus_tsk(UBYTE tid)
{
UWORD tmp ;
tmp = (1 << tid);
ready &= ~tmp;
suspend |= tmp;
waitq &= ~tmp;
}
void slp_tsk(void)
{
sus_tsk(run_tsk);
}
void wai_tsk(UWORD x)
{
UWORD tmp ;
tmp = (1 << run_tsk);
ready &= ~tmp;
suspend &= ~tmp;
waitq |= tmp;
tcb[run_tsk].wcount = x ;
}
UBYTE is_tsk_ready(UBYTE tid)
{
return( (ready >> tid) & 1 ) ;
}
void timer_handler(void)
{
UWORD xtmp ;
UBYTE loop ;
xtmp = waitq ;
for ( loop = 0 ; loop < TSK_ID_MAX ; loop++ ) {
if ( xtmp & 1 ) {
tcb[loop].wcount-- ;
if ( tcb[loop].wcount == 0 ) { rsm_tsk(loop); }
}
xtmp >>= 1 ;
}
}
#define IDLE_STATE 0
#define RUN_STATE 1
UBYTE istate ;
UBYTE itrg ;
/*------------------------*/
/* task function protoype */
/*------------------------*/
void tsk0_proc(void)
{
UBYTE tmp ;
/* get switch state and inverse */
tmp = (GPIO_ReadInputPin(GPIOE,GPIO_PIN_1) ^ 1);
/* shift register */
itrg <<= 1 ;
itrg |= tmp ;
/* masking */
itrg &= 7 ;
/* judge */
if ( itrg == 0x03 || itrg == 0x01 ) {
if ( istate == RUN_STATE ) {
/* change state */
istate = IDLE_STATE ;
/* suspend */
sus_tsk(TSK_ID1);
sus_tsk(TSK_ID2);
/* turn off LEDs */
GPIO_WriteHigh(GPIOE,GPIO_PIN_2 | GPIO_PIN_3);
} else {
/* change state */
istate = RUN_STATE ;
/* suspend */
rsm_tsk(TSK_ID1);
rsm_tsk(TSK_ID2);
}
}
/* 50ms = 5 * 10ms */
wai_tsk(TSK0_INTERVAL);
}
void tsk1_proc(void)
{
/* invert */
GPIO_WriteReverse(GPIOE,GPIO_PIN_2);
/* 2 * 1000 ms = 200 * 10ms */
wai_tsk(TSK1_INTERVAL);
}
void tsk2_proc(void)
{
/* invert */
GPIO_WriteReverse(GPIOE,GPIO_PIN_3);
/* 3 * 1000 ms = 300 * 10ms */
wai_tsk(TSK2_INTERVAL);
}
void tsk3_proc(void)
{
/* invert */
GPIO_WriteReverse(GPIOD,GPIO_PIN_0);
/* 1 * 1000 ms = 100 * 10ms */
wai_tsk(TSK3_INTERVAL);
}
void main(void)
{
TCBP pcur_tsk ;
/* initialize */
{
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO,CLK_SOURCE_HSE,DISABLE,CLK_CURRENTCLOCKSTATE_DISABLE);
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1 );
CLK_SYSCLKConfig( CLK_PRESCALER_CPUDIV1 );
/* set I/O */
GPIO_Init(GPIOE,GPIO_PIN_1,GPIO_MODE_IN_PU_NO_IT);
GPIO_Init(GPIOE,GPIO_PIN_2 | GPIO_PIN_3,GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_WriteHigh(GPIOE,GPIO_PIN_2 | GPIO_PIN_3);
/* (debug) set I/O */
GPIO_Init(GPIOD,GPIO_PIN_0,GPIO_MODE_OUT_PP_HIGH_FAST);
/* initialize timer 4 */
TIM4_DeInit();
/* initialize counter 250 */
TIM4_SetCounter(6);
/* 16MHz / 128 / 250 = 2ms */
TIM4_TimeBaseInit(TIM4_PRESCALER_128,ARR4-1);
/* configure */
TIM4_ITConfig(TIM4_IT_UPDATE,ENABLE);
/* enable timer 4 */
TIM4_Cmd(ENABLE);
}
/* initialize monitor */
init_os();
/* regist task */
cre_tsk(TSK_ID0,tsk0_proc);
cre_tsk(TSK_ID1,tsk1_proc);
cre_tsk(TSK_ID2,tsk2_proc);
cre_tsk(TSK_ID3,tsk3_proc);
/* initialize task states */
sta_tsk(TSK_ID0,TTS_READY);
sta_tsk(TSK_ID1,TTS_SUSPEND);
sta_tsk(TSK_ID2,TTS_SUSPEND);
sta_tsk(TSK_ID3,TTS_READY);
istate = IDLE_STATE ;
os_cnt = 0 ;
/* enable interruption */
enableInterrupts();
run_tsk = TSK_ID0 ;
/* endless loop */
while ( ON ) {
/* task dispacher */
pcur_tsk = tcb[run_tsk] ;
if ( is_tsk_ready( run_tsk ) == YES ) {
(*(pcur_tsk.tsk))();
}
run_tsk++;
if ( run_tsk == TSK_ID_MAX ) {
run_tsk = TSK_ID0 ;
}
}
}
void TIM4_interrupt(void) interrupt 23
{
/* clear interrupt flag */
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
/* initialize counter 250 */
TIM4_SetCounter(6);
/* counter increment */
os_cnt++ ;
/* judge */
if ( os_cnt == 5 ) {
/* clear counter */
os_cnt = 0 ;
/* update */
timer_handler();
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(UBYTE* file,ULONG line)
{
while (ON) { }
}
#endif
PE2、PE3に、2つのLEDを接続し、2つのタスクに点滅を
任せています。
各タスクが担当する処理は、次のようにしました。
- task0 2つのタスクの調整
- task1 LEDを2秒周期で点滅
- task2 LEDを3秒周期で点滅
- task3 ボード上のLEDを1秒周期で点滅
PE1には、スイッチを接続し、スイッチを
押す度に、消灯と点滅動作を切替えます。
---------------------------------------------------
この後は、ある程度ファームウエア、デジタル回路の
テストが済むまで、塩漬け(冬眠状態)に。
---------------------------------------------------
目次
前
次