電子ブロック工房 / MachiKania https://www.rad51.net/blog/mycom/ IC・トランジスタで出来たコンピューターを設計・製作するためのブログ / マチカニア BASIC システム ja Jeans CMS © Weblog http://backend.userland.com/rss https://www.rad51.net/jeans/skins/jeans/images/jeans2.gif 電子ブロック工房 https://www.rad51.net/blog/mycom/ MachiKaniaの「auxcode」機能について https://www.rad51.net/blog/mycom/?itemid=987
MachiKania では、BASIC で様々なことを行う機能を提供してきた:

1.液晶ディスプレイや NTSC ビデオに、(日本語を含む)文字やグラフィックスを容易に表示
2.キーボードを接続して、BASIC コードを編集しながら実行する、スタンドアローンPCとしての機能
3.SPI・I2C・UART などの I/O 機能を、BASIC コードから容易に使用する方法を提供
4.複雑な動作を行うコードを、容易に利用するためのクラスライブラリーを提供

ここで書いた3の部分は、MachiKania 本体で提供、4の部分はクラスで提供している。ほとんどのクラスが BASIC で書かれているが、いくつかは C で書かれたコードを BASIC から呼び出す形をとっている(方法1方法2)。

C で書かれたコードの中には、容易に MachiKania から呼び出すように修正できるものもあれば、そういったことが非常に難しいものがある。例えば、RP2040 の PIO 機能を使ったものは、BASIC で利用できるように実装するのは非常に難しい。

「auxcode 機能」は、そういった C のコードを MachiKania で実行できるようにするものだ。「auxcode 機能」を使うには MachiKania 本体のビルドが必要になるが、どうしても必要な機能を MachiKania に取り込むのには汎用性が高いと言える。

auxcode 機能を使うには

auxcode 機能は、MachiKania 本体に次のような機能追加を行うものだ

1.BASIC ステートメントの追加
2.整数型関数の追加
3.文字列型関数の追加
4.浮動小数点型関数の追加
5.上記ステートメント・関数を実行する機能の追加

auxcode 機能はすべて、ソースコード中の「auxcode」ディレクトリーに収める形で提供する。MachiKania のソースコードにはデフォルトで auxcode ディレクトリーがあり、そこには次の2つのファイルが収められている。

  auxcode.c
  auxcode.cmake

これらのファイルは、デフォルトでは次の通り。

auxcode.c
#include "pico/stdlib.h"
#include "../compiler.h"

int aux_statements(void){
	return ERROR_STATEMENT_NOT_DETECTED;
}
int aux_int_functions(void){
	return ERROR_STATEMENT_NOT_DETECTED;
}
int aux_str_functions(void){
	return ERROR_STATEMENT_NOT_DETECTED;
}
int aux_float_functions(void){
	return ERROR_STATEMENT_NOT_DETECTED;
}
int lib_aux(int r0, int r1, int r2){
	return r0;
}

auxcode.cmake
add_library(aux_files
	auxcode/auxcode.c
)
target_link_libraries(aux_files 
	pico_stdlib
)

auxcode.c に書かれている5つの関数は、少し上のパラグラフで述べた5つの機能に相当する。auxcode.cmake は、デフォルトの auxcode.c をコンパイルするための、必要最小限の構成である。追加する機能は、これらのファイルを編集し、必要であればファイルを追加する。

auxcode 機能の使用例

ここでは、どのようにして auxcode 機能を使うのか、使用例を挙げて説明する。次のレポジトリーでは、HB01B0 というカメラを MachiKania で使うためのコードを、収めた。
https://github.com/kmorimatsu/hm01b0_machikania
追加したい機能は、以下の通り

1.HM01B0_INIT ステートメント
2.HM01B0_CAPTURE ステートメント
3.HM01B0_DRAW ステートメント
4.HM01B0_REG_WRITE ステートメント
5.HM01B0_ZOOM ステートメント
6.HM01B0_CAPTURE ステートメント
7.HM01B0_ANALYZE([x]) 関数(整数型)

上記の目的のため、次のコードを用意する。

1.上記1-6のステートメントを BASIC コンパイラーが認識できるように、「aux_statements()」関数を編集
2.上記7の関数を BASIC コンパイラーが認識できるように、「aux_int_functions()」関数を編集
3.上記1-7の構文を実行する際に呼び出されるコードを記述
4.カメラを制御するための C コードを、修正して追加
5.MachiKania のビルドの際に、追加の C ファイルがコンパイルされるように、auxcode.cmake を編集

順に見ていこう。

1.ステートメントを認識させる

hm01b0_machikania の auxcode.c の、aux_statements() 関数は次の通り。
int aux_statements(void){
	if (instruction_is("HM01B0_INIT")) return hm01b0_init_statement();
	if (instruction_is("HM01B0_CAPTURE")) return hm01b0_capture_statement();
	if (instruction_is("HM01B0_DRAW")) return hm01b0_draw_statement();
	if (instruction_is("HM01B0_REG_WRITE")) return hm01b0_reg_write_statement();
	if (instruction_is("HM01B0_ZOOM")) return hm01b0_zoom_statement();
	return ERROR_STATEMENT_NOT_DETECTED;
}

ステートメントを認識させるには、ここで
  「if (instruction_is("HM01B0_INIT"))」
のように記述する。続けて、
  「return hm01b0_init_statement();」
の例のように続ける。

「hm01b0_init_statement()」は、次のように書かれている。
int hm01b0_init_statement(void){
	// The first argument is the pointer to video buffer (324*324 bytes)
	return argn_function(LIB_AUXCODE,
		ARG_INTEGER<<ARG1 |
		LIB_AUX_HM01B0_INIT<<LIBOPTION);
}

コメントにあるように、「HM01B0_INIT」ステートメントは、整数型の引数を一つ取る(ポインターを整数として処理)。
  「ARG_INTEGER<<ARG1」
の部分の記述は、そのためのものだ。引数が文字列なら「ARG_INTEGER」ではなく「ARG_STRING」と、浮動小数点型なら「ARG_FLOAT」とする。

「LIB_AUXCODE」は、BASIC コードを実行中に制御を「lib_aux()」に移すために必要なので、そのままにして使う。また、
  「LIB_AUX_HM01B0_INIT<<LIBOPTION」
は「lib_aux()」内で「HM01B0_INIT」ステートメントの実行であることを認識させるために必要なコードで、
  「LIB_AUX_HM01B0_INIT」
等にはそれぞれ、固有の値を割り当てておく。

2.関数を認識させる

「aux_int_functions()」関数は、次の通り。
int aux_int_functions(void){
	if (instruction_is("HM01B0_ANALYZE(")) return hm01b0_analyze_function();
	return ERROR_STATEMENT_NOT_DETECTED;
}

