図-RL78スタートアップ

CS+プロジェクトの作成へジャンプ
当サイトURL:https://fx.yokaton.com/rl78z/

目次

マイコンでプログラムする部分

キーワード一覧

当サイトURL:https://fx.yokaton.com/rl78z/
※これらのキーワードは、ホワイトボード内にも入ってます(右ボタン – コピーで取得可能)

オシロスコープ、ロジアナ、ロジック・アナライザとオシロスコープの違い、MSO
CAN、LIN、アナライザ、モニタ、車載ネットワーク、車載通信プロトコル
静電スイッチ、静電容量、オフグリッド、MPPT、光センサ、無線モジュール、ADコンバーター
ペリフェラル、デバイス
デジタル入出力、I/Oインタフェース
UART、非同期通信、パリティ、チェックサム、デリミタ
SPI通信インターフェース、CS、SS、イネーブル、ディセーブル
エッヂトリガ、レベルトリガ、SPI
PWM制御、スイッチング制御
RL78マイコン タイマー割込みでLチカ、RL78 兼用端子
マイコン アルゴリズム、RL78 アセンブラ

検索方法について

ルネサスのサイト内の検索機能を利用する。
ChatGPTやGeminiを利用する(Deep Researchも便利に使えます)。
単純にググっても結構ヒットします。

Geminiで「CS+の使い方を知りたい」と入力してみてください。ルネサスの検索サイトも案内してくれます。https://www.renesas.com/us/en/support/software-search
ChatGPTはエッジ内で使えば最新型を無料で利用可能です。こちらも上手く利用してみてください。

こちらはルネサスの日本語サイトです。
黄色枠の部分をクリックすることで色々な情報を入手できます。

例えばマニュアルが欲しいなら、上図のドキュメントをクリックし、下図の通りにクリックすれば、マニュアル類の一覧が表示されます。

少しだけですが追加でリンクを載せておきます。

当社の作っているもの

内製品


オシロスコープ





CAN/LINアナライザ・モニタ、車載ネットワーク、車載通信プロトコル

紹介動画








特注品


キーワード:静電スイッチ、静電容量、LIN、PWM、AD






キーワード:オフグリッド、MPPT、光センサ、無線モジュール、ADコンバーター

マイコンの中身と動作

デバイス、ペリフェラル、プロトコル

キーワード:デバイス、ペリフェラル、プロトコル
青色部分がデバイス、LINはペリフェラル。













マイコンがやること







I/O(図1/2)

キーワード:デジタル入出力、I/Oインタフェース、inportb、outportb、マイコンとFPGAの違い、I/Oインタフェース、mbed、RTOS


トイレの電気みたいにSWを動かすのがOUTPORT、逆に外部のSWの様子を調べるのがINPORT。
合わせてI/Oポートと呼ぶ。
SWなので1bitずつ操作するし1bitずつ調べる。


講習ではP56をOUTにし、P137をINとして使います。

P5_bit.no6 = 1; // P56と言う名前の足が1になる。
少し待ってから
P5_bit.no6 = 0; // P56と言う名前の足が0になる。
P56にオシロを繋いで波形を見るとこうなる。

負論理の場合は、P5_bit.no6 = 0; // P56と言う名前の足が0になる。


















UART(図4)

キーワード:UART、非同期通信、パリティ、チェックサム、デリミタ、ASCIIコード表

























1.250mA・・・
















// 標準チェックサム生成(モジュロ256方式)
uint8_t s_MakeCsum(uint8_t buff[], int bytecnt) 
{
    uint8_t i, csum;
    uint16_t up = 0;
    for (i=0; i<bytecnt; ++i) up+=buff[i];
    while (up & 0xff00u) {
        up = ((up & 0xff) + (up >> 8));
    }
    csum = (uint8_t)up;
    return ~csum;
}








SPI(図5/6)

キーワード:CS、SS、イネーブル、ディセーブル、エッヂトリガ、レベルトリガ、SPI、全二重インターフェース
SPI通信インターフェースの基本を学ぶ(入門編)

  • MOSI(Master Out Slave In)
  • MISO(Master In Slave Out)
  • SCK(Serial Clock):Masterが出力する
  • SS(Slave Select):Masterが出力する

CS=SS、MOSI=MasterOut、MISO=MasterIn


クロックの位相が逆の例(立ち下がりエッジでラッチ)
























I2C(アイ スクエアド シー)

キーワード:パーティーライン構成、マルチドロップ、ライブラリ、プルアップ抵抗、SCL、SDA









マスター → スレーブと送信する場合









マスター ← スレーブと受信する場合














PWM(図3)

キーワード:PWM制御、スイッチング制御、パワー・デバイス、MOSFET


デジタル信号を使ってアナログ的な出力を制御する技術です。
もしモーターに興味があるなら以下のキーワードで探せます。
ブラシレスモーター、パルスモーター、インバータ、サーボ、速度制御、クローズドループ、エンコーダ、加減速カーブ、オリエンタルモーター(モーター屋)








