Go Down

Topic: Audio exciters driven simultaneously (Read 3309 times) previous topic - next topic

Grumpy_Mike

#30
Jan 19, 2018, 07:50 pm Last Edit: Jan 19, 2018, 08:23 pm by Grumpy_Mike
Quote
What new value does it have to be loaded for next time?
The value in the count down register. This could happen automatically depending on the specific timer. But it dosn't matter if you do it again.

Quote
What is the reload timer (tcnt2) code that I posted used for at each timer interrupt?
The value in the count down register.

Quote
In case I would like to change and use the PWM method, I just have to use a code similar to the one posted in the previous post, correct?
No. You have to use a second timer and use the value loaded from the look up table into the PWM register. Note that their are not enough timers to make 5 waveforms using PWM.

birdm3n

Quote
there are not enough timers to make 5 waveforms using PWM
Looking at the samd21 data sheet (Arduino m0 pro micro controller), I noticed that the number of timers goes from 3 to 7. There are just 4 timers for the waveforms, right?

Just for clarifing, for count you mean the index of the lookup table? otherwise what is the count used for?

And still don't get why at every interrupt I have to set the tcnt2 if it is not modified in any instruction.

By the way, I don't understand why I should use a count down register. I want to use PWM (I'm sorry I have changed idea) and from what I understood, I need a lookup table with the values of the sine wave, an interrupt handler to increment the index of the lookup table, a timer that produces the interrupt and the function analogWrite() to output the sine wave values. Supposing the size of the lookup table equals to 256, the counter must go from 0 to 255 in order to output all the sine wave values and once it reaches 255, it must reset to 0 in order to repeat the sine wave. In order to have a frequency of about 100Hz, after all the math done in the previous post, we arrived at the conclusion that I need to use the value 234 but for what? Use it as the size of the lookup table? I don't get the point. Could you be more specific? Thank you for the patience you are having.

Grumpy_Mike

Quote
And still don't get why at every interrupt I have to set the tcnt2 if it is not modified in any instruction.
Because the hardware changes it.

Quote
Just for clarifing, for count you mean the index of the lookup table?
Yes.

Quote
I want to use PWM (I'm sorry I have changed idea)
Sigh, why are you making life more difficult for yourself? You hardly seem to have understanding to spare and you have added another level of complication.

Quote
Thank you for the patience you are having.
Warning, it is running out.

Quote
and the function analogWrite() to output the sine wave values.
No you don't use analogWrite, you change the appropriate register in the timer. 

Quote
n order to have a frequency of about 100Hz, after all the math done in the previous post, we arrived at the conclusion that I need to use the value 234 but for what?
To control the time between each sample taken from the look up table and passed to the output. That count is decremented by the hardware at a rate given by the clock which is pre divided by the prescaler. 

Quote
Could you be more specific?
Don't tempt me.

birdm3n

Ok now I got it, maybe  :)

The value 234 is the interval from one interrupt to another, so every time that the interrupt occurs it means that the value in the register is equal to 0 and I have to reload it to 234 in order to have another interrupt with a frequency of 100Hz.

So now, in the interrupt handler, I have to reload the value in the register, output the value of the lookup table in the PWM register and increment the index of the lookup table, right? I hope that this is the procedure. Do you agree with what I've just written? Moreover with 5 timers can I generate 2 different sine waves (2 because one sine wave is the audio output and the other one is the same for the other 4 exciters, with exception for the amplitude)?

Theoretically I just have to output one value at the time on 5 PWM registers which 4 of them are the same except for the amplitude and that's it no?

Grumpy_Mike

Quote
Theoretically I just have to output one value at the time on 5 PWM registers which 4 of them are the same except for the amplitude and that's it no?
No.

You want the phase to be different for each waveform so while your master signal just does this then each one of your extra oscillators need its own offset to add to the count to get the sample to use.

birdm3n

Do you agree with me in what I told you in the post #33?

Moreover the count of the master signal has to start from 0 while the one of the extra oscillators has to start from the half of the sine wave lookup table in order to cancel the master wave. In this way when the master signal is positive, the other waves are negative while when the master signal is negative, the other waves are positive. Do you think that it can work?

Grumpy_Mike

If I didn't put you right that means I agree.

Quote
Do you think that it can work?
That is altogether an other matter. What people class as working is a very vague concept. It will not be perfect, nothing ever is, but their will be a degree of cancellation. I am not too sure what you aim is and what you will count as success. Or over what area you want the cancellation and at what distance the cancellation oscillators are from the vibration source.

birdm3n

Hi Grumpy_Mike, I tried to develop the system but I have a bottleneck due to the low frequency of the i2c communication. So I would like to implement the pwm sine wave generator. I developed this code till now, can you help me to modify it in order to use the PWM instead of the DAC?

Code: [Select]

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_MCP4725.h>
#include <Adafruit_MMA8451.h>
// Output 25kHz single slope PWM with timer TCC0 on D7

volatile int flag = 0;
int ind = -1;

Adafruit_MCP4725 dac;

#define DAC_RESOLUTION (10)

