Change frequency for MCP4725

For other supported Arduino products from Adafruit: Shields, accessories, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
JeffThompson
 
Posts: 42
Joined: Mon Jun 14, 2010 3:05 pm

Change frequency for MCP4725

Post by JeffThompson »

I've hooked up the MCP4725 to my Arduino and can get it to output a sinewave using the example code. But how do I change the frequency?

I (think) that changing the number of steps in the waveform lookup table changes the frequency: more values in the array = longer wavelength = lower pitch. And I think changing the TWBR clock speed in the library changes how quickly the array is read? But I can't figure out how to use these values to set a specific frequency.

How, for example, might I create a 440Hz sinewave?

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Change frequency for MCP4725

Post by adafruit_support_mike »

The technically correct answer is "emit the complete set of samples every 2,273 microseconds."

There are two mutually-constrained values there: the number of samples you have, and the delay between emitting samples. The more samples you have, the less time you can wait between one and the next. "Number of samples" times "delay between samples" has to equal 2.273uS to hit 440Hz though.

In practical terms, you usually want a maximum delay between samples so the output looks/sounds smooth. Dividing the period of the frequency you want by that maximum delay tells you the minimum number of samples you'll need. The maximum number of samples is limited by how fast you can send values out, so the size of your sample set will be somewhere between those two numbers.

As a technical trick, make the number of samples a multiple of 2^n where n is the number of octaves you want to play. Going up an octave simply doubles the frequency, so instead of emitting samples [1,2,3,...] once, emit samples [2,4,6,...] with the same delay, and play them twice. That way you get good resolution on your low frequencies, and good speed on your high frequencies.

User avatar
JeffThompson
 
Posts: 42
Joined: Mon Jun 14, 2010 3:05 pm

Re: Change frequency for MCP4725

Post by JeffThompson »

Thanks Mike! Whew – I know that your reply makes sense, but my head is swimming a bit.
  • How did you come up with a delay time of 2.273uS for 440Hz?
  • How do you set that delay?
  • "Period of the frequency you want" is not the same thing as the frequency?
  • Is the speed of the MCP4725 = the 200kHz listed on the product page?
If you don't mind, can you walk me through how you arrived at 2.273uS for 440Hz and what you'd set the number of samples and TWBR to?

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Change frequency for MCP4725

Post by adafruit_support_mike »

JeffThompson wrote:How did you come up with a delay time of 2.273uS for 440Hz?
If you want 440 of something to happen in 1 second, each one has to take 1/440th of a second. 1/440=0.002272727, which can also be written 2,272.727/1,000,000. 1 microsecond is 1/1,000,000 seconds, and a bit of rounding gives us 2,273uS.
JeffThompson wrote:How do you set that delay?
With an Arduino, you'd probably use the delayMicroseconds() function to get a short interval.
JeffThompson wrote:"Period of the frequency you want" is not the same thing as the frequency?
Period and frequency are inverses of each other. Period (usual symbol 'T') means "how long it takes". Frequency (usual symbol F), means "how often it happens".

The mathematical formula is T=1/F
JeffThompson wrote:Is the speed of the MCP4725 = the 200kHz listed on the product page?
Kind of.

200kHz output means you change the DAC's output value 200,000 times per second. That puts the period for each output value at 1/200,000th of a second, or 5uS. The main limit on update frequency is how long it takes to get the new settings into the chip, so the values above say it's possible to update the chip's output every 5uS if you have a microcontroller that can talk fast enough.

To make that happen, the microcontroller has to send data to the chip at 3.4 million bits per second, or 3.4MHz.

An Arduino normally transmits I2C data at 100kHz, about 34 times slower than the maximum data frequency. That means it will take about 5uS x 34 = 170uS per update. That's the update period, so the update frequency will be about 5.9kHz.

You can make an Arduino send I2C data at 400kHz, which would take the update rate up to about 23.5kHz.

That doesn't mean you get a 23.5kHz sine wave. It means you get 23,500 (or 5,900) different output values per second. If you want 440 copies of a sine wave, you can't have more than 23,500/440=53.47 or 5,900/440=13.36 different output values per sine wave.

