かみやんの技術者ブログ

主にプログラムの話です

SH7125でシリアル通信

AKI-H8/3069F-LANからAKI-SH7125+ベースボードに変更したため、ファームウェアの作り直し。

  • マイコンHello WorldといえばLEDの点滅。まずはベースボードのLED点滅。あっさり完了。
  • 次に、割り込みを使わないポーリングによるシリアル通信(1byte版)。あっさり完了。
  • 次に、割り込みを使ったシリアル通信(1byte版)。あっさり完了。
  • 次に、リングバッファを使ったシリアル通信。リングバッファのソースは、H8/3069Fのときに書いたソースを移植であっさり完了。

gccからHEWになって良かったこと。

  • iodefine.hが自動生成されてI/Oレジスタの参照や代入がとっても楽になった

gccからHEWになって良くないところ。

  • C言語でinline関数が宣言できず、小さい関数を高速化したいときに関数ではなくdefineマクロにしないといけない。
  • エラーメッセージが、すごく簡易(古めかしいコンパイラな雰囲気)

あと、フラッシュROMの書き込みは、ルネサス純正のFDTに変えたが、h8writeよりも劇的に高速。これは楽チン。

RAMが8kbyteしかないため、リングバッファは、送信用500byte、受信用500byteにしてみた。あと、リングバッファのオーバーフローチェックは入れていない。シリアル通信の割り込みもエラー関係の割り込みもハンドリングしていない。受信処理や送信処理が追いつかないときは、データが破棄されると思われる。
シリアル通信のソースは、下記。

Serial.h

//Serial.h
//Eiji Kamiya
//Licence : New BSD

#ifndef __SERIAL_H__
#define __SERIAL_H__
#include "typedefine.h"

//初期化
void InitializeSerial(void);
//文字列送信
void SerialPuts(const char *str);
//1文字送信
void SerialPutc(char ch);
//バイト配列送信
void SerialWriteData(uint8* buf,int16 size);
//受信バッファにあるデータサイズ
int16 GetRecieveBufferDataSize();
//1文字受信
int16 SerialGetc();
//バイト配列受信
int16 SerialReadData(uint8* buf,int16 size);
#endif//__SERIAL_H__

Serial.c

/***********************************************************************/
/*                                                                     */
/*  FILE        :Serial.c                                              */
/*  DESCRIPTION :Main Program                                          */
/*  CPU TYPE    :SH7125                                                */
/*                                                                     */
/*  This file is generated by Renesas Project Generator (Ver.4.5).     */
/*                                                                     */
/***********************************************************************/
//シリアル通信割り込み版
//AKI-SH7125+ベースボード
//Eiji Kamiya
//Licence : New BSD

#include <string.h>
#include "typedefine.h"
#include "iodefine.h" 
#include "Serial.h"
#include "RingBuffer.h"

//定数定義

//構造体定義

//グローバル変数
RingBuffer g_send;		//送信用リングバッファ
RingBuffer g_recieve;	//受信用リングバッファ

//プロトタイプ宣言
//シリアル通信:1文字送信(同期処理)
void PutChar(char ch);
//シリアル通信:1文字受信(同期処理)
char GetChar();

//シリアル通信:初期化
void InitializeSerial(void)
{
	int i;
	//リングバッファ
	InitializeRingBuffer(&g_send);
	InitializeRingBuffer(&g_recieve);
	//スタンバイコントロールレジスタ(省電力モード)
    STB.CR3.BIT._SCI1=0;//SCI1起動
	//送受信割込禁止、送受信禁止
    SCI1.SCSCR.BYTE=0x00;
	//シリアルモードレジスタ:通信フォーマット、クロックソースを選択
    SCI1.SCSMR.BYTE=0x00;
	//ビットレートレジスタ
	//25MHz, 9600bpsのときBRR=(25000000/(32*9600)) - 1 = 80 
	//25Mhz,38400bpsのときBRR=(25000000/(32*38400))- 1 = 19
    SCI1.SCBRR=19;
	for(i=0;i<100000;i++){
	}
	//ピンファンクションコントローラ
	//RXD1(PA3) PACRL1(14-12):001
    PFC.PACRL1.BYTE.H=0x10;  
	//TXD1(PA4) PACRL2(2-0):001
    PFC.PACRL2.BYTE.L=0x01;  
	//シリアルコントロールレジスタ
    SCI1.SCSCR.BIT.TE=1;  //送信可
    SCI1.SCSCR.BIT.RE=1;  //受信可	
    SCI1.SCSCR.BIT.RIE=1; //受信割り込みON
    SCI1.SCSCR.BIT.TIE=0; //送信割り込みOFF
}