volatile int sintable[256] PROGMEM = {
    512,524,537,549,562,574,587,599,611,624,636,648,660,672,684,696,707,719,730,741,753,764,774,785,796,806,816,826,836,846,855,864,873,882,890,899,907,915,922,930,
937,944,950,957,963,968,974,979,984,989,993,997,1001,1004,1008,1011,1013,1015,1017,1019,1021,1022,1022,1023,1023,1023,1022,1022,1021,1019,1017,1015,1013,1011,1008,1004,1001,997,993,989,
984,979,974,968,963,957,950,944,937,930,922,915,907,899,890,882,873,864,855,846,836,826,816,806,796,785,774,764,753,741,730,719,707,696,684,672,660,648,636,624,
611,599,587,574,562,549,537,524,512,499,486,474,461,449,436,424,412,399,387,375,363,351,339,327,316,304,293,282,270,259,249,238,227,217,207,197,187,177,168,159,
150,141,133,124,116,108,101,93,86,79,73,66,60,55,49,44,39,34,30,26,22,19,15,12,10,8,6,4,2,1,1,0,0,0,1,1,2,4,6,8,
10,12,15,19,22,26,30,34,39,44,49,55,60,66,73,79,86,93,101,108,116,124,133,141,150,159,168,177,187,197,207,217,227,238,249,259,270,282,293,304,
316,327,339,351,363,375,387,399,412,424,436,449,461,474,486,499
};


void setup()
{
  ind = i+128;
  Wire.begin();
  Wire.setClock(400000);
  Serial.begin(9600);
  dac.begin(0x62);
 
  Serial.println("MCP4725A found!");

  REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
                    GCLK_GENDIV_ID(4);            // Select Generic Clock (GCLK) 4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                     GCLK_GENCTRL_GENEN |         // Enable GCLK4
                     GCLK_GENCTRL_SRC_DFLL48M |   // Set the 48MHz clock source
                     GCLK_GENCTRL_ID(4);          // Select GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Feed GCLK4 to TCC0 and TCC1
  REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN |         // Enable GCLK4 to TCC0 and TCC1
                     GCLK_CLKCTRL_GEN_GCLK4 |     // Select GCLK4
                     GCLK_CLKCTRL_ID_TCC0_TCC1;   // Feed GCLK4 to TCC0 and TCC1
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization

  // Normal (single slope) PWM operation: timers countinuously count up to PER register value and then is reset to 0
  REG_TCC0_WAVE |= TCC_WAVE_WAVEGEN_NPWM;         // Setup single slope PWM on TCC0
  while (TCC0->SYNCBUSY.bit.WAVE);                // Wait for synchronization

  // Each timer counts up to a maximum or TOP value set by the PER register,
  // this determines the frequency of the PWM operation:
  REG_TCC0_PER = 1919;                            // Set the frequency of the PWM on TCC0 to 25kHz
  while(TCC0->SYNCBUSY.bit.PER);                  // Wait for synchronization
 
  // Set the PWM signal to output 50% duty cycle on D7
  REG_TCC0_CCB3 = 959;                            // TCC0 CCB3 - on output on D7 50% duty cycle
  while(TCC0->SYNCBUSY.bit.CCB3);                 // Wait for synchronization

  NVIC_SetPriority(TCC0_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TCC0 to 0 (highest)
  NVIC_EnableIRQ(TCC0_IRQn);         // Connect TCC0 to Nested Vector Interrupt Controller (NVIC)

  REG_TCC0_INTENSET = TC_INTENSET_OVF;            // Enable TCC0 overflow interrupt

  // Divide the 48MHz signal by 1 giving 48MHz (20.83ns) TCC0 timer tick and enable the outputs
  REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV1 |    // Divide GCLK4 by 1
                    TCC_CTRLA_ENABLE;             // Enable the TCC0 output
  while (TCC0->SYNCBUSY.bit.ENABLE);              // Wait for synchronization 
}

void loop() {
  if(flag){
    dac.setVoltage(pgm_read_word(&(sintable[ind])), false);
    flag = 0;
  }
}

// Ineterrupt handler called every time the TCC0 timer overflows
void TCC0_Handler()                              // Interrupt Service Routine (ISR) for timer TCC0
{     
  // Check for overflow (OVF) interrupt
  if (TCC0->INTFLAG.bit.OVF && TCC0->INTENSET.bit.OVF)             
  {
    flag = 1;
    ind++;
    if(ind == 256)
      ind = 0;
    REG_TCC0_INTFLAG = TC_INTFLAG_OVF;         // Clear the OVF interrupt flag
  }
}

ard_newbie


I don't know which board you are working on (M0 pro ?), however if you want to output 5 PWM signals (e.g. a sine wave for all PWM signals) with synchro frequencies and variable phase and amplitude, you might be interested by the DUE (I don't know whether the M0 pro has or not this feature).

The DUE has a PWM synchro feature, with the possibility of an automatic update of duty cycles via DMA ( buffer transfer without processor Intervention). Moreover, Inside the PWM interrupt Handler triggered after each period, you can update the amplitude and phase of each of the PWM signals for the next period.

Of course, it depends on the frequency of your synchro PWM signals (I have seen 100 Hz ?) because the update of 5 buffers should take place between two PWM interrupt triggers, plus the necessary time to do some math to calculate 4 new amplitudes and phases for the next period...

birdm3n

Quote
I don't know which board you are working on
I'm using arduino m0 pro and I want to output 4 sine waves that should have the same frequency of 100Hz and different amplitude. Due to the fact that the sine waves have a frequency of 100Hz each value of the lookupt table needs to be outputed with a frequency of 25kHz.

I want to use this board, is it possible to use it or do I have to change it?

ard_newbie


As I previously said, I don't know the MO pro board. Read carefully the PWM section of the datasheet for the uc attached to this board, and you will have the answer.

Go Up