Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

memcpy command alternating data while copying

I am using a STM32 G474 to create a wavefrom with it's internal DAC. I give a lookup table to the direct memory access (DMA) module and that gives the values at the right time to the corresponding DAC channel. What sounds like the hard part is actually pretty straight forward and works just fine.

#define NS  64                             # number of samples

uint32_t Wave_Low[NS] = {2048,[...],2047};  # lookup table

int main(void)
{
HAL_DAC_Start_DMA( &hdac2,   DAC_CHANNEL_1, (uint32_t*)Wave_High, NS, DAC_ALIGN_12B_R);
*/ start DMA       use DAC2  channel 1  */
}

As the next step I want to change the signal form within the code. As I want this to happen without interruption, stopping the DMA and reinitializing it doesn't work (there is a 500 µs delay without a signal in between). Therefore I need to overwrite the lookup table. I've tried it like this:

#define NS  64                             # number of samples

uint32_t Wave_Low[NS] = {2048,[...],2047};  # lookup table 1
uint32_t Wave_High[NS] = {4096,[...],4067}; # lookup table 2
uint32_t Wave_Active[NS];                  #used lookup table

int main(void)
{  
memcpy(Wave_Active , Wave_High, NS );      #assign high wave as the currently used one

HAL_DAC_Start_DMA( &hdac2,   DAC_CHANNEL_1, (uint32_t*)Wave_Active, NS, DAC_ALIGN_12B_R);
*/ start DMA       use DAC2  channel 1  */
}

From my understanding this code should show the exact same behavior but the DAC signal differs significantly by showing the positive part of a sawtooth signal instead of the centered sine wave it's supposed to show. I'm a bit rusty with embedded C but that behavior definitely irritates me.

like image 751
phil_o_matic Avatar asked Jul 10 '26 11:07

phil_o_matic


1 Answers

Several problems:

  • DMA buffers need to be volatile qualified or otherwise the compiler might go bananas when generating the code accessing them.

  • You use memcpy incorrectly, should have been memcpy(Wave_Active , Wave_High, sizeof Wave_Active);

  • The use of memcpy to begin with is often incorrect when it comes to hardware-related programming. Copying 256 bytes takes a lot of time. Worst case, your DAC might even request new data before you are done copying.

    The correct way to write such code would be to have several allocated buffers, then swap an "active" pointer to point at the one used. With the disclaimer that I don't understand the purpose of these arrays, something like this would be an immense speed optimization:

      volatile uint32_t Wave_Low[NS] = {2048,[...],2047};  # lookup table 1
      volatile uint32_t Wave_High[NS] = {4096,[...],4067}; # lookup table 2
      volatile uint32_t* Wave_Active = Wave_High;
    
      ...
      if(DMA_flag)
      {
        Wave_Active = (Wave_Active==Wave_Low) ? Wave_High : Wave_Low;
    
        /* you might have to tell the DMA which array to use next time here */
      }
    
like image 59
Lundin Avatar answered Jul 13 '26 12:07

Lundin