Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

Modular SGDMA Streaming

Hi,

I'm trying to stream data from an ADC to my DDR RAM. I’ve hit a roadblock with using the modular SGDMA core to do streaming to memory mapped transfers to DDR RAM. An interrupt that is supposed to go off when the transfer is complete never goes off. This isn’t because the data never stops being written but is actually because the data never begins to be written. I’ve noticed this because I print out some of the memory addresses during the wait for the interrupt -> the values that get written out don’t correspond to the values being fed into the SGDMA. I’ve noticed issues which point to either a software or hardware problem.

The software issue is that the IOWR and IORD commands don’t seem to be working correctly.

IOWR_32DIRECT(MEM_IF_DDR2_EMIF_0_BASE, testNumber, testNumber);

IORD (MEM_IF_DDR2_EMIF_0_BASE, testNumber);

/////////////////////////////////////////////////////////////^Doesn’t work

memcpy(MEM_IF_DDR2_EMIF_0_BASE + testNumber*sizeof(int), &testNumber, sizeof(testNumber)); ->writing

memcpy(&value, (MEM_IF_DDR2_EMIF_0_BASE+testNumber*sizeof(int)), sizeof(int)); ->reading

////////////////////////////////////////////////////////////^Works

I’m not sure if this is because in my tests I am writing to RAM, I will look into that, but this is an issue since the data transfer descriptor is initialized using the IOWR_32DIRECT function. I don’t think this is the issue though because I’m able to call these same functions successfully when I do memory-mapped to memory-mapped data transfers. I've attached the c file that I'm using to test the streaming data transfer (main.c), the line that doesn't work is# 74: if (sgdma_interrupt_fired == 1) -> I've changed this to a while check and noticed that the interrupt never gets asserted.

The next area that I think might be an issue is the way I collect data from the incrementing register (the one I’m streaming data from). I simply connected the bus streaming data bus to the streaming sink of the write master in the Qsys project. I have an image of that project with the connection circled (Qsys.png). Is that the correct way to connect streaming data to a Qsys project? Is there anything that’s obviously wrong with the way I’ve set up the connections? Any advice on how to approach figuring out why the interrupt I need doesn’t go off?

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Your image is so small it's difficult to see. Can you add a signaltap instance on the stream interface to check that anything is actually going through it?

    As for your problem with the macros, it's probably because the 32DIRECT versions use a byte offset, while IORD/IOWR use a word offset. Therefore you either need to multiply testNumber by sizeof(int) in your line with IOWR_32DIRECT, or only use IOWR and IORD. This should probably work:

    IOWR(MEM_IF_DDR2_EMIF_0_BASE, testNumber, testNumber);
    IORD (MEM_IF_DDR2_EMIF_0_BASE, testNumber);

    Using direct addressing, either with pointers or memcpy work also, but you need to be careful if your CPU has a data cache. Then you need to flush or invalidate it before or after the operation.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi Daixiwen,

    I've attached a screenshot of the signals being tapped from the write master's data sink, it looks like the streaming data is going through correctly. The CSR IRQ also goes off which indicates when the write is complete. However, there is a problem on the software side, the exception does not get handled.

    The way I have the system set up right now is I "fake" an avalon streaming interface to stream data from an ADC to a FIFO. That fifo is connected to the data sink of the SGDMA using the avalon streaming interface. I used a PIO to allow the NIOS II software to set the valid bit of the top level module's "fake" streaming avalon bus (this signal is tapped and shown in the attached image as "adc_ready_pio_export"). The interrupt signal is also shown as "csr_irq".

    The interrupt remains at 1 after the standard descriptor register is written to. It seems like the nios 2 processor registers an unhandled exception right after interrupt signal goes up. The following are the instructions that get called prior to the interrupt going off (the PIO that controls the write is set to high) and the assembly instructions of the exception handler.

    90 IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, 1);

    00000320: movi r3,1

    00000324: movhi r2,16388

    00000328: addi r2,r2,2128

    0000032c: stwio r3,0(r2)

    96 if(value == 0){

    00000330: ldw r2,-4(fp)

    alt_exception_unknown:

    40000094: break 0

    40000098: ldw r5,68(sp)

    4000009c: ldw ea,72(sp)

    400000a0: ldw ra,0(sp)

    400000a4: wrctl estatus,r5

    400000a8: ldw at,8(sp)

    400000ac: ldw r2,12(sp)

    400000b0: ldw r3,16(sp)

    400000b4: ldw r4,20(sp)

    400000b8: ldw r5,24(sp)

    400000bc: ldw r6,28(sp)

    400000c0: ldw r7,32(sp)

    400000c4: ldw r8,36(sp)

    400000c8: ldw r9,40(sp)

    400000cc: ldw r10,44(sp)

    400000d0: ldw r11,48(sp)

    400000d4: ldw r12,52(sp)

    400000d8: ldw r13,56(sp)

    400000dc: ldw r14,60(sp)

    400000e0: ldw r15,64(sp)

    400000e4: addi sp,sp,76

    400000e8: eret

    I also printed out the register values at the time the exception occurs:

    zero 0

    at 3735928559

    r2 3690725375

    r3 488

    r4 1

    r5 0

    r6 2155905152

    r7 4278124287

    r8 67528

    r9 70204

    r10 5

    r11 3

    r12 67532

    r13 1073740280

    r14 67528

    r15 196218880

    r16 69016

    r17 67552

    r18 3735928559

    r19 3735928559

    r20 3735928559

    r21 3735928559

    r22 3735928559

    r23 3735928559

    et 3735928559

    bt 4294967295

    gp 0x0001a844

    sp 0x3ffffeb8

    fp 0x3fffff18

    ea 0x0bb21004

    sstatus 4294967295

    ra 0x000001ec

    pc 0x40000094

    status 0

    estatus 0

    bstatus 4294967295

    ienable 5

    ipending 1

    cpuid 0

    ctl6 4294967295

    exception 20

    pteaddr 4294967295

    tlbacc 4294967295

    tlbmisc 4294967295

    eccinj 4294967295

    badaddr 0

    config 4294967295

    mpubase 4294967295

    mpuacc 4294967295

    The register that seemed to be the most important was the exception register which held a value of 20. A subset of the exception register corresponds to the cause of the exception. That subset corresponded to cause# 5 which is an "Illegal Instruction Exception". I'm not sure why I'm getting this exception since the instructions being run prior to the interrupt seem valid. Any idea what's causing this problem?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I have another update, it seems like I can only write 488 words of data before this exception occurs. This indicates to me that there might be a buffer that's filling up (I don't know why I would be getting an illegal instruction error though). The other strange thing is that the depth of all of my buffers is 1024, I would expect a buffer error to occur at around that number of words being transferred not 488.