//シリアル通信:文字列送信
void SerialPuts(const char* str)
{
	int16 len=strlen(str);
	int16 capa=GetRingBufferCapacity(&g_send);
	char ch;
	if(len>capa){//送信バッファより長い文字列のとき
		len=capa;
	}
	WriteRingBuffer(&g_send,(const uint8*)str,0,len);
    SCI1.SCSCR.BIT.TIE=1; //送信割り込みON
}

//シリアル通信:1文字送信
void SerialPutc(char ch)
{
	int16 capa=GetRingBufferCapacity(&g_send);
	if(capa==0){//送信バッファがいっぱいのとき
		return;
	}
	WriteRingBufferByte(&g_send,ch);
    SCI1.SCSCR.BIT.TIE=1; //送信割り込みON
}

//バイト配列送信
void SerialWriteData(uint8* buf,int16 size)
{
	int len=GetRingBufferCapacity(&g_send);
	if(size>len){//送信バッファの空き領域よりデータが大きいとき
		size=len;
	}
	WriteRingBuffer(&g_send,buf,0,size);
    SCI1.SCSCR.BIT.TIE=1; //送信割り込みON
}

//受信バッファにあるデータサイズ
int16 GetRecieveBufferDataSize()
{
	return GetRingBufferSize(&g_recieve);
}

//1文字受信
int16 SerialGetc()
{
	if(IsRingBufferEmpty(&g_recieve)){//空のとき
		return -1;
	}
	return ReadRingBufferByte(&g_recieve);
}

//バイト配列受信
int16 SerialReadData(uint8* buf,int16 size)
{
	int len=GetRingBufferSize(&g_recieve);
	if(size>len){
		size=len;
	}
	ReadRingBuffer(&g_recieve,buf,0,size);
	return size;
}

//シリアル通信:1文字送信(同期処理)
void PutChar(char ch)
{
	while (SCI1.SCSSR.BIT.TDRE==0);
	SCI1.SCSSR.BIT.TDRE=0;//フラグをクリア
	SCI1.SCTDR=ch;
}

//シリアル通信:1文字受信(同期処理)
char GetChar()
{
	char ch;
    while ((SCI1.SCSSR.BYTE & 0x40)==0);
    ch = SCI1.SCRDR;
	SCI1.SCSSR.BYTE = SCI1.SCSSR.BYTE & 0xBF;
	return ch;
}

//シリアル通信:受信割り込み
//intprg.cのINT_SCI1_RXI1に記述を追加すること
void int_sci1_rxi()
{
	WriteRingBufferByte(&g_recieve,GetChar());
}

//シリアル通信:送信割り込み
//intprg.cのINT_SCI1_TXI1に記述を追加すること
void int_sci1_txi()
{
	char ch;
	if(IsRingBufferEmpty(&g_send)==false){//送信バッファにデータがあるとき
		ch=ReadRingBufferByte(&g_send);
		PutChar(ch);
		if(IsRingBufferEmpty(&g_send)){//送信バッファにデータがなくなったとき
		    SCI1.SCSCR.BIT.TIE=0; //送信割り込みOFF
		}
	}
}

RingBuffer.h

//RingBuffer ibis inc. Eiji Kamiya 2008/9/5-
//Licence : New BSD
#ifndef _RING_BUFFER_
#define _RING_BUFFER_

#include "typedefine.h"

//----------------------------------------------------------------------------
// 定数定義
//----------------------------------------------------------------------------
#define RING_BUFFER_SIZE		500		//リングバッファサイズ

//----------------------------------------------------------------------------
// 構造体定義
//----------------------------------------------------------------------------
//リングバッファ
//start==endの場合はデータが空、フルの場合は、endがstart-1
//よって最大限データが格納できるのは、RING_BUFFER_SIZE-1バイトまで。
typedef struct {
	uint8 buffer[RING_BUFFER_SIZE];		//バッファ
	int16 start;						//データ開始位置(ここが指している値を含む)
	int16 end;							//データ終了位置(ここが指している値は含まない)
} RingBuffer;							

//----------------------------------------------------------------------------
// マクロ
//----------------------------------------------------------------------------
//リングバッファが空か
#define IsRingBufferEmpty(ring_ptr) ((ring_ptr)->start==(ring_ptr)->end)