AD

キーワード:AD(またはADC)、サンプリングレート、分解能、マルチプレクサ











その他の通信ペリフェラル

RL78/G11 ユーザーズマニュアル ハードウェア編 P36の実物図。

測定器について(オシロとロジアナ)

測定器としてオシロスコープとロジックアナライザがあります。
ソフト屋に便利なのはロジアナ。
細かい電圧なんてどうでも良くて、HかLかだけ分かれば良い。
これなら中国製を千円ほどで入手できます。これとか
しかも2CHとかケチなことを言わず8CHとか平気で見えます。
ただし細かい電圧やノイズの観測ができないので、見落としが有ります。
「オシロが使えた上でロジアナ」かもしれません。

ここで使うハードとソフト

※ホワイトボード参照。
秋月 RL78/G11スティック型評価ボード
E2lite内蔵のRL78/G11CPUボード(電圧コンバータ内蔵 0.7~5.5>3.3V)。
説明図 AE-RL78G11-STICK_manual_20190124.pdf

※上記ボードの付属マニュアルの必要な章

  • 0.はじめに:ボードの名前とはたらき
  • 付録2:ソフトウェア
    CS+ for CC のみ使う
  • 付録4:オンボードの緑色のLED を点滅させる
    CS+で直に作ってE2で動作させる。
  • 付録5:マイコン周辺の回路

ボード写真とキーワード(図8~12)

ディップスイッチ


図9







ブレッドボード用端子(2.54mm)








回路図


図10







図11

P56を0にするとLED点灯、1で消灯。
SW1を押すとP137は0、放せば1。


図12






今回やること

1,手動(プログラム)でLED3ランプをパタパタ=OUT
2,SW1のパタパタを取得=IN
なのでソフト屋としては、IOのピン配置だけ分かればOKです。

マイコンでCを使う場合の特徴

ホワイトボードにリンク有り。
苦しんで覚えるC言語  ブラウザで実行できるサイト

RL78は、パソコンよりも非力なので、8bit型と16bit型だけで済むように工夫するのが吉です。
浮動小数点演算用のペリフェラルは載ってないし、longでさえも標準ライブラリ経由での使用となります。
これらを使う場合は、コンパイラのマニュアルのライブラリ関数を確認してください。

ライブラリを使うとコードサイズが大きくなります。
実行速度も遅くなる結果、消費電力も増えることになります。

2進数4bit → 16進数の一桁の覚え方

この3つを覚えれば他は直ぐ思いつきます。
0110 → 0x6
1010 → 0xa
1100 → 0xc

変数の幅

マイコンでは、ほぼ整数型しか使わない(floatを使うと遅い、でかい)
char ← 8bit
int ← 16bit

しかもほぼunsignedしか使わない。
unsigned char ← A/Bレジとか
unsigned int ← HL/BC/IXレジとか

短縮型(r_cg_macrodriver.h内にtypedefがある)。
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;

uint8_t a, b, c; //モロにRAM上に連続で3byte確保される。
この3byte を0にしたい。
a=0;
b=0;
c=0; // a=b=c=0;でも出力されるアセンブラのソースは同じ

uint8_t a[500]; //モロにRAM上に連続で500byte確保される。
uint16_t i; //iは16bit
for (i=0; i<500; ++i) a[i]=0; //*a++=0;

uint8_t *x; //ポインタ(RAMに連続的にアクセスしたい場合に使う)
x=&a; //aのRAM上の番地が入る
*x=1; //a=1と同じ結果になる

関数と戻り値について

※「C言語の復習」をやってるなら、ここは不要。

typedef unsigned char uchar; // ← 8bit RL78では uint8_t
typedef unsigned int uint;   // ← 16bit RL78では uint16_t

uchar a,b,c;  ← uint8_t a,b,c;
uint a,b,c;  ← uint16_t a,b,c;
unsigned char a,b,c;

/*
// コメント
*/

// 値渡し関数と戻り値について
uchar keisan(uchar a2, uchar b3) // { ← ここでもOK
{
 uchar total;
 total = a2+b3;
 return total;//  ← returnで返す
}
// main()
{
 uchar a,b,c;
 a=1;b=2;
 c=keisan(a,b);
}

// 何も渡さないならvoid
uchar keisan(void){}

// アドレス渡し(ポインタ)
c=keisan(&a,&b);
void keisan(uchar *a, uchar *b)
{
*a=5; 
*b=6;
}

// 論理演算と条件分岐など
if (a == 1) {
...
} else {
...
}

