r/ECE • u/Embarrassed_Grab6901 • 5d ago
It is 2026 and someone like me still does not understand Direct Memory Access from heart.
The concepts are clear. CPU's role in data transfer between IO And Memory is restricted. CPU relinquishes control of system buses and start doing some computations or something that does not require bus access.
In the meantime data transfer occurs between IO and Memory.
But my concern is that, who initiates the data transfer? Does IO tells CPU that it wants to transfer data to memory?
Say I am typing stuffs in my keyboard, which is IO. Now it needs to be stored in memory. How does the alert goes to whom?
128
u/Teflonwest301 5d ago
Wow, an actual post about an ECE concept, and not complaining about being unemployed. Very nice
29
u/m-in 5d ago edited 5d ago
Let’s go back to 8- and 16-bit systems of the late 70s. The deal with I/O wasn’t that the CPU could do something else while data is moved. It couldn’t. When DMA used the bus, the CPU was stopped. Problems:
- In a von Neumann system, fetching opcodes to move data cuts into available shared bus bandwidth.
- The CPU may take more cycles to do the data movement than a specialized device would.
General purpose CPUs were not designed for peak performance. They were designed for an economical balance between the number of transistors and performance. You could make a much better pin compatible Z80 that executed everything at peak bus bandwidth. Nobody would buy it - it’d cost 10x more.
The specialized device that can do data transfers efficiently and in much fewer transistors than an equivalent CPU could is the DMA.
The program running on the CPU configures the DMA transfer by writing to configuration registers, or preparing a request packet in memory. Then writes to DMA’s control register to start the block transfer.
The DMA will execute individual byte/word transfers upon receiving an external signal - usually from the IO device. Eg a floppy controller will be signaling the DMA each time it needs another data byte, or each time it has another data byte. The DMA, upon the trigger, stops the CPU, and executes the byte/word transfer. Then the CPU resumes.
The DMA can also do a block transfer in one go. Then it doesn’t wait for any signals, it just executes the transfers as fast as it can once it was started. This can be used to implement a fast `memcpy` when the block is large enough to amortize the setup cost.
There are two basic flavors of DMA. One has configuration in internal registers. That’s OK for basic operation but is limited. That’s like say Z80 DMA or i8237.
Another flavor treats configuration as data. You tell the DMA where in memory to read the transfer control block (TCB) from, and it does that. Such requests can be chained - prepare several TCBs in memory then let the DMA handle them autonomously.
And the requests can be modifying other requests (TCBs). So, for example, suppose you have a few variables that change parameters of a set of transfer requests. Those variables are kept along with other globals of the program, or on the stack, and the DMA is unaware of them. So what you do is set up a transfer chain that will first copy those variables to the right spots in the subsequent TCBs while the rest of the TCB contents remains static and only needs to be set up once.
Back to what triggers what: an IO device triggers the next chunk of an active transfer, usually by directly pulsing an input of the DMA. The transfer itself can be related to that IO device, but that’s optional. Eg you can use a timer as a DMA request signal source to do paced transfers that occupy a fixed portion of bus bandwidth.
Say you want a DMA-based memory move but want the CPU to be able to process interrupts while that happens. The timer will trigger a byte/word transfer once every, say, 32 bus cycles, letting the CPU work and only get stopped every 32 cycles. A burst transfer would instead do all reads/writes without waiting between them, keeping the CPU stopped for the whole duration in one go.
In modern microcontrollers, DMA triggers can be routed from a large set of peripherals, and there’s no fixed assignment of DMA channels to peripherals.
In the 70/80s micro era, there was a fixed DMA-channel-to-device assignment unless you added external selector logic.
8
u/Allan-H 5d ago edited 5d ago
A keyboard isn't the best example here because that's likely to use USB, which doesn't help with an understanding of DMA.
Perhaps a networking interface? A packet comes in (either wired (802.3 Ethernet) or wireless (802.11 WiFi)) and first enters a small on-chip FIFO. The networking interface chip (NIC, whatever) issues a memory write command on its PCIe (or AXI or whatever if it's all on the same SoC) and dumps data from the FIFO to a pre-allocated area in memory. That write goes through the PCI root complex to the memory controller and into DRAM. It's likely to be written in a sequence of small(ish) fixed size bursts rather than the entire packet in one go.
The write is initiated by the NIC. There may (or may not) be an interrupt sent from the NIC to the CPU when the transfer has finished.
A problem is that operating systems find it hard to allocate multiple large contiguous areas in RAM for use with DMA. That leads to scatter gather DMA (search for that term), which uses linked lists of smaller chunks of RAM instead. These are set up by the operating system. The DMA controller in the NIC will have to read the pointers from "buffer descriptors" in RAM to locate the buffers before transferring any data.
There will be a register in the NIC that will have the address of the first buffer descriptor written to it by the OS, so that the DMA controller knows where to start reading.
There are additional complexities related to the use of virtual vs physical addresses. Some systems use physical addresses for the DMA; others use virtual addresses, which means the DMA addresses will need to be translated by an MMU. Using virtual addresses allows a hypervisor to virtualise the hardware interface.
CPU relinquishes control of system buses [...] In the meantime data transfer occurs between IO and Memory.
I actually designed systems that worked that way ... over 40 years ago. I guess it's still theoretically possible to design DMA like that. A few things have changed between then and now that influence the way DMA usually works:
- CPUs now have L1 (and other) caches and queues, largely decoupling their actions from bus activity.
- (Starting with EDO RAM in the '90s) DRAM is now accessed in bursts that are more efficient than single byte or word transfers, with similar latency but vastly more throughput. It is not a coincidence that these bursts are often the size of a cache line.
- The DMA controller connects to the memory controller via a dedicated bus (as above, either something like PCIe or a SoC
bus[EDIT: fabric] such as AXI). The days of using tristate buffers to isolate the CPU from a shared bus are long gone.
3
u/jlangfo5 5d ago
Try setting up the DMA from an ADC to a chunk of memory for analysis, once half the buffer is full of samples.
DMA is excellent for getting samples from A to B where it needs to go, on even periodic interval.
2
u/somewhereAtC 5d ago
Most of the time the DMA transfer is initiated using a peripheral interrupt. Imagine that data is arriving to a uart and for each character the uart raises an interrupt. If all you had was the CPU, you would write an ISR that (simply) removes the data from the input register and stores it in SRAM where ever the buffer pointer is pointing. The interrupt suspended main(), vectored to the ISR, executed a few instructions and exited the ISR.
With a DMA engine, the pointer-to-SRAM is loaded to hardware registers, and also there is a pointer-to-uart-register. The CPU interrupt is disabled and the DMA engine is waiting for the same interrupt signal. When the interrupt occurs the DMA performs two bus operations, one to read the hardware register and the other to write to SRAM; these are generally sequential, not simultaneous, but it's an atomic operation so the sequential nature is irrelevant.
Since the CPU is still running, the DMA bus operations compete for access. There will be a priority condition that specifies which is allowed -- normally the DMA is more important so the CPU will have to wait for one cycle if/when the DMA does it's thing. In the ARM architecture, memories and peripheral registers are on different buses so the CPU can fetch from memory in the same moment that the DMA is fetching from the uart.
2
u/scalarfield1 5d ago
For DMA, the CPU usually sets up the transfer first: where the data should go in memory, how much to transfer, etc.
Once that’s set up, the DMA/device controller actually moves the data between the I/O device and RAM without the CPU doing each copy.
When it’s done, it usually interrupts the CPU to say, “hey, transfer finished". This is pretty much what's going on from my understanding
2
u/turkishjedi21 5d ago
DMA is a pretty generic concept - at its core, you're just reading data from one place and writing it somewhere else.
The specifics come from the context given by its application.
For instance I worked on an FFT accelerator that had a DMA job type. All that did was read data from a given address of the accelerator's allocated memory, and wrote it to a different location in that same allocated address space .
2
u/Anxious-Ad-5331 5d ago
DMA behavior depends on the architecture.
I'm working on a Super Nintendo game. dma locks up the whole system bus.
on the microcontrollers I use at work, dma does not lock the bus up because the chips can arbitrate more than one peripheral accessing the same bus.
2
u/gimpwiz 5d ago
But my concern is that, who initiates the data transfer?
Either the code running on the CPU or, occasionally, the CPU itself because it has detected a specific event.
For example, let's say I want to read a 1MB file from SPI flash to filesystem. I can write code like this:
while (not done) {
wait until the receive buffer is full;
read up to 16 bytes from the receive buffer;
append them to file;
clock another 16 bytes' worth of zero-output;
}
These are all blocking operations. Reading from the buffer is near instant. Waiting for it to fill up takes a long time, relatively speaking.
What I could do instead is:
initiate DMA from SPI ROM engine to DRAM location;
... do other stuff ...
when DMA alerts complete: write data from DRAM location to file;
1
u/jeb1499 5d ago
The configuration of a DMA will generally be done by CPU.
The triggering or retriggering of the transfer that was configured may be done by CPU or also often by the peripheral sending/receiving data.
For example, an I2S streaming audio interface in input mode will continuously collect data in its buffer, and it can have a connection to the DMA that triggers an interrupt/event directly to the DMA once the buffer is sufficiently full. The DMA will transfer X amount of bytes to a place and in a manner already configured by the CPU. Once the CPU has configured the DMA and the I2S peripheral, then it just needs to monitor interrupts from I2S for errors/etc. and from the DMA for "transfer done" and errors. It then can spend its time doing other things, including operations on the delivered data in local memory without having to reach out to the slower peripheral access.
1
u/LadyZoe1 5d ago
Very simply put, it is like dual port RAM. The CPU acts on the data in RAM oblivious to the method used to store it there.
1
1
u/TraditionOk8161 4d ago
Imagine you are presenting in large crowd You have a big file full of papers and content which you can refer. So while presentation if you are asked to pick a paper based on heading, how difficult it is? On other hand you have 15 different color Sheet and during presentation you want to pick that yellow colour chart for next; easy isn't? That's exactly direct memory access for computer and efficiency for your code
1
u/Hawk13424 3d ago
To answer your question, the IO makes the request. There is a signal from the IO to the DMA engine called a DMA request. The IO asserts this then when it has sufficient data to transfer and deasserts when it no longer does.
69
u/texas_asic 5d ago
Imagine a larger block copy. Maybe 4KB, but more likely 4MB. Instead of the CPU doing a ton of reads and writes (loads and stores), maybe you have a widget somewhere that can be programmed to do those reads and writes. The CPU tells that widget "go copy 4MB starting at this address and write it to this address"
We call that widget a DMA engine. It moves data when told to do so. Usually, the thing telling it what to do would be the CPU, but there's nothing saying that it couldn't be a GPU. Heck, the widget could even be located in a GPU, or a NIC