Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

NIOS II DMA HAL

Altera_Forum
Honored Contributor II
3,587 Views

Anybody use the DMA HAL driver? 

 

I need correct example for stream device and memory. 

I want receive from steram device through DMA(using HAL) and save stream data to memory. 

I have written worked code using DMA registers, but can't get right result for HAL. 

 

Studying of sourcel codes for HAL DMA indirectly specifies a mistake in HAL library, but I am not confident it.
0 Kudos
18 Replies
Altera_Forum
Honored Contributor II
1,125 Views

There was a bug in the HAL/DMA. This has been fixed and will be released very soon. I don't believe there is a workaround for it. I'll check.

0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

Will companies that have purchased the NIOS-II eval board/kit get notice 

of any bug fixes/releases of NIOS-II? 

 

We plan on using HAL/DMA extensively for a project-in-progress. 

 

John
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

I'm sure you will get notice of updates. I will also post it here :-) 

Marketing will be able to tell me if it will be a downloadable release. It looks too big right now from what I can tell.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

If you are an active subscriber (meaning you purchased a Nios I/II kit less than a year ago or you purchased a Nios renewal and are still under active maintenance) then you will receive updates shipped to you automatically. We generally have 2 shipped releases per year, and 2-3 downloadable service pack releases.  

 

Check for downloads here: nios i/ii service pack downloads (https://www.altera.com/support/software/download/service_packs/nios/upd-nios_index.jsp). Warning, please do not mistake Nios I service packs for Nios II ones. The next release is a service pack, scheduled to be available for download from www.altera.com by October 15th.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

 

--- Quote Start ---  

originally posted by major@Sep 7 2004, 10:35 PM 

anybody use the dma hal driver? 

 

i need correct example for stream device and memory. 

i want receive from steram device through dma(using hal) and save stream data to memory. 

i have written worked code using dma registers, but can't get right result for hal. 

 

studying of sourcel codes for hal dma indirectly specifies a mistake in hal library, but  i am not confident it. 

--- Quote End ---  

 

Major. 

 

Have you looked at the example on page 4-21 of the Nios II Software Developer's Handbook, there is an example of exactly what you're trying to do and it works. If this does not answer your question then please post back.  

 

Lastly the bug that Kerri refers to is an edge case, and will not apply in the use case you have described.  

 

To explain the problem, it is important to understand the HAL DMA model. This expects a DMA device to be performing DMA transfers in one of three modes: 

 

- memory to memory 

- devices to memory 

- memory to device 

 

Which mode is used is expected to be determined at system creation time. 

 

In the case of the altera_avalon_dma driver, this is actually done through a run time ioctl call. The bug occurs if you have run the DMA in one of these modes, and then make the ioctl call to change to one of the other modes.  

 

This is in any case not an efficent way to make use of the DMA controller, since the pending transfer queues will need to be drained between the ioctl calls. It is better to provide additional DMA channels instead.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

Have you looked at the example on page 4-21 of the Nios II Software Developer&#39;s Handbook, there is an example of exactly what you&#39;re trying to do and it works. If this does not answer your question then please post back.  

 

Lastly the bug that Kerri refers to is an edge case, and will not apply in the use case you have described.  

 

To explain the problem, it is important to understand the HAL DMA model. This expects a DMA device to be performing DMA transfers in one of three modes: 

 

- memory to memory 

- devices to memory 

- memory to device 

 

Which mode is used is expected to be determined at system creation time. 

 

In the case of the altera_avalon_dma driver, this is actually done through a run time ioctl call. The bug occurs if you have run the DMA in one of these modes, and then make the ioctl call to change to one of the other modes.  

 

This is in any case not an efficent way to make use of the DMA controller, since the pending transfer queues will need to be drained between the ioctl calls. It is better to provide additional DMA channels instead.[/b] 

--- Quote End ---  

 

 

I use mode "devices to memory". 

I try use code on page 4-21. This code also does not work. 

 

1. This code with small error: /* Wait for the transaction to complete */ while (!dma_done); - dma_done: void result function 

2. I add to example IOCT request for RX_STREAM_ON with argumet = SPI_BASE address, before call alt_dma_rxchan_prepare. 

 

 

"Which mode is used is expected to be determined at system creation time" 

System created in "devices to memory": 

1. DMA read_master connected ONLY to SPI control port 

2. DMA write_master connected ONLY to SDRAM. 

 

This configuration work correctly through direct access to DMA registers, but don&#39;t work through HAL. 

This my worked code: 

   IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_SPI_REC_BASE, 0);    IOWR_ALTERA_AVALON_DMA_STATUS(DMA_SPI_REC_BASE, 0);      IOWR_ALTERA_AVALON_DMA_RADDRESS(DMA_SPI_REC_BASE, SPIS_DATA_BASE);    IOWR_ALTERA_AVALON_DMA_WADDRESS(DMA_SPI_REC_BASE, (alt_u32)buffer);    IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_SPI_REC_BASE, DMA_BUFF_SIZE*2);    ch =  ALTERA_AVALON_DMA_CONTROL_HW_MSK        | ALTERA_AVALON_DMA_CONTROL_GO_MSK        | ALTERA_AVALON_DMA_CONTROL_LEEN_MSK        | ALTERA_AVALON_DMA_CONTROL_RCON_MSK;          IOWR_ALTERA_AVALON_DMA_CONTROL(DMA_SPI_REC_BASE, ch);    printf("Wait data...\n");    while(1){      ch = IORD_ALTERA_AVALON_DMA_STATUS(DMA_SPI_REC_BASE);      if( ch & (~ALTERA_AVALON_DMA_STATUS_BUSY_MSK) )      {        printf("DMA %d\n", ch);        break;      }    } 

 