//----------------------------------------------------------------------------
// プロトタイプ宣言
//----------------------------------------------------------------------------
//リングバッファの初期化
void InitializeRingBuffer(RingBuffer* ring);
//リングバッファのデータサイズ
int16 GetRingBufferSize(RingBuffer* ring);
//リングバッファで2byteピーク
int16 GetRingBufferShort(RingBuffer* ring,int16 offset);
//リングバッファで1byte読み込み
uint8 ReadRingBufferByte(RingBuffer* ring);
//リングバッファで2byte読み込み
int16 ReadRingBufferShort(RingBuffer* ring);
//リングバッファで配列読み込み
void ReadRingBuffer(RingBuffer* ring,uint8 buf[],int16 offset,int16 size);
//リングバッファの空きデータサイズ
int16 GetRingBufferCapacity(RingBuffer* ring);
//リングバッファで1byte書きこみ
void WriteRingBufferByte(RingBuffer* ring,uint8 ch);
//リングバッファに配列書き込み
void WriteRingBuffer(RingBuffer* ring,const uint8 buf[],int16 offset,int16 size);

#endif//_RING_BUFFER_

RingBuffer.c

//RingBuffer.c ibis inc. Eiji Kamiya 2008/9/5-
//Licence : New BSD
#include "RingBuffer.h"

//----------------------------------------------------------------------------
// グローバル変数の宣言
//----------------------------------------------------------------------------




//----------------------------------------------------------------------------
//リングバッファの初期化
void InitializeRingBuffer(RingBuffer* ring)
{
	ring->start=0;
	ring->end=0;
}

//リングバッファのデータサイズ
int16 GetRingBufferSize(RingBuffer* ring)
{
	if(ring->end >= ring->start){//境をまたいでいないとき
		return ring->end -ring->start;
	}
	return RING_BUFFER_SIZE - (ring->start - ring->end);
}

//リングバッファでshortピーク
int16 GetRingBufferShort(RingBuffer* ring,int16 offset)
{
	int16 a,b;
	int16 o=(ring->start + offset)%RING_BUFFER_SIZE;
	if( o + 2 <= RING_BUFFER_SIZE){//またがないとき
		a=ring->buffer[o];
		b=ring->buffer[o+1];
	} else {//1バイトまたぐとき
		a=ring->buffer[o];
		b=ring->buffer[0];
	}
	return (a&0xff)|(b<<8);
}

//リングバッファで1byte読み込み
uint8 ReadRingBufferByte(RingBuffer* ring)
{
	uint8 a;
	
	a=ring->buffer[ring->start];
	ring->start++;
	ring->start%=RING_BUFFER_SIZE;
	return a;
}

//リングバッファでshort読み込み
int16 ReadRingBufferShort(RingBuffer* ring)
{
	int16 a,b;
	a=ring->buffer[ring->start];
	b=ring->buffer[(ring->start+1)%RING_BUFFER_SIZE];
	ring->start+=2;
	ring->start%=RING_BUFFER_SIZE;
	return (a&0xff)|(b<<8);
}

//リングバッファで配列読み込み
void ReadRingBuffer(RingBuffer* ring,uint8 buf[],int16 offset,int16 size)
{
	int16 i;
	uint8* p=buf+offset;
	
	for(i=0;i<size;i++){
		*(p++)=ring->buffer[ring->start];
		ring->start++;
		ring->start%=RING_BUFFER_SIZE;
	}
}

//リングバッファの空きデータサイズ
int16 GetRingBufferCapacity(RingBuffer* ring)
{
	if(ring->end >= ring->start){//境をまたいでいないとき
		return RING_BUFFER_SIZE-(ring->end -ring->start)-1;
	}
	return ring->start - ring->end -1;
}

//リングバッファで1byte書きこみ
void WriteRingBufferByte(RingBuffer* ring,uint8 ch)
{
	ring->buffer[ring->end++]=ch;
	ring->end%=RING_BUFFER_SIZE;
}

//リングバッファに配列書き込み
void WriteRingBuffer(RingBuffer* ring,const uint8 buf[],int16 offset,int16 size)
{
	int16 i;
	uint8* p=buf+offset;
	for(i=0;i<size;i++){
		ring->buffer[ring->end]=*(p++);
		ring->end++;
		ring->end%=RING_BUFFER_SIZE;
	}
}

intprg.c

// 221 SCI1 RXI1
void INT_SCI1_RXI1(void){int_sci1_rxi();}
// 222 SCI1 TXI1
void INT_SCI1_TXI1(void){int_sci1_txi();}

main.c

//Licence : New BSD
//メイン
void main(void)
{
//メイン
void main(void)
{
	int size;		//受信したサイズ
	uint8 buf[64];	//受信バッファ
		
	//初期化
	InitializeSerial();
	INTC.IPRL.BIT._SCI1 = 0xF;//SCI1の割り込みレベル設定 
	SerialPuts("AKI-SH7125 firmware ver.0.01\r\n");
	
	//メイン
	//受信したデータをそのままエコーバックするだけ
	while(1){
		size=GetRecieveBufferDataSize();
		if(size>0){
			size=SerialReadData(buf,sizeof(buf));
			SerialWriteData(buf,size);
		}
	}
}