if (a==1 && b==2) {

switch (a) {
  case 1:..; break;
  case 2:..; break;
  default:..; break;
}

a=0;
while (a < 5) {
  ...
  ++a;
}
for (a=0; a < 5; ++a) {
  ...
}

bit演算とシフト演算

※ホワイトボード有り
bit演算は割と使う。

AND(両方とも1なら)
1011 = 0xb(11) a = 0xb;
1110 = 0xe(14) b = 0xe;
ーーーーーーーーーーーーーー
1010 = 0xa(10) c = a & b;

OR(どっちかが1なら)
1011
1110
ーーーーーーーーーーーーーー
1111 c = a | b;

XOR(片方だけが1なら) ← 両方同じなら0,違っていたら1
1011
1110
ーーーーーーーーーーーーーー
0101 c = a ^ b;

NOT(反転する)
1011
ーーーーーーーーーーーーーー
0100 c = ~ b;


右シフト(半分になる)
0100(0x4) → 0010(0x2)
左シフト(2倍になる)
0100(0x4) → 1000(0x8)

CS+(開発ツール)を使う

統合開発環境(IDE)と言う。
機能は豊富だが使うところだけ覚えればOK。

意外と重要なこと

main.cと言うファイル名は使わない(コード生成で削除される)。
プロジェクト全部を時々バックアップする。
Ctrl+sを頻繁に使う。

ツールの情報などのサイト(時間のあるときに)

※ホワイトボードにもリンク有り。

CS+のコード生成と生成されたAPI関数の使い方が分かる。
コード生成プラグイン学習ガイド
API関数のリファレンス

CPUの機能の動画(分かりやすく短く簡潔に纏まってるので目を通しておくとお得)。
RL78ワークショップ





CS+のDownloadとインストール

※「C言語の復習」をやってるなら、ここは不要。
ホワイトボードのリンクまたは統合開発環境 CS+で検索。
「CS+ for CC」を使う(CA,CXは昔のコンパイラ)。

他にe2studio(Eclipseというオープンソースの開発環境でARMコア用)もあります。お好みでどうぞ。

それではインストールを進めてください。
CS+ Quick Start Guide (1/4) – インストール | Renesas ← CS+インストールの説明動画

プロジェクトの作成とコード生成(図13)

または・・・

CPUはR5F1058A

端子配置図を出す。

_RESETのみ×が付いてる(×は入力の意味)。
後ほどP56とP137をセットします。

周辺機能のコード生成

ここからは左のツリーで選び、右側で設定していきます。
「端子割り当て設定」はデフォルト。
「確定する」を押してから再度左側を見ると赤!マークが消えてます。
これで先ずは動きます。

ここは全部デフォルト。
クロックは最高速度、オンチップオシレーター、XTALは外付けされてない。
最下行のRESET端子設定が「使用する」であることを確認。

OCDは使用する(E2lite)。
セキュリティーIDは使わない(後ほどアレコレ面倒が出てくる)。

その他の設定は全部デフォルト。

WDTを使用しない。

ポート設定

ポートはこの図を見ながら設定していきます。

P56出力。

P137入力。
「コードを生成」する。

配置表を確認。
なおコード生成するとmain.cファイルが消えてることを確認する。

配置図も確認(マウスのくりくりで拡大する)。
P137×、P56○
×:IN、○:OUT、○×:I/O

その他の設定

コンパイラの設定を変更する。
・CREF出力する(これをしないとstatic関数へのF12ジャンプが出来ない)。
・デバッグ優先(変数が見にくいので)。

コメントのネストの許可。

エミュレーターの選択。
RL78 E2 lite(市販品と同じなので、後々切り離して使える)。

プロジェクトを保存して再起動・デバッグ確認

ここで一旦CS+から抜けて再起動する(プロジェクト全体を時々保存しないと酷い目に合う)。

ボードをUSB接続する → 赤いLEDが点灯、緑が点滅。
①ビルド → E2へダウンロード(ビルドだけならF7)。赤LEDが点滅(TOOL0のせい)。
②デバッグ状態から抜ける(他は使えば分かる)。

なおデバッグ状態から抜けなくてもコードは書ける。

LED3の点滅(図14)

コードは、矢印間のみ記述可能(それ以外に記述すると、コード生成時に消されてしまう)。
P5_bit.no6 = 0; // P56 Out
P5_bit.no6 = 1; // P56 Out

デバッグ画面

①ビルド → E2へダウンロード(ビルドだけならF7)。
⑥E2から抜ける。
②ステップイン。
③ステップオーバー。
④RUN。
⑤STOP。
なおデバッグ状態から抜けなくてもコードは書ける(コード生成はできない)。







SW1を直読みする(図15)





デバッガ内でローカル変数を表示させる

矢印部分を上手く設定しないと、ローカル変数の一部しか見えず勘違いしやすいので要注意。
基数を変えるには赤矢印を右クリック。






別ファイルの作り方

※main.cは、コード生成時に削除されるので使わない。
別ファイルの追加の仕方。

_main.cの追加確認と、userdefine.hへのプロトタイプ書き込み。

r_cg_main.c内からMyMain関数をコールする。

そのまま#includeをコピーして、_main.c内にペーストする。

_main.c内にMyMain関数を書く。




#includeのイメージ。
キーワード:ワンパスのコンパイラ、プロトタイプ宣言、後方参照


MyMainからデバッグしたい

以上で開発環境が全て整いました。
この時点でプロジェクトをフォルダごとバックアップしてください ← 非常に重要

意外と重要なこと(再掲)

main.cと言うファイル名は使わない(コード生成で削除される)。
プロジェクト全部を時々バックアップする。
Ctrl+sを頻繁に使う。

別ファイルの作り方-ex0

①_sub1.cと言うファイルを追加してください。
②その中にsub_test(void)と言う名前の関数を書いてください。
③それをMyMain()からコールします。
ステップインで追跡できればOK。

①コメント
②は_main.cからのコピーで
③にはstaticを点けちゃダメ(他のソースファイルからコールされるから)

③をコピーしてuserdefine.hに追加する。

MyMainからコールしてデバッガでステップインする。

おまけ

①_sub2.cと言うファイルを追加してください。
②その中にsub2_test(void)と言う名前の関数を書いてください。
③この関数sub2_testをsub_test()からコールします。
ステップインで追跡できればOK。

①_sub3.cと言うファイルを追加してください。
②その中にsub3_test(void)と言う名前の関数を書いてください。
③この関数sub3_testをMyMain()からコールします。
ステップインで追跡できればOK。

プログラミング

開発環境の構築が出来ました。
コード生成に影響されない、自分専用のソースの追加方法も分かりました。
ご苦労様でした。
ここからは、構築したこの環境を使ってプログラムを書きましょう。

SW1の値をLED3に出力する

思いつく限りの書き方でどうぞ。
P5_bit.no6 = 0など、ビットフィールドが使われてることに気付いてください。

P13_bitの意味

キーワード:ビットフィールド

大量のLEDが付いていたらビットフィールドじゃ面倒くさい。
例えばP51~P54をまとめて点灯するなら「P5=0xe1」の一行で済む(1110-0001)。

”iodefine.h”内に宣言有り。
typedef struct
{
unsigned char no0:1;
unsigned char no1:1;
unsigned char no2:1;
unsigned char no3:1;
unsigned char no4:1;
unsigned char no5:1;
unsigned char no6:1;
unsigned char no7:1;
} __bitf_T;

#define P5 (*(volatile __near unsigned char *)0xFF05)
#define P5_bit (*(volatile __near __bitf_T *)0xFF05)
なので、以下のように記述可能。

P5=0xbf; // LED on 1011-1111
P5=0xff; // LED off 1111-1111

*(uint8_t *)0xFF05=0xbf;
*(unsigned char *)0xFF05=0xbf;

define P13 (*(volatile __near unsigned char *)0xFF0D)
define P13_bit (*(volatile __near __bitf_T *)0xFF0D)

プロジェクト内のキーワードの見つけ方

  • 探したいワードにポインタを移動
  • Ctrl+f
  • 「一括検索」タブを選択
  • メッセージ窓の反転したワードをWクリック

SFR

表示 → SFRで開く。
ポートの値が見えるし、直接書き込むことも可能。

練習問題(ex1~ex7)

タイミングチャートをコーディング-ex1

ソフトを作ってると、この手のタイミングチャートがやたら出てきます。
①LEDは消えてる → ②SWを押す → ③放すのを待つ → 少し待つ → ④LEDを点ける → 少し待つ → ⑤LEDを消す
これをプログラムしてみてください。

回答例

クリックすると回答例が開きます。
//***********************************************************
// _ex1:SW1を押したら少し待ってLED3を点灯する(説明用)
// 先に動作だけを書き、後でコードを入れていく。
//***********************************************************
static void _ex1(void)
{
    while (1U)
    {
		// SWが押されるまで待つ
		// SWが放されるのを待つ(チャタリング注意)
		// 少し待つ
		// LEDを点灯する
		// 少し待つ
		// LEDを消灯する
    }
}
// delay
// tm:待ち時間(単位1ms)
static void delay(uint16_t tm)
{
	uint16_t i,j;
	for (i=0; i<tm; ++i) {
		for (j=0; j<0x95e; ++j) NOP();//95e
	}
}
// SW1を押したら少し待ってLED3を点灯する
static void ex1(void)
{
	uint16_t i;
	P5_bit.no6 = 1;	// led off
    while (1U)
    {
		// SWが押されるまで待つ
		while (P13_bit.no7 == 1);
		// SWが放されるのを待つ(チャタリング注意)
		while (P13_bit.no7 == 0);
		// 少し待つ
		delay(200);
		// LEDを点灯する
		P5_bit.no6 = 0;
		// 少し待つ
		delay(500);
		P5_bit.no6 = 1;
		// LEDを消灯する
    }
}

CS+画面右下の実行時間表示に注意。

SW1とLED3で練習-ex2

SW1を押す度にLEDの点滅回数を増やす。5回押したら最初に戻る。
1回押すと1回点滅、もう1回押すと2回点滅・・・5回押すと5回点滅。
6回押すと1回点滅、もう1回押すと2回点滅・・・10回押すと5回点滅。

回答例

クリックすると回答例が開きます。
// SW1を押す度にLEDの点滅回数を増やす。5回押したら最初に戻る。
static void ex2(void)
{
	uint16_t i, swcnt = 1;
	P5_bit.no6 = 1;	// led off
    while (1U)
    {
		while (P13_bit.no7 == 1);
		while (P13_bit.no7 == 0);
		
		for (i=0; i<swcnt; ++i) {
			delay(500);
			P5_bit.no6 = 0;
			delay(500);
			P5_bit.no6 = 1;
		}
		if (++swcnt > 5) swcnt = 1;
    }
}

SW1とLED3で練習-ex3

逆にSW1を押す度にLEDの点滅回数を減らす。5回押したら最初に戻る。

回答例

クリックすると回答例が開きます。
// 逆にSW1を押す度にLEDの点滅回数を減らす。5回押したら最初に戻る。
static void ex3(void)
{
	uint16_t i, swcnt = 5;
	P5_bit.no6 = 1;	// led off
    while (1U)
    {
		while (P13_bit.no7 == 1);
		while (P13_bit.no7 == 0);
		
		for (i=0; i<swcnt; ++i) {
			delay(500);
			P5_bit.no6 = 0;
			delay(500);
			P5_bit.no6 = 1;
		}
		if (--swcnt == 0) swcnt = 5;
    }
}

SW1とLED3で練習-ex4

SW1を押してる時間を測り、その時間だけLED3を点灯する。
SW1を短く押すとLED3も短く点灯。
SW1を長く押すとLED3も長く点灯。
delay関数と同じようなソフトウエアのタイマーで構いません。

回答例

クリックすると回答例が開きます。
// SW1を押してる時間を測り、その時間だけLED3を点灯する。
static void ex4(void)
{
	uint16_t i, swtm;
	P5_bit.no6 = 1;	// led off
    while (1U)
    {
		while (P13_bit.no7 == 1);
		for (swtm=0; P13_bit.no7==0; ++swtm) delay(100);// 100ms×65535=109分
		
		delay(500);
		P5_bit.no6 = 0;
		for (i=0; i<swtm; ++i) delay(100);
		P5_bit.no6 = 1;
    }
}

SW1とLED3で練習-ex5

SW1を押した回数だけLED3を点滅する。

回答例

クリックすると回答例が開きます。

SW入力はチャタリングを考慮して別関数とした(チャタリングは後ほど)。
LED点滅も別関数とした。

// SW1を押した回数だけLED3を点滅する。
static void getsw(void)
{
	while (P13_bit.no7 == 1);
	delay(50);
	while (P13_bit.no7 == 0);
	delay(50);
}
static void led(uint cnt)
{
	uint16_t i;
	for (i=0; i<cnt; ++i ) {
		delay(500);
		P5_bit.no6 = 0;
		delay(500);
		P5_bit.no6 = 1;
	}
}	
static void ex5(void)
{
	uint16_t i, swcnt, swtm;
	P5_bit.no6 = 1;	// led off
    while (1U)
    {
		swcnt = 0;
		while (1U) {
			getsw();
			++swcnt;
			for (swtm=0; P13_bit.no7==1 && swtm<10; ++swtm) {
				delay(100);
				//if (swtm >= 10) break;	// 1000msを越えたら抜ける
			}
			if (swtm >= 10) break;
		}
		led(swcnt);
    }
}

割込みとGlobal変数

割込みとGlobal変数はセットで覚えてください。

P137をINTP0に設定する。
先にPort機能を解除しておく。
※「使用しない」に設定しても読み込むこと(INPORT)は出来る。恐らくコード生成機能の都合上だと思う。

割り込み機能でINTP0をチェック。
続けてコード生成。

r_cg_intp_user.c内にNOP();を追加。
ビルドしてE2に送信し、NOPの位置にBPをセット。そしてRUN。
SWを押すとNOPで止まる。

MyMainの入口に”R_INTC0_Start();”以下を追加。
whileループ内のNOPにBPをセットしてRUN・・・SWを3回押すとブレークすることを確認。
※チャタリングで割り込み回数が不定になるが後で詳しく。

// _main.c
uint8_t G_var;  // 実体を宣言

void MyMain(void)
{
	R_INTC0_Start();

	while (1) {
		if (G_var > 3) {
			NOP();
			G_var = 0;
		}
	}
}

// r_cg_intp_user.c
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
extern uint8_t G_var;  // ▲▲▲ 実体を使う事を定義 ▲▲▲
/* End user code. Do not edit comment generated here */

/***********************************************************************************************************************
* Function Name: r_intc0_interrupt
* Description  : None
* Arguments    : None
* Return Value : None
***********************************************************************************************************************/
static void __near r_intc0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	++G_var;  // ▲▲▲ 一行追加
	NOP();
    /* End user code. Do not edit comment generated here */
}

