cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 vs STM32G4 DDS generation through external DAC AD5640 14-bit DAC w/ SPI

AA6
Associate II

Hello,

I have implemented a DDS sine wave generator where I use a timer interrupt to update DDS phase word and also use the same timer triggering a SPI transmission via DMA to an external DAC using a nucleo-g431rb. I am now doing the same thing with a nucleoh723zg on a different pcb, but cannot achieve the same performance. I've only uploaded 1 spectrum image of the H7 output but the problem is the image I uploaded is not the constant spectrum, it's center frequency changes -20 to 20 Hz every sweep.

I am using ~16MHz SPI speed and I have checked hardware of both pcbs, there is no problem with the communication and DAC CS jitter is very low (or none) for both MCUs.

I also checked the phase word variables on the run via uart in H7 and saw that there are reoccurring (not periodic though) jumps in phase word. But I use uart so cannot be exactly sure about that.

I'm sure there are no missing interrupts which I'm controlling by flipping a GPIO pin.

I can use a direct write to SPI data register or use a buffer and update it and give that buffer to the DMA triggered by the same timer, both approaches worked in G4 board and both are giving the same results in H7.

My code and DDS output spectrums and scope images are below. I am using LL functions everywhere except for some initialization stuff that are turned off shortly after.

For reference

I've tried lowering SPI clock and lowering system clock

I've had problems with DMA when I used Dcache then I closed it, now using DMA and directly writing to SPI DR gives the same results. 

Another thing that might be useful:

Last time I uploaded code to G4 was ~3 weeks ago, from the images I can see that there is no problem with the uploaded code or LUT in the ROM. However when I disconnect and reconnect H7, before uploading code again the signal in the scope is distorted, probably meaning some ROM corruption occurs when disconnecting or just powering up)

I'm thinking there is a problem with accessing phase accumulator variable (pa) in RAM but I turned off caching and also made all relevant variables volatile. Also I'm not using any optimization, and other things I'm supposed to do (sampling an external ADC via SPI etc.) are turned off, interrupt timings are not missed for sure.

 

//bi++; //buffer index (uint8_t)
pa += pp; //pa: phase accumulator, pp: phase word
di = (pa >> 17) & bm; // LUT size is 2^15 so 17 bit shift
//txBuffer[bi] = ((uint16_t) (amp*LUT[di])); //buffer used in G4 DMA
SPI5->TXDR = (uint16_t) (amp*LUT[di]);
/*                             //uart phase accumulator variable test, 
if (dac_i == dac_test_size_i){ //pa is stored in a seperate bufferand then sent in
    uart_start = 1;            //another place to not interfere with interrupt  
}
else{
    dac_test_arr[dac_i] = pa;
    dac_i++;
}
//*/
LL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); //interrupt control GPIO

 G4 spectrumG4 spectrumH7 spectrumH7 spectrumH7 scope before uploading new codeH7 scope before uploading new codeG4 scopeG4 scopeH7 scopeH7 scopePhase Accumulator values at every updatePhase Accumulator values at every update

13 REPLIES 13
AScha.3
Super User

Hi,

whats the update rate of DDS ?

and which DAC ?

+

you should run on an H7 always with optimizer, i use -O2  always.

+ with d-cache off , helping .

 

BUT i would do it different on an H7 : to reduce time with INT

- make circular DMA , 2 x 1 K ; clocked by a timer ; DMA sending to SPI -> dac output ;

- in callbacks write the calculated phase values (1000 values)

So about 99% less busy with interrupt handling.

If you feel a post has answered your question, please click "Accept as Solution".

Hi,

I'm using AD5640 14-bit DAC, 

DDS update rate is around 300kHz for G4, I tried from 500kHz to very low frequencies for H7, none of which work. 

I have to sample 2 external ADCs via SPI very accurately and I use IIR filtering so I don't want to use bursts for data acquisition or DDS. I was able to do everything timed very accurately on G4, I bought an H7  for data processing speed so that I can sample faster.

Using any optimization was somehow messing with my recieve only master SPI channels (idk why) so that's why I'm not using them. 

 

So you dont want my recommendations, how to do....ok.

+

SPI5->TXDR = (uint16_t) (amp*LUT[di]);

you write to SPI dr , as in G4 , but on H7 is different:

AScha3_0-1778523041519.png

I think only by using DMA->SPI you will get a perfect fix timing.

If you feel a post has answered your question, please click "Accept as Solution".

Sorry I explained it rather complicated, I can also use DMA to SPI (TIM1 DMA MemtoPeriph: txBuffer->SPI5). The commented txBuffer line in my code snippet is taken from H7 (in G4 it is exactly the same except for SPI no.) and it works as well. It doesn't matter whether I directly write to SPI->TXDR or use DMA and enter SPI->TXDR as DMA peripheral, output waveform frequency spectrum is the same.

