How to create Sine pwm (phase matched) using Arduino due

Hi all,
Please help me in generating Phase matched sine pwm using arduino due.
i have code which is working on Arduino uno same thing i have to acheive using arduino due.

Here is the code for UNO,

//PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.

int sin_pwm[1005]={128,129,130,130,131,132,133,134,134,135,136,137,138,138,139,140,141,142,142,143,144,145,146,146,
147,148,149,150,150,151,152,153,154,154,155,156,157,157,158,159,160,161,161,162,163,164,164,165,
166,167,168,168,169,170,171,171,172,173,174,174,175,176,177,177,178,179,180,180,181,182,182,183,
184,185,185,186,187,188,188,189,190,190,191,192,192,193,194,195,195,196,197,197,198,199,199,200,
201,201,202,203,203,204,205,205,206,206,207,208,208,209,210,210,211,211,212,213,213,214,214,215,
216,216,217,217,218,219,219,220,220,221,221,222,222,223,223,224,225,225,226,226,227,227,228,228,
229,229,230,230,231,231,232,232,232,233,233,234,234,235,235,236,236,237,237,237,238,238,239,239,
239,240,240,241,241,241,242,242,242,243,243,243,244,244,244,245,245,245,246,246,246,247,247,247,
248,248,248,248,249,249,249,249,250,250,250,250,251,251,251,251,252,252,252,252,252,253,253,253,
253,253,253,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,256,256,256,256,
256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,
256,255,255,255,255,255,255,255,255,255,255,254,254,254,254,254,254,254,253,253,253,253,253,253,
252,252,252,252,252,251,251,251,251,250,250,250,250,249,249,249,249,248,248,248,248,247,247,247,
246,246,246,245,245,245,244,244,244,243,243,243,242,242,242,241,241,241,240,240,239,239,239,238,
238,237,237,237,236,236,235,235,234,234,233,233,232,232,232,231,231,230,230,229,229,228,228,227,
227,226,226,225,225,224,223,223,222,222,221,221,220,220,219,219,218,217,217,216,216,215,214,214,
213,213,212,211,211,210,210,209,208,208,207,206,206,205,205,204,203,203,202,201,201,200,199,199,
198,197,197,196,195,195,194,193,192,192,191,190,190,189,188,188,187,186,185,185,184,183,182,182,
181,180,180,179,178,177,177,176,175,174,174,173,172,171,171,170,169,168,168,167,166,165,164,164,
163,162,161,161,160,159,158,157,157,156,155,154,154,153,152,151,150,150,149,148,147,146,146,145,
144,143,142,142,141,140,139,138,138,137,136,135,134,134,133,132,131,130,130,129,128,127,126,126,
125,124,123,122,122,121,120,119,118,118,117,116,115,114,114,113,112,111,110,110,109,108,107,106,
106,105,104,103,102,102,101,100,99,99,98,97,96,95,95,94,93,92,92,91,90,89,88,88,
87,86,85,85,84,83,82,82,81,80,79,79,78,77,76,76,75,74,74,73,72,71,71,70,
69,68,68,67,66,66,65,64,64,63,62,61,61,60,59,59,58,57,57,56,55,55,54,53,
53,52,51,51,50,50,49,48,48,47,46,46,45,45,44,43,43,42,42,41,40,40,39,39,
38,37,37,36,36,35,35,34,34,33,33,32,31,31,30,30,29,29,28,28,27,27,26,26,
25,25,24,24,24,23,23,22,22,21,21,20,20,19,19,19,18,18,17,17,17,16,16,15,
15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,10,10,9,9,9,8,8,8,8,
7,7,7,7,6,6,6,6,5,5,5,5,4,4,4,4,4,3,3,3,3,3,3,2,
2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,
4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,10,10,10,11,
11,11,12,12,12,13,13,13,14,14,14,15,15,15,16,16,17,17,17,18,18,19,19,19,
20,20,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,
31,32,33,33,34,34,35,35,36,36,37,37,38,39,39,40,40,41,42,42,43,43,44,45,
45,46,46,47,48,48,49,50,50,51,51,52,53,53,54,55,55,56,57,57,58,59,59,60,
61,61,62,63,64,64,65,66,66,67,68,68,69,70,71,71,72,73,74,74,75,76,76,77,
78,79,79,80,81,82,82,83,84,85,85,86,87,88,88,89,90,91,92,92,93,94,95,95,
96,97,98,99,99,100,101,102,102,103,104,105,106,106,107,108,109,110,110,111,112,113,114,114,
115,116,117,118,118,119,120,121,122,122,123,124,125,126,126,127,128};

