Goal: to acquire a high-throughput ADC-generated data flow (1 Msample/s @ 16bits) into a System-on-Chip processor. Purpose: real-time data visualization and some (minor) processing in real-time

What are the pros and cons of the various architectures to achieve the goal.

Architecture 1

A Dual Port RAM, taking data from an FPGA which glues the SPI output of the ADCs and the port 1 of the RAM. The SoC IC is connected to this RAM on port 2 using an external memory bus and sees the sampled data in its own memory space. The processor is 100% free from managing the ADC. The sample data is visible in a double buffering scheme from Soc end with interrupts informing the SoC when the buffers are full.

Architecture 2

As in Architecture 1, making the dual port RAM visible on a PCIe bus as an endpoint device (as opposed to using the External Memory Bus which we have seen in several SoCs).

Architecture 3

Use an Soc with embedded SPI controllers and DMA. Program the DMA to be triggered by the End-of-Conversion signal of the ADCs and to move data from the SPI FIFO to memory.

Architecture 4

Use a dual or quad-core processor and devote one core to control the SPI interface with the ADC and poll a GPIO port to detect end-of-conversion.In fact, this solutions implements by software DMA-like functionality.

Architecture 5 Your solution?

  • 1
    \$\begingroup\$ Have you looked at an SPI to USB converter? you might be able to bypass the SoC complete and send your ADC data directly to your computer. SPI is good to at least 5MB/s (40Mbps) and USB supposedly can do 60MB/s but in reality it's closer to 30MB/s (240Mbps or ~15 Msamples/sec) \$\endgroup\$
    – Sam
    Nov 25, 2016 at 22:06
  • 1
    \$\begingroup\$ Thanks for this suggestion. I was not aware of an SPI to USB converter. Will look it up. In the past I have implemented a similar data acquisition system using a Microchip PIC with a USB 2.0 connection to the PC. Developing a custom USB driver on Windows was kind of painful and thought I could avoid it this time. \$\endgroup\$
    – user110091
    Nov 27, 2016 at 13:38

2 Answers 2


First of all, 1 MS/s at 16 bit is just 2MB/s – that's really not too much for USB2 to carry. There's no need for dual port RAM, if we're talking about devices that would lend themselves to visualization or has PCIe like your Arch2 suggests, in my opinion.

The fact that you're doing visualization implies you don't care about latency – what's half a millisecond to the human eye? So, you're pretty free with respect to choice of sample transport.


Arch 1

Lots of components, including an FPGA that does nothing but write a lowly 1 million samples per second to a RAM interface. I'd say, if you go that way, use a feasibly fast bus, and that would include simple SPI or QSPI, and a bit of RAM with the FPGA to implement a ring buffer. No need for dual-port RAM – you'd need to communicate information like "ok, there's new samples available for you" or "no, nothing to fetch right now", anyways.

Arch 2

PCIe sounds like a huge overhead here. Again, the rate we're talking about is 2MB/s.

Arch 3

If your ADC, and your SoC allow you to do that, start with that! Certainly sounds like the easiest, lowest-component-count solution. Often, this doesn't work for electrical reasons. SPI is absolutely a normal interface for an embedded system to have, so I'd assume that it'd be rather easy to find a controller that has it.

Problem remains that you'd still need someone to e.g. generate your sample clock etc.

Arch 4

well, yeah, as you say, a less great version of 3.

Arch 5

1MS/s isn't really high-throughput. In fact, I remember writing firmware for a now defunct ARM cortex-M0 project that ran the internal ADC at 500kS/s and pushed the data through USB2 to a PC. With a slightly more capable MCU, you should be able to do the same. That way, you'd have cheap-as-hell device dedicated to handling ADC data and stuffing it in USB packets, and you'd just have to write a couple lines of Python or C to run on your embedded device to ask the microcontroller for USB bulk packets full of data. Bonus: you can clock down your main CPU whenever you want to, and it will have no effect on the sampling.

Arch 6

Kinda easy. You can all do minimal visualization, sampling at several megasamples per second (complex) and a bit of analysis on ARM cortex-M4, with the help of a bit of glue-FPGA (without own RAM, iirc). This is proven by the open design of the HackRF one. I think it might be worth for you to look into this. From my perspective, it sounds like you'd basically just want to throw out all the RF stuff in that, and use it as is. You'd even get drivers and firmware for free!

HackRF digital block diagram
HackRF hardware components diagrams from the project wiki

Above diagram is simplified, as mentioned, there's a small "glue" FPGA between the ADC/DAC hybrid and the LPC Cortex-M4, as the schematic will tell you.

  • \$\begingroup\$ Thanks for fixing my fix - apparently my script never encountered this kind of markup before ... \$\endgroup\$
    – Glorfindel
    Mar 11, 2023 at 11:36
  • 1
    \$\begingroup\$ @Glorfindel thanks for improving my post! \$\endgroup\$ Mar 11, 2023 at 12:08

I'd suggest a 5th architecture, using a 16-bit-wide buffer between ADC and any logic boxes. To achieve 16 meaningful bits (I presume you do want the LSB to be meaningful), you need to keep the logic-box transient noise out of the ADC.

Any logic-box will have 0.5vpp ringing {OK, maybe 0.2vpp ringing, if VDD is 1.8v} with 0.5nS edges, on its internal GND and RAIL. This internal trash couples thru ESD diodes and FET gates to the ADC outputs; the transferred charge demands a path back home, which will include the ADC's analog input and the ADC's Reference and ADC GND.

Assume 1volt/nanosecond logic-box trash and 3pF ESD etc coupling. This injects 3 milliAmps into each ADC output; 16 output pins (parallel output) is 48 milliAmps, with Trise (it is differentiated by the capacitance) of 0.25nS.

Assume the only path out of the ADC is 1nH path (call it GND). What is the voltage across that inductor (this is our GND upset). $$V = L*dI/dt$$ $$V = 1nH * 0.048amps/0.25nS$$ $$V = 0.192 volts$$

Thus I suggest architecture #5, to include a buffer between ADC and the logic.


simulate this circuit – Schematic created using CircuitLab


Notice the GND upset we created inside the ADC, at 0.192 volts, is not much smaller than the bouncing inside the MCU/logic-box at 0.5volts. We need to SLOW DOWN the risetime of the currents flowing into our ADC, and into our 16-wide buffer. Insert 16 resistors, value 1Kohm. The resistor does not slow the edges, but does limit the current to 0.5v/1Kohm = 0.5mA. Now add 10pF on each of the 16 lines, right at the ADC (or at the MCU side of the buffer); this splits up the current by 3pf/(3+10) = ~1/4; more importantly, the edge is slowed by 4:1.

With the double differentiation, this edge-slowing has a 4^2 = 16:1 improvement in injected current. But you've added 32 components. But you've reduced the ringing (inside ADC, or inside the buffer between ADC and MCU) by 3ma/0.5ma * 16 or one-hundred to one. 40 dB. Draw some schematics, sketch the current flows, look at slewrates of edges and how those edges charge/discharge the ESD diodes inside all ICs, with the ESD diodes currents exploring All possible paths back to the MCU. ALL possible paths, proportional to conductance.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.