Arduino micro SPWM

Hello everyone, I'm in the process of programming a SPWM. Unfortunately I can only get a frequency of 5kHz although I calculated 80kHz in my calculation of the OCR1A. Does anyone have any tips for me?

float p;
int m;
int n;
int plot;
int val;

//Sinussignal
signed char S[1600]=
{0,0,0,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11,12,12,12,13,13,14,14,14,15,15,16,16,16,17,17,17,18,18,
19,19,19,20,20,21,21,21,22,22,22,23,23,24,24,24,25,25,26,26,26,27,27,27,28,28,29,29,29,30,30,30,31,31,32,32,32,33,33,33,34,
34,34,35,35,36,36,36,37,37,37,38,38,38,39,39,40,40,40,41,41,41,42,42,42,43,43,43,44,44,45,45,45,46,46,46,47,47,47,48,48,48,
49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,54,54,54,55,55,55,56,56,56,57,57,57,58,58,58,59,59,59,60,60,60,60,61,61,61,62,
62,62,63,63,63,64,64,64,64,65,65,65,66,66,66,67,67,67,67,68,68,68,69,69,69,69,70,70,70,70,71,71,71,72,72,72,72,73,73,73,73,
74,74,74,75,75,75,75,76,76,76,76,77,77,77,77,78,78,78,78,79,79,79,79,79,80,80,80,80,81,81,81,81,82,82,82,82,82,83,83,83,83,
84,84,84,84,84,85,85,85,85,85,86,86,86,86,86,87,87,87,87,87,88,88,88,88,88,88,89,89,89,89,89,89,90,90,90,90,90,90,91,91,91,
91,91,91,92,92,92,92,92,92,92,93,93,93,93,93,93,93,94,94,94,94,94,94,94,94,95,95,95,95,95,95,95,95,96,96,96,96,96,96,96,96,
96,96,97,97,97,97,97,97,97,97,97,97,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99,99,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,97,97,97,97,97,97,97,
97,97,97,97,96,96,96,96,96,96,96,96,96,96,95,95,95,95,95,95,95,95,94,94,94,94,94,94,94,94,93,93,93,93,93,93,93,92,92,92,92,
92,92,92,91,91,91,91,91,91,90,90,90,90,90,90,89,89,89,89,89,89,88,88,88,88,88,88,87,87,87,87,87,86,86,86,86,86,85,85,85,85,
85,84,84,84,84,84,83,83,83,83,82,82,82,82,82,81,81,81,81,80,80,80,80,79,79,79,79,79,78,78,78,78,77,77,77,77,76,76,76,76,75,
75,75,75,74,74,74,73,73,73,73,72,72,72,72,71,71,71,70,70,70,70,69,69,69,69,68,68,68,67,67,67,67,66,66,66,65,65,65,64,64,64,
64,63,63,63,62,62,62,61,61,61,60,60,60,60,59,59,59,58,58,58,57,57,57,56,56,56,55,55,55,54,54,54,53,53,53,52,52,52,51,51,51,
50,50,50,49,49,49,48,48,48,47,47,47,46,46,46,45,45,45,44,44,43,43,43,42,42,42,41,41,41,40,40,40,39,39,38,38,38,37,37,37,36,
36,36,35,35,34,34,34,33,33,33,32,32,32,31,31,30,30,30,29,29,29,28,28,27,27,27,26,26,26,25,25,24,24,24,23,23,22,22,22,21,21,
21,20,20,19,19,19,18,18,17,17,17,16,16,16,15,15,14,14,14,13,13,12,12,12,11,11,10,10,10,9,9,9,8,8,7,7,7,6,6,5,5,5,4,4,3,3,3,
2,2,1,1,1,0,0,0,0,0,-1,-1,-1,-2,-2,-3,-3,-3,-4,-4,-5,-5,-5,-6,-6,-7,-7,-7,-8,-8,-9,-9,-9,-10,-10,-10,-11,-11,-12,-12,-12,
-13,-13,-14,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-18,-18,-19,-19,-19,-20,-20,-21,-21,-21,-22,-22,-22,-23,-23,-24,-24,
-24,-25,-25,-26,-26,-26,-27,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,
-36,-36,-36,-37,-37,-37,-38,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-45,-45,-45,-46,-46,
-46,-47,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-56,-56,
-56,-57,-57,-57,-58,-58,-58,-59,-59,-59,-60,-60,-60,-60,-61,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-65,-65,-65,
-66,-66,-66,-67,-67,-67,-67,-68,-68,-68,-69,-69,-69,-69,-70,-70,-70,-70,-71,-71,-71,-72,-72,-72,-72,-73,-73,-73,-73,-74,
-74,-74,-75,-75,-75,-75,-76,-76,-76,-76,-77,-77,-77,-77,-78,-78,-78,-78,-79,-79,-79,-79,-79,-80,-80,-80,-80,-81,-81,-81,
-81,-82,-82,-82,-82,-82,-83,-83,-83,-83,-84,-84,-84,-84,-84,-85,-85,-85,-85,-85,-86,-86,-86,-86,-86,-87,-87,-87,-87,-87,
-88,-88,-88,-88,-88,-88,-89,-89,-89,-89,-89,-89,-90,-90,-90,-90,-90,-90,-91,-91,-91,-91,-91,-91,-92,-92,-92,-92,-92,-92,
-92,-93,-93,-93,-93,-93,-93,-93,-94,-94,-94,-94,-94,-94,-94,-94,-95,-95,-95,-95,-95,-95,-95,-95,-96,-96,-96,-96,-96,-96,
-96,-96,-96,-96,-97,-97,-97,-97,-97,-97,-97,-97,-97,-97,-97,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-97,-97,
-97,-97,-97,-97,-97,-97,-97,-97,-97,-96,-96,-96,-96,-96,-96,-96,-96,-96,-96,-95,-95,-95,-95,-95,-95,-95,-95,-94,-94,-94,
-94,-94,-94,-94,-94,-93,-93,-93,-93,-93,-93,-93,-92,-92,-92,-92,-92,-92,-92,-91,-91,-91,-91,-91,-91,-90,-90,-90,-90,-90,
-90,-89,-89,-89,-89,-89,-89,-88,-88,-88,-88,-88,-88,-87,-87,-87,-87,-87,-86,-86,-86,-86,-86,-85,-85,-85,-85,-85,-84,-84,
-84,-84,-84,-83,-83,-83,-83,-82,-82,-82,-82,-82,-81,-81,-81,-81,-80,-80,-80,-80,-79,-79,-79,-79,-79,-78,-78,-78,-78,-77,
-77,-77,-77,-76,-76,-76,-76,-75,-75,-75,-75,-74,-74,-74,-73,-73,-73,-73,-72,-72,-72,-72,-71,-71,-71,-70,-70,-70,-70,-69,
-69,-69,-69,-68,-68,-68,-67,-67,-67,-67,-66,-66,-66,-65,-65,-65,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-61,-60,
-60,-60,-60,-59,-59,-59,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-52,-51,-51,-51,
-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,
-40,-40,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-30,-29,
-29,-29,-28,-28,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-24,-23,-23,-22,-22,-22,-21,-21,-21,-20,-20,-19,-19,-19,-18,-18,
-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-14,-13,-13,-12,-12,-12,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-7,-7,-7,-6,-6,-5,-5,
-5,-4,-4,-3,-3,-3,-2,-2,-1,-1,-1,0,0};