SW1を割り込みで取る(図16~)

割込み関数内は素早く抜ける ← チョー重要!

上記の応用編。
MyMainの入口に”R_INTC0_Start();”以下を追加。
whileループ内のNOPにBPをセットしてRUN・・・SWを3回押すとブレークすることを確認。
※チャタリングで割り込み回数が不定になるが後で詳しく。

// _main.c
uint8_t G_var;  // 実体を宣言

void MyMain(void)
{
	R_INTC0_Start();

	while (1) {
		if (G_var > 3) {
			NOP();
			G_var = 0;
		}
	}
}

// r_cg_intp_user.c
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
extern uint8_t G_var;  // ▲▲▲ 実体を使う事を定義 ▲▲▲
/* End user code. Do not edit comment generated here */

/***********************************************************************************************************************
* Function Name: r_intc0_interrupt
* Description  : None
* Arguments    : None
* Return Value : None
***********************************************************************************************************************/
static void __near r_intc0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	++G_var;  // ▲▲▲ 一行追加
	NOP();
    /* End user code. Do not edit comment generated here */
}

チャタリングの確認

IOでポートを読んでるときには気にならないが、割り込みでは問題化する。
上の例題で if (G_var > 3) { を if (G_var > 10) { とかにすると、10回押す前にNOPに来る可能性がある。
または「あれ?時々変だわ」となる。

チャタリングがあるので、実際には何度も割り込みが発生してる可能性がある。
こう言うのだけはオシロじゃ無いと分からない(ロジアナでは遅すぎて無理)。
このボードのSW1はチャタが少ない。

割込みとGlobal変数の使い方の練習-ex6

この組合せは良く使います。
LEDを点滅させておき、SW1が押される度に点滅動作をOnOffする(SWをINで読まずに割り込みを使う)。

回答例

クリックすると回答例が開きます。
// _main.c
// SW1が押される度にLED3の点滅をOnOffする(割り込みを使う)。
uint8_t G_var;
static void ex6(void)
{
	while (1U) {
		while (G_var == 1) NOP();
		led(1);
	}
}
void MyMain(void)
{
	R_INTC0_Start();
	ex6();
}

// r_cg_intp_user.c
/***********************************************************************************************************************
Global variables and functions
***********************************************************************************************************************/
/* Start user code for global. Do not edit comment generated here */
extern uint8_t G_var;  // ▲▲▲ 実体を使う事を定義 ▲▲▲
/* End user code. Do not edit comment generated here */

/***********************************************************************************************************************
* Function Name: r_intc0_interrupt
* Description  : None
* Arguments    : None
* Return Value : None
***********************************************************************************************************************/
static void __near r_intc0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	//++G_var;
	G_var ^= 1;  // XOR(両方同じなら0)
	NOP();
    /* End user code. Do not edit comment generated here */
}

タイマー割り込みでLED3を点滅する

コード生成すると3本のファイルが追加される。

// 1秒ごとにLED点滅を繰り返す。SWを押すと点滅が止まる
// _main.c
void MyMain(void)
{
	char w;
    R_TAU0_Channel0_Start();
	while (1U)
    {
		w=P13_bit.no7;
        if (w == 0) P5_bit.no6 = w;
    }
}

// r_cg_tau_user.c
static void __near r_tau0_channel0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	P5_bit.no6 ^= 1;
    /* End user code. Do not edit comment generated here */
}


