Go Down

Topic: How to set Sinewave with Frequency? (Read 509 times) previous topic - next topic

saicheng

Jun 09, 2014, 04:46 am Last Edit: Jun 10, 2014, 05:09 am by saicheng Reason: 1
I use the code

Code: [Select]
// RCArduino DDS Sinewave for Arduino Due
// RCArduino DDS Sinewave by RCArduino is licensed under a Creative Commons Attribution 3.0 Unported License.
// Based on a work at rcarduino.blogspot.com.

// For helpful background information on Arduino Due Timer Configuration, refer to the following link
// thanks to Sebastian Vik
// http://arduino.cc/forum/index.php?action=post;topic=130423.15;num_replies=20

// For background information on the DDS Technique see
// http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/

// For audio sketches making extensive use of DDS Techniques, search the RCArduino Blog
// for the tags Audio or synth

// These are the clock frequencies available to the timers /2,/8,/32,/128
// 84Mhz/2 = 42.000 MHz
// 84Mhz/8 = 10.500 MHz
// 84Mhz/32 = 2.625 MHz
// 84Mhz/128 = 656.250 KHz
//
// 44.1Khz = CD Sample Rate
// Lets aim for as close to the CD Sample Rate as we can get -
//
// 42Mhz/44.1Khz = 952.38
// 10.5Mhz/44.1Khz = 238.09 // best fit divide by 8 = TIMER_CLOCK2 and 238 ticks per sample
// 2.625Hmz/44.1Khz = 59.5
// 656Khz/44.1Khz = 14.88

// 84Mhz/44.1Khz = 1904 instructions per tick

// the phase accumulator points to the current sample in our wavetable
uint32_t ulPhaseAccumulator = 0;
// the phase increment controls the rate at which we move through the wave table
// higher values = higher frequencies
volatile uint32_t ulPhaseIncrement = 0;   // 32 bit phase increment, see below

// full waveform = 0 to SAMPLES_PER_CYCLE
// Phase Increment for 1 Hz =(SAMPLES_PER_CYCLE_FIXEDPOINT/SAMPLE_RATE) = 1Hz
// Phase Increment for frequency F = (SAMPLES_PER_CYCLE/SAMPLE_RATE)*F
#define SAMPLE_RATE 5000.0
#define SAMPLES_PER_CYCLE 2000
#define SAMPLES_PER_CYCLE_FIXEDPOINT (SAMPLES_PER_CYCLE<<20)
#define TICKS_PER_CYCLE (float)((float)SAMPLES_PER_CYCLE_FIXEDPOINT/(float)SAMPLE_RATE)

// to represent 600 we need 10 bits
// Our fixed point format will be 10P22 = 32 bits


// We have 521K flash and 96K ram to play with

// Create a table to hold the phase increments we need to generate midi note frequencies at our 44.1Khz sample rate
#define MIDI_NOTES 1000
uint32_t nMidiPhaseIncrement[MIDI_NOTES];

// fill the note table with the phase increment values we require to generate the note
void createNoteTable(float fSampleRate)
{
  for(uint32_t unMidiNote = 0;unMidiNote < MIDI_NOTES;unMidiNote++)
  {
    // Correct calculation for frequency
    Serial.print(unMidiNote);
    Serial.print(" ");
    float fFrequency = ((pow(2.0,(unMidiNote)/12)) * 2.0);
    Serial.print(fFrequency);
    Serial.print(" ");
   
    nMidiPhaseIncrement[unMidiNote] = fFrequency*TICKS_PER_CYCLE*10;
    Serial.println(nMidiPhaseIncrement[unMidiNote]);
  }
}

// Create a table to hold pre computed sinewave, the table has a resolution of 600 samples
#define WAVE_SAMPLES 2000
// default int is 32 bit, in most cases its best to use uint32_t but for large arrays its better to use smaller
// data types if possible, here we are storing 12 bit samples in 16 bit ints
uint16_t nSineTable[WAVE_SAMPLES];

// create the individual samples for our sinewave table
void createSineTable()
{
  for(uint32_t nIndex = 0;nIndex < WAVE_SAMPLES;nIndex++)
  {
    // normalised to 12 bit range 0-4095
    nSineTable[nIndex] = (uint16_t)  (((1+sin(((2.0*PI)/WAVE_SAMPLES)*nIndex))*4095.0)/2);
    Serial.println(nSineTable[nIndex]);
  }
}
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect(false);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK2);
        uint32_t rc = VARIANT_MCK/8/frequency; //128 because we selected TIMER_CLOCK4 above
        TC_SetRA(tc, channel, 32/2); //50% high, 50% low
        TC_SetRC(tc, channel, 16);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
          analogWrite(DAC0,0);
}



void setup()
{
  Serial.begin(9600);

  createNoteTable(SAMPLE_RATE);
  createSineTable();
startTimer(TC1, 1, TC4_IRQn, 1);
  // this is a cheat - enable the DAC

}

void loop()
{
  // read analog input 0 drop the range from 0-1024 to 0-127 with a right shift 3 places,
  // then look up the phaseIncrement required to generate the note in our nMidiPhaseIncrement table
  uint32_t ulInput = analogRead(0);
  ulPhaseIncrement = nMidiPhaseIncrement[ulInput>>3];
}

void TC4_Handler()
{
  // We need to get the status to clear it and allow the interrupt to fire again
  TC_GetStatus(TC1, 1);

  ulPhaseAccumulator += ulPhaseIncrement;   // 32 bit phase increment, see below

  // if the phase accumulator over flows - we have been through one cycle at the current pitch,
  // now we need to reset the grains ready for our next cycle
  if(ulPhaseAccumulator > SAMPLES_PER_CYCLE_FIXEDPOINT)
  {
   // DB 02/Jan/2012 - carry the remainder of the phase accumulator
   ulPhaseAccumulator -= SAMPLEAS_PER_CYCLE_FIXEDPOINT;
   }

  // get the current sample 
  uint32_t ulOutput = nSineTable[ulPhaseAccumulator>>20];

  // we cheated and user analogWrite to enable the dac, but here we want to be fast so
  // write directly
  dacc_write_conversion_data(DACC_INTERFACE, ulOutput);
}


I didn`t know how to set Frequency?
PS.Frequency rate: 20khz~200khz

iyahdub

Above the Nyquist frequency. and starts aliasing. So, highest you can achieve should be :
Sampling_rate / 2 = Nyquist frequency
i.e. 44.100/2 =22.050 kHz
10 LET Loop=Infinite
20 GO TO 10

MarkT

In practice ~16kHz is the upper limit, about 40% of the sampling frequency.

The variable ulPhaseIncrement is set proportional to the desired frequency,
a little maths will tell you the constant of proportionality.
[ I won't respond to messages, use the forum please ]

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy