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

I think, you 've missed the point. Clock tree starts from st-link-v3 than arrives to HSE (bypass mode) on nucleo H7. So to do it right, reprogram st-link to output 8.33 MHz, than reconfigure HSE /PLL to new source, so PLL 'd stay in allowed range <960 MHz or so. See picture, and link

My scope does show jittery clock for new board before I make updates. Rigol 200 MHz, timers or MCO has to be set above 40-50 MHz (GPIO very fast speed). Scope also has SA mode, likely all modern DSO have. Try.

H753 upgrade.png

Why to generate "pa" "di" in real-time? H7 has a lot of memory, synthesize LUT and pass array to DMA. Below is my code to generate sine wave with harmonics for test purposes.

    for( uint32_t i = 0; i < BUF_SIZE; i++) {  
      double accm = 0.0;
      for( uint32_t j = 1; j < 8; j++) {      
      //for( uint32_t j = 1; j < 4; j++) {      
        freq =       j * dac_freq1;
        magn = magnt_set[dac_n][j];
        faza = phase_set[dac_n][j];
        //wave = sinf(( i * freq *(2 *3.1415926535 /BUF_SIZE)) + (ANGL_RAD * faza));
        wave = sin(( i * freq *(2 *3.1415926535 /BUF_SIZE)) + (ANGL_RAD * faza));
        wave *= magn;
        accm +=  wave;
        }
      accm *= 2047.0f;
      //accm += 2048.0f;
      buf_dacs[dac_n][i] = roundf( accm );
      }

Code runs on nucleo-G474re, 

Thank you for responding again, I will try to use STlink clock tomorrow and update,

I need sub mHz frequency control at the DAC output so the phase word will constantly be changing in real application. If the STlink clock won't effect CPU clocking it will make no difference, I have went through timing stuff with G4 as well and managed to get a working device including sampling, data processing and control loops. I am sure there is no timing issue with DMA or SPI or timers.

 

I 'd not be so sure. SPI in all uCPU has it's own pre-selector and runs on divided master clock. So streaming data by a timer trigger that is not "align" to SPI is always produces two frequency beating. To avoid this you need to clock DMA transfer in sync with SPI's pre-selector. It's possible, just complicated.

Another way is simply set SPI to run as a master/ DMA mode, so SPI fetches data by itself, H7 & G4 both have upgraded SPI hardware that capable to generate CS line updates. H7 even has programmable delay time, so fine tunning of the SPI data words speed possible. F4-F7 for example does not have this feature, CS drops to low state as as soon as master SPI enable.

mHz hard to get by timers, still you can pre-set array that is updated on regular bases sineLUT -> mHz.sineLUT in "for" loop, than re-fill DMA in HC and TC interrupts

For debugging, again I'd set array to "latch" "pa" "di" - 20-100 kBytes in a single snap for analysis later on , getting data over serial to external debugging toll or IDE environment.

AA6
Associate II

Update: I had another nucleo board (H7S3L8) lying around so I tried it today.

I'm only using the boot project with internal flash memory (LUT is smaller because H7S3 has only 64kB flash) and I managed to get it working (clean spectrum) using the same interrupt routines, DMA and SPI writes.

Now I will start again with H723ZG (new .ioc and project) and if it doesn't work I'll order another one and see where the problem lies but I think starting clean should do the trick. I'll update the thread when I find the source of the problem in 1-2 weeks.