// _main.c
// 3秒ごとにLED点滅を繰り返す
static uint8_t intrcnt;
void main_tmintr(void)
{
	++intrcnt;
}
void MyMain(void)
{
	NOP();
	R_TAU0_Channel0_Start();
	P5_bit.no6 = 1;	// LED off
	while (1U)
    {
		if (intrcnt == 3) {
			intrcnt = 0;
			P5_bit.no6 = 0;
			delay(100);
			P5_bit.no6 = 1;
		}
    }
}

// r_cg_tau_user.c
static void __near r_tau0_channel0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	main_tmintr();
    /* End user code. Do not edit comment generated here */
}

// r_cg_userdefine.h
/***********************************************************************************************************************
User definitions
***********************************************************************************************************************/

/* Start user code for function. Do not edit comment generated here */
typedef unsigned char uchar;
typedef unsigned int uint; 
void MyMain(void);
void main_tmintr(void);
extern uint8_t G_intv;
/* End user code. 

タイマー割り込み練習-ex7

2秒ごとにLEDを100ms点灯する。時間は正確に。
タイマー割り込みを使う。

回答例

クリックすると回答例が開きます。
// _main.c
static uint8_t intrcnt;
void main_tmintr(void)
{
	++intrcnt;
}
void MyMain(void)
{
	NOP();
	R_TAU0_Channel0_Start();
	while (1) {
		if (intrcnt == 20) {
			P5_bit.no6 = 0;
			while (intrcnt == 20) NOP();
			intrcnt = 0;
			P5_bit.no6 = 1;
		}
	}
}

// r_cg_tau_user.c
static void __near r_tau0_channel0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	//P5_bit.no6 ^= 1;
	main_tmintr();
    /* End user code. Do not edit comment generated here */
}

