CCWO Embedded Space

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

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の記事