はじめに
ラズパイ3ではUARTが2つ用意されていますが、実際に外部接続用に利用できるのは1つしかありません。複数の機器とUARTでシリアル通信する場合にUSBアダプターを追加したりとハードウェアを増やすのも嫌なので、ソフトウェアのUARTデバイスを利用してみます。
ソフトウェアでUART通信するので、高速な通信はできないのですが接続しようとしているGPS受信器キットのデフォルトボーレートが9600bpsと低速なので何とかなるだろうと。
なお、ラズパイ4ではUART1~5まで使えるようになったみたいです。ちょっと欲しいかも…
追記事項あり
- 動作が不安定なので、常時利用は難しいかも。詳細はこちら。
Goal
- GPS受信キットからのUART送信をソフトウェアUARTで受け取れること
事前確認
下記設定がすんでいる前提です。
- シリアルコンソールの無効化
- UARTの有効化
- UART0とUART1(Mini UART) の入れ替え
なお、UART0とUART1の入れ替え後は下記となっている想定です。
pi@raspberrypi:~/project/soft_uart $ ll /dev | grep serial
lrwxrwxrwx 1 root root 7 Jul 19 14:28 serial0 -> ttyAMA0
lrwxrwxrwx 1 root root 5 Jul 19 14:28 serial1 -> ttyS0
ソフトウェアUARTの設定
基本は下記Githubに書いてある通りです。
https://github.com/adrianomarto/soft_uart
git clone https://github.com/adrianomarto/soft_uart
sudo apt-get install raspberrypi-kernel-headers
cd soft_uart
make
sudo make install
sudo insmod soft_uart.ko
下記のように /dev/ttySOFT0
があればOKです。
pi@raspberrypi:~/project/soft_uart $ ll /dev | grep SOFT
crw-rw---- 1 root dialout 240, 0 Jul 19 15:13 ttySOFT0
なお、再起動には使えなくなるので再度 sudo insmod soft_uart.ko
を実行してください。継続利用する場合はOS起動時にロードできるようrcスクリプトなどに書いてください、
ラズパイ側の接続
デフォルトでは以下の設定となっているのでGPIO17と27をワイヤで直結して試してみます。
- gpio_tx: int [default = 17]
- gpio_rx: int [default = 27]
GPIO17(TX) --> GPIO27(RX)
確認
minicomで接続確認1
ボーレート9600で確認してみます。
minicom -b 9600 -D /dev/ttySOFT0
別の端末で以下を実行します。
echo "hello" > /dev/ttySOFT0
へんなタブが気になりますが、ハードウェアのUART側(UART0)も同じ表示になったのでよしとします。
GPS受信キットでの確認
ここまでくれば大丈夫でしょう。試してみます。
特に問題なしでした!
参考サイト
下記サイトのほぼそのままになりました。情報助かりました!
- RPIで複数のUARTを使う方法
感想
- シリアル通信周り/電源回りなどを考えるとArduinoの偉大さがよくわかる
- mrubyがESP32あたりでさくっと動けばなー。今のアップロード手順だと初心者としてはTraial&Errorのたびに心が折れる…
- RasbperyPi OSは最初から英語版でいれるべきだった。
- ワイヤ断線ヤバイ…気づくのに時間がかかった…
追記事項
プログラムを中断&再度実行を数回繰り返すとシリアルポートからの読み込みができなくなる現象が発生。
- 読み込みができないようでプログラムが永遠にブロックされる
- いったんモジュールを削除してから再度モジュールをロードするとうまく動く
- プログラムをずっと起動しておく分には問題なさげ
そこで以下を試すも改善せず。
-
Ctrl + C
で停止時にきちんとポートを閉じるようにSIGINT
をトラップ- 修正後のソースは後述
- CPU周波数の固定化(250MHzに固定)
-
echo "core_freq=250" | sudo tee -a /boot/config.txt
後再起動
-
結局以下の力技で回避した。まさに技
[PATH_TO_SOFT_UART_DIR]
は環境に合わせてください。
require 'serialport'
require 'nmea_plus'
puts `sudo rmmod soft_uart.ko`
sleep 0.1
puts `cd [PATH_TO_SOFT_UART_DIR] && sudo insmod soft_uart.ko`
sp = SerialPort.new('/dev/ttySOFT0', 9600, 8, 1, 0) # see: https://rubydoc.info/gems/serialport/SerialPort#set_modem_params-instance_method
# 最低限お行儀よく振る舞う
trap 'SIGINT' do
sp.close if sp
exit
end
source_decorder = NMEAPlus::SourceDecoder.new(sp)
source_decorder.each_complete_message do |message|
# see: https://github.com/ianfixes/nmea_plus/blob/master/lib/nmea_plus/message/nmea/rmc.rb
if 'GPRMC' == message.data_type
puts message.utc_time
puts message.active? # false: データ無効
puts message.latitude
puts message.longitude
#puts message.speed_over_ground_knots
#puts message.track_made_good_degrees_true
#puts message.magnetic_variation_degrees
puts message.faa_mode # A: 単独測位(精度3m程度), D: 相対測位(精度0.4m程度)
puts
end
end
-
minicomが日本語ロケールだと表示がずれてしまうので、
LANG=C minicom -s
を試したのですが英語化されず…raspi-configからの設定はなぜか効かなかったの、GUI画面の設定からロケールを変更しました。 ↩