1

I am trying to use this DMA driver to transfer memory from a streaming device to SDRAM.

This is my design in Qsys/Platform designer:

enter image description here

The design streams a predictable pattern of 6x6x6x6x to SDRAM.

The design is verified as working correctly via u-boot by performing the following in uboot:

SOCFPGA_AGILEX5 # md 0x20010000 1               # Read SysID
20010000: acd5cafe                             ....
SOCFPGA_AGILEX5 # md 0x00000000 1               # Read SDRAM
00000000: 9400000a                             ....
SOCFPGA_AGILEX5 # mw 0x22000044 0x1             # Stop Descriptors    
SOCFPGA_AGILEX5 # mw 0x22000044 0x20            # Stop Descriptors
SOCFPGA_AGILEX5 # mw 0x22000044 0x2             # Reset Dispatcher
SOCFPGA_AGILEX5 # mw 0x22000064 0x00000000      # Choose destination address
SOCFPGA_AGILEX5 # mw 0x22000068 0x8             # Write length in bytes
SOCFPGA_AGILEX5 # md 0x22000040 1               # Check status
22000040: 00000002                             ....
SOCFPGA_AGILEX5 # mw 0x2200006c 0x00004000
SOCFPGA_AGILEX5 # sleep 1
SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000      # Execute read
SOCFPGA_AGILEX5 # md 0x22000040 1               # Check status
22000040: 00000002                             ....
SOCFPGA_AGILEX5 # md 0x00000000 1
00000000: 00000000                             ....
SOCFPGA_AGILEX5 # mw 0x22000044 0x2             # Reset Dispatcher
SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000
SOCFPGA_AGILEX5 # md 0x00000000 1
00000000: 64646464                             ....
SOCFPGA_AGILEX5 # mw 0x22000044 0x2
SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000
SOCFPGA_AGILEX5 # md 0x00000000 1
00000000: 65656565                             ....
SOCFPGA_AGILEX5 # mw 0x22000044 0x2
SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000
SOCFPGA_AGILEX5 # md 0x00000000 1
00000000: 67676767                             ....
SOCFPGA_AGILEX5 # mw 0x22000044 0x2
SOCFPGA_AGILEX5 # mw 0x2200006c 0x80004000
SOCFPGA_AGILEX5 # md 0x00000000 1
00000000: 67676767                             ....

Based on the README.md in the driver repo, I have changed my device tree to include these elements:

    clk_0: clk_0 {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <100000000>;  /* 100.00 MHz */
        clock-output-names = "clk_0";
    }; 

    msgdma_streaming_read_0: msgdma@22000040 {
        compatible = "altr,altera-msgdma-st-1.0";
        reg = <0x0 0x22000040 0x0 0x00000020>,
                <0x0 0x22000060 0x0 0x00000010>;
        reg-names = "csr", "descriptor_slave";
        string-property = "msgdma_read";
        interrupts = <0 19 4>;
        interrupt-parent = <&intc>;
        clocks = <&clk_0>;
    };

The interrupt number is based on my .qsys design, which included this snippet:

...
<altera:connection altera:kind="interrupt" altera:version="24.3" altera:start="subsys_hps.f2h_irq0_in" altera:end="msgdma_0.csr_irq">
  <altera:connection_parameter altera:parameter_name="irqNumber" altera:parameter_value="2">
  </altera:connection_parameter>
</altera:connection>
...

The kernel module builds and loads to the SoC:

root@localhost:~# insmod altera_msgdma_st.ko
root@localhost:~# lsmod
Module                  Size  Used by
altera_msgdma_st       20480  0
root@localhost:~# ls /dev | grep msgdma
altera_msgdma_rd0
root@localhost:~# dmesg | tail -1
[  689.957318] Registered Altera MSGDMA device 0 (in READ mode) ...

I have then written a C program to move data:

dma_read_st.c:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>

// https://github.com/pavelfpl/altera_msgdma_st/blob/master/altera_msgdma_ioctl.h
#include "../dma_driver/altera_msgdma_ioctl.h" 

#define READ_COUNT 3  // Number of times to read
#define DELAY_US 100000  // Delay between reads in microseconds (100ms)
#define BUFFER_SIZE 8  // Size of the buffer to read
#define MIN_BLOCK_SIZE 8  // Minimum block size for reads

int main() {
    const char *device = "/dev/altera_msgdma_rd0";
    int fd = open(device, O_RDONLY);
    if (fd < 0) {
        perror("Failed to open device");
        return 1;
    }

    if (ioctl(fd, IO_ALTERA_MSGDMA_STOP_RESET) < 0) {
        perror("Failed to send STOP_RESET ioctl");
        close(fd);
        return 1;
    }
    printf("STOP_RESET ioctl sent successfully\n");

    unsigned long buffer_size = BUFFER_SIZE;
    if (ioctl(fd, IO_ALTERA_MSGDMA_SET_BUFFER_SIZE, &buffer_size) < 0) {
        perror("Failed to set buffer size");
        close(fd);
        return 1;
    }

    unsigned long block_size = MIN_BLOCK_SIZE;
    if (ioctl(fd, IO_ALTERA_MSGDMA_SET_MIN_BLOCK_SIZE, &block_size) < 0) {
        perror("Failed to set min block size");
        close(fd);
        return 1;
    }

    unsigned char buffer[BUFFER_SIZE];
    for (int read_num = 0; read_num < READ_COUNT; read_num++) {
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
        if (bytes_read < 0) {
            perror("Failed to read from device");
            close(fd);
            return 1;
        }

        printf("Read #%d: %zd bytes:\n", read_num + 1, bytes_read);
        for (int i = 0; i < bytes_read; i++) {
            printf("0x%02x ", buffer[i]);
        }
        printf("\n");

        usleep(DELAY_US);

        memset(buffer, 0, sizeof(buffer));
    }

    close(fd);
    return 0;
}

However, the program outputs the following:

root@localhost:~# ./read_dma_st
STOP_RESET ioctl sent successfully
Read #1: 8 bytes:
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
Read #2: 8 bytes:
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
Read #3: 8 bytes:
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

Instead of the expected 6x6x6x6x pattern.

I am not sure what to try next - does anyone have some experience with this?

Many thanks, K

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.