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.
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 */
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With