Showing results for 
Search instead for 
Did you mean: 
Honored Contributor I

How-to: Transfering data from UART trough SG-DMA with little intervention from CPU



I am trying to fill a RAM with data from a host PC through a UART core (RS-232 Serial Port) by using an SG-DMA controlled by a Nios II CPU (by the usual use of SG-DMA descriptors). 


The documentation for the DMA (not SG-DMA but I would expect the following to be true for both) explicitly mentions: 


--- Quote Start ---  

The DMA controller is capable of performing Avalon transfers with flow control, enabling it to automatically transfer data to or from a slow peripheral with flow control (for example, uart), at the maximum pace allowed by the peripheral. 

--- Quote End ---  



My understanding is that I can build a descriptor telling the (SG-)DMA "get n bytes from the UART core's rxdata register and put them in the RAM; one-by-one when they arrive." which should look like this: 

alt_sgdma_descriptor* desc = /*...*/; alt_sgdma_descriptor* next = /*...*/; alt_u32* read_addr = (alt_u32* const) SGDMA_M_READ_<UART Core>_BASE; alt_u32* write_addr = (alt_u32* const) SGDMA_M_WRITE_<RAM>_BASE; alt_avalon_sgdma_construct_mem_to_mem_desc(desc, next, read_addr, write_addr, n, 1 /*Reads from a fixed address*/, 0 /*Doesn't write to a fixed address*/); 

and then 

alt_avalon_sgdma_do_async_transfer(sgdma, desc); 

and I would then expect the SG-DMA to wait for each byte to arrive then transfer it to the RAM at an address incremented at each transfer. Unfortunately, it looks like the SG-DMA reads n times the rxdata register without any flow control form the UART resulting in an incorrect transfer. 


When I look at the system generated by Qsys, I don't understand how the UART would actually be able to handle the flow control (i.e. to say to the SG-DMA to wait between bytes) as the only output signals it has are txd (which goes out of the FPGA), readdata (which is a data signal, not control) and the irq (which goes to the CPU, not the SG-DMA) so that I see no way for it to regulate the data transfer (e.g. a <...>_waitrequest signal). Seeing how general the above code is, I don't expect the SG-DMA to detect that it's working with an UART core and pole the right bit in the right register of the core to detect that new data has arrived, either (but I might be wrong). Therefore, I am not surprised of the previously described behaviour. 


Currently, I use the Nios II CPU as a "bridge for flow control" between the two where it waits for IRQs from both the UART Core and the SG-DMA stating that, respectively, new data is available and a transfer can take place and then constructs the descriptor for the single-byte transfer for the SG-DMA before calling alt_avalon_sgdma_do_async_transfer(). This works but is obviously not what I want as the CPU is active for transferring each byte and the overhead is higher than if I was to make the transfer directly through the CPU, instead. 


So what is the correct way to program the SG-DMA "to automatically transfer data from UART with flow control" as described in the documentation? 


If required, I join a picture of the Qsys connections between these entities. (NB: the CPU is connected to the UART for the initialization part).
0 Kudos
0 Replies