int i=1,j=0;

void analogWrite25k(int pin, int value)
{
switch (pin)
{
case 9:
OCR1A = value;
break;

case 10:
  OCR1B = value;
  break;
  
default: // no other pin will work
  break;

}
}

void setup() // Configure Timer 1 for PWM @ 25 kHz.
{
TCCR1A = 0; // undo the configuration done by...
TCCR1B = 0; // ...the Arduino core library
TCNT1 = 0; // reset timer
TCCR1A = _BV(COM1A1) // non-inverted PWM on ch. A
| _BV(COM1B1) // same on ch; B
| _BV(WGM11); // mode 10: ph. correct PWM, TOP = ICR1
TCCR1B = _BV(WGM13) // ditto
| _BV(CS10); // prescaler = 1
ICR1 = 320; // TOP = 320

TCCR1A = 0b10110000 | (TCCR1A & 0b00001111) ;

// Set the PWM pins as output.
pinMode( 9, OUTPUT);
pinMode(10, OUTPUT);
}

void loop()
{
// Just an example:
analogWrite25k( 9,sin_pwm[i]);
analogWrite25k(10,sin_pwm[i]+4);j++;
if(j==5){delayMicroseconds(1);i++;j=0;}
if(i==1000){ i=1;}
}

I modifed the above code for due which is like this,

//1kHz
int sine[] = {2048,2305,2557,2802,3034,3251,3449,3625,3777,3901,3995,4059,4092,4092,4060,3996,3902,3778,3628,3452,3254,3037,2805,2560,2308,2051,1795,1542,1297,1065,847,649,473,321,197,102,37,4,4,35,99,193,316,466,642,839,1056,1288,1533,1785,2041};

// the setup routine runs once when you press reset:
void setup() {
/* Frequency = 20kHz over pin 2 */

PMC->PMC_PCER0 |= PMC_PCER0_PID27; // TC0 power ON - Timer Counter 0 channel 0 IS TC0 - See page 38
PIOB->PIO_PDR |= PIO_PDR_P25; // The pin is no more driven by GPIO
PIOB->PIO_ABSR |= PIO_PB25B_TIOA0; // Periperal type B - See page 859
TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // MCK/2, 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 TIOA0 on RA compare match -- See page 883
| TC_CMR_ACPC_SET; // Set TIOA0 on RC compare match

TC0->TC_CHANNEL[0].TC_RC = 2100; //<********************* Frequency = (Mck/2)/TC_RC Hz = 20 KHz
TC0->TC_CHANNEL[0].TC_RA = 210; //<******************** Duty cycle = (TC_RA/TC_RC) * 100 % = 10% (210); 50% (1050); 100% (2100)
TC0->TC_CHANNEL[0].TC_IER = TC_IER_CPCS; // Interrupt on RC compare match
NVIC_EnableIRQ(TC0_IRQn);
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC0 counter and enable

/* Frequency = 20kHz over pin 3 */

PMC->PMC_PCER1 |= PMC_PCER1_PID34; // TC7 power ON - Timer Counter 2 channel 1 IS TC7 - See page 38
PIOC->PIO_PDR |= PIO_PDR_P28; // The pin is no more driven by GPIO
PIOC->PIO_ABSR |= PIO_PC28B_TIOA7; // Periperal type B - See page 859
TC2->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // MCK/2, 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 TIOA7 on RA compare match -- See page 883
| TC_CMR_ACPC_SET; // Set TIOA7 on RC compare match

TC2->TC_CHANNEL[1].TC_RC = 2100; //<********************* Frequency = (Mck/2)/TC_RC Hz = 20 KHz
//TC2->TC_CHANNEL[1].TC_RA = 210; //<******************** Duty cycle = (TC_RA/TC_RC) * 100 % = 10% (210); 50% (1050); 100% (2100)
TC2->TC_CHANNEL[1].TC_IER = TC_IER_CPCS; // Interrupt on RC compare match
NVIC_EnableIRQ(TC7_IRQn);
TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger TC7 counter and enable

//pinMode(2, OUTPUT); pinMode(9, OUTPUT);

analogWriteResolution(12);

}

