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.

Sine Wave Generation with SPI and TIM interrupt in STM32

Status
Not open for further replies.
Hi,

Do you recognize the tiny horizontal distortion at positve going zero cross?
(Like a class B amplifier)

Klaus
 

You mean like in the attached file? @KlausST
 

Attachments

  • InkedIMG_8736_LI.jpg
    InkedIMG_8736_LI.jpg
    3.3 MB · Views: 164

Hi,

I have one more question. I want to control the maximum amplitude of the signal based on user input. For example, if the user requires 1V output, the sine wave swings between 0-1V. I tried it with multiplying by 100, then I lost the sine wave and got the Post#1 output signal. Do you have a suggestion about it? @KlausST

Code:
DACA_Buf = DAC_A_Write << 12 | 100*Wave_LUT[z];

Edit: I guess it works with like this,

uint16_t Divison_Table[z] = Wave_LUT_100_Per_Modulation[z]/15.4;
DACA_Buf = DAC_A_Write << 12 | Divison_Table[z];
 
Last edited:

If you try to do this by just reducing the value of the DAC word you wind up effectively
lowering the resolution of the sinewave as the sample set decreases in number of unique values.

The DAC has a Vref pin you could modulate with another DAC or digital pot, depends on accuracy
you are trying to achieve. You could use a PWM to create a DAC for that inside the processor,
followed by a filter and buffer to Vref pin. Thats one way.

Note Vref pin has limited range.

Ore use a PWM again and a transconductance OpAmp or voltage controlled gain amp and control
the G of the OpAmp and drive the Vref pin with that. Or place controlled G element in the signal
path. That eliminates the limited range problem of the Vref pin on your main pin.

Or (if you need two independent DAC channels) get a quad or triple DAC and use one DAC to control
the Vref pin on the main DAC voltage controlled G element in the signal path.


Regards Dana.
 
Last edited:

Hi,

Still the riddle if post#20.

Your table value include offset 2048 and sine with amplitude of 2047.
If you do the multiply, divide, shift....then you manipulate not only the sine amplitude, but the offset, too.

You could generate the sinewave without offset .... multiply it and add it to the offset at runtime.
Mind: the sinewave then needs signed table variable.

Klaus
 

Thank you @danadakk for your comments. I noted for a future version of my circuit.

Thank you @KlausST ! It worked with your suggestions. I have one more question. When I placed the callback function in an if statement in the while loop, I got a 'function definition is not allowed here' error. Is the callback function defined in a certain place every time?

Code:
if (MDepth == 33){
                        void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
                        {
                            if (htim == &htim6 )
                                    {
                                        Divison_Table[z] = round((102.4-(102.4*0.33)) + (0.33*(Wave_LUT[z]/(1575/102.4)))); // 15.4 is calculated with 1575 divide by D value. Vout=Vsupply*(D/4095)
                                        HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
                                        DACA_Buf = DAC_A_Write << 12 | Divison_Table[z];
                                        HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACA_Buf,2,100);
                                        HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
                                        
                                        HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
                                        DACB_Buf = DAC_B_Write << 12 | Divison_Table[z];
                                        HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACB_Buf,2,100);
                                        HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
                                        
                                        z++;
                                        if (z>=127)z=0;
                                    
                                }
                            }
                        }
 

Hi,

I' m no C specialist, but the callback is a function called by the interrupt handler.
It's name is a fixed keyword .... and I don't think it's allowed to to put such a root function after an "if" or within a loop.
I'm rather sure it needs to be at the root (I'm not sure if "root" is the correct phrase here)

I even don't understsnd what you want to achieve with this.

Klaus
 

Actually, I just want to operate the DAC based on TIM interrupt frequency. Because of that, I placed the callback function in here. @KlausST
 

Hi,

Makes no sense.

You already have set up the timer to trigger an interrupt with a given frequency.
With every trigger the callback gets called.
Within the callback you send data to the DAC.
--> So this already is what you want. The DAC is updated with timer interrupt frequency

Klaus
 

I am sorry I wrote as wrong. I mean that I want to call the timer triggered DAC in an if loop in the while loop. Placing a flag in the callback function, then calling it in the if statement can be a solution? @KlausST
 

Hi,

The "call" comes from the raw interrupt handler..
And the function itself must neither be in a loop nor in an "if".

Still don't understand your idea.

Klaus
 

Maybe, it is better to explain my plan with the codes. I placed a flag in interrupt.
Code:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
                            if (htim == &htim6 )
                                    {
                                        TIM_Flag=1;
                                    }
}

Then, I check the flag in an if condition in a while loop.

Code:
while(1)
...
else if (MSet == 1){
                if (TIM_Flag ==1){
                    if (MDepth == 33)
                                            {
                                            Divison_Table[z] = round((102.4-(102.4*0.33)) + (0.33*(Wave_LUT[z]/(1575/102.4)))); // 15.4 is calculated with 1575 divide by D value. Vout=Vsupply*(D/4095)
                                            HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
                                            DACA_Buf = DAC_A_Write << 12 | Divison_Table[z];
                                            HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACA_Buf,2,100);
                                            HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
                                            
                                            HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_RESET);
                                            DACB_Buf = DAC_B_Write << 12 | Divison_Table[z];
                                            HAL_SPI_Transmit(&hspi2,(uint8_t*)&DACB_Buf,2,100);
                                            HAL_GPIO_WritePin(DAC_CS_GPIO_Port, DAC_CS_Pin, GPIO_PIN_SET);
                                            
                                            z++;
                                            if (z>=127)z=0;
                                            }

DAC output didn't generate a sine wave. @KlausST
 

Hi,

Now you are doing DAC communication in main.... did this recommend anybody?
Or why did you move it from interrupt context to main context?

If I had to do this (no need for anyone else to do it the same way):
* Prepare the table in main
* write the first value without update (timing not critic, may run in interrupt context or main context.
* ...
* when interrupt is called (interrupt context) I'd write the second value with both channels update.
* ...
*****
Another approach is to run the ISR twice as often. One time one channel, next time other channel.
***
In either case i'd prepare the SPI command before the ISR runs...then in ISR I'd just output the prepared data.
A fixed delay does not hurt ... but whith outputing the data as soon as possible I avoid jittery SPI timing.

And I'd avoid float calculations. (Depends on microcontroller)
The data to the DAC is integer, thus a float calculation doesn't bring much benefit in precision.

Klaus
 

No, I get the Mdepth, MSet variables etc. with UART communication in the main while loop. So in that sequence, I placed the DAC commands in while loop after receiving the parameters from the UART.

How can I implement this, "Another approach is to run the ISR twice as often. One time one channel, next time other channel"? @KlausST
 

How can I implement this, "Another approach is to run the ISR twice as often. One time one channel, next time other channel"?
...what about a static variable counting 0-1-0-1-0-1-0....
For the according channel.

Klaus
 

Can you show me a simple example? Then I can try to implement in my case. @KlausST
 

Hi,

really?

pseudo code:
Code:
function xx
{
   static uint8_t channel
   if (channel == 1)
   {
      update DAC_channel1
      channel = 0
   }
   else
   {
      update DAC_channel0
      channel = 1
   }
}//end of function

Klaus
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top