There can be you can result a correct code for HAL operations?
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

Could you post the HAL code that&#39;s not working for you?

0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

TO_BE_DONE

0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

The use of transmit and receive in this context is a little confusing, since they have different meanings depending on whether you view things from outside or inside the DMA. The confusion is made worse by the fact that the documentation (and apparently the comments as well) are wrong in the 1.0 version of the Nios II kit. 

 

Try using ALT_DMA_TX_STREAM_ON rather than ALT_DMA_RX_STREAM_ON. That should fix your problem.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

Thanks. I try it check tomorrow and inform about result. 

Yes, comments for alt_avalon_dma_launch_rxonly: 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

/* 

* alt_avalon_dma_launch_rxonly() is called to launch a new transaction when 

* only the receive channel is using incrementing addresses,  

* i.e. the transmit channel is accessing a single memory location (which is 

* probably a device register).  

*/[/b] 

--- Quote End ---  

 

But in function code set DMA control flag RCON, and too(WCON) for alt_avalon_dma_launch_txonly. 

 

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

The use of transmit and receive in this context is a little confusing, since they have different meanings depending on whether you view things from outside or inside the DMA.[/b] 

--- Quote End ---  

 

 

Receive or send DMA mode defined by connection WriteMaster and ReadMaster of the DMA channel (in current DMA opperation) and independet from view point (outside or inside the DMA).
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

I check idea with change the ALT_DMA_RX_STREAM_ON to ALT_DMA_TX_STREAM_ON in the IOCTL request. 

All init steps passed correctly. But program haalted after call "alt_dma_rxchan_prepare". 

Program passes to an infinite cycle of ISR from DMA (i set break point in alt_avalon_dma_irq function). 

The first time ISR ocurred before programm return form alt_dma_rxchan_prepare, after write to DMA_CONTROL register. 

In ISR apdated DMA slot information, and programm go to infinite ISR cycle, however request for data send to SHARC processor not sended and no data was sended to SPI. 

 

This is HAL bug?
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

I can&#39;t see any obvious source of this problem. However I do notice that in your test code you use a transfer size of DMA_BUFF_SIZE*2 and in your HAL example you use a size of 1024. I don&#39;t know what value you have set for DMA_BUFF_BYTESIZE, but could it be that you have a memory overwrite here?

0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

<div class='quotetop'>QUOTE </div> 

--- Quote Start ---  

However I do notice that in your test code you use a transfer size of DMA_BUFF_SIZE*2 and in your HAL example you use a size of 1024.[/b] 

--- Quote End ---  

 

 

Excuse me. In my case it is bad style. 

 

For dirrect DMA registers acsess: 

 

For DMA_BUFF_SIZE*2:# define DMA_BUFF_SIZE (1024*1024+1) // transaction word 16-bit 

alt_u16 *buffer=NULL; 

buffer = (alt_u16 *)memalign(2, DMA_BUFF_SIZE*2); // allocate memory for DMA_BUFF_SIZE 16-bit words 

............... 

............... 

IOWR_ALTERA_AVALON_DMA_LENGTH(DMA_SPI_REC_BASE, DMA_BUFF_SIZE*2); 

 

For HAL example:# define DMA_BUFF_BYTESIZE 1024 

alt_u16 buffer[DMA_BUFF_BYTESIZE]; 

alt_dma_rxchan_prepare (rx, &buffer[0], 1024, NULL, NULL); 

 

Memory overwritenn cann&#39;t occur, becouse: 

1. In prepare call I request less bytes then allocated for buffer. 

2. DMA HAL passed to infinite ISR cycle before call of function Send2Sharc(0xA5); This function initiate the transfer process.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

I have just tried to run your code on the Stratix 1S10ES full reference design (with RX_STREAM changed to TX_STREAM), and it seems to work fine. The important change I made is that I removed all the references to the SPI, and instead directed the DMA to read from a location in memory. 

 