// r_cg_userdefine.h
/***********************************************************************************************************************
User definitions
***********************************************************************************************************************/
/* Start user code for function. Do not edit comment generated here */
void main_tmintr(void);
void MyMain(void);
/* End user code. Do not edit comment generated here */

典型的なタイマー割込みの使い方はこちらです。

// 典型的なタイマー割込みの使用例
// _main.c
static void int10(void)
{
	NOP();
}
static void int20(void)
{
	NOP();
}
void main_tmintr(void)
{
	static uint8_t intrcnt;
	++intrcnt;
    // インターバルが100msの場合、1秒と2秒ごとに関数がコールされる
	if (intrcnt == 10) int10();
	if (intrcnt == 20) {
		int20();
		intrcnt = 0;
	}
}
void MyMain(void)
{
	NOP();
	R_TAU0_Channel0_Start();
	while (1) NOP();
}

// r_cg_tau_user.c
static void __near r_tau0_channel0_interrupt(void)
{
    /* Start user code. Do not edit comment generated here */
	//P5_bit.no6 ^= 1;
	main_tmintr();
    /* End user code. Do not edit comment generated here */
}

// r_cg_userdefine.h
/***********************************************************************************************************************
User definitions
***********************************************************************************************************************/
/* Start user code for function. Do not edit comment generated here */
void main_tmintr(void);
void MyMain(void);
/* End user code. Do not edit comment generated here */

