minimizing the ADC to DAC delay - Page 1
Forum section: electronics / projects

author: metebalci
author_rank: Frequent Contributor
timestamp: January 29, 2024, 03:29:18 pm
content: I am trying to do something which digitizes a signal or two with independent ADCs and calculates something with them and outputs the result with the DAC. At the moment I am using STM32G474, with system clock ~ 150 MHz, ADC clock ~ 50 MHz, it has multiple ADCs and I am running ADC1 and ADC2 in dual mode, which as far as I understand simultaneously converts two signals. This all works fine but I wonder if/how I can minimize the total delay of this process (my aim is ~2us, lets say to reach 1% of the output). What I did at the moment can be completed under 8us or so, with a simple process in between (such as taking the sqrt of one signal). The process time is I think negligible, and it comes to how ADC/DAC conversion speed can be improved.The datasheet of the MCU ishttps://www.st.com/resource/en/datasheet/stm32g474cb.pdfIt says ADC total conversion time (including sampling time) is minimum 0.25 us and DAC settling time to +/- 1 LSB is maximum 2.9 us (typical 1.6us). So I guess it means the best would be around ~2us and the worst would be 3.2us + maybe additional sampling time for the ADC. As far as I see this is not bad for a this class MCU.What should I pay attention to ? Is my objective (2us) realistic with such an MCU ?(At the moment, I am doing the processing and DAC output in the ADC interrupt handler, I will try polling as well I dont know the interrupt latency.)

author: Kleinstein
author_rank: Super Contributor
timestamp: January 29, 2024, 07:17:35 pm
content: Calculating the square root can be rather slow. I don't know the details on the CPU, but the square root is one of the more tricky and slower operations, way worse than a devision. So the processing part may still be relevant even at 150 MHz. There are different ways to calculate the square root and with the likely limited resolution that is needed one may get faster than the normal compiler code.As the DAC seems to be a bit slow, one could use an external DAC with parallel interface - these can be quite fast, though it also depends on the type.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 29, 2024, 07:38:11 pm
content: Quote from: Kleinstein on January 29, 2024, 07:17:35 pmThis one I am using is Cortex-M4 with FPU, so sqrtf is 14 cycles I believe, and I guess it means it takes less time than one ADC conversion.I havent used a DAC like this before, and actually I was surprised to see settling time is in single digit us range and I think it is like this for many if not all similar MCUs. I think an external DAC and/or an external buffer improves this but I did not understand if it is reasonable (cost, complexity etc).

author: macaba
author_rank: Regular Contributor
timestamp: January 29, 2024, 08:05:11 pm
content: This topic is something I’ve been looking at a lot lately. Cortex M4 is a good start - you can do fixed point integer operations in an efficient way. 14 cycles to do a sqrt is good.Perhaps disable interrupts and implement a polling loop. This does mean things like systick won’t update, and any parameter updates coming over a UART (or similar) would need to fit into a FIFO (if applicable) or use DMA, ready to be checked at a convenient time in your control loop. Binary parameters only in the control messages, no string parsing.You may be able to speed up the DAC using the circuit in this application note:https://www.st.com/resource/en/application_note/an4566-extending-the-dac-performance-of-stm32-microcontrollers-stmicroelectronics.pdf

