ZYBO 인터럽트로 시간을 관리해 보았습니다.

19148 단어 FPGAzybo

소개



제어 공학을 하고 있으므로 실시간 제어를 할 수 있는 컨트롤러를 만들고 싶었습니다.

시간 관리 방법



여러가지 시간을 관리하는 방법은 있습니다만, 가능한 한 가벼운 처리로 시간 관리를 하고 싶었습니다. 사이클 카운터를 감시하는 바쁜 루프 등은 하고 싶지 않습니다. 외부에 타이머라도 설치해 제어 주기를 관리하는 타이머라도 만든 편이 좋지 않을까 생각하고, 타이머를 만들어 IRQ_F2P에 연결해 UIO의 인터럽트를 사용해 보았습니다.

인터럽트 타이머 IP



AXI4 Peripheral의 IP를 만들었습니다. 사용자 회로에 다음과 같은 회로를 써 보았습니다. irq_ps는 타이머 출력에서 ​​slv_reg2를 시간주기를 결정하는 레지스터로 만들었습니다. clk는 AXI_ACLOCK과 연결되어 있으며 100MHz입니다.

AXI_TIMER.v
    reg [31:0] irqgen_cnt; initial irqgen_cnt=32'b0;
    wire irq_ps_in;
    wire ena_irq;
    assign ena_irq=slv_reg1[1];
    assign irq_ps=(ena_irq==1'b1)? irq_ps_in:1'b0;
    assign irq_ps_in=(irqgen_cnt<32'd100)? 1'b1:1'b0;
    always@(posedge clk)
    begin
        irqgen_cnt<=(irqgen_cnt==slv_reg2)? 24'b0:irqgen_cnt+24'b1;
    end

이 IP의 출력과 ZYNQ Processing sysgtem 블록의 IRQ_F2P를 연결했습니다. 이번에는 위의 타이머를 DAC용 IP( htps : // m / tvrcw / ms / 61c0 9 9c8 843에서 f4 )에 넣고 있습니다.

Bitstream 파일을 출력하여 Linux에 전달했습니다.

Linux에서 작업



Linux 환경은 @ikwzm 같은 배포의 것입니다. 이 환경에서 UIO 인터럽트를 사용할 수 있습니다. Device Tree Overlay를 사용하므로 "/plugin/;"을 더해야합니다. ( h tps:// 퀵했다. 작은 m/이상 kwzm/있어 MS/03D518b7C46d1그래 49943 )

devicetree.dts
/dts-v1/;/plugin/;
/ {
    fragment@0 {
        target-path = "/amba/fpga-region0";

        __overlay__ {
            #address-cells = <0x1>;
            #size-cells = <0x1>;

            firmware-name = "IRQ.bin"; 

            irq-uio@43c10000 {
                compatible = "generic-uio";
                reg = <0x43c00000 0x1000>;
                interrupt-parent = <&intc>;
                interrupts = <0 29 4>;
            };
        };
    } ;
} ;

"interrupts"를 "interrupt"로 잘못하면 움직이지 않으므로 주의가 필요합니다. IRQ_F2P[0]은 인터럽트 번호 61로 ARM의 GIC는 32를 뺀 것 같기 때문에 29를 지정하고 있습니다.
이번에는 50 us, 100 us, 200 us의 제어주기를 관리하려고 합니다. 시간 측정을 위해 C로 프로그램을 썼습니다. 도중에 DAC에 대한 설명이 있습니다. 깨끗한 정현파가 나오면 좋다고 생각합니다.

IRQtest.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

int uio_irq_on(int uio_fd){
    unsigned int irq_on=1;
    return write(uio_fd,&irq_on,sizeof(irq_on));
}

int uio_wait_irq(int uio_fd){
    unsigned int ret=0;
    return read(uio_fd,&ret,sizeof(ret));
}


int main()
{
    int uio_fd;
    if((uio_fd=open("/dev/uio0",O_RDWR))==-1){
        printf("Can not open /dev/uio0\n"); exit(1);
    }

    volatile unsigned int* map_addr;
    map_addr=(unsigned int*)mmap(NULL,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,uio_fd,0); 

    int ena=0x0;
    ena|=(1<<0);
    ena|=(1<<1);
//  map_addr[2]=0x00004e1f; //200us
    map_addr[2]=0x0000270f; //100us
//  map_addr[2]=0x00001387; //50us
    map_addr[1]=ena;    //enable DAC

    unsigned int d=0.0;
    volatile double wave=0.0;
    const double bitweight=20.0/pow(2,16);
    const double midscale=pow(2,15);

    volatile double t=0.0;
    const double Ts=1e-4;
    double logt[10000]={0.0};

    struct timespec st,ed;
    struct timespec stx,edx;
    clock_gettime(CLOCK_MONOTONIC,&stx);
    clock_gettime(CLOCK_MONOTONIC,&st);

    wave=1;

    for(int i=0;i<1e4;i++){

        if(uio_irq_on(uio_fd)==-1){  printf("error1\n");break;};
        if(uio_wait_irq(uio_fd)==-1){printf("error2\n");break;};

        wave=4.0*sin(100.0*2.0*M_PI*t);
        d=wave/bitweight+midscale;
        map_addr[0]=d;

        clock_gettime(CLOCK_MONOTONIC,&ed);
        logt[i]=(ed.tv_nsec-st.tv_nsec)*1e-9;
        st=ed;

        t+=Ts;
    }

    clock_gettime(CLOCK_MONOTONIC,&edx);
    printf("%lf %lf\n",(edx.tv_sec-stx.tv_sec)+(edx.tv_nsec-stx.tv_nsec)*1e-9,t);

    FILE *lt;
    lt=fopen("sampling.dat","w");
    for(int i=0;i<1e4;i++) fprintf(lt,"%lf\n",logt[i]);
    fclose(lt);

    map_addr[1]=0;
    munmap((void*)map_addr, 0x1000);
    close(uio_fd);

    return 0;
}


위에서 50 us, 100 us, 200 us의 타이머 출력에서 ​​인터럽트를 걸었을 때의 주기입니다.




현재는 그다지 안정적이지 않지만 100 us 정도라면 사용할 수 있을까 하는 느낌입니다. 개량하면 사용물이 될 것 같기 때문에 기대가 생겼습니다.

주기 100us, 진폭 4V, 주파수 100Hz의 정현파를 생성해 본 곳, 안정적으로 출력되고 있었습니다. 간단한 시험 정도라면 지금부터라도 사용할 수 있을 것 같은 생각이 듭니다.


ZYBO에서도 전혀 갈 수 있다고 생각했습니다만, 100 us보다 빨리 하고 싶다고 생각합니다. 전혀 모릅니다만 ZYNQ MPSoC의 Cortex-R5를 사용하면 인터럽트 처리가 안정될까요?

좋은 웹페이지 즐겨찾기