void TC7_Handler() {

TC2->TC_CHANNEL[1].TC_SR;
}

// the loop routine runs over and over again forever:
void loop() {

for(int i = 0; i<50;i++){
if(sine[i]>4095) {
sine[i]=4095;

 }

TC2->TC_CHANNEL[1].TC_RA = sine[i];}

PWM->PWM_CH_NUM[1].PWM_CDTY = 1050;
delay(3);

/*
analogWrite(3,TC2->TC_CHANNEL[1].TC_RA=210);
delay(30000);
analogWrite(3,TC2->TC_CHANNEL[1].TC_RA=1050);
delay(30000);
analogWrite(3,TC2->TC_CHANNEL[1].TC_RA=2100);
delay(30000);
*/
}

but doesn't working as expected,

unable to get sine pwm....
thanks in advance

Please read the forum guide in the sticky post and then edit your post above and correct the code tags!

After that, please explain the concept of "sine PWM".

Hi paul,
i need to generate pwm signal based on sine table

Why not use the builtin sin() function [edit] instead of that huge table?

That does not make sense because PWM is digital and Sinewave is analog!
edit: Or, do you want a digital representation of a sinewave?

Do you actually mean "Direct digital synthesis"?
http://www.cs.nott.ac.uk/~pszjm2/projects/other/Arduino_music_using_Direct_Digital_Synthesis.html

like this

Please edit your post to add code tags.

Thanks for reply,
i need to generate phase matched PWM signal with respect to sine table(Same as above image).i am doing it in Arduino Uno but unable to implement in Arduino Due.

i am generating 20Khz pwm using Timer in Arduino Due but i dont no how to assign values to ICR1 and OCR registers (as we do in Uno).Here in Due their is no registers like ICR and OCR.

Please help on this
i need two PWM signals which complements( second PWM is Invert of Fisrt PWM) each other.

i tried using analogWrite without using timer it is working but very less frequency.i need atleast 20kHz for both PWM signals.

Thanks in advance

Thanks for reply,
Sine table can be modified,
Please help on due timers, how to acheive 20kHz sine PWM signals using Arduino Due

Yes that is what you get, it is already matched to the table. But you are actually asking for two signals that are 180 degrees apart.

This is simple, you just run two pointers through the same look up table that are half le length of the table apart.

To change the PWM frequency you simply have to change the division ratio in the pre scale register.

As you have found the timers are different in the Due, so get the Data sheet for the Due's processor and see how they have changed and what they are called.