//Dreiecksignal
int D[16]={0,137,275,412,550,412,275,137,0,-137,-275,-412,-550,-412,-275,-137};

void setup(){
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode( A0,INPUT);

// Timer1 instalisieren
TCCR1A = 0; //Register definiert zurĂĽcksetzten
TCCR1B = 0; //zuerst Register definiert zurĂĽcksetzen
TCNT1 = 0;  //Zählerwert zurücksetzten

//Timer1 80kHZ einstellen
OCR1A = 199; // (16000000)/(80000*1) 1 <65536
TCCR1B |= (1 << WGM12); //CTC mode
//TCCR1B |= (0 << CS12) | (0 << CS11) | (1 >> CS10); //kein Prescale
TCCR1B |= (1 << CS10); // clk/1 prescale 1024
TIMSK1 |= (1 << OCIE1A); //Aktivieren des Timer-Vergleichs-Interrupt

}

ISR(TIMER1_COMPA_vect){ // Interrupt
if (D[n] < val*S[m]) {
bitSet(PORTC, 6); // Pin 5 HIGH
}
else {
bitClear(PORTC, 6); // Pin 5 LOW
}
if (D[n] < val*S[m]) {
bitSet(PORTD, 7); // Pin 6 HIGH
}
else {
bitClear(PORTD, 7); // Pin 6 LOW
}
n=n+1;
if(n>15)
n=0;
m=m+1;
if(m>1599)
m=0;
}
void loop() {
p = analogRead(A0); // Potiwert
plot = map(p, 0, +500, 1, 5); // Amplituden der Sinussignal bestimmen
//delay(300);
val=plot;
}

