Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Generating Sine Wave Through External DAC (STM32)

Status
Not open for further replies.

uranyumx

Full Member level 1
Joined
Mar 5, 2011
Messages
96
Helped
1
Reputation
2
Reaction score
0
Trophy points
1,286
Activity points
2,053
Hello guys,

Now I try to generate a sine wave with STM32F7 microprocessor with using external 8 bit DAC (DAC082S085). The microprocessor and DAC is communicated each other with SPI transmit only master mode. Now, there is a generated sine wave which looks like an interrupted shape. Do you have any idea to solve this problem?

Thank you,

Here is my code:

Code:
uint8_t DAC_A_Write = 0x1; // DAC's A output is selected 0 0 0 1
uint16_t DACA_Buf; // Output A of the DAC
short a;

double I;
uint16_t s[512];
uint16_t m=0;

for (I = 0 ; I < 512 ; I++)
		{
				
			s[m] = 127+round((sin( I * 6.28/360))/0.02); // 0.02 is the step size
			if (m <= 512) m++;
			HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
			DACA_Buf = DAC_A_Write<<12 | s[m]<<4;
			HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACA_Buf,2,100);
			HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
		}

sine wave with sine function 0.png
 

The equation is the problem.
sin( I * 6.28/360)

Try plotting it in excel or something.

sine has a full cycle from 0 to 2pi. You are indexing from 0-511 and end up going from 0 to 511/360*2pi which is past a full cycle, that is you restart your cycle every 360 counts, i.e. cycle restarts early by 152 counts (512-360).

You need to either change the indexing form 0 to 359 or change the equation to sin( I * 6.28/512).
 

s[m] = 127+round( ( sin( I * 6.28/360) ) /0.02 )
1 2 3 3 2 1

by counting parenthesis, you can see that the division by 0.02 is outside the parenthesis surrounding sin and amounts to a multiply by 50

you have a for loop - I from 0 to 512 so sin runs 512/360 or 1.42 cycles and restarts - which is what you are seeing

m is initialized before the for loop and increments inside the for loop but never re-initialized. I do not understand what you are doing with m

recommend you run I from 0 to 359 for 1 cycle of sin in 1 degree steps
or 0 to 719 in 1/2 degree steps
 

Thank you guys for your quick responds!

Now I realized my mistake and fix it.

Code:
for (I = 0 ; I < 359 ; I++)
		{
			s[m] = 127+round((sin( I * 6.28/360))/0.02); // 0.02 is the step size
			m++;
			m=0;
			HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
			DACA_Buf = DAC_A_Write<<12 | s[m]<<4;
			HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACA_Buf,2,100);
			HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
		}

m is initialized before the for loop and increments inside the for loop but never re-initialized. I do not understand what you are doing with m

I tried the fixed this issue too. With m variable, I plan to make indexing of the s array.

I get a result but there is a short delay before starting the sine function. Why is this reason and fix it?

sine wave with sine function _2 0.png
 

Either what every you do outside the for loop takes too much time or starting up a new for loop takes a lot of time.

I'm not a SW engineer so I don't know how long it takes SW to set up a new for loop. In HDLs the for loop is unrolled by the synthesis tools and it just replicates the logic. We have to use counters and FSMs to precisely time such loops and don't see these kinds of issues.

Not sure why you both have an s array and compute the sine values on-the-fly. If you compute them in the loop why bother storing them in an array? I can understand computing them beforehand to create an array, which you can then index later in a loop to speed up the DAC output loop.
 

You are asking about the timing of code that is not shown in your post. How can we know?
 

Code:
			m++;
			m=0;
This part of your code makes no sense - it means that you are always using 's[0]' to hold the value. Therefore why create an array when all you need is a single variable.
I suspect that you are getting a few things mixed up here.
For a start, setting up a 'for' loop is trivial as far as the generated code is concerned. If there is a short delay before staring the sine wave generation it is more likely to come from some part of you r code that you are not showing us.
Calculating a 'sine' value is expensive for any microcontroller (even if it does have an FPU) as it involves a lot of calculation for each value - and you are calculating 360 for each time you use this code. If you are worried about speed then there are a couple of things you could do.
Firstly pre-calculate all of the sine values into an array and then just read from the array when they are needed. That way you do the expensive bit once at the start. If you want to you can skip the calculation part and just use constants - especially if you use the next 'idea'.
Even better is to realise that you only need to calculate from 0 to 89 degrees - from 90-179 you walk back through the array of values; for 180 to 269 you walk forward through the array again but negate the values; and for 270 to 259 you both walk backwards and negate.
Susan
 

you might calculate the values you want to send to the DAC external to the processor
and program in 360 data points

or as Susan has described, 90 points and be clever

or, since powers of 2 are natural to a computer, you could use 256 data points, equally spaced
or 512 data points, also equally spaced

30 years ago, I used an 8 bit counter and 256 data points in a memory to produce
a 60 hz signal

you can do the same in your processor
frequency depends on clock rate
 

Thank you for your responds!

Actually, the problem is solved with two ways. The first one is that with disable the rest of the code in while loop except DAC command. But it is not an optimal solution. Because I have to call other codes in the rest of the while loop.

The other solution is that I set a timer with interrupt mode. With each interrupt, the sine function 'I' variable is updated. With this way, I control the the sine wave frequency with adjusting the timer prescaler and counterperiod parameters.

Generating sine wave with an array may be better option. Thanks for this advice but I plan to make an amplitude modulation as a next step. So with 'sine' function, my job would be easier. Otherwise, I have to calculate the array parameters for each modulation percentage case.

Thanks for your time!
 

Hi,

--> "interrupt" method is the recommended method.

****
Waveform/Amplitude modulation.
* "Waveform" is one thing (lookup table is a good solution for a small microcontroller)
* "Amplitude modulation" is another thing. Indeed it´s just a "multiply" function. Most microcontrollers can do this easily.

My recommendation: Lookup_table --> multiply --> output.


Klaus
 

Thank you, I will keep in mind that too!
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top