AnsweredAssumed Answered

AD9467 and AXI DMA

Question asked by rscavetta on Nov 11, 2015
Latest reply on Nov 13, 2015 by rscavetta

Hey Guys,

 

I'm getting some strange behaviour using AXI DMA to retrieve continuous samples from the AD9467 on the Zedboard.

 

Environment

-------------------

     HW: ZedBoard Rev D, AD9467

     Linux source: xcomm_zynq branch of the ADI Linux sources ( https://github.com/analogdevicesinc/linux.git )

     Device Tree: zynq-zed-adv7511-ad9467-fmc-250ebz.dts

 

Build process

--------------------

$ make make zynq_xcomm_adv7511_defconfig

$ make UIMAGE_LOADADDR=0x8000 uImage

$ make zynq-zed-adv7511-ad9467-fmc-250ebz.dtb

 

The current iomem map is:

zbconsole:~/projects/axidma # cat /proc/iomem
00000000-18ffffff : System RAM
  00008000-005f3cfb : Kernel code
  00628000-006833e7 : Kernel data
41600000-4160ffff : /fpga-axi@0/i2c@41600000
44a00000-44a0ffff : /fpga-axi@0/cf-ad9467-core-lpc@44A00000
44a30000-44a3ffff : /fpga-axi@0/rx-dmac@44A30000
70e00000-70e0ffff : /fpga-axi@0/axi_hdmi@70e00000
75c00000-75c00fff : /fpga-axi@0/axi-spdif-tx@0x75c00000
77600000-77600fff : /fpga-axi@0/axi-i2s@0x77600000
79000000-7900ffff : /fpga-axi@0/axi-clkgen@79000000
e0001000-e0001fff : xuartps
e0002000-e0002fff : /amba@0/usb@e0002000
  e0002000-e0002fff : /amba@0/usb@e0002000
e0006000-e0006fff : /amba@0/spi@e0006000
e000a000-e000afff : /amba@0/gpio@e000a000
e000b000-e000bfff : /amba@0/eth@e000b000
e000d000-e000dfff : /amba@0/qspi@e000d000
e0100000-e0100fff : mmc0
f8003000-f8003fff : /amba@0/ps7-dma@f8003000
  f8003000-f8003fff : /amba@0/ps7-dma@f8003000
f8007000-f80070ff : /amba@0/devcfg@f8007000
f8007100-f800711f : /amba@0/xadc@f8007100
f800c000-f800cfff : /amba@0/ps7-ocm@f800c000
fffc0000-ffffffff : f800c000.ps7-ocm

 

Device tree entry for ADC & AXI DMA:

 

&fpga_axi {

    rx_dma: rx-dmac@44A30000 {

        compatible = "adi,axi-dmac-1.00.a";

        reg = <0x44A30000 0x10000>;

        #dma-cells = <1>;

        interrupts = <0 57 0>;

        clocks = <&clkc 16>;

 

        dma-channel {

            adi,type = <0>;

        };

    };

    cf_ad9467_core_0: cf-ad9467-core-lpc@44A00000 {

        compatible = "xlnx,cf-ad9467-core-1.00.a";

        reg = <0x44A00000 0x10000>;

        dmas = <&rx_dma 0>;

        dma-names = "rx";

        spibus-connected = <&adc_ad9467>;

        xlnx,dphase-timeout = <0x8>;

        xlnx,num-mem = <0x1>;

        xlnx,num-reg = <0x1>;

        xlnx,s-axi-min-size = <0x1ff>;

        xlnx,slv-awidth = <0x20>;

        xlnx,slv-dwidth = <0x20>;

        xlnx,use-wstrb = <0x0>;

    } ;

};

 

We have set aside 112MB out of the zedboard's 512MB for dma receiving buffers starting at 0x19000000.

Enable the AD9467 in test mode with the following commands in a script:

echo  "524288"          > /sys/bus/iio/devices/iio:device2/buffer/length
echo "checkerboard" > /sys/bus/iio/devices/iio:device2/in_voltage0_test_mode
echo "1"                     > /sys/bus/iio/devices/iio:device2/scan_elements/in_voltage0_en
echo "1"                     > /sys/bus/iio/devices/iio:device2/buffer/enable

 

In this mode I expect to see alternating samples if 0x5555 and 0xAAAA.

 

When reading from the iio device directly I get the correct samples so I believe the ADC is working correctly e.g.

zbconsole:~/projects/axidma #  hd < /dev/iio:device2
00000000  aa aa 55 55 aa aa 55 55  aa aa 55 55 aa aa 55 55  |..UU..UU..UU..UU|
00300000  55 55 aa aa 55 55 aa aa  55 55 aa aa 55 55 aa aa  |UU..UU..UU..UU..|
00400000  aa aa 55 55 aa aa 55 55  aa aa 55 55 aa aa 55 55  |..UU..UU..UU..UU|
...

 

However when I try to copy samples to a buffer via the AXI DMA I only see one test pattern or the other (0xAAAA or 0x5555) but never the alternating pattern we expect.

 

To get started I used some sample code found in the no-OS driver (no-OS/cf_ad9467.c at master · analogdevicesinc/no-OS · GitHub)

 

My version of this code looks like this in Linux userland:

...

//open /dev/mem

//map the AD9467 Control Regs

...

mapped_dmac_base_addr = mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0x44A30000);

