2019年12月18日水曜日

PSoC5LP で いまさら mruby/c を試してみる その3 (お試し編) (PSoC AdventCalendar2019)


さて。
PSoC Advent Calendar 2019 での 3つめですね。

mruby/c 2.0 でうごく、サンプルはできたので
いろいろできそうだけど。

で、ちょっと気になったのは最初によんだ
利用説明書
の記述。

内蔵デバイスをいろいろ、使えるようにしてくれてるん
だろうなぁ、とか思いつつ、 読み進めていったんだけど

こういう記述があつまってるところはないかしら?

まぁ、
mutex、sleep()、relinquish()
があればタスク管理上はほぼ問題なくなるだろうし
いいんだけれど。
mruby/c で
『あれ、どう記述したらいいんだろう???』
ってのに対応できる資料がないのはイタイからね。


で、微妙に気になったのが、UARTについての記述。










PSoC5だと UDBの分だけ、 UARTつかえるよ!っていうのは
いいとして、PSoC5LP PrototypingKit の UART部は
KitProg2(デバッガ部)のPSoCに直結されて
PCからは、USB-CDC そのものだから、本来は
デバッグ出力用の hal_write()  のほうに割り付けて
しまうほうがうれしいとおもんだけどなぁ。
まぁ、uartクラス的に書くのかは勉強になる。
ただ、気になるのは、
『PSoC5LP開発環境の仕様により、ボーレートの変更がソフトウェアでできません。
   標準で、19200bps固定です。』
っていう記述。

うっそーん!  できるよ、あたりまえじゃん!
これは
PSoCのこと、わかってないんじゃないの?
ってタイミングでかかれたんだろうなぁ。

たしかに、PSoC の UARTコンポーネントでは
速度を指定するAPIは生成されないですね。
ただ、できないわけではないよ。

2017年版の Advent Calendarでも 書いたので
詳細は そちらを参照してもらえばいいけれど、
要は、UARTも基準となっている、IMOのクロックに
同期してうごいているので、これを正しい分周比に
かえてやれば、好きな周波数なんて簡単に設定できますよ、
ってことですね。

=========
#include <stdint.h>
void setBitRate(uint32_t rate)
{
uint16_t div;
div = (uint16_t)((uint32_t)BCLK__BUS_CLK__HZ / (uint32_t)((uint32_t)rate * 8)) ;
UART_1_Stop();
UART_1_IntClock_SetDividerRegister(div, 1); // 設定変更+リスタート
UART_1_Start();
}
view raw setBitRate hosted with ❤ by GitHub

=========
こんなかんじですかね。

PSoC Creater で生成したプロジェクトを利用すると
利用するマスタークロックは  cyfitter.h というファイルに

BCLK__BUS_CLK__HZ


として定義されています。

IMO を 48MHz で定義した プロジェクト の場合であれば

#define BCLK__BUS_CLK__HZ 48000000U
ですね。
欲しい速度(bitrate)を 8倍することで Byte/Secの単位とし
それを分周比として
UART_1_IntClock_SetDividerRegister()
という関数に引き渡してやればいいだけですね。

問題は、与える分周比をどうやって算出するのか、 だけど
たとえば 115200bps がほしいのなら
  115200bps = 115.2kHz
で、1バイト分のサンプリング = 8倍 が欲しい周波数なわけです。

サンプリングを8倍した 921.6kHz が与えられれば、いいわけです。
ここまでくれば簡単で、
この921.6kHzを生成するのに、48MHzを52分周すると
近似として  923.076kHz 得られるじゃない?ってことですね。

式にすると
 52 = 48000000 / (115200 * 8)
ですね。

というわけで、この関数をmruby/c から呼べるように
用意すればいいだけです。

=========
// 通信速度設定
static void c_setBitRate(mrb_vm *vm, mrb_value *v, int argc)
{
uint32_t rate = GET_INT_ARG(1);
setBitRate(rate);
}
// 通信速度設定本体
void setBitRate(uint32_t rate)
{
uint16 div;
div = (uint16_t)((uint32_t)BCLK__BUS_CLK__HZ / (uint32_t)((uint32_t)rate * 8)) ;
hal_uart_Stop();
hal_uart_IntClock_SetDividerRegister(div, 1); // 設定変更+リスタート
hal_uart_Start();
}
int main(void)
{
CyGlobalIntEnable; /* Enable global interrupts. */
hal_uart_Start();
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
mrbc_init(memory_pool, MEMORY_SIZE);
isr_mrbcTick_StartEx(mrbcTick); // SYSTICKを実装
mrbc_define_method(0, mrbc_class_object, "sw1_read", c_sw1_read);
mrbc_define_method(0, mrbc_class_object, "led1_write", c_led1_write);
mrbc_define_method(0, mrbc_class_object, "setBitRate", c_setBitRate);
mrbc_create_task( sample1, 0 );
console_print("\r\n\x1b(B\x1b)B\x1b[2JStart Program.\n");
mrbc_run();
return 0;
}

=========
c_setBitRate関数が 実際にmrubyから呼び出しされる
関数ですね。

このプログラムでは UARTを
hal_uart
というコンポーネント名で登録したので、上記のように
なっています。
mruby から
setBitRate( 115200 )
みたいによべばいいですね。

=====================================
いろいろつかってみると、結局のところ
デバッグができるのが、PSoC 版のいいところ
なのかも。

肝心のmrubyでは、デバッグできないもん。
実際、前回のように、
いま、なぜ動かないのか?
を確認できないのはつらい。

じゃ、結局『ぜんぶCでかきゃ、いいじゃん!』ってなりそうなものだけど、
マルチタスク的にコンパクトにいろいろやりたいとなると
案外Cだと骨が折れるんですよ。
基本になる挙動は、 Cで関数単位で記述しておいて
タスク起動と同期を mruby で制御、ってのが
もっともお手軽なのかもしれません。
実装サイズがコンパクトなRTOS的につかう!
のが最適なのか、とおもいますね。

さて、ちょっとmruby の文法、勉強しないと。。。


0 件のコメント:

コメントを投稿