In practice, handling fractional sample values makes things too complicated, so you just use the integers 53 or 13, then figure out how long each output value will need to last if you're setting that many values in the period of the output frequency you want (2,273uS for 440Hz).

User avatar
JeffThompson
 
Posts: 42
Joined: Mon Jun 14, 2010 3:05 pm

Re: Change frequency for MCP4725

Post by JeffThompson »

Thank you! This was not super intuitive, but I think I understand the frequency-to-period and sample rate.

It doesn't seem to be working as expected, though.

My Arduino code:

Code: Select all

#include <Wire.h>
#include <Adafruit_MCP4725.h>

// 100kHz clock
const PROGMEM uint16_t sineLookup[14] = { 
  2048, 3000, 3733, 4081, 3963, 3406, 2538, 1558,
  690, 133, 15, 363, 1096, 2048
};
const int wavelength = 14;

// 400kHz clock
//const PROGMEM uint16_t sineLookup[54] = { 
//  2048,2290,2529,2761,2983,3192,3385,3559,
//  3712,3842,3946,4024,4074,4095,4088,4052,
//  3988,3897,3780,3638,3475,3291,3089,2874,
//  2646,2410,2169,1927,1686,1450,1222,1007,
//  805,621,458,316,199,108,44,8,
//  1,22,72,150,254,384,537,711,
//  904,1113,1335,1567,1806,2048
//};
//const int wavelength = 54;

Adafruit_MCP4725 dac;


void setup(void) {
  dac.begin(0x62);
}


void loop(void) {
  for (uint16_t i=0; i<wavelength; i++) {
    dac.setVoltage(pgm_read_word(&(sineLookup[i])), false);
  }
}
And the Adafruit MCP4725 library, changed to run either 400 or 100kHz:

Code: Select all

#ifdef TWBR
  uint8_t twbrback = TWBR;
  TWBR = ((F_CPU / 400000L) - 16) / 2; // Set I2C frequency to 400kHz
  // TWBR = ((F_CPU / 100000L) - 16) / 2; // Set I2C frequency to 100kHz
#endif
Weirdly, I get the right pitch (or pretty close to it) with the 14-item array, which (as I understand it) should be for the 100kHz clock, not 400...

Am I close? Thank you!

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Change frequency for MCP4725

Post by adafruit_support_mike »

You're sending all the samples through the DAC as fast as they can go.

Try this:

Code: Select all

int period = 1000000 / 440;         //  period of 440hz in microseconds
int rate   = period / wavelength;   //  length of time between samples

int sample = 0;

void loop(void) {
    dac.setVoltage(pgm_read_word(&(sineLookup[ sample ])), false);
    sample = ( sample < wavelength ) ? sample + 1 : 0;
    delayMicroseconds( rate );
}

User avatar
abdullahhinaidi
 
Posts: 1
Joined: Mon Mar 26, 2018 1:43 am

Re: Change frequency for MCP4725

Post by abdullahhinaidi »

I need to change the output frequency up to 1000 HZ. I did not understand what should I change, and how can I change it to any other frequency.

User avatar
JeffThompson
 
Posts: 42
Joined: Mon Jun 14, 2010 3:05 pm

Re: Change frequency for MCP4725

Post by JeffThompson »

I think you would change the

Code: Select all

440
in the code directly above to

Code: Select all

1000
.

User avatar
salmo
 
Posts: 1
Joined: Tue May 01, 2018 2:41 pm

Re: Change frequency for MCP4725

Post by salmo »

Hello,
The delay time for 440Hz is 2,273ms (millisecond), not 2,273us (microsecond) ?

User avatar
petrepa
 
Posts: 1
Joined: Mon Jul 09, 2018 7:00 am

Re: Change frequency for MCP4725

Post by petrepa »

Hi, guys!

Did you figure this out? Working on a project where I need to be able to set the frequency, but can not find out how to do it.

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Arduino products from Adafruit”