...

// set channel to RUN
    dmac_write(AXI_DMAC_REG_CTRL, 0x0);
    dmac_write(AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE);
    dmac_write(AXI_DMAC_REG_IRQ_MASK, 0x0);

    dmac_read(AXI_DMAC_REG_TRANSFER_ID, &transfer_id);
    dmac_read(AXI_DMAC_REG_IRQ_PENDING, &reg_val);
    dmac_write(AXI_DMAC_REG_IRQ_PENDING, reg_val);

 

    // physical destination address
    dmac_write(AXI_DMAC_REG_DEST_ADDRESS, 0x19000000);
    dmac_write(AXI_DMAC_REG_DEST_STRIDE, 0x0);

    dmac_write(AXI_DMAC_REG_SRC_ADDRESS, 0x0);
    dmac_write(AXI_DMAC_REG_SRC_STRIDE, 0x0);
    dmac_write(AXI_DMAC_REG_Y_LENGTH, 0x0);

    dmac_write(AXI_DMAC_REG_X_LENGTH, 524288);

    dmac_write(AXI_DMAC_REG_START_TRANSFER, 0x1);

 

    // Wait until the new transfer is queued.
    fprintf(stderr, "waiting for transfer to be queued...\n");
    do {
        dmac_read(AXI_DMAC_REG_START_TRANSFER, &reg_val);
    } while(reg_val == 1);

 

    // Start xfer & wait until completed.
    dmac_write(AXI_DMAC_REG_START_TRANSFER, 0x1);

 

    fprintf(stderr, "waiting for transfer to complete...\n");
    do {
        dmac_read(AXI_DMAC_REG_IRQ_PENDING, &reg_val);
    } while(reg_val != (AXI_DMAC_IRQ_SOT | AXI_DMAC_IRQ_EOT));
    dmac_write(AXI_DMAC_REG_IRQ_PENDING, reg_val);

 

    // Wait until the transfer with the ID transfer_id is completed.
    fprintf(stderr, "waiting for transfer_id 0x%04X to complete...\n", transfer_id);
    do {
        dmac_read(AXI_DMAC_REG_TRANSFER_DONE, &reg_val);
    } while((reg_val & (1 << transfer_id)) != (1 << transfer_id));


...


static void dmac_read(uint32_t reg_addr, uint32_t *reg_data)
{
    *reg_data = *(uint32_t *) (mapped_dmac_base_addr + reg_addr);
}

 

static void dmac_write(uint32_t reg_addr, uint32_t reg_data)
{
    *(uint32_t *) (mapped_dmac_base_addr + reg_addr) = reg_data;
}

 

 

So the above code yields this output:

root@zedboard:~/projects/axidma# ./frdmatest