author: Nominal Animal
author_rank: Super Contributor
timestamp: January 29, 2024, 08:05:49 pm
content: 12-bit ADC provides a value between 0 and 4096. Its square root is between 0 and 64. If you have 4096 bytes of RAM to spare, you can just fill it with the square root of the index, and even have two fractional bits for added precision (so instead of 0..63 you store 0..255, and divide the final result by four). Then, there is no computation, just a memory lookup.If you do 12-bit ADC and 9-16-bit DAC, then you need two bytes per entry, or a 8192 bytes for the table. To get the same precision as is possible for sqrtf(), you need four bytes (one float) per entry, or 16384 bytes.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 29, 2024, 08:17:14 pm
content: Quote from: macaba on January 29, 2024, 08:05:11 pmThanks for the suggestions. I will try the polling loop the first. I think I can live without systick and uart, I will probably have one parameter but it will be a physical input anyway, something like a dipswitch.I actually saw this appnote, but calibration requirement made me worried a bit, but probably I should try it if I cant get close to my target.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 29, 2024, 08:30:19 pm
content: Quote from: Nominal Animal on January 29, 2024, 08:05:49 pmYou are quite right but I said sqrt just as an example. Actually it can be any function with one or two (theoretically even more) arguments. So I try to not use precalculation.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 30, 2024, 05:02:11 pm
content: Here is an update. First, my probing before was bad, the numbers I mentioned in my first post was actually better. I fixed the issue now.I have disabled all interrupts before the loop, and also not checking any flags of ADC and DAC. The loop basically reads the common ADC data register containing values of ADC1 and ADC2 conversion results, maps them to float [-1,1], calls floating point sqrt function, remaps the return value back to [0, 4095] and writes this back to DAC.Also compiling the code with -O2 optimization.In the image attached, X (cyan) is the input going to ADC, Z (purple) is the DAC output, TR (yellow) is a digital output signal where high pulse indicates the whole process (from reading from adc to writing to dac). The quick summary is, the whole loop is ~0.6us. I am not checking the flags of ADC since I dont care if it is the new or old value, but because the process is ~0.6us and ADC conversion time is I think around ~0.25us, it should be fine (ADC is running continuously) but if not, it just misses a sample. DAC is more problematic since it takes > 0.6us, in this case, some of the output data is discarded I believe. I see the 90% rise time (half of full scale) ~0.75us, which is I think compatible with the numbers in datasheet (full scale maximum value is ~2.5us).So my 2us target is probably difficult but not far from what can be done. If by using an external buffer, DAC settling time can also be reduced to 0.25us, that would be very good.

author: macaba
author_rank: Regular Contributor
timestamp: January 30, 2024, 05:51:56 pm
content: It's good to see this go beyond theory - that's an encouraging initial measurement.The DAC settling time seems like the biggest contributor to delay so far, whether this is actually a problem depends on your end application.

author: uer166
author_rank: Super Contributor
timestamp: January 30, 2024, 05:56:03 pm
content: Can you try buffering the DAC with one of the internal opamps? I wonder if DAC buffer/drive strength is contributing to the settling time. Opamp might make it worse or better, would be cool to try either way.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 30, 2024, 06:58:55 pm
content: Quote from: uer166 on January 30, 2024, 05:56:03 pmInteresting idea. The appnote mentioned before talks about the opamp selection for an external buffer and looking at the datasheet internal opamp seems like it may work for 5Msps or so. I havent used the internal opamp before, I will check.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 31, 2024, 12:12:34 pm
content: Another update. I tried both the internal OPAMP and an external OPAMP as DAC output buffer with internal DAC buffer disabled. The internal OPAMP I tried both as a voltage follower and as a non-inverting amp with filtering.The result with the internal OPAMP as a voltage follower was slightly worse than DAC's buffer, the limitations of this also mentioned in the app note.I thought the internal OPAMP in non-inverting (pga mode) with filtering (that is I think the only way to eliminate the the internal input resistor) mode should work, but I could not make it work properly, there was a large overshoot/oscillation and I could not eliminate it. The output resistance of DAC is I think slightly over 10K and the internal OPAMP feedback resistor is 10K when G=-1, maybe this is the problem or something else or maybe it is just me I couldnt make it.For the external OPAMP, I do not have LMH6645 which is used in the app note, but I have LMH6609, so I used that as described in the app note but without the capacitor in the feedback loop and with 15K feedback resistor. The capture below is from this trial. The yellowish Z is the output from LMH6609, cyan is input to ADC, the gray (TR) ones are the digital signal for processing loop. I keep the same processing loop as before but for the sake of simplicity now (because I need to calibrate the gain, offset etc. to make this correct for sqrt), the output is made equal to input, so it is following it (however the buffer is inverting, so the output is (3.3V - input)). So the rise or fall time is approx. 10x better than before (couldnt make measurements work properly yet), they are in the ~100ns range. I have the LMH6609 on the breadboard, maybe the oscillations are because of that. Also, the app note uses a 5pF capacitor in the feedback loop, I do not have a 5pF at hand but I tried 10pF and oscillations was still there.

author: macaba
author_rank: Regular Contributor
timestamp: January 31, 2024, 02:02:13 pm
content: That is a very nice result.Op-amp in a TIA topology usually needs that feedback capacitor for stability. To make it worse, you're using an extremely fast opamp. I would not be suprised if 22pF or 47pF is needed if you're on breadboard.