It looks like in your case you have some configuration problem relating to the SPI. From here it&#39;s difficult to determine the source of the problem beyond that...
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

I have not read carefully the previous posts(I will do that later). I have a problem which is simlar to the one described by rugbybloke: 

 

I have wrote 3 subroutines, one for peripheral-to-memory, one for memeory-to-peripheral, another for memory-to-memory. If I only call a single subroutine in the main function, ereryone will work properly; but when I call them in a queue, with ioctl to switch among them, bugs emerging. 

For example: (the three mode will be abbreviated as P2M,M2P,M2M) 

When I call those 3 routines in cycle with P2M the first: 

P2M(1)--->M2P(1)--->M2M(1)--->P2M(2)--->M2P(2)---->M2M(2)--->......... 

Then the first one---P2M(1) will work properly, when it turns to M2P(1), it will do the work of P2M with the inverse destination address and start address that assigned to M2P(1);M2M will do the work of M2P(1),P2M(2) do the work of M2M(1).........It seems that the next routine will do the work of the previous one, but the addresses of P and M are its own. 

I do not know whether I have described clearly. I will attach my code here, anyone who interest in it can test it on your board.  

******************************************************************************** 

****** 

Note: 

1: copy_1_to_range is just the P2M, range_to_1 is M2P and range_to_range is M2M. 

2: Here, I use SRAM as the test memory and SDRAM as the data and program memory. And also I use a fixed  

memory cell in SRAM as the peripheral. The base address of SRAM is 0x00800000. 

3: To anyone who has good ideas and advices for my program, I&#39;d like to receive your email to talk about 

DMA or anything else about NiosII. My email is: RemyMartin@eyou.com 

******************************************************************************** 

******# include <stdio.h># include <stddef.h># include <stdlib.h># include "sys/alt_dma.h"# include "alt_types.h"# include "altera_avalon_dma_regs.h"# include "altera_avalon_dma.h"# include "system.h"# include "string.h" 

 

/* ************************************************************************* */ 

/* The following routines is for transmintting & receiving callback routines */ 

/* ************************************************************************* */ 

volatile alt_32 transmitdone=0; 

volatile alt_32 receivedone=0; 

 

void transmit_done() 

transmitdone=1; 

 

void receive_done() 

receivedone=1; 

 

/* ************************************************************************* */ 

/* The following routines is for 1-to-range processing. */ 

/* ************************************************************************* */ 

void copy_1_to_range(const char* dma_name, 

void* start_addr, //Here,start_addr is the "1"  

void* desti_addr, //and desti_addr is the "range" 

alt_32 transfer_count, 

alt_32 transfer_mode) 

alt_32 flag; 

alt_dma_rxchan rxchan; 

 

if((rxchan=alt_dma_rxchan_open(dma_name))==NULL) 

printf("\n Failed to open receive channel(1-to-range)!\n"); 

exit(1); 

alt_dma_rxchan_ioctl(rxchan,transfer_mode,NULL); 

alt_dma_rxchan_ioctl(rxchan,ALT_DMA_TX_STREAM_ON,start_addr); 

 

if((flag=alt_dma_rxchan_prepare(rxchan,desti_addr,transfer_count,receive_done,NU 

LL))<0) 

printf("\n Failed to post receive request(1-to-range)!\n"); 

exit(1); 

 

while(!receivedone); 

receivedone=0; 

alt_dma_rxchan_ioctl(rxchan,ALT_DMA_TX_STREAM_OFF,NULL); 

alt_dma_rxchan_close(rxchan); 

 

 

/* ************************************************************************* */ 

/* The following routines is for range-to-1 processing. */ 

/* ************************************************************************* */ 

void copy_range_to_1(const char* dma_name, 

void* start_addr, //Here,start_addr is the "range" 

void* desti_addr, //and desti_addr is the "1" 

alt_32 transfer_count, 

alt_32 transfer_mode) 

alt_32 flag; 

alt_dma_txchan txchan; 

 

if((txchan=alt_dma_txchan_open(dma_name))==NULL) 

printf("\n Failed to open transmit channel(range-to-1)!\n"); 

exit(1); 

alt_dma_txchan_ioctl(txchan,transfer_mode,NULL); 

alt_dma_txchan_ioctl(txchan,ALT_DMA_RX_STREAM_ON,start_addr); 

 

if((flag=alt_dma_txchan_send(txchan,desti_addr,transfer_count,transmit_done,NULL 

))<0) 

printf("\n Failed to post transmit request(range-to-1)!\n"); 

exit(1); 

 

while(!transmitdone); 

transmitdone=0; 

alt_dma_txchan_ioctl(txchan,ALT_DMA_RX_STREAM_OFF,NULL); 

//alt_dma_txchan_close(txchan); 

 

}  

 

/* ************************************************************************* */ 