mapping DMAC Control registers...
DMAC_BASE_ADDR (0x0x44a30000) mapped at 0x0xb6ee8000
mapping DMA buffer area...
START_ADDR_DMA_BUFFER (0x0x19000000) mapped at 0x0xb6d85000 for a length of 524288
Control regs before xfer...
AXI_DMAC_REG_IRQ_MASK             (0x0080): 0x00000000
AXI_DMAC_REG_IRQ_PENDING          (0x0084): 0x00000000
AXI_DMAC_REG_IRQ_SOURCE           (0x0088): 0x00000000
AXI_DMAC_REG_CTRL                 (0x0400): 0x00000001
AXI_DMAC_REG_TRANSFER_ID          (0x0404): 0x00000002
AXI_DMAC_REG_START_TRANSFER       (0x0408): 0x00000000
AXI_DMAC_REG_FLAGS                (0x040C): 0x00000000
AXI_DMAC_REG_DEST_ADDRESS         (0x0410): 0x19000000
AXI_DMAC_REG_SRC_ADDRESS          (0x0414): 0x00000000
AXI_DMAC_REG_X_LENGTH             (0x0418): 0x0007FFFF
AXI_DMAC_REG_Y_LENGTH             (0x041C): 0x00000000
AXI_DMAC_REG_DEST_STRIDE          (0x0420): 0x00000000
AXI_DMAC_REG_SRC_STRIDE           (0x0424): 0x00000000
AXI_DMAC_REG_TRANSFER_DONE        (0x0428): 0x00000003
AXI_DMAC_REG_ACTIVE_TRANSFER_ID   (0x042C): 0x00000002
AXI_DMAC_REG_STATUS               (0x0430): 0x00000000
AXI_DMAC_REG_CURRENT_SRC_ADDR     (0x0434): 0x19080000
AXI_DMAC_REG_CURRENT_DEST_ADDR    (0x0438): 0x00000000
DMA enabled
transfer id = 0x0000
dest addr = 0x19000000
waiting for transfer to be queued...
waiting for transfer to complete...
waiting for transfer_id 0x0000 to complete...

DMA buffer dump (1st 128)

[00000000] 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555
[00000020] 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555
[00000040] 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555
[00000060] 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555 5555
transfered data... bufsize: 524288
Control regs after xfer...
AXI_DMAC_REG_IRQ_MASK             (0x0080): 0x00000000
AXI_DMAC_REG_IRQ_PENDING          (0x0084): 0x00000000
AXI_DMAC_REG_IRQ_SOURCE           (0x0088): 0x00000000
AXI_DMAC_REG_CTRL                 (0x0400): 0x00000001
AXI_DMAC_REG_TRANSFER_ID          (0x0404): 0x00000002
AXI_DMAC_REG_START_TRANSFER       (0x0408): 0x00000000
AXI_DMAC_REG_FLAGS                (0x040C): 0x00000000
AXI_DMAC_REG_DEST_ADDRESS         (0x0410): 0x19000000
AXI_DMAC_REG_SRC_ADDRESS          (0x0414): 0x00000000
AXI_DMAC_REG_X_LENGTH             (0x0418): 0x0007FFFF
AXI_DMAC_REG_Y_LENGTH             (0x041C): 0x00000000
AXI_DMAC_REG_DEST_STRIDE          (0x0420): 0x00000000
AXI_DMAC_REG_SRC_STRIDE           (0x0424): 0x00000000
AXI_DMAC_REG_TRANSFER_DONE        (0x0428): 0x00000001
AXI_DMAC_REG_ACTIVE_TRANSFER_ID   (0x042C): 0x00000001
AXI_DMAC_REG_STATUS               (0x0430): 0x00000000
AXI_DMAC_REG_CURRENT_SRC_ADDR     (0x0434): 0x19013680
AXI_DMAC_REG_CURRENT_DEST_ADDR    (0x0438): 0x00000000

 

Any insight will be greatly appreciated.  I'm still rather a novice with this stuff so I'm guessing I missed something simple.

 

Regards,

Rock

Outcomes