I also tried to select different FIFO thresholds for DMA and SPI from CubeMX, it had made a difference for receive SPIs I use for sampling when I made the threshold 02 but didn't change anything for DAC transmission.

Also, I debugged the actual SPI lines with a logic analyzer by sending the truncated linear phase data (variable "di")  so it was easier to debug and like phase accumulator it had also occasioanl jumps. As I said, these happen when I'm using DMA as well and there is nothing else going on in the MC so there is no reason to miss interrupts. Also I'm checking via GPIO pin that there are no occasional interrupt misses.

I think there is something wrong with accessing the phase accumulator variable "pa" as the values I read through UART seem to have occasional jumps. The graph I uploaded is from a 1000 continuously filled pa values to dac_test_arr  and almost every 1000 sample block have at least one jump like in the one I uploaded.

>before uploading code again the signal in the scope is distorted, probably meaning some ROM corruption

Believe me, the H7 cpu working correct. Just your prog...is under suspicion.

Again : set optimizer -O2 , read ALL warnings and correct the code. (all warnings ON in preferences...!)

With optimizer more problems are shown by the compiler, and if anything no more working, this shows also: here is something wrong in the code, find and correct it.

The optimizer just helping to find bad constructs, so use it.

+

dont this 

...(amp*LUT[di]);
just
....(LUT[di]);

any level/amp/gain has to be before truncating the value.

If you feel a post has answered your question, please click "Accept as Solution".

As I said before I tried sending only the "LUT[di]" as well as only "di" variable without scaling it with amp or passing through LUT, debugged it using logic analyzer and it jumps data points in that case too.

Regarding the scope, what I don't understand is that the waveform is corrupted (fig 3) until I upload the exact same code that produces the normal (fig 5) waveform. I have now seen some posts about memory problems even with Dcache disabled and maybe I should manage MPU regions carefully instead of disabling MPU management from CubeMX

I will try to use -O2 again tomorrow, it only messed with SPI receive channels as far as I remember but may have had effects on transmission too now that I'm looking in detail. Thanks for the replies

MPU not helping here, forget it.

I have MPU unused, on H743 , -O2, all caches ON. + cache management on DMA areas, working fine.

I have circular DMAs running, to receive SPI stream, calc. filters etc. and sending audio streams to 6 DACs , at 32b word size. Runs up to 96kHz fine, just at 192k the dac has a problem...so can set it at 190kHz max.

And i run on 200M core clock, to keep it cool. Even with 3 biquad filters in double float and FLAC decoder running, still about 70% max cpu load.

If you feel a post has answered your question, please click "Accept as Solution".
MasterT
Lead

Nucleo-H7 by default getting clock from St-Link-V3  HSI, that is internal RC oscillator. Don't know about G431, but nucleo-G474re has crystall 24 MHz, and consequently clock is very clean. I'd suggest to re-program your H7 to 8.33 MHz clock from St_Link, switching to crystal instead of RC. There is programmer application and instructions on this ST.com site

Since you have access to SA, it 'd make sense to conduct some measurements before/ after you reconfigure clock base. Set GPIO pin to be driven by  timer-PWM and compare spectral width on G4 and H7.

I use MPU to configure memory to run with DMA on H7, and I also always activate D & I cache.

It also 'd make sense to make DDS using internal DAC, since it' exclude SPI complication. When it runs smoothly - no issues with memory/DMA etc observed, than switch to external DAC.

BTW, internal DAC's is not so bad after all, especially when buffered by external OP_amp, check out:

AN4566 Application note
Extending the DAC performance of STM32 microcontrollers

 

Hello again,

I'm using HSE crystal clock at 8 MHz, tried 8.33 today, didn't change anything. 

I've also tried -O2 optimization, no luck. I added -Wall, -Wextra, -pedantic flags for additional warnings, nothing there as well. But they might give something when I turn on SPI receive channels again.

I used to manage DMA buffer update in a different timer with same period as my DAC updating timer when I first started with G4, then I had noticed I didn't need that. So, I also tried using an additional timer in H7 today but it gave the same result.

I tried using DMA with Dcache&Icache enabled and fixed the transmission with SCB_ClearDcache_by_Addr(), but the result is the same spectrum.

I am sure I have no timing problems in hardware as my SPI CS signal shows no jitter in scope, and I remember I was able to get away with a little jitter when developing with G4, though I fixed it later. Also I think you would agree that the signal from the scope doesn't shout noisy spectrum at first glance, I've only noticed it when I tried to sweep a high Q resonator, spectrum analyzer is not my usual debugging tool.

Would you suggest another way to track variables "pa" or "di" other than uart? As I said any continuously filled test section of that buffer shouldn't have any jumps.