上の「aux_statements()」の例と同様だが、「"HM01B0_ANALYZE("」のように、「(」が付加されている。文字列型関数の場合は「"XXXX$("」のようにして「aux_str_functions()」に記述、浮動小数点型関数の場合は「"XXXX#("」のようにして「aux_float_functions()」に記述する。

「hm01b0_analyze_function()」関数は、次のように記述されている。
int hm01b0_analyze_function(void){
	// The first argument is number of raws to analyze (default 240).
	g_default_args[1]=240;
	return argn_function(LIB_AUXCODE,
		ARG_INTEGER_OPTIONAL<<ARG1 |
		LIB_AUX_HM01B0_ANALYZE<<LIBOPTION);
}

ここで実装する「HM01B0()」関数の引数は実数値で、省略された場合のデフォルト値は240である。そういった場合は、
  「g_default_args[1]=240;」
のようにデフォルト値を指定したのちに、
  「ARG_INTEGER_OPTIONAL<<ARG1」
のように記述して対処する。

3.構文を実行する際に呼び出されるコードを記述する

ステートメントや関数を実行する際に呼び出されるコードは、「lib_aux()」関数内に記述する。
int lib_aux(int r0, int r1, int r2){
	switch(r2){
		case LIB_AUX_HM01B0_INIT:
			hm01b0_init((uint8_t*)r0);
			break;
(略)
		case LIB_AUX_HM01B0_ANALYZE:
			return (int)hm01b0_analyze(r0);
			break;
		default:
			break;
	}
	return r0;
}

この C 関数は、r0, r1, r2 という3つの引数を持つが、これらは、CPU (ARM Cortex-M0+) のレジスター値である。r2 に上で述べた「LIBOPTION」の値が入っているから、それで分岐して使う。

ここで紹介している「HM01B0_INIT」と「HM01B0_ANALYZE」というステートメント・関数は、引数が1つだ。そういう場合は、引数は「r0」に格納されている。なお、引数が2つの場合は第一引数が「r1」、第二引数が「r0」に格納される。引数が3個以上の場合は最後の引数が「r0」に、それ以外の引数は「r1」ポインターで指定される配列に格納される。

ここではそれぞれ、「hm01b0_init()」と「hm01b0_analyze()」という関数を呼び出すようになっている。これらは、別のCファイル(hm01b0.c)で記述されている。

4.C ファイルを追加する
多くの場合、auxcode.c という単一のファイルにすべてのコードを収めることはできないだろう。機能の実装のために、複数の C ファイルを auxcode ディレクトリーに展開することになる。

hb01b0_machikania の場合、auxcode ディレクトリーに含まれるCファイルは次の3つである。
  auxcode/auxcode.c
  auxcode/hm01b0.c
  auxcode/arducam/arducam.c
必要な機能の実装のために、これらのCファイルは別のところからコピーして修正するか、自分で一から書いて使うことになる。

5.C ファイルをビルドの際に認識させる

デフォルトでは MachiKania のビルドの際に「auxcode.c」しかコンパイルされないので、「hm0xb0.c」と「arducam.c」もコンパイルされるように指定する。これには、「auxcode.cmake」ファイルの編集が必要だ。

例では、「auxcode.cmake」ファイルは次の通り。
add_library(aux_files
	auxcode/auxcode.c
	auxcode/hm01b0.c
	auxcode/arducam/arducam.c
)
target_link_libraries(aux_files 
	pico_stdlib
	hardware_dma
	hardware_i2c
	hardware_pio
	hardware_pwm
)
pico_generate_pio_header(aux_files ${CMAKE_CURRENT_LIST_DIR}/image.pio)

「add_library()」に、コンパイルが必要な C ファイルを追加する。それぞれで使用する必要な Pico の機能(hardware_i2cやhardware_pwm等)については「target_link_libraries()」に追加する。例では PIO も使っているので、それに必要な行(pico_generate_pio_header)も追加されている。

C のプログラムを MachiKania にどんどん取り込もう

Raspberry Pi Pico 用の周辺機器には、C でサンプルプログラム等が供給されているものが多い。簡単なものなら BASIC に移植して MachiKania で使えるが、多くの場合は簡単には移植できない。そういった C のコードでも「auxcode」機能を使えば MachiKania でも使えるようになるものは、多いだろう。この機能を利用して、より多くの周辺機器が MachiKania で使えるようになることを期待する。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=987 Sun, 02 Mar 2025 18:07:17 PST ITEM987_20250302
MachiKania type PU を公開 https://www.rad51.net/blog/mycom/?itemid=986

MachiKania type PU を、公開しました。
GitHub リリースページはこちら
公式ホームページはこちら

MachiKania type PU は、MachiKania type P の姉妹バージョンです。type P は、ILI9341 等の液晶ディスプレイに表示しますが、type PU では NTSC のビデオ画面に表示するようにしました。これにより、大画面での表示が可能になりました。

typePU2.png

液晶ディスプレイではなく NTSC ビデオ出力にした事で、回路が type P より簡潔になっています(回路図は、GitHubページのpuerulusの項を参照)。NTSC ビデオ出力は、抵抗1本とコンデンサー1個の簡単なものです。上の写真は、私の type PU のプロトタイプ版です(Raspberry Pi Pico は、外してあります)。Pi Pico 用のソケット以外は、micro SD のソケット、NTSC 用のプラグ、タクトスイッチ、圧電ブザーと、少数の抵抗・コンデンサーだけです。

XIAO-RP2040 等のピン数が少ない基板でも画面表示が出来るようになったので、これらの小さな基板を使った組込み開発が容易になりました。現在の所、次のマイコン基板に対応しています。

・Raspberry Pi Pico
・Raspberry Pi Pico W
・Raspberry Pi Pico 2
・Seeed studio XIAO RP2040
・Pimoroni Tiny 2040
・Waveshare RP2040-Zero
・Seeed studio XIAO RP2350
・Pimoroni Tiny 2350
・Waveshare RP2350-Zero

keyboard.png

また、type P と同様、USB キーボードに接続可能です。これにより、MachiKania type PU・NTSC モニター・USB キーボードによるスタンドアローンな BASIC プログラム開発環境を構築することができます。BASIC は今まで通りコンパイラーなので、高速実行が可能です。

開発裏話

Type PU 開発のきっかけは、Twitter でらびやんさんの、Raspberry Pi Pico による NTSC ビデオシグナル作成デモを見た事です。
lovyan03.png
これを、なんとか MachiKania に取り込めないかと言う事で、らびやんさんとライセンスの交渉をし、MIT ライセンスとして使わせていただくことができるようになりました。

その後、ケンケンさんと私の双方で、この NTSC ビデオ信号プログラムを MachiKania に取り込む方法を模索しました。ケンケンさんは Raspberry Pi Pico の1ボードで MachiKania と NTSC ビデオルーチンの両方を実装、私は、2枚の Raspberry Pi Pico ボードをそれぞれ MachiKania と NTSC ビデオルーチンに割り当てて並列で実行する方法です。最終的にケンケンさんがうまく行った方法を取り入れる事になりました。

この、NTSC 版 MachiKania の開発コードは、ケンケンさん命名で、"puerulus"です。Wikipediaによると、puerulusというのはイセエビの幼生で、phyllosoma から一段発生が進んだものらしいです。MachiKaniaの開発コードは、nauplia -> zoea -> megalopa -> phyllosoma -> puerulus と、甲殻類の発生をなぞっています。ちなみに、MachiKania は、待兼山と言う地名にちなんだ造語です。

MachiKania のソースコード管理はずっとオープンでやってきて、初期のころは SVN で、今は Git(GitHub) でソースコードの管理を行っています。puerulus のソースコードと phyllosoma のソースコードで異なるのは、モニター表示部分だけ(NTSC 出力か LCD 出力か)です。ソースコードを別々に管理すると、今後のアップデートの際に同じ変更を両方のコードに対して行う事になり、煩雑なだけでなく、思わぬバグを混入してしまう原因となります。そこで、puerulus のソースコードと phyllosoma のソースコードを統合して一つにし、config の設定を変えることで type PU をビルドするのか、type P をビルドするのか、選択できるようにしました。Type PU の公式版の公開が、ケンケンさんのテスト版の公開から3か月以上遅れたのは、統合化に時間がかかったのが大きな理由です。ソースコードの統合により、Pico だけでなく Pico 2 にも対応できることが分かり、それによる微修正等を行っていたこともありますが。

MachiKania type PU の正式公開に伴って、同じ NTSC ビデオ出力版の type Z とtype M の開発を終了する事になりました。もともと、ずっと新規バージョンを公開していなかったので、実質的に開発は中断状態だったのですが、ケンケンさんとの相談で、完全に開発停止する事になりました。

今後の MachiKania の発展は、type P と type PU で行っていくことになります。使っていただいている皆様、今後とも、MachiKania をご贔屓に、よろしくお願いします。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=986 Sat, 28 Dec 2024 15:47:25 PST ITEM986_20241228
MachiKania type P ver 1.4 を公開 https://www.rad51.net/blog/mycom/?itemid=982
公式ページはこちら
GitHub リリースページはこちら

ReadMeに記載した更新履歴は、次の通りです。
Phyllosoma 1.40/KM-1505 (2024.2.17)
 ・サンプルプログラムに、FILEMAN.BAS(ファイルマネージャー)を追加。
 ・クラスライブラリーに、BUTTON(ボタン操作), GEN3O(源ノ角ゴシック表示), 
  QRCODE(QRCODE表示), TSC2046(タッチパネル操作)を追加。
 ・液晶を使わない場合に、SPI命令でspi1を使う事を可能にした。
 ・PUTBMP命令で、横幅が長い画像を表示する際の不具合を修正。
 ・ファイル一覧表示の際、ファイル更新日時の表示を可能にした。
 ・ファイル一覧表示の際の、ファイル名・ファイル更新日時による表示順に対応。
 ・ILI9488液晶で縦置の際の表示不具合を修正。
 ・FRENAME, MKDIR命令及びFRENAME(), MKDIR()関数の追加。
 ・補助コード(auxcode)を追加できる機能を実装

ファイルマネージャーの同梱と、ファイル一覧の機能向上

今回の目玉機能は、ファイルマネージャーを同梱した事です。これにより、スタンドアローン機としての最低限の機能は、ほぼそろった事になります。PC と連携しなくても MachiKania のみで、一通りの事は出来るようになったと思います。ファイルマネージャーはサンプルプログラムとして、「FILEMAN.BAS」の名で保存されていますので、選択して実行してください。なお、ファイルマネージャーは USB キーボード版で利用できます。

また、ファイル一覧表示の際に、ファイル名順やファイル作成時刻順で表示できるようになりました。今までは、MMC/SDカードに保存のファイル数が多くなると、目的のファイルを見つけ出すのに苦労しましたが、そういった苦労なしで見つけることができるようになりました。加えて、ファイル作成時刻を閲覧する事も出来るようになりました。

auxcode機能

MachiKania で、C で書いたコードを実行する方法として、今まで2つの方法を提供してきました(方法1方法2)。これらの方法では、クラスファイルを作成することができるので、いったんクラス化してしまえば、BASIC プログラムから取り込んで呼び出すことが可能です。ただ、クラス化するにあたって色々とコツが必要で、場合によってはうまくクラス化できないようなケースもあります。

そこで、MachiKania をソースコードからビルドする際に、補助機能を追加してビルドする事で、さまざまな種類の C コードを取り込めるようにしました。「auxcode」と名付けた機能が、それです。

ver 1.4 以降の MachiKania のソースコードには、「auxcode」という名のディレクトリーがあります(GitHub 該当ページはこちら)。デフォルトでは「auxcode.c」と「auxcode.cmake」の2つのファイルがありますが、これを書き換えた後に、MachiKania 全体をビルドすれば、補助機能が追加された MachiKania ができます。次のレポジトリーが、一例です。

https://github.com/kmorimatsu/hm01b0_machikania

これは、HM01B0 カメラを MachiKania で使うためのものです。このレポジトリーにある「auxcode」ディレクりーを MachiKania ソースコードに上書き保存してビルドすると、HM01B0 カメラに対応した MachiKania が作成されます。実行すると「HM01B0_INIT」「HM01B0_CAPTURE」「HM01B0_DRAW」「HM01B0_REG_WRITE」の4つの命令が追加で使えるようになり、それらを用いて HM01B0 カメラを制御したり画面に映像を表示したりできるようになります。

今後、MachiKania の新しいバージョンが公開された際にも、「auxcode」を新しいバージョンのソースコードにコピーしてビルドしなおすことで、将来のバージョンにも対応できます。「auxcode」の書き方は、HM01B0 の例を参考にしてください。リクエストがあれば、書き方についてもブログ記事を書くかもしれません。

追加のクラスライブラリー

BUTTON, GEN3O, QRCODE, TSC2046 の4つのクラスを、クラスライブラリーに追加しました。それぞれ、

・BUTTON は、6つあるボタンの読み取りを容易にする
・GEN3O は、CKNJ16 より大きなサイズのフォントを表示する
・QRCODE は、文字通り QRCODE を画面に表示する
・TSC2046 は、タッチパネルを利用する

際に、便利に使えるものです。今後も、クラスライブラリーを充実させていく予定です。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=982 Fri, 16 Feb 2024 19:19:19 PST ITEM982_20240216
MachiKania type P ver 1.3 に、天気予報を喋らせる https://www.rad51.net/blog/mycom/?itemid=981
作例として、天気予報の情報サイトからデーターを取ってきて、今日と明日の天気予報を得るような物を作ってみました。NTPから今日の日付も取ってこられるので、その情報も使います。今日の日付と天気予報は、画面に表示させるのではなくスピーカーで話させるようにしてみました。完成写真は、以下の通りです。小さな箱に、電源スイッチとスピーカーが取り付けられたものです。

2023-09-26-weatherBox.jpg

どんなものか

まずは、どんな動作をするのかの参考に、twitter.com に実行中の動画を載せましたので、ご覧ください(下の画像をクリックすると、twitter.comの該当ポストに移動します;音が出ます)。

2023-09-30-twitter.com.jpg

スイッチを入れておよそ10秒待つと、まず今日の日付と曜日、次に今日の天気予報と最高気温、続けて明日の天気予報と最低気温、最高気温を音声で知らせてくれます。紹介したものは英語のバージョンですが、日本語のバージョンも用意してあります。

箱の中身と、回路

箱の中は、こんな感じです。写真上は、電池・スピーカー・電源スイッチ。下は、Raspberry Pi Pico W。その左にあるDIP-8の石はアンプ IC (NJM2113D)です。

2023-09-30-inside1.jpg

別の角度からです。手前に見えるのは、micro-SDです。アダプターを、基板に半田付けしてあります。

2023-09-30-inside2.jpg

回路図は、下の通りです(クリックで、拡大)。Raspberry Pi Pico Wには、他にMachiKania の基本構成の通り、SDカードを接続しています。液晶ディスプレイは使用しないので、接続していません。

2023-09-30-schematic.png

プログラム

プログラムは、MachiKania BASIC で書かれており、「MACHIKAP.BAS」のファイル名で保存してあります。

useclass JSON,WGET
usevar Min0,Max0,Fnum0,Fstr0
usevar Min1,Max1,Fnum1,Fstr1

out 6,1

if val(strftime$("%Y"))<2023 then ntp

j$=WGET::FORSTRING$("https://dataservice.accuweather.com/forecasts/v1/daily/5day/332097?apikey=[AccuWeather API key]")
o=new(JSON,j$)

Min0=int(o.FQUERY#(".DailyForecasts[0].Temperature.Minimum.Value")+0.5)
Max0=int(o.FQUERY#(".DailyForecasts[0].Temperature.Maximum.Value")+0.5)
Fnum0=o.IQUERY(".DailyForecasts[0].Day.Icon")
Fstr0$=o.SQUERY$(".DailyForecasts[0].Day.IconPhrase")
Min1=int(o.FQUERY#(".DailyForecasts[1].Temperature.Minimum.Value")+0.5)
Max1=int(o.FQUERY#(".DailyForecasts[1].Temperature.Maximum.Value")+0.5)
Fnum1=o.IQUERY(".DailyForecasts[1].Day.Icon")
Fstr1$=o.SQUERY$(".DailyForecasts[1].Day.IconPhrase")

do
  c=coretimer()
  
  setdir "/wav"
  out 6,0
  gosub pwaveb,"todayis1.wav"
  gosub pwaveb,"todayis2.wav"
  gosub pwaveb,"week"+strftime$("%a")+".wav"
  gosub pwaveb,"month"+dec$(val(strftime$("%m")))+".wav"
  gosub pwaveb,"day"+dec$(val(strftime$("%d")))+".wav"
  gosub pwaveb,"forecas1.wav"
  gosub pwaveb,"weath"+dec$(Fnum0)+".wav"
  gosub pwaveb,"temp1.wav"
  gosub pwaveb,dec$(Max0)+"deg.wav"
  gosub pwaveb,"forecas2.wav"
  gosub pwaveb,"weath"+dec$(Fnum1)+".wav"
  gosub pwaveb,"temp3.wav"
  gosub pwaveb,dec$(Min1)+"deg.wav"
  gosub pwaveb,"temp4.wav"
  gosub pwaveb,dec$(Max1)+"deg.wav"
  out 6,1
  
  do until 60000000<coretimer()-c : idle :loop
loop

label pwaveb
  print args$(1);
  PLAYWAVE args$(1)
  print " ... ";
  do while playwave(0)
    idle
  loop
  print "done"
return

天気予報は、AccuWeather から得ています。上のコードの URL の所で「[AccuWeather API key]」は、私の個人用のAPIキーです。AccuWeatherは、登録すれば無料で使えますので、必要ならば登録して API key を取得してください。また「332097」は、私が住んでいる町(カリフォルニア・デービス)の番号です。これを他の番号に変えれば、別の町の情報を得ることができます。

上のコードとほぼ同じものを、GitHubレポジトリーに上げましたので、参考にしてください(ENGLISH.BASがそれ)。

https://github.com/kmorimatsu/machikania-basic/tree/main/weather

URLは、"http://www.rad51.net/projects/weather/tokyo.php"としています。これを使用する分には、AccuWeatherのアカウントは必要ありません。ただし、東京限定です(osaka.phpも使えます)。

GitHubには、「TOKYO.BAS」「OSAKA.BAS」の2つのプログラムも載せてあります。こちらは、日本語で今日の日付・曜日・天気予報を喋るものです。それぞれ、東京・大阪の天気予報バージョンです。

JSONクラスについて

このプロジェクトでは、WGET クラス以外に JSON クラスを用いています。JSON クラスも、WGET と同様に、ver 1.3 でライブラリーに追加しました。JSON 文字列の中から、目的のものを抽出するのに便利です。詳しい使い方は、help.txtを参照してください。

ここでは、JSON クラスをどのように使っているかを説明します。まず、「o=new(JSON,j$)」で JSON オブジェクトを作成しています。「j$」は、web サイトから得られた JSON 文字列です。

続けて、「o.FQUERY#(".DailyForecasts[0].Temperature.Minimum.Value")」のように使っています。「FQUERY#()」は、浮動小数点実数値を読み込むためのメソッドです。「".DailyForecasts[0].Temperature.Minimum.Value"」の部分で、どの情報を読み出すかを指定しています。この例では、「DailyForecasts」をまず見つけ、これが配列なので「[0]」で配列の一番初めの内容を調べます。続けて「Temperature」「Minimum」「Value」順で追っています。「IQUERY()」「SQUERY$()」も同様で、それぞれ、整数値・文字列の内容を調べて読み込むためのメソッドです。

音声データーについて

発声する音声データーは、実行時にその都度作成するのではなく、予めすべての可能性について発声させたものを WAVE ファイルにして保存してあり、その中から選んで再生しています。英語のデーターは https://ttsreader.com/ から取得して、「wav」ディレクトリーに配置しました。日本語のデーターは https://note.cman.jp/other/voice/ から取得して「wavjp」ディレクトリーに配置してあります。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=981 Sun, 01 Oct 2023 00:28:30 PDT ITEM981_20231001
MachiKania type P ver 1.3 で、http サーバー https://www.rad51.net/blog/mycom/?itemid=980 WiFi 接続及びインターネット接続が出来るようになりました。この記事では、MachiKania を http サーバーとして利用する方法について述べます。

ver 1.3 では WiFi 機能の追加に伴って13種類の新たな命令・関数が追加されていますが、それらを使ってサーバーを構築するのは、骨の折れる作業です。そこで、需要の高い http サーバーを構築するためのクラス、HTTPD を作成しました。

この、HTTPD クラスを用いれば、簡単に http サーバー(www サーバー)を構築することができます。この記事では、HTTPD クラスの使い方について述べます。

サンプルプログラム

ver 1.3 の配布アーカイブには、HTTPDクラス用のサンプルプログラムが付いています。「HDEAMON.BAS」がそれで、以下の内容です。

useclass HTTPD
h=new(HTTPD,80,"/httproot")
print "server started as http://";ifconfig$(0);"/"
do
  h.START()
  system 201,val(h.GETPARAM$("led"))
  print h.LASTURI$()
loop


REM 次の内容を、"index.htm"のファイル名で保存し、
REM "httproot"ディレクトリーに配置する。
REM ただし、各行冒頭の「REM 」は、削除すること。

REM <html><head><title>Test</title>
REM <meta name="viewport" content="width=1, initial-scale=5"></head>
REM <body>
REM <h5 style="text-align:center"><a href="?led=1">ON</a></h5>
REM <h5 style="text-align:center"><a href="?led=0">OFF</a></h5>
REM </body></html>

11行目以下は、コメントです。このコメントの内容に従って、「index.htm」という名のファイルを用意し、「httproot」ディレクトリーを作成してそこにコピーしてください。「HDEAMON.BAS」を実行すると、下のような表示になるはずです。

2023-09-27-hdeamon.jpg

「192.168.137.109」の所は、環境によって異なります。多くの場合、「192.168」から始まる4つの数字になる筈で、http サーバーが走っているローカルLANのIPアドレスです。この場合、「http://192.168.137.109/」に、ブラウザーからアクセスしてみます。PCでもスマートフォンでも構いません。下は、スマートフォンから接続した時の表示です。

2023-09-27-smartphone.jpg

MachiKaniaの画面は、下のようになります。

2023-09-27-hdeamon2.jpg

ここで、スマートフォンの画面で「ON」「OFF」「ON」の順でゆっくり押すと、Raspberry Pi Pico W の LED が、ついたり消えたりするはずです。MachiKania の画面は、以下のようになります。

2023-09-27-hdeamon3.jpg

どうでしょうか。MachiKania 上に http サーバーが構築できて、PCやスマートフォンからアクセスする事で、MahiKaniaに信号を送ることができるのが、分かると思います。

ほぼ同じ操作を動画にしてtwitter.comに上げましたので、興味があればご覧ください。

2023-09-27-movie.png

より複雑な web ページも、構築可能

上で紹介したサーバーで表示されるのは、たった6行からなるシンプルな HTML ですが、より複雑なページや、画像を含むページを表示可能です。

試しに、役者の阿部寛さんのホームページをローカルな環境の MachiKania type P で構築した http サーバー上にコピーさせていただき(外部公開していません)、ブラウザーからアクセスしてみました。動画を、twitter.comに上げてあります。

2023-09-27-abe.png

ファイル一覧とPCへのファイルダウンロード

HTTPD クラスは、ディレクトリー中のファイル一覧表示機能を持っています。例えば、以下の BASIC プログラムを実行すると、MMC/SDカードの一覧が、Apache のファイル一覧に似た形式で表示されます。

useclass HTTPD
h=new(HTTPD,80,"/")
do
  h.START()
loop

ディレクトリー間の移動も可能です。下は、「/LIB/WGET/」ディレクトリーに移動した時の表示です。表示は左から順に、ファイル名・更新日時・バイトサイズ・属性フラグです。

2023-09-27-wgetdir.png

ファイル名をクリックすると、当該ファイルをダウンロードする事も可能です。この機能を使うと、MachiKania 上のファイルを簡単にPCに取り込むことができます。

HTTPD クラスでサーバーを構築する場合、逆に、ディレクトリー一覧を表示させたくないときもあると思います。そういった場合は、該当のディレクトリーに「index.htm」を作成してください。ファイル内容は、空でも「<html></html>」でも、何でも良いです。

他のタイプのサーバーも構築可能

http サーバー以外のサーバーも、理論的には構築可能です。下は、TELNETサーバーを構築した例です。アルファベットの大文字は小文字に、小文字は大文字に変換して表示される仕様です。

TCPSERVER 23,0
print "Server started at port 23"
do
  do
    delayms 10
    c=TCPACCEPT()
  loop until c
  print "Connected"
  TCPSEND("Hello TELNET server!\r\n",-1,c)
  do while TCPSTATUS(0,c)
    for i=1 to 1000
      delayms 1
      if 0=TCPRECEIVE(&b,1,c) then continue
      i=0
      break
    next
    if 0x40<b and b<0x5b then
      b=b+0x20
    elseif 0x60<b and b<0x7b then
      b=b-0x20
    endif
    if i then b=0
    TCPSEND &b,1,c
    if 0x0d=b then
      b=0x0a
      TCPSEND &b,1,c
    endif
  loop
  print "Closed"
loop

実行中の様子の動画は、twitter.comに上げました。

2023-09-27-telnet.png ]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=980 Fri, 29 Sep 2023 19:25:34 PDT ITEM980_20230929
MachiKania type P ver 1.3 で、http クライアント https://www.rad51.net/blog/mycom/?itemid=979 WiFi 接続及びインターネット接続が出来るようになりました。この記事では、MachiKania を http クライアントとして利用する方法について述べます。

ver 1.3 では WiFi 機能の追加に伴って13種類の新たな命令・関数が追加されています。それらを使えば様々なインターネット接続(クライアント・サーバー)を行うことができますが、非常に複雑な手続きが必要です。そこで、インターネットの接続で最もよく使う、http プロトコルに関して、クラスライブラリーを用意しました。

ここでは、新規に追加されたクラスのうち、WGET クラスについて説明します。http クライアントを簡易に構築するためのクラスです。

最も簡単な使用方法

WGETクラスは、オブジェクトを作成せずに、スタティックメソッド呼び出しで使います(help.txtを参照)。多くの方が一番よく使うのは、おそらく「WGET::FORSTRING$()」です。以下の例は、もっとも簡単なサンプルプログラムです。

useclass WGET
t$=WGET::FORSTRING$("http://www.rad51.net/projects/typep/")
print t$

Webページにアクセスして、その内容を表示するものです。上のコードを実行すると、結果は以下の例のようになるはずです。
2023-09-24-wget.jpg
「<html>」から「</html>」が、指定のURLから取得した内容です。

多くの場合、「WGET::FORSTRING$()」を使うのが、確実で簡単な方法でしょう。得る情報がテキストなら(HTML, JSON, RSSなど)、この方法で簡単に得ることができます。

バイナリーファイルのダウンロード

「WGET::FORSTRING$()」では、ヌル文字(\0)を含むデーター、例えば画像ファイルの取り込みが出来ません。そういったデーターをインターネットからダウンロードしてくるには、「WGET::FORFILE()」もしくは「WGET::FORBUFFER()」を使います。下は、「WGET::FORFILE()」を使って、TIFFファイルをダウンロードしてファイルとして保存し、表示する例です(TIFFファイルは、16色もしくは256色の、圧縮無しのものに対応)。

useclass WGET,CSWTIF
WGET::FORFILE("temp.tif","http://www.rad51.net/projects/typep/image.tif")
i=new(CSWTIF,"temp.tif")
point 0,200
i.SHOW()

実行結果は、以下の例のようになるはずです。
2023-09-26-wget_forfile.jpg

「WGET::FORBUFFER()」を使う場合は、少し複雑ですが、以下のように書きます。実行結果は、上と同じです。下のコードの「b,4800」で、「b」はバッファーアドレス、「4800」はバッファーの有効バイト数です(ここで使用したTIFFファイルは、4770バイトです)。

useclass WGET,CSWTIF
dim b(1199)
s=WGET::FORBUFFER(b,4800,"http://www.rad51.net/projects/typep/image.tif")
fopen "temp.tif","w"
fput b,s
fclose
i=new(CSWTIF,"temp.tif")
point 0,200
i.SHOW()

セキュアーコネクション(https)も可能

httpプロトコルをセキュアーコネクションで行いたい場合(http ではなく、https)も、WGETを使えます。使い方は同じで、URLに"https://"と書くだけです。

ただし、ドキュメントの wifi.txt にも書きましたが、MachiKania で https サイトにアクセスした場合、通常のブラウザーによる https サイトへのアクセスに比べて、セキュリティーレベルが低いです。MachiKania から https サイトへのアクセスでは、パスワードや個人情報などを送付しないようにしてください。こちらから送付する情報なしでデーターを取得するだけなら、何も問題にする必要はありません。

WGETクラスの利用例

WGETクラスを利用して、天気予報をインターネットから得て知らせてくれる箱を作りました。詳しくは、別記事で説明します
2023-09-26-weatherBox.jpg]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=979 Fri, 29 Sep 2023 19:25:20 PDT ITEM979_20230929
MachiKania type P ver 1.3 で、ネット接続 https://www.rad51.net/blog/mycom/?itemid=978
公式ページはこちら
GitHubリリースページはこちら

ReadMeに記載した更新履歴は、次の通りです。
・Raspberry Pi Pico W を用いた WiFi 接続に対応。次の命令・関数を追加: 
 DNS$(), IFCONFIG$(), NTP, TCPACCEPT(), TCPCLIENT, TCPCLOSE, TCPRECEIVE, 
 TCPSEND, TCPSERVER, TCPSTATUS, TLSCLIENT, WIFIERR(), WIFIERR$()
・GCOLOR()関数の不具合を修正
・一部USBキーボードでのキー入力不具合に対応
・EOFの時、FGETC()関数が-1を返すようにした
・embed用にXIAO RP2040, RP2040-Zero, and Tiny-2040に対応
・SPIの対応ポートをINIファイルで指定出来るようにした
・SERIALステートメントの第3引数を省略した時の不具合を修正
・例外をトラップして画面表示するようにした
・CORETIMERが電源投入後およそ2000秒後から不具合を起こす事を修正
・ILI9488に対応
・RTC(Real Time Clock)をサポート。次の命令・関数を追加: 
 GETTIME$(), SETTIME. STRFTIME$()
・ファイル保存時の日時設定をサポート
・NTPサーバーによるRTCのセットをサポート
・SYSTEM 201 呼び出しにより、ボード付属のLEDのオン・オフを出来るようにした
・メモリーアロケーションの不具合を修正
・FREMOVE/SETDIR等のファイル関連命令を使用時の、ガベージコレクション不具合を修正
・WAVEプレーヤーの安定性を改善
・クラスのスタティックメソッド呼び出し不具合を修正
・FFINGD$(), FINFO(), FINFO$()の3つの関数を追加。ファイル一覧の作成が可能に
・REM 文に「"」を含む際のコンパイル時の不具合を修正


WiFi 接続機能

ver 1.3 で追加された目玉機能は、WiFi 接続です。WiFi 対応の Raspberry Pi Pico W で MachiKania を利用する事により、インターネットに接続して情報を得たり、イントラネットでサーバーを構築して他の機器と接続したりすることができるようになりました。まずは、ドキュメントのwifi.txtをお読みください。

WiFi接続用のBASIC命令群が多数追加されています。ただし、これらを直接利用してネット接続するコードを書くのは骨が折れるので、ネット接続を容易に行えるクラスを用意しました。

・WGET クラス。インターネットのhttp、httpsサイトから情報を得ることができる。
・HTTPDクラス。http サーバーを構築することができる。

これらに関しては、別途記事を書きましたので、そちらを参照してください(WGETの記事はこちらHTTPDの記事はこちら)。

WiFi機能を使用する場合は、次の点に注意して下さい。

1.Raspberry Pi Pico Wを使用する(Raspberry Pi Picoでは不可)。
2.Raspberry Pi Pico W用のuf2ファイル(pico_w_ili9341/phyllosoma.uf2等)をロードする。
3.MACHIKAP.INIで、WiFi を使うように設定する(「USEWIFI」を有効にする)。
4.MACHIKAP.INIでWiFi接続用のSSIDとパスワードを指定する(「WIFISSID=」及び「WIFIPASSWD=」)。
5.MACHIKAP.INIで、国情報を設定する(日本の場合は、「WIFICOUNTRY=JP」)
6.リアルタイムクロックを利用する場合(下記参照)は、MACHIKAP.INIで「INITIALNTP」を有効にする。

なお、5.のWIFICOUNTRYは、cyw43のソースコード(cyg43-driver/src/syw43_country.h)の60行目辺りからを参考にしてください。

設定がうまく行けば、起動時に次のような表示になります。ただし、「192.168.1.156」と「macserver」の部分は、環境によって異なります。
2023-09-23-MachiKaniaWiFi.jpg
このような表示が確認できれば、MachiKaniaでWiFiを使う準備が整いました。

リアルタイムクロック

リアルタイムクロック(Real Time Clock; RTC)が使えるようになりました。現在時刻は、プログラム中で指定する事も、ネット上のNTPサーバーから取得して設定する事も出来ます。また、ファイル保存時に、作成時刻・日時を設定する事が出来るようになりました。

NTPサーバーを利用して現在時刻を取得する方法で、リアルタイムクロックを使用する場合は、次の点に注意してください。

1.Raspberry Pi Pico Wを使う。
2.Pi Pico W 用のuf2ファイルをロードする。
3.MACHIKAP.INIで、WiFi を使うように設定する(「USEWIFI」を有効にする)
4.MACHIKAP.INIで、タイムゾーンを設定する(日本なら、TIMEZONE=9)
5.MACHIKAP.INIで、起動時にNTPサーバーに接続する様に設定する(「INITIALNTP」を有効にする)

RTCを扱う命令・関数として、GETTIME$(), SETTIME, STRFTIME$() の3つを用意しました。これらの使い方の詳細は、help.txtを参照してください。なお、一連の命令・関数では、日付・時刻を扱うために、ISO-8601 形式の文字列を使います。 ISO-8601 文字列は、次の例のような書式です(日付と時刻の間に「T」が挟まれています)。

2023-09-01T13:00:00(2023年9月1日午後1時0分0秒の場合)

XIAO RP2040, RP2040-Zero, Tiny-2040などの、小型RP2040ボードに対応

Ver 1.2までは、Raspberry Pi Picoや、ピンに互換性のあるYD-RP2040などが対象でしたが、Ver 1.3からは、XIAO RP2040, RP2040-Zero, Tiny-2040といった、ピン数の少ない小型互換ボードでも使えるようになりました。ただし、ピン数がRaspberry Pi Picoより少ないため、組込み機能(embed)での対応です。

RP2040-Zero, Tiny-2040で使う場合、デフォルトではSPI用のポートが取れないので、MACHIKAP.INIでSPI用のポートを設定できるようにしました。多くの場合、以下のように設定すれば使えるようになります。
SPIMISO=4
SPIMOSI=7
SPICLK=6
このように設定すれば、MISOがGP4で、MOSIがGP7で、CLKがGP6で使えるようになります。その他の使い方は、Ver1.2と同じです。上記のように設定したMACHIKAP.INI以外にBASICプログラムを含むMACHIKAP.BASを用意して、convert.phpもしくはconvert_kb.phpを実行してください。

Seeed XIAO RP2040の場合、GP5が使えないため、専用のuf2ファイルを用意しました。machikap-p2-130-RC3.zipに含まれている「xiao_embed」ディレクトリーのものを使用してください。なお、I/Oの割り当ては、下の通りです。

・GP0 I/O bit0 / UART TX / PWM3
・GP1 I/O bit1 / UART RX / SPI CS / PWM2
・GP2 I/O bit2 / SPI SCK / PWM1
・GP3 I/O bit3 / SPI MOSI
・GP4 I/O bit4 / SPI MISO
・GP6 I/O bit6 / I2C SDA
・GP7 I/O bit7 / I2C SCL

ILI9488液晶に対応

ILI9341の2倍の大きさの、ILI9488に対応しました。キャラクター表示の場合60x40文字、グラフィック表示の場合480x320ピクセルの表示が可能です。machikap-p2-130-RC3.zipに含まれている「pico_ili9488」ディレクトリーもしくは「pico_w_ili9488」のものを使用してください。それぞれ、Raspberry Pi Pico用と、Raspberry Pi Pico W用(WiFi用)です。

その他

その他、バグ修正と、色々追加機能があります。

CPUが例外を起こした場合、例外原因などを画面に表示するようにしました。何が不具合が起きた時の原因を調べやすくなりました。

Raspberry Pi PicoとRaspberry Pi Pico Wのボード搭載LEDの制御が、SYSTEMステートメントで行えるようになりました。「SYSTEM 201,1」でオン、「SYSTEM 201,0」でオフです。

MMC/SDカードに存在するファイルの一覧を、BASICプログラム中で得ることができるようになりました。FFINGD$(), FINFO(), FINFO$()の3つの関数を追加しています。使用方法は、help.txtを参照してください。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=978 Fri, 29 Sep 2023 19:24:59 PDT ITEM978_20230929
MachiKania type Pで、BASICコードからCで書かれたコードを呼び出す、その2 https://www.rad51.net/blog/mycom/?itemid=977 ひとつ前の記事では、CプロジェクトをHEXファイルに変換し、そこから必要なC関数を呼び出す方法について述べた。この記事では、もう一つの方法について述べる。

HEXファイルに変換する方法においては、複雑なCでのコーディングが必要な多くの事例に対応できる。一つの例として、正規表現エンジンを実装するMachiKaniaクラス(REGEXP クラス)の実装について述べた。

この記事で述べる方法では、Cのプロジェクトから必要なコードを抜き取って BASIC コードに変換してプログラムに埋め込む方法を取る。HEXを介する方法と比べた長所は、以下の通り。

1.一つの BASIC ファイルの中に C コードを埋め込むことができる
2.HEX を介した方法では HEX コードのメモリ上での配置位置を考慮する必要があったが、この方法ではその必要が無い
3.C プログラムの中から必要なものだけを抜き取って BASIC プログラムに埋め込むので、メモリー占有領域を最小限にできる


他方、短所は以下の通り

1.複雑な C プログラムでは対応できない場合がある

従って、それほど大きくない C のプログラムの場合はこの記事で述べる方法が有利である。後に述べる「c_convert.php」スクリプトの実行でエラーが出る、あるいは、作成されたBASIC プログラムが意図したように動作しない場合は、HEXを介する方法に移行すればよい。

BASIC に C コードを埋め込む例(hcw1アプリケーション)

先の記事と同様、次のような C 関数を BASIC から呼び出す例について述べる。
int add_values(int a, int b){
	return a+b;
}

この例を説明するために、GitHubレポジトリーを作成したので、参照していただきたい。Git Cloneした後に「hcw1」ブランチにスイッチし、Commit Log を見ていただければ、説明が分かりやすいと思う。
2023-03-18-log.png
また、この記事では、1から5までの手順ごとに該当レポジトリーへのリンクを付けたので、そちらも見ていただきたい。

1.まずは、Hello, World! から
まず、Cのプロジェクトを一つ作成する必要がある。何でも良いのだが、ここではpico-examplesからhello_usb.cを選んで、若干変更した物から始める事とする。これは、ビルドした後にPi Picoにインストールすれば、USB シリアル接続を通して、コンソール上に「Hello, World!」と表示し続けるプログラムだ(前の記事と同じ)。
#include <stdio.h>
#include "pico/stdlib.h"

int main() {
	stdio_init_all();
	while (true) {
		printf("Hello, world!\n");
		sleep_ms(1000);
	}
	return 0;
}
このプロジェクトをcmake/makeでビルドすると、hello_cw.uf2に加えてhello_cw.hexが作成されることが分かる。このようにして作成されたhexファイルを用いることになる。

2.目的のコードを、プロジェクト内に記述する
Cアプリケーションを記述してテストする環境が整ったので、ここで目的のコードを書いてみる。なお、ひとつ前の記事の方法とは異なり、この記事の方法では、プログラムはRAM上ではなくフラッシュ上に構築する方法を取る。上で述べたadd_values()関数を追加して、テスト結果を表示するようなものにした。
#include <stdio.h>
#include "pico/stdlib.h"

int add_values(int a, int b){
	return a+b;
}

int main() {
	int a=0,b=0;
	stdio_init_all();
	while (true) {
		printf("%d + %d = %d\n", a, b, add_values(a,b));
		a+=1;
		b+=2;
		sleep_ms(1000);
	}
	return 0;
}

3.C コンパイラーの最適化を無効にする
ARM gcc コンパイラーの最適化を無効にするため、CMakeFiles.txtに次の記述を追加している。
add_definitions(-O0)

ひとつ前の記事でも述べたが、この記事で述べる方法でも、C のコードを埋め込もうとする場合、以下の点に注意が必要だ。

a.呼び出そうとするC関数が、必ずビルドオブジェクトに含まれるようにする
b.呼び出そうとするC関数の引数は、4つまで
c.呼び出そうとするC関数の引数の取り扱いに関して、ビルドの際の最適化で標準のARMレジスター使用(R0, R1, R2, R3を使用する)から変更されないようにする


a.の対策のためには、必要な関数がすべて、「main()」関数、もしくはそこから呼び出される関数の中で、最低一度は呼び出される必要がある。でないと、リンクの際に不必要な関数コードとして、削除されてしまう。

また、Cコンパイラー(gcc)が行う最適化のために、関数がインライン展開されてしまう事もあり、そうなると外部から呼び出すことができなくなってしまう。これを防ぐ方法にはさまざまあり、1:目的の関数を「main.c」とは別のファイル内に記述する、2:「__declspec(noinline)」アトリビュートを使う、3:最適化を行わない、などがある。

b.は ARM gcc コンパイラーの規約に関係するもので、これを遵守しないと(引数を5つ以上にしてしまうと)、正常に動作しない。

c.の対策は色々と複雑で、同一のCファイル内で目的の関数を呼び出している場合に変なレジスター使用が起こるようだ。最適化の一つなので、当然ながら最適化を行わないようにすることで回避することができる。

以上の事から、トラブルを防ぐにはgccの最適化を停止することが有効である。CMakeLists.txtに「add_definitions(-O0)」の一行を加えたのは、そのためである。特殊な作例で、実行速度が最大でないといけないようなケースにはこの方法は使えないが、そうでなければ、最適化を停止して使用するのが無難だろう。

4.PHPスクリプトを配置する
作成されたHEXファイルを呼び出すBASICプログラムを自動作成するためのスクリプト「c_convert.php」を用意した。このスクリプトは、PHPで記述されているので、PHPがない場合はインストールが必要である。このPHPスクリプトは汎用であるが、冒頭の記述(13-34行目辺り)を若干編集して使用する。今回の例では、次のようになっている。
class configclass{
	// File names
	public $dis_file='./build/hello_cw.dis';
	public $map_file='./build/hello_cw.elf.map';
	public $hex_file='./build/hello_cw.hex';
	//public $debug_file='./machikap/machikap.bas';
	
	// Functions to be exported
	public $functions=array(
//		'machikania_init',
		'add_values',
	);
	
	// Additional .rodata to be used (function names are excluded)
	public $rodata=array(
	);
	
	// Excluded addresses as .rodata and RAM
	public $excluded=array(
		0x20040000,
	);
};
$dis_file, $map_file, $hex_fileでは、ビルドの際に作成された「*.dis」「*.map」「*.hex」の3つのファイルの位置を指定する。$debug_fileはオプションで、PC-Connect機能を利用してデバッグを行っている際の、BASICファイルの位置を指定する。必要が無い場合は、「//」でコメントアウトしておく。また、$functionsには、BASICから呼び出したいCの関数名を列挙しておく。$rodataには、自動認識されないが必要な部品名を文字列で指定したリストを指定する。逆に、$excludedには必要のない部品の物理アドレスのリストを指定する。通常は、$rodataと$excludedの設定は変更の必要は無いはずだ。

5.Cプログラムのビルドと、PHPスクリプトの実行
ここまで準備できれば、Cプログラムをビルドした後に、PHPスクリプトを実行する。「result.txt」と「log.txt」の二つのファイルが出来ているはずだ。ここでの例のように進めると、「result.txt」の内容は次のようになる。
USEVAR C_RAM
GOSUB INIT_C
END

LABEL INIT_C
  DIM C_RAM(0)
  REM ram vectors
  REM rodata vectors
  REM ram function vectors
  REM callback function vectors
RETURN

ALIGN4
LABEL C_ADD_VALUES
  EXEC $68f0,$6931,$6972,$69b3,$f000,$f802,$bd00,$46c0

REM 28 bytes
LABEL C_FUNCTIONS
EXEC $b580,$b082,$af00,$6078,$6039,$687a,$683b,$18d3,$0018,$46bd,$b002,$bd80,$b580,$b082

REM 0 bytes
LABEL C_RODATA
このBASICプログラムは、C コードを埋め込んで呼び出しできるようにした、必要最小限の構成になっている。目的のコードを、3行目の「gosub INIT_C」と4行目の「end」の間に書けばよい。例えば、次のように変更して、BASICプログラムを完成させてみよう。
USEVAR C_RAM
GOSUB INIT_C

for i=1 to 10
  print a,b,a+b,gosub(C_ADD_VALUES,a,b)
  a=a+1
  b=b+2
next

END

LABEL INIT_C
  DIM C_RAM(0)
  REM ram vectors
  REM rodata vectors
  REM ram function vectors
  REM callback function vectors
RETURN

ALIGN4
LABEL C_ADD_VALUES
  EXEC $68f0,$6931,$6972,$69b3,$f000,$f802,$bd00,$46c0

REM 28 bytes
LABEL C_FUNCTIONS
EXEC $b580,$b082,$af00,$6078,$6039,$687a,$683b,$18d3,$0018,$46bd,$b002,$bd80,$b580,$b082

REM 0 bytes
LABEL C_RODATA
あとは、このBASICプログラムをMMC/SDカードにコピーすれば、実行することができる。実行時のスナップショットは、以下の通り。
2023-03-18-20230318_205201.png

以上が、簡単なCコードをBASICプログラムに埋め込んで呼び出すための手順である。

エラーが出た場合

「c_convert.php」は、ひとつ前の記事で述べた「c_convert2.php」と比べて少し複雑なアルゴリズムを用いていて、C のコードから必要部分を抜き出して BASIC に埋め込む動作をしている。残念ながら、複雑な構造の C コードに関しては、解析がうまく行かず、PHPスクリプトの実行中にエラーになったり、完成した BASIC プログラムが正常に動作しない事が起きうる。そういう場合は、ひとつ前の記事で述べた HEX ファイルを作成する方法の方が対応できる範囲が広いので、そちらを試していただきたい。

どんどん C コードを取り込もう

ひとつ前の記事では、複雑な C プログラムの MachiKania BASIC への取り込みについて述べたが、手続きが複雑であった。簡単な C プログラムならこの記事で書いた方法でより簡便に取り込める。それにより、MachiKania の応用範囲がさらに広くなることを、期待している。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=977 Sun, 26 Mar 2023 10:45:14 PDT ITEM977_20230326
MachiKania type Pで、BASICコードからCで書かれたコードを呼び出す https://www.rad51.net/blog/mycom/?itemid=976
方法は大きく分けて二通りあって、一つは RAM 上に HEX アプリケーションを読み込んでそこに含まれる機能を呼び出す方法である。RAM 上にアプリケーションを配置して HEX ファイルを作成する方法は、別の記事で紹介した。この記事では、作成したHEXファイル中にある C で関数をどのようにして呼び出すかについて述べる。この手法を用いて HELLO_CW アプリケーションREGEXP クラスを作成したので、それを例に挙げながら説明する。

もう一つは、C でビルドしたオブジェクトから、必要な機能だけをピックアップして、BASIC の EXEC ステートメントに変換して埋め込む方法である。簡単な C のコードを実行させる場合には、この方法が簡便でサイズもコンパクトにできるが、これについては、別の記事で取り上げることにする。

この記事では HEX アプリケーションを読み込んでそこに含まれる機能を呼び出す方法について述べたい。複雑な C のコードを呼び出すのに向いた方法である。

BASIC からHEX アプリケーションを呼び出す例(hello_cwアプリケーション)

もっとも簡単な例として、2つの整数値の和を返す関数をCで次のように記述して、この関数を呼び出す方法について説明する。
int add_values(int a, int b){
	return a+b;
}

この例を説明するために、GitHubレポジトリーを作成したので、参照していただきたい。Git CloneしてCommit Logを見ていただければ、説明が分かりやすいと思う。
2023-03-17-log.png
また、この記事では、1から8までの手順ごとに該当レポジトリーへのリンクを付けたので、そちらも見ていただきたい。

1.まずは、Hello, World! から
まず、Cのプロジェクトを一つ作成する必要がある。何でも良いのだが、ここではpico-examplesからhello_usb.cを選んで、若干変更した物から始める事とする。これは、ビルドした後にPi Picoにインストールすれば、USB シリアル接続を通して、コンソール上に「Hello, World!」と表示し続けるプログラムだ。
#include <stdio.h>
#include "pico/stdlib.h"

int main() {
	stdio_init_all();
	while (true) {
		printf("Hello, world!\n");
		sleep_ms(1000);
	}
	return 0;
}
このプロジェクトをcmake/makeでビルドすると、hello_cw.uf2に加えてhello_cw.hexが作成されることが分かる。このようにして作成されたhexファイルを用いることになる。

2.RAM上のアプリケーションに変更する
このHello, World!アプリケーションは、hello_cw.uf2をRPI-RP2ドライブにコピーすると、フラッシュ上にプログラムが構築され、電源を切ったりリセットボタンを押したりしても、同じプログラムが実行される。しかし、今回必要なCプログラムは、フラッシュ上に構築されるものではなく、RAM上に実行コードが構築されるタイプの物である。このための変更を行う。この方法については、別に記事を書いてあるので、詳細はそちらを参照していただきたい。この変更を施すと、hello_cw.uf2をRPI-RP2ドライブにコピーした直後は目的のプログラムが実行されるが、リセットボタンを押すと、元の(フラッシュにインストールされていた)プログラムに戻ることが分かる。

3.目的のコードを、プロジェクト内に記述する
Cアプリケーションを記述してテストする環境が整ったので、ここで目的のコードを書いてみる。上で述べたadd_values()関数を追加して、テスト結果を表示するようなものにした。
#include <stdio.h>
#include "pico/stdlib.h"

int add_values(int a, int b){
	return a+b;
}

int main() {
	int a=0,b=0;
	stdio_init_all();
	while (true) {
		printf("%d + %d = %d\n", a, b, add_values(a,b));
		a+=1;
		b+=2;
		sleep_ms(1000);
	}
	return 0;
}

4.RAM格納アドレスを変更する
今のままでは、作成されたCアプリケーションが、0x20000000から配置され、これはMachiKania BASICの実行コード配置位置と重なってしまう。そこで、これらが重ならないように、配置されるRAMアドレスを修正しなければならない。0x20000000から0x2002FFFFまでがMachiKania BASICのコード格納領域なので、始めの方のアドレスをBASICコード用に少し取っておいて、その少し後ぐらいに格納すればよい。ここでは、0x20010000からの64K bytesを使う事とする。「memmap_no_flash.ld」の26行目を、次のように書き換える。
RAM(rwx) : ORIGIN =  0x20010000, LENGTH = 64k

5.MachiKaniaライブラリーを取り込む
ここで、アプリケーションに、MachiKania BASICと連携するためのライブラリーを取り込む。
2023-03-17-include.png
「machikania.c」と「machikania.h」を追加した。これらのファイルはhello_cwプロジェクトに特化したものではなく、共通の物なので、他のケースでもここからコピーして使えるはずである。また、「hello_usb.c」を編集して、以下のような内容にした。
#include <stdio.h>
#include "pico/stdlib.h"
#include "machikania.h"

int add_values(int a, int b){
	return a+b;
}

int main() {
	int a=0,b=0;
	stdio_init_all();
	machikania_init();
	while (true) {
		printf("%d + %d = %d\n", a, b, add_values(a,b));
		a+=1;
		b+=2;
		sleep_ms(1000);
	}
	return 0;
}
「#include "machikania.h"」と、「machikania_init();」の2行を加えてある。また、「CMakeFiles.txt」は、「machikania.c」をビルドの対象に加えるようにするだけでなく、12行目に以下の行を追加している。
add_definitions(-O0)
この設定項目の追加の意味については、次の段落で述べる。

この記事で述べる方法で、MachiKaniaからHEXファイル内のコードを呼び出そうとする場合、以下の点に注意が必要だ。

a.呼び出そうとするC関数が、必ずHEXオブジェクトに含まれるようにする
b.呼び出そうとするC関数の引数は、4つまで
c.呼び出そうとするC関数の引数の取り扱いに関して、ビルドの際の最適化で標準のARMレジスター使用(R0, R1, R2, R3を使用する)から変更されないようにする


a.の対策のためには、必要な関数がすべて、「main()」関数、もしくはそこから呼び出される関数の中で、最低一度は呼び出される必要がある。でないと、リンクの際に不必要な関数コードとして、削除されてしまう。

また、Cコンパイラー(gcc)が行う最適化のために、関数がインライン展開されてしまう事もあり、そうなると外部から呼び出すことができなくなってしまう。これを防ぐ方法にはさまざまあり、1:目的の関数を「main.c」とは別のファイル内に記述する、2:「__declspec(noinline)」アトリビュートを使う、3:最適化を行わない、などがある。

b.は ARM gcc コンパイラーの規約に関係するもので、これを遵守しないと(引数を5つ以上にしてしまうと)、正常に動作しない。

c.の対策は色々と複雑で、同一のCファイル内で目的の関数を呼び出している場合に変なレジスター使用が起こるようだ。最適化の一つなので、当然ながら最適化を行わないようにすることで回避することができる。

以上の事から、トラブルを防ぐにはgccの最適化を停止することが有効である。CMakeLists.txtに「add_definitions(-O0)」の一行を加えたのは、そのためである。特殊な作例で、実行速度が最大でないといけないようなケースにはこの方法は使えないが、そうでなければ、最適化を停止して使用するのが無難だろう。

6.PHPスクリプトを配置する
作成されたHEXファイルを呼び出すBASICプログラムを自動作成するためのスクリプト「c_convert2.php」を用意した。このスクリプトは、PHPで記述されているので、PHPがない場合はインストールが必要である。このPHPスクリプトは汎用であるが、冒頭の記述(13-26行目辺り)を若干編集して使用する。今回の例では、次のようになっている。
class configclass{
	// File names
	public $dis_file='./build/hello_cw.dis';
	public $map_file='./build/hello_cw.elf.map';
	public $hex_file='./build/hello_cw.hex';
	//public $debug_file='./machikap/machikap.bas';
	//public $debug_hex='./machikap/hello_cw.hex';
	
	// Functions to be exported
	public $functions=array(
		'machikania_init',
		'add_values',
	);
};
$dis_file, $map_file, $hex_fileでは、ビルドの際に作成された「*.dis」「*.map」「*.hex」の3つのファイルの位置を指定する。$debug_file, $debug_hexはオプションで、PC-Connect機能を利用してデバッグを行っている際の、BASICファイルとHEXファイルの位置を指定する。必要が無い場合は、「//」でコメントアウトしておく。また、$functionsには、BASICから呼び出したいCの関数名を列挙しておく。

7.不必要なUSB機能を削除する
Pi PicoのUSBシリアル機能は、アプリケーション作成時やデバッグ時には便利であるが、完成したHEXファイルには必要が無い機能である。USBシリアル機能のためには大きなプログラム領域が必要なので、これを削除することで、HEXファイル及び占有RAM領域を小さくすることができる。USBシリアル機能を削除するためには、CMakeLists.txtの26行目を、次のようにすればよい。
pico_enable_stdio_usb(hello_cw 0)

8.Cプログラムのビルドと、PHPスクリプトの実行
ここまで準備できれば、Cプログラムをビルドした後に、PHPスクリプトを実行する。「result.txt」と「log.txt」の二つのファイルが出来ているはずだ。ここでの例のように進めると、「result.txt」の内容は次のようになる。
useclass CLDHEX
usevar C_CODE
gosub INIT_C
end

label INIT_C
  var A,V
  REM Load the main code
  A=$20010000
  C_CODE=new(CLDHEX,"HELLO_CW.HEX",A,65536)
  REM data_cpy_table
  REM Link functions
  V=(A+1168-DATAADDRESS(C_MACHIKANIA_INIT)-12)>>1
  poke16 DATAADDRESS(C_MACHIKANIA_INIT)+8,$f000+(V>>11)
  poke16 DATAADDRESS(C_MACHIKANIA_INIT)+10,$f800+(V and $7ff)
  V=(A+1068-DATAADDRESS(C_ADD_VALUES)-12)>>1
  poke16 DATAADDRESS(C_ADD_VALUES)+8,$f000+(V>>11)
  poke16 DATAADDRESS(C_ADD_VALUES)+10,$f800+(V and $7ff)
  REM Initialize C global variables
  gosub C_MACHIKANIA_INIT
return

label C_MACHIKANIA_INIT
  exec $68f0,$6931,$6972,$69b3,$f000,$f800,$bd00
label C_ADD_VALUES
  exec $68f0,$6931,$6972,$69b3,$f000,$f800,$bd00
このBASICプログラムは、カレントディレクトリーにあるHEXファイル(HELLO_CW.HEX)を取り込み、Cプログラム中の「machikania_init();」を呼び出すだけの、必要最小限の構成になっている。目的のコードを、3行目の「gosub INIT_C」と4行目の「end」の間に書けばよい。例えば、次のように変更して、BASICプログラムを完成させてみよう。
useclass CLDHEX
usevar C_CODE
gosub INIT_C

for i=1 to 10
  print a,b,a+b,gosub(C_ADD_VALUES,a,b)
  a=a+1
  b=b+2
next

end

label INIT_C
  var A,V
  REM Load the main code
  A=$20010000
  C_CODE=new(CLDHEX,"HELLO_CW.HEX",A,65536)
  REM data_cpy_table
  REM Link functions
  V=(A+1168-DATAADDRESS(C_MACHIKANIA_INIT)-12)>>1
  poke16 DATAADDRESS(C_MACHIKANIA_INIT)+8,$f000+(V>>11)
  poke16 DATAADDRESS(C_MACHIKANIA_INIT)+10,$f800+(V and $7ff)
  V=(A+1068-DATAADDRESS(C_ADD_VALUES)-12)>>1
  poke16 DATAADDRESS(C_ADD_VALUES)+8,$f000+(V>>11)
  poke16 DATAADDRESS(C_ADD_VALUES)+10,$f800+(V and $7ff)
  REM Initialize C global variables
  gosub C_MACHIKANIA_INIT
return

label C_MACHIKANIA_INIT
  exec $68f0,$6931,$6972,$69b3,$f000,$f800,$bd00
label C_ADD_VALUES
  exec $68f0,$6931,$6972,$69b3,$f000,$f800,$bd00
あとは、このBASICプログラムとHELLO_CW.HEXをMMC/SDカードにコピーすれば、実行することができる。実行時のスナップショットは、以下の通り。
2023-03-18-20230318_012739.png

以上が、簡単なCコードをHEXに変換して、MachiKania BASICプログラムから呼び出すための手順である。

応用編:REGEXPクラスでの使用例

HEX アプリケーションを利用する方法について、応用例について取り上げる。また、ここでは動作のメカニズムに関しても少し説明する。REGEXP クラスを見ていただきたい。上で述べたHELLO_CWプログラムはCのコードを実行するための最小限の構成であるが、REGEXPクラスでは、次のように発展させてある。

・RAM配置アドレスの異なる複数のHEXファイルを作成し、メモリーの空きを見つけて適切なHEXプログラムをロードする
・複数の*.cファイルにまたがる、少し規模の大きいプログラムである
・mallocを使用している
・RAM占有領域を、必要最小限の大きさ(32 kb)に制限している


このクラスの構造がどうなっているか、まず説明しよう。REGEXP ディレクトリーには、以下のファイル・ディレクトリーが存在する。

2023-01-30-dir.png

help.txtは説明書きなので、ここでは取り上げない。「regexp.bas」以外に「hex」ディレクトリーと「c」ディレクトリーがある。「hex」ディレクトリーに含まれるファイルは、以下の通り。

2023-01-30-hexdir.png

ここには、7つの HEX ファイルがあり、それぞれでRAM上の配置アドレスが異なる。「c」ディレクトリーに含まれるファイルは、以下の通り。

2023-01-30-cdir.png

ここには、「c_convert2.php」という PHP スクリプトと、C のソースコードを含む「src」ディレクトリーがある。

まずは、regexp.bas の中身から見てみよう。ソースコードは、こちらで閲覧していただきたい。なお、ここではc_convert2.phpで自動作成されるコードについてのみ説明し、REGEXPクラスが扱う正規表現エンジンに関するコードの説明は割愛する。

まず冒頭の6行目:
useclass CLDHEX
CDLHEXクラスを読み込んでいる。このクラスは、HEX ファイルを読み込んで、RAM に構築する役割がある。なお、ここで作成した HEX ファイルは、前の記事で説明したように作成されたもので、アプリケーションはフラッシュ上でなく、RAM上に構築される。上記「HEX」ディレクトリーにあるものがそれで、REGEXPクラスでは7つある中から適応するもの(なるだけ、格納アドレスが若い物)を選んで読み込むようにしてある。

次に見ていただきたいのが、111行目の
label INIT_C
以降のコードである。ここは、REGEXP クラスの実行時の初めに呼ばれる部分で、C で書かれたコードを BASIC から呼び出すための前準備をしている。まず、
A=gosub(INIT_C_LDHEX)
でHEXファイルをロードして、その後に複数の「POKE16」ステートメントを実行している。これらは、「C_PRECOMP」「C_REGCOMP」等のサブルーチン呼び出しで、HEXファイル中のどのアドレスを呼び出すかを、設定するための物である。

136行目の「label C_MACHIKANIA_INIT」以下のコードを見ていただきたい。EXEC ステートメントが並んでいる。これらの機械語は、次のアセンブリーコードである。
68f0          ldr    r0, [r6, #12]
6931          ldr    r1, [r6, #16]
6972          ldr    r2, [r6, #20]
69b3          ldr    r3, [r6, #24]
f000 f800     bl    <xxxx>
bd00          pop    {pc}
「[r6, #12]」等は、MachiKania BASIC の「ARGS(1)」等に相当するコードで、サブルーチン呼び出し時の引数を、R0 などの ARM レジスターに代入している。ここから分かるように、関数の引数は4つまでに限定される。「bl」 インストラクションは、上で述べた「POKE16」ステートメントにより、HEXファイル中の該当する関数へジャンプするアセンブリーに置き換えられる。これらの仕様により、BASICコードからHEXファイル中の該当する関数を呼び出す事が可能になる。最後の「pop {pc}」は、MachiKania BASIC の「RETURN」ステートメントに相当する。

HEXファイルの作成方法と、HEX 中の C 関数を呼び出すBASICコードの作成方法

HEXファイルは、「c/src」ディレクトリー内のソースコードをビルドすると、作成できる。一回のビルドで、7つのHEXファイルが同時に作成できる構成である。対応するリンカースクリプトは、「c/src/lds」ディレクトリーにある7つで、0x20002000, 0x20004000, 0x20008000, 0x2000c000, 0x20010000, 0x20018000, 0x20020000 の RAM アドレスに、32k バイトの長さでビルドオブジェクトを配置するタイプの物だ(memmap_no_flash.ld を元に作成; 領域の長さはビルドオブジェクトが収まるぎりぎりの長さ+α)。ビルドすると、*.hex だけでなく、*.elf, *.uf2, *.dis, *.map などのファイルも同じディレクトリーに作成される。私は、すべて「build」という名のディレクトリーに作成されるようにした。

次に、BASIC コードを作成する。これは、上で説明した C コードのビルドが終わった後に、「c_convert2.php」スクリプトをPHPで実行することにより行う。このスクリプトを使用する前に、以下の箇所を編集する。
class configclass{
	// File names
	public $dis_file='./build/regexp02.dis';
	public $map_file='./build/regexp02.elf.map';
	public $hex_file='./build/regexp02.hex';
	public $debug_file='./machikap/regexp.bas';
	public $debug_hex='./machikap/regexp02.hex';
	
	// Functions to be exported
	public $functions=array(
		'machikania_init',
		'precomp',
		'regcomp',
		'regexec',
		'regsub',
	);
};
「$dis_file」「$map_file」「$hex_file」には、3つのビルドオブジェクトファイルの格納位置を指定する。「$debug_file」と「$debug_hex」はオプションで、指定しなくても良いが、このスクリプトを実行後にテストを行いたい場合、書き換える BASIC ファイルと HEX ファイルを指定する(PC-connect 機能を用いてデバッグを行う事を想定;指定しない場合は、これらの2つの行を「//」でコメントアウトする)。「$functions」には、エクスポートしたい C コードの関数を指定する。REGEXPの例では、5つの関数が指定されている。

「c_convert2.php」を実行すると、「result.txt」が作成される。この BASIC ファイルには、HEX 中の C 関数を呼び出すための必要最小限のコードが含まれるため、目的のアプリケーションを作成するために編集して用いる。

C ソースコードの書き方

ここでの C のソースコードを書く際は、いくらか工夫が必要である。

1.上でも述べたが、フラッシュ領域ではなく RAM 領域にコードを配置する(リンカースクリプトは memmap_no_flash.ld を元に作成)。
2.必要のないライブラリーなどは、なるだけ取り込まれないようにする。
3.gcc による最適化は、行わない。

「c/src/CMakeLists.txt」の次の記述を見ていただきたい。
set(PICO_NO_FLASH 1)
set(ENABLE_USB_UART 0)
add_definitions(-O0)
上で述べた3つの事項に該当する部分の記述である。「PICO_NO_FLASH 1」は、フラッシュを用いずに RAM 領域にコードを構築するのに必要な設定。「ENABLE_USB_UART 0」は、USBを用いたシリアル通信機能を含めないための指定である(CMakeListsSub.txtの中で「pico_enable_stdio_usb(${ENV_TARGET} ${ENABLE_USB_UART})」として使用されている)。この通信機能は、C のコードをデバッグするときには必要であるが、最終的な HEX ファイルに含める必要はない。最後の「-O0」は、gcc によるコンパイルの際に最適化を行わないようにする指定だ。最適化を行うと、時として関数の引数の扱いを変えたりすることによる誤動作の可能性があるので、最適化をオフにしておくことをお勧めする。

BASIC から呼び出しを行いたい関数は、なるだけmain() 関数とは別の C ファイルに記述するようにする(CMakeLists.txtで「add_definitions(-O0)」を指定した場合は、同じCファイルに記述可能)。また、main() 関数内では、これらの関数を呼び出すコードを記述しておく。これにより、最終的なビルドオブジェクトに、必要とする関数のコードが必ず含まれるようにする。

C から MachiKania の機能を呼び出すためのコードは、「machikania.c」に用意した。使用の際は、「machikania.h」をインクルードして用いる。なお、ここには「malloc()」「calloc()」「free()」「exit()」の4つの関数も含まれているので、これらを用いたい場合も、「machikania.c」と「machikania.h」が必要だ。

HEX ファイルは、一つでも良い

REGEXP では、他のクラスファイルなどとのコードの配置を考えて、複数の HEX ファイルを準備してフィットする物を用いるという、複雑な構成になっている。多くのケースでは、そのような複雑な構成を取る必要はないだろう。HEX ファイルは、一つだけでも良い。リンカースクリプトとしては、「c/src/lds」ディレクトリーの中から一つだけ選んで用いればよい。多くのケースで、「memmap_no_flash_02.ld」であろう。メインの BASIC ファイルや、読み込むクラスファイルのサイズが大きければ、より下位のアドレスを用いる ld ファイルを用いればよい。

どんどん C コードを取り込もう

この記事と、HELLO_CW アプリケーション・REGEXP クラスの例を参考にすれば、C でのソースコードが公表されている様々な機能を、MachiKania に取り込むことができる。それにより、MachiKania の応用範囲がさらに広くなることを、期待している。]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=976 Sun, 26 Mar 2023 09:44:54 PDT ITEM976_20230326
Raspberry Pi Picoで、RAM領域にアプリケーションを配置する https://www.rad51.net/blog/mycom/?itemid=975
この記事では、フラッシュ領域ではなく RAM 領域(アドレス 0x20000000 からの 256 kbytes)にプログラムを配置する方法について述べる。ソースコードに若干の変更を加えるだけでよい。(ビルドすると、uf2 ファイルだけではなく hex ファイルも作成されるが、この hex ファイルは、MachiKania type P でファイル選択すると、実行可能。)

1.フラッシュ領域を使わないリンカースクリプトをコピー

Pi Pico のアプリケーションをビルドすると、デフォルトでは「pico-sdk/src/rp2_common/pico_standard_link」ディレクトリーに存在する「memmap_default.ld」がリンカースクリプトとして使用される。同ディレクトリーにある「memmap_no_flash.ld」が目的のリンカースクリプトなので、これを「CMakeLists.txt」があるディレクトリーにコピーする。

MachiKania type P 用の HEX ファイルを作成する場合は、コピーした「memmap_no_flash.ld」の26行目、「RAM(rwx) : ORIGIN = 0x20000000, 」の次の「LENGTH = 256k」を、「LENGTH = 192k」と書き換える。他の用途に用いる場合は、この変更は必須ではない。

2.CMakeLists.txt を修正する

次の2つの行を、CMakeLists.txt のどこかに書き加える。
set(PICO_NO_FLASH 1)

pico_set_linker_script(target_name ${CMAKE_CURRENT_SOURCE_DIR}/memmap_no_flash.ld)
ただし、「target_name」は、ビルドの際の任意のターゲット名に書き換える事。

3.あとは、いつも通りビルド

以上の変更を加えたのちに、いつも通りビルドすれば、RAM 領域にアプリケーションが配置された uf2 ファイルと hex ファイルが作成される。 ]]>
MachiKania https://www.rad51.net/blog/mycom/?itemid=975 Mon, 30 Jan 2023 15:35:30 PST ITEM975_20230130