systeminit.c内に追加されたコードの確認

RESETからの動きの概要

SPIのモード設定の復習

前エッジ、後エッジ、CLKの種類の4つを思い出して下さい。
コード生成ではここで設定します。

マニュアルの見方

hdwinitでのDIの意味

Systeminitの解析

RL78/G11 ユーザーズマニュアル ハードウェア編

マイコン概略

秋月 RL78/G11スティック型評価ボードのページより・・・
・マイコン名:RL78/G11
・型名R5F1058 25ピン
・CPU:R5F1058AALA
・ROM:16kB
・RAM:1.5kB
・GPIO:13
・電源電圧min.:0.7V
・電源電圧max:5.5V ← 普通は全体を揃えて3.3Vを使う
・IO電圧min.:3.3V
・IO電圧max.:3.3V
・ローパワーモード有り

RL78/G11 ユーザーズマニュアル ハードウェア編

図27(P37より・・・)

端子名称(P128より・・・)








図28(P31より・・・)







図29(P31より・・・)










IAWCTLの設定場所はここ(全部デフォルト)。








図30(P32より・・・)








SW1を割り込みで取る(P137のINTP0設定)

図31(P46より・・・)






図32(P31より・・・)
図28を拡大した図。






図33(P856より・・・)







図34(P857より・・・)








②④立ち下がりエッジ
③⑤立ち上がりエッジ

ルネサス プログラミング(前編)




兼用端子の設定

図35(P128より・・・)








Cの練習関係

苦しんで覚えるC言語  ブラウザで実行できるサイト

// _ringbuff.h
#ifndef _RINGBUFF_H
#define _RINGBUFF_H

void        RBinit(uint8_t*buff, uint16_t size);
uint16_t    RBloc(void);
void        RBset(uint8_t d);
uint8_t     RBget(void);

#endif  // _RINGBUFF_H
// _ringbuff.c
#include "r_cg_macrodriver.h"
#include "r_cg_userdefine.h"
#include "_ringbuff.h"

// 管理用の変数(必要ならvolatileを追加)
uint8_t *bptr;
uint16_t ip, op, bsize, remain;

// 初期化("size - 1"個のデータが保存される)
void RBinit(uint8_t*buff, uint16_t size)
{
    bptr = buff;
    bsize = size;
    ip = op = remain = 0;
}
// データ存在の検査
uint16_t RBloc(void)
{
    //return (ip == op)? 0: 1;  //  データがあれば"1"
    return remain;  // 残りデータ個数を返す
}
// データを1個セット
void RBset(uint8_t d)
{
    bptr[ip] = d;
    if (++ip == bsize) ip = 0;
    if (ip == op) {
        if (++op == bsize) op = 0;
    } else ++remain;
}
// データを1個取り出し
uint8_t RBget(void)
{
    uint8_t w;
    while (RBloc() == 0) NOP();
    w = bptr[op];
    if (++op == bsize) op = 0;
    --remain;
    return w;
}

講習まとめ

アセンブラ(図40~)

  • 先にCで書いて動作確認する。
  • 次にコンパイラにアセンブラのソースを出すように指示。
  • 出力されたソースを見て大体の様子を掴む(どうせボロいコードなはず)。
  • SECTION宣言などだけ利用して、中身は全部書き直す。
    これで速度が2倍くらいにはなります。