/* The following routines is for range-to-range processing. */ 

/* ************************************************************************* */ 

void copy_range_to_range(const char* dma_name, 

void* start_addr, 

void* desti_addr, 

alt_32 transfer_count, 

alt_32 transfer_mode) 

alt_32 flag; 

alt_dma_txchan txchan; 

alt_dma_rxchan rxchan; 

 

/* Creat the transmit channel */ 

 

if((txchan=alt_dma_txchan_open(dma_name))==NULL) 

printf("\n Failed to open transmit channel(range-to-range)!\n"); 

exit(1); 

 

/* Creat the receive channel */ 

 

if((rxchan=alt_dma_rxchan_open(dma_name))==NULL) 

printf("\n Failed to open receive channel(range-to-range)\n"); 

exit(1); 

 

/* Post the transmit request */ 

 

alt_dma_txchan_ioctl(txchan,transfer_mode,NULL); 

if((flag=alt_dma_txchan_send(txchan,start_addr,transfer_count,transmit_done,NULL 

))<0) 

printf("\n Failed to post transmit request, the reason is %i\n",flag); 

exit(1); 

 

/* Post the receive request */ 

 

alt_dma_rxchan_ioctl(rxchan,transfer_mode,NULL); 

if((flag=alt_dma_rxchan_prepare(rxchan,desti_addr,transfer_count,receive_done,NU 

LL))<0) 

printf("\n Failed to post receive request, the reason is %i\n",flag); 

exit(1); 

 

while(!(transmitdone & receivedone)); 

transmitdone=0; 

receivedone=0; 

alt_dma_txchan_close(txchan); 

alt_dma_rxchan_close(rxchan); 

 

/* ************************************************************************* */ 

/* The main routine */ 

/* ************************************************************************* */ 

main() 

char* name="/dev/dma_no1"; 

while(1){ 

copy_1_to_range(name, 

(void*)0x00800000, 

(void*)0x00800010, 

8, 

ALT_DMA_SET_MODE_8); 

 

copy_range_to_1(name, 

(void*)0x00800020, 

(void*)0x00800030, 

12, 

ALT_DMA_SET_MODE_32); 

 

copy_range_to_range(name, 

(void*)0x00800040, 

(void*)0x00800050, 

16, 

ALT_DMA_SET_MODE_8);} 

 

}
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

The receive and transmit are rather complexing in Nios II. 

As for the alt_dma_txchan_...and alt_dma_rxchan_....., the memory is the reference, that means: if u use alt_dma_txchan, the the memory is the transmitting one; if u use alt_dma_rxchan, the the memory is the receiving one. 

But when it turns to the parameters of ioctl, the meaning is the reverse: ALT_DMA_TX_STREAM means the peripheral will do the stream transmitting work, so does the ALT_DMA_RX-STREAM. 

It pained me so much when I use ALT_DMA_TX_STREAM_ON/OFF in alt_dma_rxchan_ioctl(). 

I have not fully understand the alt_avalon_dma_launch_bidir/txonly/rxonly yet, it&#39;s rather confusing. 

 

In Nios I, the programming of DMA is rather easy, only copy_1_to_range(),copy_range_to_1() and copy_range_to_range() will do almost all the work!
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

It&#39;s unfortunate, but it&#39;s true. The HAL DMA interface is much more complicated than the old Nios I example functions. There&#39;s two reasons for this: 

 

1. The HAL uses a callback interface rather than blocking waiting for the DMA to complete. This allows the processor to continue execution and do something useful while a DMA is underway - this is after all the reason for using a DMA rather than memcpy(). 

 

2. A DMA process is described in terms of two half DMA&#39;s. While this is a little unatural when looking at the altera_avalon_dma component, it provides a much more general infrastructure which should be able to support future DMA controllers. 

 

To solve your particular problem, I&#39;d recommend providing a seperate DMA device for each peripheral you wish to communicate with - so in your case you&#39;d have three channels. That way you only call the ioctl at most once for each channel, and you avoid this problem. 

 

Even if the bug was not there, I believe you&#39;d find that this becomes necessary in any case once you start putting together a real system. Given that all the transfers are being processed in parallel to you main code execution, you&#39;ll find that it becomes difficult to synchronise the DMA activity so that you call the ioctls at the right time. 

 

You&#39;ll also have the problem of figuring out where incoming packets have come from. This way it&#39;s easy in that there&#39;s a one to one correspondance between DMA channel and source. 

 

I hope that makes sense, and solves your problem.
0 Kudos
Altera_Forum
Honored Contributor II
1,125 Views

Thank you.  

But by now, I am working for a new DMA driver which is more suitable for my project. Although @ltera will fix this problem soon, I think it&#39;s a good and useful experience which will give me a indepth view into 

the DMA, after all DMA will be used extensively in my project.
0 Kudos
Reply