Python에서 FPGA/UART 사용 (Zybo)

UART 사용



Linux UART 드라이버와 통신하려고합니다. 그러기 위해서는 어쨌든 u-boot에서 다시 만들어야 할 것 같다.

먼저 디자인



거친 디자인을 먼저 보여줍니다. async_trasnmitter라는 모듈을 사용하고 있습니다. 이것은 verilog로 작성된 것으로 파이썬이 아닙니다. fpga4fun.com에서 빌려.

async.v



async_transmitter는 두 번 클릭하여 paramter를 변경할 수 있습니다. 기준 클록이 125MHz이므로 초기 설정의 50MHz에서 변경해 둡니다.



합성 및 실험



vio에서 0x31을 보냅니다. 아, 리눅스가 일어났지만 신경쓰지 않는다. design_1_i/vio_0_probe_out0에 1을 쓴 순간에 움직입니다.



결과는 1 투성이가 되지 않습니다. 통제하지 않으니까.


Zynq 측의 UART를 사용하면



참고로 쓰면 Zynq 측의 UART0 를 유효하게 한다 dtb 를 써 보면(자) Linux 가 잘 동작하지 않습니다. 당연합니다만, u-boot 로 행해지는 초기화와 Linux 의 초기화가 불일치라면 최악, 일어나지 않는 것 같습니다.

그래서 위의 디자인은 PMOD에서 UART를 내고 USB-UART를 통해 PC (Windows)와 통신하고 있습니다.

수신자 추가



1의 무한 송신은 재미 없기 때문에 echo 백시키는 회로로 합니다.



수신측도 125MHz로 하는 파라미터 설정을 합니다. 그렇게 하지 않으면 글자 깨져요(경험자는 말한다).



핀 설정도 붙여 둡시다.

zybo.xdc
## PL System Clock
set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports clk]
create_clock -period 8.000 -name sys_clk_pin -waveform {0.000 4.000} -add [get_ports clk]

## LED
set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports led0]

## Buttons
set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports btn0]

set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports TxD_0]
set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports RxD_0]

잘 움직였다. Hello Hello 라고 써 있는 것이 에코백 된 문자. 그 전에의 1의 열이 하나 전의 처리. 그리고 부분적으로 깨져있는 것이 실패한 처리.



Polyphony 사용



여기까지는 Polyphony 붙어 있지 않습니다. 네. 사용하지 않았습니다. 필터로 대문자를 소문자로 소문자를 대문자로 만드는 모듈을 만듭니다.



letter_x.py
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


@polyphony.module
class letter_x:
    def __init__(self):
        self.tx_start = Port(bit, 'out', 0)
        self.tx_data = Port(bit8, 'out', 0)
        self.tx_busy = Port(bit, 'in')

        self.rx_ready = Port(bit, 'in')
        self.rx_data = Port(bit8, 'in')

        self.append_worker(self.main_worker)

    def main_worker(self):
        while is_worker_running():
            wait_value(1, self.rx_ready)
            data = self.rx_data.rd()

            if ( data > 0x40 ) &  ( data < 0x60 ) :
                data += 0x20
            elif ( data > 0x60 ) &  ( data < 0x80 ) :
                data -= 0x20

            wait_value(0, self.tx_busy)
            self.tx_data.wr(data)
            self.tx_start.wr(1)

            clkfence()
            self.tx_start.wr(0)
            wait_value(0, self.tx_busy)

            print(data)

@polyphony.testbench
def test(obj):
    data_list = (0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21)
    obj.tx_busy.wr(0)
    obj.rx_ready.wr(0)

    for iter in data_list:
        obj.rx_data.wr(iter)
        obj.rx_ready.wr(1)
        clkfence()

        obj.rx_ready.wr(0)
        wait_value(1, obj.tx_start)
        data = obj.tx_data.rd()
        print(data)

if __name__ == '__main__':
    obj = letter_x()
    test(obj)


컴파일하고 Vivado에 임베디드 합성을 실행해 보겠습니다.



이해하기 어렵지만 Hello Good-Bye가 에코 백되어 hELLO gOOD-bYE가되었습니다.

이어서 함수화



worker 의 clkfence 가 나오고 이해하기 어려우므로, 함수화/라이브러리화해 버립니다.

filter.py
 cat filter.py
def filter_func(data):
    if ( data > 0x40 ) &  ( data < 0x60 ) :
        data += 0x20
    elif ( data > 0x60 ) &  ( data < 0x80 ) :
        data -= 0x20

    return data

사용 측에서는 import 한 후 filter_func 를 호출하면 됩니다. 이것으로 약간 어려운 부분은 밖에 낼 수 있었습니다.

사용하는 쪽
from filter import filter_func
<>
    def main_worker(self):
        while is_worker_running():
            wait_value(1, self.rx_ready)
            data = self.rx_data.rd()

            data = filter_func(data)

            wait_value(0, self.tx_busy)
            self.tx_data.wr(data)
            self.tx_start.wr(1)

            clkfence()
            self.tx_start.wr(0)
            wait_value(0, self.tx_busy)

            print(data)



좋은 웹페이지 즐겨찾기