SPI: 중속 시리얼 사용

17023 단어 FPGAPython3Polyphony
「지에 일하면 뿔이 서 있다. 정에 굳게 하면 흐른다. 의지를 통과하면 거북하다. 토각에 사람의 세상은 살기 어렵다.」

SPI (Serial Peripheral Interfac)는 빠르지 않을 것입니다. Wikipedia에서는 비교적 저속으로 표현되고 있다. 확실히 마이크로 컴퓨터의 세계에서는 핀 밖에 클럭을 내고, IC (Peripheral)와 연결하는 것이 많을지도 모른다. 경우에 따라서는 손 솔더나 브레드보드를 ​​경유하기 때문에 그리 빠른 속도라고 할 수는 없을 것이다. 그러나 FPGA 내부에서 SPI를 사용하면 200MHz와 같은 비교적 빠른 속도의 클럭도 생각할 수 있다. 여기에서는 SPI를 중속이라고 파악한다.


SPI I/F가있는 주변 장치의 예

SPI의 실제 움직임에 대해서는 권말(가 아니라 아래쪽)의 그림이나 다른 문헌에 양보하는 것으로, 소프트웨어의 입장으로부터 SPI를 생각해 본다. SPI 클럭의 SCLK는 실제 규칙적인 클럭이 아닐 수 있습니다. 주변 장치 중 일부는 최저 클럭을 결정하고 있지만 대부분의 경우 CPU에서 GPIO로 연결하여 MISO 및 MOSI와 같은 데이터 라인과 함께 초저속으로 액세스 할 수 있습니다. 소프트웨어 입장에서 이해하고 싶은 사람은 Polyphony에서 HDL을 짜기 전에 GPIO로 직접 프로그래밍하고 액세스하는 것이 좋습니다.

클록의 세세한 제어가 약한 Polyphony 에서도, 소프트웨어적인 요령으로 SPI 에 액세스 할 수가 있다. 그리고 생성되는 코드는 Verilog-HDL이므로 의외로 고속이다(중속이다).

출처를 보여주세요.

ad7091r.py
import polyphony
from polyphony.io import Port
from polyphony.typing import bit, uint3, uint12, uint16
from polyphony.timing import clksleep, clkfence, wait_rising, wait_falling


CONVST_PULSE_CYCLE = 10
CONVERSION_CYCLE = 40


@polyphony.module
class AD7091R_SPIC:
    def __init__(self):
        self.sclk = Port(bit, 'out')
        self.sdo  = Port(bit, 'in')
        self.sdi  = Port(bit, 'out')
        self.convst_n = Port(bit, 'out', init=1)
        self.cs_n = Port(bit, 'out', init=1)

        self.dout = Port(uint12, 'out')
        self.chout = Port(uint3, 'out')
        self.din = Port(uint16, 'in')
        self.data_ready = Port(bit, 'out')
        self.append_worker(self.main)

    def main(self):
        while polyphony.is_worker_running():
            self.convst_n.wr(1)
            self.cs_n.wr(1)
            self.data_ready.wr(0)
            clkfence()

            self.convst_n.wr(0)
            clksleep(10)

            self.convst_n.wr(1)
            clksleep(40)

            # starting ADC I/O
            self.cs_n.wr(0)
            sdo_tmp = 0
            clksleep(1)

            for i in range(16):
                self.sclk.wr(0)
                clkfence()
                sdi_tmp = 1 if (self.din() & (1 << (15 - i))) else 0
                self.sdi.wr(sdi_tmp)
                clksleep(1)
                self.sclk.wr(1)
                clkfence()
                sdo_d = self.sdo.rd()
                sdo_tmp = sdo_tmp << 1 | sdo_d
                #print('sdo read!', i, sdo_d)

            self.sclk.wr(0)
            self.dout.wr(sdo_tmp & 0x0fff)
            self.chout.wr((sdo_tmp & 0x7000) >> 12)
            self.cs_n.wr(1)
            clkfence()
            self.data_ready.wr(1)


@polyphony.testbench
@polyphony.rule(scheduling='parallel')
def test(spic):
    datas = (0xdead, 0xbeef, 0xffff, 0x0000, 0x800)
    for data in datas:
        #print('!!', data)
        wait_falling(spic.convst_n)
        #print('convst_n fall', spic.convst_n())
        wait_rising(spic.convst_n)
        #print('convst_n rise', spic.convst_n())
        wait_falling(spic.cs_n)
        #print('cs_n fall', spic.cs_n())
        spic.din.wr(0b1111000011110000)
        for i in range(16):
            databit = 1 if data & (1 << (15 - i)) else 0
            #print('sdo write from test', i, databit)
            spic.sdo.wr(databit)
            wait_rising(spic.sclk)
        wait_rising(spic.cs_n)
        wait_rising(spic.data_ready)
        clksleep(1)
        #print(spic.dout())
        assert spic.dout() == data & 0x0fff
        assert spic.chout() == (data & 0x7000) >> 12


if __name__ == '__main__':
    spic = AD7091R_SPIC()
    test(spic)

wait_falling 이나 wait_rising 혹은 이 소스에는 없지만 wait_value 등의 함수를 사용해 , 클럭의 변화를 파악할 수가 있다. 시비어한 클럭 제어가 없으면 Polyphony에서도 충분히 IO 제어는 할 수 있다. 덧붙여 프로그램 안에 있는 @polyphony.rule 는 Version 0.3.2 에서는 서포트되어 있지 않고 무시될 뿐이다.

SPI 파형 예



SPI 주변 장치에 액세스하는 것은 상당히 힘든 일이다. 그 칩의 (페리페럴의) 사양서를 읽고, 제대로 생각한 것처럼 파형이 나오고 있는지 확인하지 않으면 안 된다.

여기에서는 덤으로 Polyphony로 디버그했을 때의 파형을 붙여 둔다.

SPI의 쓰기/읽기는 마스터 측이 CS를 어서 트 (일반적으로 음 논리이므로 GND로 떨어 뜨린다)하고, 그 사이에 SCLK를 클럭으로 공급하고 그 상승에서 수행한다. 읽기/쓰기를 나타내는 신호선이 없기 때문에 항상 쓰기와 읽기가 동시에 수행됩니다.

명령을 받고 응답을 반환하는 유형은 Master가 쓰고 계속 읽을 것입니다. 기록과 판독이 반드시 동시에 행해지기 때문에, 기록시에는 의미없는 판독 데이터가 판독되고, 판독시에는 의미없는 기록 데이터가 흐른다.

칩에 따라서는 읽기만의 것 기입/읽어들이 동시로 의미가 있는 것과, 각각 규정되는 칩의 사양에 의해 천차만별이다.

"SPI 쓰기, 읽기", "SPI 읽기 전용", "SPI 동시에 쓰기/읽기"의 예를 제시한다. 뭔가 도움이되면.





좋은 웹페이지 즐겨찾기