さて。
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のクロックに
同期してうごいているので、これを正しい分周比に
かえてやれば、好きな周波数なんて簡単に設定できますよ、
ってことですね。
=========
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} |
=========
こんなかんじですかね。
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 から呼べるように
用意すればいいだけです。
=========
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 通信速度設定 | |
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 の文法、勉強しないと。。。