ARM Linux の UART と通信する
外の UART とは通信できました。次の要求は ARM との UART 通信です。Linux で出来れば応用範囲が広がります。
Zynq の UART
Zynq の Linux などのコンソール用の UART はなぜか UART1 がアサインされています。理由は不明ですが、伝統的にそうなっています。そこで UART0 を増やすと、tty の番号がずれます。UART0 がコンソールになってしまいます。USB UART で PC に繋がっている方は物理的に UART1 なので、混乱してしまいます。
UART を変えて(増やして)”表示しなくなったら"その辺を疑うのがいいかと思います。私は混乱しました。
デザイン
echo を階層化してみました。Linux 側の UART の TX/RX を PL に出して、フィルターを介して外の USB Uart と接続されています。これで、外の繋いである USB UART から(PC から) 入力すると Linux の UART に入力されます。
echo のデザイン
階層化されたデザインは次の通りです。フィルターの letter_x_obj は小文字を大文字に、大文字を小文字にします。
合成して実行
Linux 側で tty を 115200 にする必要があります。cat で入力待ちしてそとの USB Uart から文字を打ち込むと変換された文字を見ることが出来ます。
fpga@debian-fpga:~$ stty 115200 < /dev/ttyPS0
fpga@debian-fpga:~$ cat < /dev/ttyPS0
jgeil
jgeil
・ello
hello
HELLO
MYDER
mYJI
echo などで /dev/ttyPS0 へ出力することもできますが、ちゃんとオーバランを考慮していないので文字抜けが発生してしまいました。ここは改良の余地があります。
Linux の UART を折り返す。
デザインを変更しました。Linux の UART からデータが入ってくると、calc0 で計算して UART へ折り返すようにしました。いままでのようにフィルターを介してもいいのですが、ここは足し算をして返すようにしました。
足し算のプログラム
もうほんとに足し算しかしてません。
> cat my_lib.py
def func(a , b):
return a + b
呼び出しもと
これは queue を使っています。リクエストとして [len , ID , arg0 , arg1] のバイナリが来ることを期待しています。返答は [len, ID, rv] です。本当は json にしたかったのですが、時間がなくできませんでした。ということで bson という名前になっています。
import polyphony
from polyphony import is_worker_running
from polyphony.io import Port, Queue
from polyphony.typing import bit, bit8
from polyphony.timing import clksleep, clkfence, wait_value
from my_lib import func
@polyphony.module
class bson_server:
def __init__(self):
self.bson_req = Queue(bit8, 'in')
self.bson_reply = Queue(bit8, 'out')
self.append_worker(self.main_worker)
def main_worker(self):
while is_worker_running():
len = self.bson_req.rd()
id = self.bson_req.rd()
a_0 = self.bson_req.rd()
b_0 = self.bson_req.rd()
rv = func(a_0, b_0)
self.bson_reply.wr(2)
self.bson_reply.wr(id)
self.bson_reply.wr(rv)
@polyphony.testbench
def test(obj):
bson_lst = [3, 10, 3, 4]
for iter in bson_lst:
obj.bson_req.wr(iter)
for i in range(3):
print(obj.bson_reply.rd())
if __name__ == '__main__':
obj = bson_server()
test(obj)
Python で実行
シミュレーションとして Python で実行しておきます。
> python bson.py
2
10
7
Polyphony でコンパイル
コンパイルすると bson_server_obj.v ができます。また polyphony_out.v ができるので fifo だけ抜き出して fifo.v とします。
デザインに組み込む
bson_server_obj.v と fifo.v をデザインに組み込みます。
あとは合成すれば出来上がり
Linux でテスト
UART0 と 1 で混乱して動かないと思ってしまいました。この問題(オペミス)よっぽどおおいんですね。AR に書かれている。
https://japan.xilinx.com/support/answers/64339.html
「この場合のカーネル ブートは、実際は停止するわけではありません。」
これ DTS の順番を変えるだけで解決しそうな気がします、、、(未確認)
Python でテスト
こっちの方が簡単です。
fpga@debian-fpga:~/uart$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04)
[GCC 6.3.0 20170118] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import termios
>>> import tty
>>> b = bytearray([3, 0x41, 5, 6])
>>> (print(b))
bytearray(b'\x03A\x05\x06')
>>> print(len(b))
4
>>> f = open('/dev/ttyPS0', 'w')
>>> print(f)
<_io.TextIOWrapper name='/dev/ttyPS0' mode='w' encoding='ANSI_X3.4-1968'>
>>> fds=f.fileno()
>>> tty.setraw(fds)
>>> print(fds)
4
>>> os.write(fds, b)
4
>>> x = os.read(fds, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor
>>> f = open('/dev/ttyPS0', 'r')
>>> fds=f.fileno()
>>> os.read(fds,4)
b'\x02A\x0b'
ポイントは raw モードにする事みたいです。
C でテスト
tty デバイスですが tty として使うわけではないのでそこを考慮しないいといけません。送信列に 0x03 があって、これはシェル的には ^C に相当します。そのため 0x5E 0x43 (つまり ^C) が差し込まれたりして混乱しました。open 時の引数に O_NOCTTY を設定すると親の tty のコントロールから逃れることが出来ます。
次のプログラム上は raw モードにしてませんが、本来ならすべきです。このコマンドを起動する前に stty raw < /dev/ttyPS0 と stty 115200 < /dev/ttyPS0 を実行しています。
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
int
main(int argc, char **argv)
{
struct termios oterm;
char bson_lst[] = {0x03, 0x41, 0x22, 0x44, '\n'};
int i;
char *file = argv[1];
int fds;
fds = open(file, O_RDWR | O_NOCTTY);
if ( fds < 0 ) {
perror("permission error?");
return 1;
}
/*
return 2;
}
oterm.c_lflag &= ~ICANON;
if(tcsetattr(fds, TCSAFLUSH, &oterm) == -1){
perror("tcgetattr failure");
return 2;
}
oterm.c_lflag &= ~ICANON;
if(tcsetattr(fds, TCSAFLUSH, &oterm) == -1){
perror("tcgetattr failure");
return 2;
}
*/
int rv;
unsigned char rv_lst[4];
for ( i = 0 ; i < 4; i++ ) {
rv = write(fds, &bson_lst[i], 1);
fprintf(stderr, "%d:%02x\n", rv, bson_lst[i]);
}
for ( i = 0 ; i < 3; i++ ) {
rv = read(fds, rv_lst, 1);
fprintf(stderr, "%d:%02x\n", rv, rv_lst[0]);
if ( rv < 0 ) {
perror("he?");
return 3;
}
}
}
fpga@debian-fpga:~/uart$ stty 115200 < /dev/ttyPS0
fpga@debian-fpga:~/uart$ stty raw < /dev/ttyPS0
fpga@debian-fpga:~/uart$ stty < /dev/ttyPS0
speed 115200 baud; line = 0;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost
-isig -icanon
fpga@debian-fpga:~/uart$ ./rw /dev/ttyPS0
1:03
1:41
1:22
1:44
1:02
1:41
1:66
参考までに書くと、実行結果として 0x22 + 0x44 の結果 0x66 が返ってきています。
0x22 + 0x44 は polyphony で記述した計算です。つまり、UART で書いた値に対して IP(FPGA 側のハードウェア) で計算した結果が戻ってきたという事になります。
将来的には json に対応したいと考えています。