Go Down

Topic: sine pulse that goes on and off at a specific frequency with a voltage ramp (Read 341 times) previous topic - next topic

ranibar


Hi,

for my project I need to be able to generate a sine wave that goes on and off at specific frequency; for example a 10Khz sine wave that goes on and off at a 4hz. amplitude modulation can be a good approximation to what I need. so that would be also good to know how to generate an amplitude modulated sine wave.
and another requirement for the signal is that the on and off are not abrupt but have an amplitude ramp.
moreover I need to get the signal out through the DAC0 port.
can you help with this?
I have been trying all sorts of libraries for signal generation with no luck.

Thank you

ard_newbie


I partially understand the shape of the signal output from DAC0 you are trying to program.

Draw and post an example of the waveform (F = 10 KHz ?) you are trying to output from your DUE for a few periods (F = 4 Hz ?) with an amplitude ramp.

ranibar

Here is how it looks in Audacity.
note however I am not looking for audio particularly. just an analog signal (not using pwm) so I can tap into higher frequencies (up to 100khz).

so the ramp is only few ms. the pulse is about 100ms long and the silence between pulses is about 150 ms.
so I want to be able to change these parameters programatically:
the frequency of the wave (i.e. 10 khz). how many times a second it happens (i.e. 4 hz); probably also changing the time of on and off. and the length of the ramp.

ard_newbie

I would use a DAC DMA transfer of a sin wave (10 KHz) and  vary the amplitude every time it's necessary by setting a Flag within the DAC Handler.

In loop(), test the Flag and implement the amplitude update accordingly. Since 4Hz gives a 250 ms period, you don't even need to trigger a timer, millis() would suffice.

An example sketch for a DAC DMA transfer (not tested though):
Code: [Select]

/***********************************************************************************/
/*                           DAC0 output of a 10 KHz sin wave                           */
/***********************************************************************************/

const uint32_t sinsize  = 42 ;
const uint8_t TC_RC = 100;
const uint8_t TC_RA = TC_RC / 2;

uint32_t sinus[2][sinsize];
uint32_t _sinus[sinsize];

uint16_t Amplitude = 2047;  // 0 <= Amplitude <= 4095

volatile uint8_t bufn;
volatile boolean UpdateAmplitude;

void setup() {
  for (int i = 0; i < sinsize; i++)
  {
    _sinus[i]  = sin(i * 2 * PI / sinsize) + 1;  //  0 <= _sinus [i] <= 2
  }

  for (int i = 0; i < sinsize; i++)
  {
    sinus[0][i]  = sinus[1][i] = Amplitude * _sinus[i];  //  0 <= sinus[0][i] <=  Amplitude
  }

  // Fire !
  tc_setup();
  dac_setup();
}

void loop() {

  uint8_t Nextbufn;

  if (UpdateAmplitude == true)
  {
    UpdateAmplitude = false;

    // When OFF : Amplitude = 0
    // When ON : 0< Amplitude <= 2047
    // To do : increase Amplitude from 0 to 2047 with a given granularity
   
    // e.g.: Amplitude = 1000
    Amplitude = 1000;
    Nextbufn = (bufn + 1) & 1;
    for (int i = 0; i < sinsize; i++)
    {
      sinus[Nextbufn][i]  = Amplitude * _sinus[i];
    }
  }
}

void dac_setup () {

  PMC->PMC_PCER1 = PMC_PCER1_PID38;     // DACC power ON
  DACC->DACC_CR = DACC_CR_SWRST ;       // Reset DACC

  DACC->DACC_MR = DACC_MR_TRGEN_EN                   // Hardware trigger select
                  | DACC_MR_TRGSEL(0b011)            // Trigger by TIOA2 Rising edge
                  | DACC_MR_USER_SEL_CHANNEL0
                  | DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_8
                  | DACC_MR_MAXS;

  DACC->DACC_IER |= DACC_IER_TXBUFE;                 // Interrupt used by PDC DMA

  DACC->DACC_ACR = DACC_ACR_IBCTLCH0(0b10)           // For DAC frequency > 500 KHz
                   | DACC_ACR_IBCTLCH1(0b10)
                   | DACC_ACR_IBCTLDACCORE(0b01);

  NVIC_EnableIRQ(DACC_IRQn);                         // Enable DACC interrupt
  DACC->DACC_CHER = DACC_CHER_CH0;                   // enable channel 0 = DAC0

  /*************   configure PDC/DMA  for DAC *******************/

  DACC->DACC_TPR  = (uint32_t)sinus[0];         // DMA buffer
  DACC->DACC_TCR  = sinsize;
  DACC->DACC_TNPR = (uint32_t)sinus[1];         // next DMA buffer (circular buffer)
  DACC->DACC_TNCR = sinsize;
  bufn = 1;
  DACC->DACC_PTCR = DACC_PTCR_TXTEN;            // Enable PDC Transmit channel request

}

// DACC Handler is fired at F = 420000 / 42 = 10000 Hz
void DACC_Handler() {

  DACC->DACC_ISR;   // Read and save DAC status register

  bufn = (bufn + 1) & 1; // move DMA pointer to next buffer
  DACC->DACC_TNPR = (uint32_t)sinus[bufn];
  DACC->DACC_TNCR = sinsize;
  UpdateAmplitude = true;
}

void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                      // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1  // MCK/2 = 42 MHz, clk on rising edge
                              | TC_CMR_WAVE               // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC       // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR         // Clear TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;          // Set TIOA2 on RC compare match


  TC0->TC_CHANNEL[2].TC_RC = TC_RC;  //<*********************  Frequency = (Mck/2)/TC_RC = 420000 Hz
  TC0->TC_CHANNEL[2].TC_RA = TC_RA;  //<********************   Any Duty cycle in between 1 and TC_RC

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC2 counter and enable
}


Note: Because you need the full DAC range, you will have to add some hardware:
http://ardupiclab.blogspot.com/2015/07/how-to-modify-analog-output-range-of.html

ranibar

That's great. Thank you very much.

I will look at it and update.

ranibar

Hi Again,

While your code is very well annotated I have little background in such coding.

Frankly I don't quite understand the code. I played with it to try to understand it. but it seems I am missing something. particularly the DACC_Handler() - is it fired all the time regardless of what's in the for loop?
I understand that we have here two vectors in the buffer and we alternate between them we we call the DACC_Handler? with regard to the ramp
 
// When OFF : Amplitude = 0
    // When ON : 0< Amplitude <= 2047
    // To do : increase Amplitude from 0 to 2047 with a given granularity
   
if I make the amplitude change by some increment every run of the loop? and we get into the loop by setting millis() to be 250 for example?

more help would be much appreciated.

Thank you

Go Up