Cやアセンブラでポートを操作してSPIする場合のコード。

// Cでの連続6バイト入力(検証済み)
uint8_t* SPIRcv6(uint8_t rd[])
{
    int i, lp;
    uint8_t BitPos, data;
    for (lp=0; lp<6; ++lp) {
        data = 0;
        BitPos =0x80;               // ビット位置リセット
        for(i=0; i<8; i++){         // 8ビット繰り返し
            SCK = 0;  // 立ち下がりエッジCLKの作成
            SCK = 0;
            SCK = 1;
            if (SDI) data |= BitPos;// ビット入力
            BitPos = BitPos >> 1;   // ビットシフト
        }
        rd[lp] = data;
    }
    SCK = 1;
    return(rd);     // 受信データ*を戻す
}

=======================================================================================
; 上記のCコードをアセンブラで書き換えた(速度は約二倍高速になる)
; 自分用のアセンブラ関数用ファイル 2018/8/9
;=======================================================================================
; PUBLIC宣言はここ(TEXT内で宣言すると引数のアドレスが変になる)
.PUBLIC _asmSPIRcv6

; TEXT
    .SECTION .text,TEXT
;---------------------------------------------------------------------
; void _asmSPIRcv6(uint8_t* data)
;   AX=data pointer
;   6byte取得に56uS=9.3uS/byte → 107,143byte/秒
;---------------------------------------------------------------------
_asmSPIRcv6:
    push    hl          ; HLは要保存
    movw    hl,ax       ; 引数はAXで届くんで HL ← data
    ; for(X=0; X<6; ++X) 
    clrb    x           ; X は6byteカウント用
  .lp0: 
    clrb    b           ; B は8bitカウント用
    clrb    c           ; C はMISOを1byteに纏めたもの(それを[HL]に入れる)
    mov     d,#0x80     ; D は bit7-6-5...0 とシフトしてる
  .lp1: 
    ; 立ち上がりエッジをCLKに出力
    mov     a,p0
    and     a,#0xf7     ; CLK=0 P0.3=0
    mov     p0,a
    or      a,#0x8      ; CLK=1 P0.3=1
    mov     p0,a
    ; MISO(P0.4)を読む
    mov     a,p0        ; A=MISO
    and     a,#0x10     ; check MISO bit
    bz      $.lp2       ; if 0 skip
    ; MISO=HならCにDのbitをセット
    mov     a,c
    or      a,d         ; D goes to 0x80-0x40-0x20...0x0
    mov     c,a         ; set to C
  .lp2: 
    mov     a,d         ; shr D
    shr     a,1
    mov     d,a
    ; chek 8 bits loop
    inc     b           ; ++B
    mov     a,b
    cmp     a,#8
    bnz     $.lp1
    ; set 8 bits to data[]
    mov     a,c
    mov     [hl],a
    incw    hl
    ; chk 6 loop count
    inc     x           ; ++X
    mov     a,x
    cmp     a,#6
    bnz     $.lp0
    ; end
    pop     hl
    ret

C言語の復習

苦しんで覚えるC言語  ブラウザで実行できるサイト

キーワード:プロトタイプ宣言、前方参照、後方参照、フリーフォーマット、値渡し関数、戻り値、void型、静的変数、ポインタ、

CS+のDownloadとインストール

ホワイトボードのリンクまたは「統合開発環境 CS+」で検索。
「CS+ for CC」を使う(CA,CXは昔のコンパイラ)。

それではインストールを進めてください。
CS+ Quick Start Guide (1/4) – インストール | Renesas ← ルネサスのサイト

プロジェクトの作成

・マイコン名:RL78/G11
・型名R5F1058 25ピン

この時点で端子配置表と配置図を見る。
どちらも_RESETのみ定義されている。
端子図を出す。

_RESETのみ×が付いてる(×は入力の意味)。
Cの練習なのでP56とP137は使いません。

その他の設定

コンパイラの設定を変更する。
・CREF出力する(これをしないとstatic関数へのF12ジャンプが出来ない)。
・デバッグ優先(変数が見にくいので)。

コメントのネストの許可。

実際のコーディングでの重要注意

main.cと言うファイル名は使わない(コード生成で削除される)。
プロジェクトを保存して再起動・デバッグ確認。 ← 非常に重要
時々はプロジェクト全体をバックアップ。

CS+シミュレータを利用する

デバッガ内でローカル変数を表示させる

コーディング

マイコンで使うときは必ずwhileで囲う。

実コーディングではワーニングを全て消す。
エラー番号で検索可能(より詳細に原因を掴める)。

①ビルド → E2へダウンロード(ビルドだけならF7)。
⑥E2から抜ける。
②ステップイン。
③ステップオーバー。
④RUN。
⑤STOP。
※画面下部のファンクションキー

コメント

コメントする

目次