Using HPS DMA in De1-SoC


#1

I have GHRD and try to transfer data(0 to 127 count) from HPS RAM to FPGA OCRAM using HPS DMA.
When i look at result(showing on leds FPGA OCRAM contents) i must see leds showing 0 to 127.
But, something goes wrong and i see only 0 to 3. I guess there is zeros between numbers in FPGA OCRAM after transfer, because i see on leds 0-0-1-0-2-0-3.
And i dont know how many zeros between numbers.
But leds should show in that order: 0-1-2-3-4-5-…-127.

I cant find where i made mistake, please help me, i spend nearly 3 days, but it still dont work right way.
Maybe problem is that i use DMA wrong way?

P.s.: its bare-metal app, De1-SoC board

There is how i try to do this

firstly i setup dma:
indent preformatted text by 4 spaces
ALT_STATUS_CODE socfpga_dma_setup(){
printf(“INFO: Setup DMA System …\n”);

    ALT_STATUS_CODE status = ALT_E_SUCCESS;


    if (status == ALT_E_SUCCESS)
    {
        // Configure everything as defaults.


        ALT_DMA_CFG_t dma_config;
        dma_config.manager_sec = ALT_DMA_SECURITY_DEFAULT;
        for (int i = 0; i < 8; ++i)
        {
            dma_config.irq_sec[i] = ALT_DMA_SECURITY_DEFAULT;
        }
        for (int i = 0; i < 32; ++i)
        {
            dma_config.periph_sec[i] = ALT_DMA_SECURITY_DEFAULT;
        }
        for (int i = 0; i < 4; ++i)
        {
            dma_config.periph_mux[i] = ALT_DMA_PERIPH_MUX_DEFAULT;
        }


        status = alt_dma_init(&dma_config);
        if (status != ALT_E_SUCCESS)
        {
            printf("ERROR: alt_dma_init() failed.\n");
        }
    }


    // Allocate the DMA channel


    if (status == ALT_E_SUCCESS)
    {
        status = alt_dma_channel_alloc_any(&channel);
        if (status != ALT_E_SUCCESS)
        {
            printf("ERROR: alt_dma_channel_alloc_any() failed.\n");
        }
        else
        {
            printf("INFO: Channel %d allocated.\n", (int)(channel));
        }
    }


    // Verify channel state


    if (status == ALT_E_SUCCESS)
    {
        ALT_DMA_CHANNEL_STATE_t state;
        status = alt_dma_channel_state_get(channel, &state);
        if (status == ALT_E_SUCCESS)
        {
            if (state != ALT_DMA_CHANNEL_STATE_STOPPED)
            {
                printf("ERROR: Bad initial channel state.\n");
                status = ALT_E_ERROR;
            }
       }
    }
    





    if (status == ALT_E_SUCCESS)
    {
        status = alt_dma_program_init(&program);
        if (status != ALT_E_SUCCESS)
        {
            printf("ERROR: alt_dma_program_init() failed.\n");
        }
        else
        {
            printf("INFO: Dma program_byffer initialized.\n");
        }
    }




    if (status == ALT_E_SUCCESS)
    {
        printf("INFO: Setup of DMA successful.\n\n");
    }
    else
    {
        printf("ERROR: Setup of DMA return non-SUCCESS %d.\n\n", (int)status);
    }


   return status;
}

then i try to make transfer:

ALT_STATUS_CODE dma_hpsram_to_fpgaram(){
    // Just base addresses of GHRD components
    const uint32_t ALT_LWFPGA_BASE         = 0xFF200000;
    const uint32_t ALT_LWFPGA_LED_OFFSET   = 0x00010040;


    const uint32_t ALT_H2F_BASE                = 0xc0000000;
    const uint32_t ALT_H2F_OCRAM_OFFSET       = 0x00000000;
    const uint32_t ALT_HPS_OCRAM              = 0xffff0000;


    // turn off leds
    alt_write_word(ALT_LWFPGA_BASE + ALT_LWFPGA_LED_OFFSET, 0);


    uint32_t temp=0;
    uint32_t offset=0;


    // write 0-127 to hps ram
    for (uint32_t i = 0; i < 128; ++i)
    {
        alt_write_byte(ALT_HPS_OCRAM+offset,temp);
        temp++;
        offset=offset+1;
    }


    // transfer data from hps ram to fpga ocram
    size_t size=128;
    uint32_t dst=ALT_H2F_BASE+ALT_H2F_OCRAM_OFFSET;
    uint32_t src=ALT_HPS_OCRAM;
    // this function i take from altera design examples (hps dma)
    dma_memory_to_memory(&src, &dst, size);


    // check result of transfer, looking at fpga ocram contents
    offset=0;
        for (uint32_t i = 0; i < 12800000; ++i)
        {
            if(i%100000==0)
            {
                // that big numbers for making leds switch less often
                alt_write_byte(ALT_LWFPGA_BASE+ALT_LWFPGA_LED_OFFSET, alt_read_byte(dst+offset));
                offset=offset+1;
            }
    }
    return ALT_E_SUCCESS;
}


indent preformatted text by 4 spaces
ALT_STATUS_CODE dma_memory_to_memory(void * src, void * dst, uint32_t size){
    ALT_STATUS_CODE status = ALT_E_SUCCESS;


    printf("INFO: Demo DMA memory to memory transfer.\n");


    // Copy source buffer over destination buffer
    if(status == ALT_E_SUCCESS)
    {
        status = alt_dma_memory_to_memory(channel, &program, dst, src, size, false, (ALT_DMA_EVENT_t)0);
    }


    // Wait for transfer to complete
    if (status == ALT_E_SUCCESS)
    {
        printf("INFO: Waiting for DMA transfer to complete.\n");
        ALT_DMA_CHANNEL_STATE_t channel_state = ALT_DMA_CHANNEL_STATE_EXECUTING;
        while((status == ALT_E_SUCCESS) && (channel_state != ALT_DMA_CHANNEL_STATE_STOPPED))
        {
            status = alt_dma_channel_state_get(channel, &channel_state);
            if(channel_state == ALT_DMA_CHANNEL_STATE_FAULTING)
            {
                ALT_DMA_CHANNEL_FAULT_t fault;
                 alt_dma_channel_fault_status_get(channel, &fault);
                 printf("ERROR: DMA CHannel Fault: %d\n", (int)fault);
                 status = ALT_E_ERROR;
            }
        }
    }
    return status;
}

#2

Sorry. I dont have time to check the code but I have an example here (https://github.com/robertofem/CycloneVSoC-examples/tree/master/Baremetal-applications/DMA_transfer_FPGA_DMAC) where i do the same. Take a look to it and try to spot the difference.

Regards


#3

Oh, yeah, i find your repository and did the same in my project, and it worked, So many thanks to you :slight_smile: it was really very usefull for me