/* * DDS - Direct digital synthesis for periodic waveform * generation. * * The implementation of the DDS relies upon integer * arithmetic. The size of accumulator is N-bits. * Assuming that the period of the output signal is * 2*pi rad, the maximum phase is represented by 2^N. * During one sample period the phase increases by the * phase increment which lead us to: * - output_frequency(phase_inc) = (frequency_sampling * / 2^N) * phase_inc (1) * * The later can be rewritten: * - phase_inc = output_frequency * resolution * * where the resolution is: * - resolution = 2^N / frequency_sampling (2) * * Also: * - N = log2(frequency_sampling/minimum_frequency) + 0.5 (3) * - maximum_output_frequency = frequency_sampling / 2 * * For a better analog reconstruction of the signal we * use: * - maximum_output_frequency = frequency_sampling / 4 (4) * * According to (4) and for a maximum output frequency of 15KHz * a 62.5KHz sampling frequency was chosen. According to (3) we * can derive the accumulator as 16 bits wide, and according to (2) * we'll have a resolution of 1.0486. * Since we're using fixed point arithmetic, we'll scale * the resolution by a factor of 2^16: * - N = 16, resolution = (2^16 * maximum_output_frequency) / * (frequency_sampling) * * Joao Mouro (http://mouro.info) * 15/05/2009 */ #include #include // Sinewave lookup table for waveform generation static const uint8_t sineTable[] PROGMEM = { 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95, 0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae, 0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4, 0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8, 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8, 0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5, 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc, 0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe, 0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7, 0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec, 0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc, 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9, 0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3, 0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c, 0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83, 0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a, 0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51, 0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b, 0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27, 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17, 0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a, 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03, 0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01, 0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13, 0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23, 0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36, 0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c, 0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63, 0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c }; const uint8_t ECGTable[] PROGMEM= { 73,74,75,75,74,73,73,73,73,72,71,69,68,67,67,67, 68,68,67,65,62,61,59,57,56,55,55,54,54,54,55,55, 55,55,55,55,54,53,51,50,49,49,52,61,77,101,132, 169,207,238,255,254,234,198,154,109,68,37,17,5, 0,1,6,13,20,28,36,45,52,57,61,64,65,66,67,68,68, 69,70,71,71,71,71,71,71,71,71,72,72,72,73,73,74, 75,75,76,77,78,79,80,81,82,83,84,86,88,91,93,96, 98,100,102,104,107,109,112,115,118,121,123,125, 126,127,127,127,127,127,126,125,124,121,119,116, 113,109,105,102,98,95,92,89,87,84,81,79,77,76,75, 74,73,72,70,69,68,67,67,67,68,68,68,69,69,69,69, 69,69,69,70,71,72,73,73,74,74,75,75,75,75,75,75, 74,74,73,73,73,73,72,72,72,71,71,71,71,71,71,71, 70,70,70,69,69,69,69,69,70,70,70,69,68,68,67,67, 67,67,66,66,66,65,65,65,65,65,65,65,65,64,64,63, 63,64,64,65,65,65,65,65,65,65,64,64,64,64,64,64, 64,64,65,65,65,66,67,68,69,71,72,73 }; const uint8_t triangleTable[] PROGMEM = { 0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e, 0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e, 0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e, 0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e, 0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e, 0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe, 0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde, 0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe, 0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1, 0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1, 0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1, 0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81, 0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61, 0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41, 0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21, 0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01 }; // PWM output (OCR1A) int pwmPin = 9; // 16 bit accumulator uint16_t phaseAccumulator = 0; // 16 bit delta uint16_t phaseIncrement = 0; // DDS resolutionls const uint32_t resolution = 68719; // wavetable lookup index(upper 8 bits of the accumulator) uint8_t index = 0; // TIMER1 will overflow at a 62.5KHz(Sampling frequency). // Updates the OCR1A value and the accumulator. // Computes the next sample to be sent to the PWM. ISR(TIMER1_OVF_vect) { static uint8_t osc = 0; // Send oscillator output to PWM OCR1A = osc; // Update accumulator phaseAccumulator += phaseIncrement; index = phaseAccumulator >> 8; // Read oscillator value for next interrupt osc = pgm_read_byte( &sineTable[index] ); } // Configures TIMER1 to fast PWM non inverted mode. // Prescaler set to 1, which means that timer overflows // every 16MHz/256 = 62.5KHz void initPWM(void) { // Set PORTB1 pin as output pinMode(pwmPin, OUTPUT); // 8-bit Fast PWM - non inverted PWM TCCR1A= _BV(COM1A1) | _BV(WGM10); // Start timer without prescaler TCCR1B = _BV(CS10) | _BV(WGM12); // Enable overflow interrupt for OCR1A TIMSK1 = _BV(TOIE1); } // Translates the desired output frequency to a phase // increment to be used with the phase accumulator. // The 16 bit shift is required to remove the 2^16 // scale factor of the resolution. void setFrequency( uint32_t frequency ) { uint64_t phaseIncr64 = resolution * frequency; phaseIncrement = phaseIncr64 >> 16; }