author: metebalci
author_rank: Frequent Contributor
timestamp: January 31, 2024, 07:56:34 pm
content: Quote from: macaba on January 31, 2024, 02:02:13 pmAnything over >10pF decreases slew rate a lot. I am not sure at this point if it makes sense to use breadboard, maybe I should prepare a dead bug, but another issue is LMH6609 spec says: "The LMH6609 operates best with a feedback resistor of approximately 250Ω for all gains of +2 and greater and for −1 and less. With lower gains in particular, large value feedback resistors will exaggerate the effects of parasitic capacitances and may lead to ringing on the pulse response and frequency response peaking.". However, in this circuit, feedback resistor is matched to the DAC output resistance which is ~12K. Probably I should try a different OPAMP, LMH6645 as in the app note or something similar.

author: jbb
author_rank: Super Contributor
timestamp: January 31, 2024, 11:24:31 pm
content: On the algorithmic front: can you pre-calculate anything? For example, an FIR filter spends most of its time dealing with old samples of the input signal; that can be done as ‘preparation work’ between updating the DAC output and receiving the new ADC conversion.A total aside: the Texas Instruments TMS320 range has come parts which include a Control Law Accelerator (CLA) for low-latency work. I’ve never used it, but my understanding is that the CLA is a small sub-processor with fast access to ADC, DAC and PWM.

author: metebalci
author_rank: Frequent Contributor
timestamp: February 01, 2024, 04:05:37 am
content: Quote from: jbb on January 31, 2024, 11:24:31 pmI can pre-calculate any single argument function but there will be some with two, maybe also three. Also, I would like to keep this part as simple as possible to add new functions, that is also why I plan to use floating point and implement functions to work from [-1,1] to [-1,1]. I am trying to replicate an analog function IC (like AD633 multiplier) but not only for basic functions like multiplication but can be anything (probably still simple but arbitrary).

author: metebalci
author_rank: Frequent Contributor
timestamp: February 01, 2024, 04:51:15 pm
content: Another update after I did multiple changes.- moved to a better scope and rechecked the probes- made a much better prototype board, still the same OPAMP but now mounted on an smd adapter with smd resistors etc. and it is on a ground plane, so no breadboard. only the feedback resistor (15K) is a THT part. Still no capacitor on the feedback.- after making these changes, there was still an oscillation and after trying multiple things I realized it is because of the extra header I had on the original header mounted to PCB, so I removed that (I am using the NUCLEO G474RE board btw).- I think it did not matter much in this case but I connected the Vref rather than Vdd to the resistor divider providing the Vref/2 to opamp vin+.- I was using a single battery supply for the opamp, I removed that and using the Vdd from the board- I also enabled the MCU instruction and data caches, I think this contributes the processing time since I am still using the same code. It decreased from ~500ns to ~300ns.The result is below. Yellow is showing the processing, so 273ns (2x ADC read, set DAC to first ADC input). Blue is the first ADC input coming from the signal generator. Green is the DAC output. This is one of the best captures, showing the best rise and fall measurements, different type of ringing or overshoot happens and then rise/fall figures are worse but still much better than the DAC internal buffer naturally. I guess now I should try different feedback capacitors and also change the feedback resistor to an SMD part but I will need parts for that so it will take time.

author: uer166
author_rank: Super Contributor
timestamp: February 01, 2024, 10:34:24 pm
content: It's interesting that you see the green trace oscillate as soon as the blue one shifts. That is not caused due to DAC output change, since it happens well before that. That would imply some instability in the power delivery/de-coupling to the opamp, or perhaps some kind of noise crosstalk to the opamp inputs.I suggest adding some bulk capacitance with higher ESR to the opamp supply, and properly de-coupling it with MLCCs of the smallest reasonable case size and same nominal value.

author: metebalci
author_rank: Frequent Contributor
timestamp: February 02, 2024, 08:09:15 am
content: Quote from: uer166 on February 01, 2024, 10:34:24 pmI have power supply decoupling (0.1u and 4.7u smd ceramic near the IC). I tried a low esr tantalum externally but didnt change anything.I also changed the supply back to a 9V battery, and then the signal is like in the first image below. When the supply is 3.3V, it saturates and ringing/oscillations near 3.3V cannot be seen.Then I soldered 2x 10pF in series in the feedback path, so 5pF as in the appnote and the result is shown in the second image below. The issue you mentioned is still there but much smaller, I also wonder about this now. I have not done a very good job soldering on the smd board so it makes sense if it is due to crosstalk.Edit: In the second image, there is also an overshoot from the signal generator (ADC input, blue trace), maybe the issue is due to that ? so not an issue related to OPAMP circuit actually. I should generate something internally and just use the DAC output like this to see if it is clean.Edit2: I realized the issue mentioned is exaggerated due to probing also, I changed the probe tip to dip adapter and it is less visible, but still it is visible.