Your interrupt rate is 80 kHz. You step through two tables: 16 elements and 1600 elements. The 16-element table will be scanned at 5 kHz (80 kHz / 16) and the 1600-element table will be scanned at 50 Hz (80 kHz / 1600).

You seem to be comparing the 5 kHz wave (sine?) to the 50 Hz wave (sine?) and turning the output pins on or off. I don't know what that is supposed to produce but I expect it has 5 kHz and 50 Hz components.

1 Like

The 16 elements are intended to represent a triangle voltage. I would like to display a sinusoidal square-wave voltage from the comparison of the slow sine curve and the fast triangle curve.

That actually works. Only the 5kHz are too slow.

Sounds like a software implementation of the hardware Phase Correct PWM. Perhaps you could use the PWM hardware to produce your signal.

What frequency of sine wave output did you want?

1 Like

yes, the direction should go. how do I do that with the hardware?
I need a frequency greater than 25kHz.

OK. That gives you fewer than 640 clock cycles to work with (16 MHz / 25 kHz = 640). Using 4-bit PWM (16 levels) you are left with 39 or fewer samples per cycle.

8	9	10	11	12	13	14	14
15	15	15	15	15	14	13	12
12	10	9	8	7	6	5	3
3	2	1	0	0	0	0	0
1	1	2	3	4	5	6

EDIT: Oops. I forgot that Phase Correct PWM goes at half speed since it counts up and down for each PWM cycle. That mans for a "greater than 25kHz" sine wave you have to cut your 4-bit PWM down to 19 samples.

8	10	12	14	15	15	14	13
11	9	6	4	2	1	0	0
1	3	5
1 Like

How do I then build a PWM signal from it?
Can't I just decrease the values of the int D? So if I take 8 values I would have to come up with 10kHz.

Set your Waveform Generation Mode (WGM) to one of the Phase Correct PWM modes where you can set TOP. Set TOP to 15 to get 4-bit PWM. That will produce 500 kHz PWM so to get a higher than 25 kHz sine wave you need fewer than 20 samples per cycle. On the Overflow interrupt, load the next sample into the Output Compare Register. Enable PWM in TCCRxA.

You would have to drop the number of values in D to below 3.2 to get over 25 kHz. Since you can't have a fractional number of samples you would have to use 3. That's not much of a triangle wave.

1 Like

Ok wow thanks for all the tips. I will try it. Thank you.

OK, I don't understand. OCR2A is TOP so there must be a 15.
OCR2B is variable and there are values ​​8, 10, ... right?
How do I set my timer register correctly?

How did you calculate these values?

EDIT: Oops. I forgot that Phase Correct PWM goes at half speed since it counts up and down for each PWM cycle. That mans for a "greater than 25kHz" sine wave you have to cut your 4-bit PWM down to 19 samples.

8	10	12	14	15	15	14	13
11	9	6	4	2	1	0	0
1	3	5

I have another idea. If I took an Arduino mega I could make my arrays bigger right?

Spreadsheet.
ROUND((SIN(2Pin/19)+1) * 15/2);0)
2*Pi is a full cycle
n is the sample number (0 to 18 for 19 samples)
+1 to make the range 0 to 2 instead of -1 to 1.
* 15/2 to scale from 0 to 2 to 0 to 15
Rounded to the nearest integer.

1 Like

If you want to use Timer2 on an ATmega328p:

// WGM=5 (Phase Correct PWM, TOP in OCR2A)
// COM2B1 (Enable PWM on OC2B)
// CS20 (No prescale)
// TOIE2 (Enable overflow interrupt
OCR2A = 15; 
TCNT2 = 0;
TCCR2A = _BV(COM2B1) | _BV(WGM20); 
TCCR2B = _BV(WGM22) | _BV(CS20);
TIFR2 = _BV(TOV2); // Clear overflow flag
TIMSK2 = _BV(TOIE2);

ISR(TIMER2_OVF_vect)
{
  static byte m = 0;
  m++;
  if(m >18)
    m=0;
  OCR2B = SineTable[m];
}
1 Like

Ok thank you. I will give it a try. The sinetable is the sine array?

Yes. An array containing a sine wave reduced to 19 samples with values between 0 and 15. A byte is plenty large enough.

const byte SineTable[19] = 
{
  8, 10, 12, 14, 15, 15, 14, 13, 
  11, 9, 6, 4, 2, 1, 0, 0, 1, 3, 5
};
1 Like

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