Thanks for the reply,
i tried this code in due board ,it is working perfectly but frquency i am getting is 1 kHz. i want it at atlest 20kHz.
int sine[125] =
{
0, 4, 8, 13, 17, 21, 25, 29, 34, 38, 42, 46, 50, 54, 57, 61, 65, 69, 72, 76, 79, 83, 86, 89, 92, 95, 98, 101, 104, 107,
109, 112, 114, 116, 118, 120, 122, 124, 126, 127, 128, 130, 131, 132, 133, 133, 134, 134, 135, 135, 135, 135, 135, 134,
134, 133, 133, 132, 131, 130, 128, 127, 126, 124, 122, 120, 118, 116, 114, 112, 109, 107, 104, 101, 98, 95, 92, 89, 86,
83, 79, 76, 72, 69, 65, 61, 57, 54, 50, 46, 42, 38, 34, 29, 25, 21, 17, 13, 8, 4

};

void setup() {

/************* Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0 ************/
PMC->PMC_PCER0 |= PMC_PCER0_PID27; // Timer Counter 0 channel 0 IS TC0, TCO power ON
PMC->PMC_PCER0 |= PMC_PCER0_PID12; // PIOB power ON, page 38

PIOB->PIO_PDR |= PIO_PDR_P25;
PIOB->PIO_ABSR |= PIO_ABSR_P25; // PB25 is driven by the TC, peripheral type B, page 858

TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 // MCK/2, 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 TIOA0 on RA compare match
| TC_CMR_ACPC_SET
| TC_CMR_TCCLKS_TIMER_CLOCK1; // Set TIOA0 on RC compare match

TC0->TC_CHANNEL[0].TC_RC = 2100; //<********************* Frequency = (Mck/2)/TC_RC = 1 MHz
TC0->TC_CHANNEL[0].TC_RA = 21; //<******************** Duty cycle = (TC_RA/TC_RC) * 100 = 50 %

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

pinMode(2,OUTPUT);pinMode(10,OUTPUT);
Serial.begin(9600);

}

void loop() {

for(int i = 0; i<100;i++){
if(sine[i]>135) {
sine[i]=135;
}

analogWriteResolution(12);
//TC0->TC_CHANNEL[0].TC_RA = 42;
analogWrite(2, sine[i]);
//analogWrite(10, sine[i]);
//delayMicroseconds(14000);
Serial.println(sine[i]);

}
}
Please suggest if i have missed anything in code.

without analogwrite operation on pin 2 i checked it is 20kHz.if i make pin 2 as output and use analogwrite function the frequency is coming down to 1kHz.

please suggest me

Thanks in advance

You have not used the PREB bits in the PWM Clock Register (PWM_CLK) to set the frequency of the counting, which ultimately defines the frequency of the PWM. See page 1020 of the data sheet.

Hi there @roshancheluva,

Have a look to the pwm_lib library at: https://github.com/antodom/pwm_lib. You can easily generate pwm signals with this library, you just have to order the pwm values from your sin table. Have a look to the examples coming with it.

I hope it helps.

Hi @antodom ,

I checked the pwm_lib and tried example "basic_test."
Now, I would like to change the frequency of another pin that is not 35 or 42. I tried with pin 3 but I got an error when changing "pwm<pwm_pin::PWMH0_PC3> pwm_pin35;" to "pwm<pwm_pin::PWMH0_PC28> pwm_pin3;"

The error states:
'PWMH0_PC28' is not a member of 'arduino_due::pwm_lib::pwm_pin'

Could you explain further what is "pwm<pwm_pin::PWMH0_PC3> pwm_pin35;" supposed to do?

Thanks in advance,

Hi there @ared20,

For generating PWM signals with Arduino DUE's ATSAM3X8E micro-controller you can not use arbitrarily any pin available, just a set of them which are listed in ATSAM3X8E's datasheet. Those pins, in turn, are mapped in pwm_lib's enumeration pmw_pin values which you can find in pwm_defs.h.

Have a look to both, the datasheet and the enumeration, to get to know which pins you can use. Also, I would advice you to read the rest of pwm_lib's documentation to get acquainted with it.

if in any doubt just ask.
I hope it helps.

1 Like

Thanks for answering my question. I tried some of the pins listed in the "pwm_defs.h" document and it worked.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.