I'm trying to, and to some success so far, generate a switched three phase signal from my Arduino Mega 2560. I've used the PWM.h example as a base and then added two more outputs to make it three phase. It worked fine for one, but when I scale it up I can't get any other PIN's than 11 & 12 to work with the code.
I suspect that it is an issue with initilating timers but when I try to read about the timers I can see why pin 10 should not work.
I get the wanted sine-wave from pin 11 and 12, but not from pin 10.
(I'm an electrical engineer so I hope I will understand even more complex explanations, but completely new to Arduino).
Thanks in advance
BR
Mellbin
Code:
#include <PWM.h>
// Three fase voltage
int U1_port = 10;
int U1_signal = 0;
int U2_port = 11;
int U2_signal = 0;
int U3_port = 12;
int U3_signal = 0;
int32_t frequency = 10000; //Switch frequency (in Hz)
int sig[500]; //Sine wave with 500 data-points resolution
float t; //Time for constructing sine wave
int fs = 500; //"Sampling time" for sine wave
//Three different "starting positions" for the sine waves, 120° spread.
int U1_counter=0;
int U2_counter=85;
int U3_counter=170;
//int f=200; //Not yet implimented
void setup()
{
//initialize all timers except for 0, to save time keeping functions
InitTimersSafe();
//sets the frequency for the specified pin
SetPinFrequencySafe(U1_port, frequency);
SetPinFrequencySafe(U2_port, frequency);
SetPinFrequencySafe(U3_port, frequency);
//Generate sine wave (500 point resolution)
for(int i = 0; i<500; i++)
{
t = (float)i/fs;
sig[i] = (int)(127.0)*(sin(2*3.14*fs*t)+1);
}
}
void loop()
{
//use this functions instead of analogWrite on 'initialized' pins
pwmWrite(U1_port, U1_signal);
pwmWrite(U2_port, U2_signal);
pwmWrite(U3_port, U3_signal);
U1_signal = sig[U1_counter];
U1_counter++;
U2_signal = sig[U2_counter];
U2_counter++;
U3_signal = sig[U3_counter];
U3_counter++;
//Sine wave contain 500 data points; loop
if (U1_counter >= 500 ) {
U1_counter=0;
}
if (U2_counter >= 500 ) {
U2_counter=0;
}
if (U3_counter >= 500 ) {
U3_counter=0;
}
delayMicroseconds(50);
}
1: you may not need such a large number of data points for your sinewave - I'd suggest 360 would be better. It will also ensure there is no glitch at wraparound.
2: You are building an array of values for a sinewave then using three different indices to retrieve values.
As the required waves are always 120 degree separation you would be better using the same index with an offset of 0, 120,240.
eg U2counter = (U1 counter + 120)%360; (modulo 360 wraps the index around at 360 degrees)
Hopefully someone with experience with the pwm library may be able to provide more help.
Thank you for the input, it seems a lot more efficient and I will updated accordningly I was thinkin about the offset indexing but didn't know how to handle the wrap around but when I see you use modulo i'm a bit upset with my self that I did not think of that, haha!
Putting a "delayMicroseconds(50);" in your loop() is not going to get you accurate timing because it will depend on what is happening in the rest of the sketch. I would recommend using the timer overflow interrupt to update the PWM value. Use a timer mode that buffers the Output Compare Register updates.
With a 10 kHz sine wave, you have 1600 clock ticks per cycle. The number of levels of PWM times the number of samples per cycle must equal 1600. That gives you 40 samples of 40 levels to 50 samples of 32 levels or 32 samples of 50 levels.
An 8-bit timer (Timer2) would be sufficient but Timer2 only has two PWM outputs. I would use Timer4 (Pins 6, 7, 8) or Timer5 (Pins 46, 45, 44).
I've complete re-worked the code now when I've read some more about Timers. I gave up the idea of the PWM-library since I didn't get it workin.
This is what the code looks like now, development still ongoing. Havn't gotten the COMPA interupt to work but atleast the overflow interupt is working.
int Ts = 50; //micro seconds
float t;
int sig[345];
int counter = 0;
void setup() {
// Set PWM pins as outputs
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
pinMode(5, OUTPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
// Initialise timers 1 and 3
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(COM1C1); // Enable the PWM outputs OC1A, OC1B and OC1C on digital pins 11, 12 and 13
TCCR1B = _BV(WGM13) | _BV(CS11); // Set phase and frequency correct PWM and prescaler of 8 on timer 1
TCCR3A = _BV(COM3A1) | _BV(COM3B1) | _BV(COM3C1); // Enable the PWM output OC3A, OC3B and OC3C on digital pins 5, 2 and 3
TCCR3B = _BV(WGM33) | _BV(CS31); // Set phase and frequency correct PWM and prescaler of 8 on timer 3
TIMSK3 = (TIMSK3 & B11111110) | 0x01; //enable overflow interupt
// TIMSK3 = (TIMSK3 & B11111001) | 0x02; //enable registar 'A' interup
ICR1 = Ts; // Set the timer 1 frequency
ICR3 = Ts; // Set the timer 3 frequency
//Generate sine wave (345 point resolution)
for(int i = 0; i<345; i++)
{
t = (float)i/345;
sig[i] = Ts/2*(sin(2*3.14*10*t)+1);
}
}
void loop() {
OCR1A = sig[counter];
OCR1B = sig[(counter+115)%345];
OCR1C = sig[(counter+230)%345];
// OCR3A = 25;
}
ISR(TIMER3_OVF_vect){
counter++;
if (counter > 344) {
counter = 0;
}
}
//ISR(TIMER3_COMPA_vect){
// counter++;
// if (counter > 344) {
// counter = 0;
// }
//}