# Optimizing clock cycles?

Using Arduino 2560

I am trying to generate this PWM signal

Here is the code

``````const int switch_a_top = PG5; //pin 4
const int switch_a_bot = PB7; //pin 13
const int switch_b_top = PH6;//pin 9
const int switch_b_bot = PB4;//pin 10
const int switch_c_top = PE4;//pin 2
const int switch_c_bot = PD3;//pin 5
const float pi = 3.141592654;

float v = 0;

float Vdc = 1.0;
float Vref = (1.0 / 2.0) * Vdc;
float Ts = 1.0 / 60.0 / 360;
float division = 1.0 / 60.0 / 360 / 360;
float k = Ts / division;
int t;
float alpha;
float T1, T2, T0;
int sector;
int n;

const uint16_t t1_comp = 0;

void vector_time(float Vdc, float Vref, float Ts, float alpha, int sector, float* T1h, float* T2h, float* T0h) {

if ((sector % 2) == 1) {
n = sector / 2 +1;
}
else {
n = sector / 2;
}

*T1h = 360 * (abs(sqrt(3) * Vref * sin((pi/3) - alpha + (n - 1) * pi/3))) / Vdc ;
*T2h = 360 * (abs(sqrt(3) * Vref * sin(alpha - (n - 1) * pi / 3) )) / Vdc ;
*T0h = 360  - *T1h - *T2h;

return;
}

void switch_state (int voltage_vector, bool* aTh, bool* bTh, bool* cTh) {

if (voltage_vector == 0) {
*aTh = 0; *bTh = 0; *cTh = 0;
}
else if (voltage_vector == 1) {
*aTh = 1; *bTh = 0; *cTh = 0;
}
else if (voltage_vector == 2) {
*aTh = 1; *bTh = 1; *cTh = 0;
}
else if ( voltage_vector == 3) {
*aTh = 0; *bTh = 1; *cTh = 0;
}
else if (voltage_vector == 4) {
*aTh = 0; *bTh = 1; *cTh = 1;
}
else if (voltage_vector == 5) {
*aTh = 0; *bTh = 0; *cTh = 1;
}
else if (voltage_vector == 6) {
*aTh = 1; *bTh = 0; *cTh = 1;
}
else if (voltage_vector == 7) {
*aTh = 1; *bTh = 1; *cTh = 1;
}

return;
}

void operation(bool aT, bool bT, bool cT) {

if (aT == 1) {
PORTG ^= (1 << switch_a_top);
PORTB &= ~(1 << switch_a_bot);

}
else {
PORTG &= ~(1 << switch_a_top);
PORTB |= (1 << switch_a_bot);

}
if (bT == 1) {

PORTH |= (1 << switch_b_top);
PORTB &= ~(1 << switch_b_bot);
}
else
{
PORTH &= ~(1 << switch_b_top);
PORTB |= (1 << switch_b_bot);
}
if (cT == 1)
{
PORTE |= (1 << switch_c_top);
PORTD &= ~(1 << switch_c_bot);
}
else
{
PORTE &= ~(1 << switch_c_top);
PORTD |= (1 << switch_c_bot);
}
}

////////////////////////////////////////////////////////////////////////////////////////

void setup() {

DDRG |= (1 << switch_a_top);
DDRB |= (1 << switch_a_bot);
DDRH |= (1 << switch_b_top);
DDRB |= (1 << switch_b_bot);
DDRE |= (1 << switch_c_top);
DDRD |= (1 << switch_c_bot);

TCCR1A = 0;// reset timer/counter 1 control register A

//set CTC
TCCR1B &= ~(1 << WGM13);
TCCR1B |= (1 << WGM12);

//set prescaler to no prescaler
TCCR1B &= ~(1 << CS12);
TCCR1B &= ~(1 << CS11);
TCCR1B |= (1 << CS10);

//reset timer 1 & set compare value
OCR1A = t1_comp;
// put your setup code here, to run once:

//enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);

//enable global interrupts
sei();

}

void loop() {
}

}
``````

// exceeded max 9000 characters
//to be continued…

``````ISR(TIMER1_COMPA_vect) {
bool aT, aB, bT, bB, cT, cB;
for (int j = 0; j < 360; j=j+1) {
t = j / 60.0 / 360;
alpha = 2.0 * pi * j / 360.0;
if ((j >= 0) && (j <= 30)) { //0,20
sector = 1;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v = v + 1) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(2.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1))    {
switch_state(1.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0 + T1) && (v < Ts))  {
switch_state(2.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 30) && (j <= 60)) {//40-60
sector = 2;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(1.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 60) && (j <= 90)) {//80
sector = 3;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1)) {
switch_state(2, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2 + T1) && (v < Ts)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 90) && (j <= 120)) {//100-120
sector = 4;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(2, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(2, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 120) && (j <= 150)) {//140
sector = 5;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2 + T1) && (v < Ts)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
``````

// exceeded max 9000 characters
//to be continued…

``````else if ((j > 150) && (j <= 180)) {//160 180
sector = 6;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(3, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 180) && (j <= 210)) { //200
sector = 7;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2 + T1) && (v < Ts)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 210) && (j <= 240)) {//220 240
sector = 8;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(4, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 240) && (j <= 270)) {// 260
sector = 9;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2 + T1) && (v < Ts)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 270) && (j <= 300)) {//280 300
sector = 10;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(5.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 300) && (j <= 330)) {//320
sector = 11;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(1.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0) && (v < T0 + T2 / 2.0 + T1)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T2 / 2.0 + T1) && (v < Ts)) {
switch_state(1.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
else if ((j > 330) && (j <= 360)) {//340 360
sector = 12;
vector_time(Vdc, Vref, Ts, alpha, sector, &T1, &T2, &T0);
for (v = 0; v < 360; v++) {
if ((v >= 0) && (v < T0)) {
switch_state(7.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0) && (v < T0 + T1 / 2.0)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0) && (v < T0 + T1 / 2.0 + T2)) {
switch_state(1.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
else if ((v >= T0 + T1 / 2.0 + T2) && (v < Ts)) {
switch_state(6.0, &aT, &bT, &cT);
operation(aT, bT, cT);
}
}
}
}
``````

I have produce the signal but the timing is off. It is suppose to loop every16.667mS but it loops more than a second. I tried to vary the output compare timer but it does not help. My guess is that my for loop statements takes too many clock cycles. I want to avoid for loop as much as possible without losing the integrity of the code. Is there a way to better program this?

This is the result I obtained

As you can see, the period is 20s. I needed the output to be like this

With a period of 16.67mS

The Essentially, you aren’t going to be able to do those sorts of calculations “live” - floating point math is much too slow on the avr. Pre-calculate an array of switch times in setup (or even make a static table at compile time) and have your ISR do little more than lookup and configure the next timeout.

Hi,
Are you trying to generate a modulated PWM to produce a 60Hz sinewave for a SineWave Inverter?

The top waveform repeats every 10ms corrseponding to 20ms waveform for 50Hz.

The bottom waveform repeats every 16.667/2 = 8.333 ms

Tom....

Yes Sir, I am trying to generate a 60Hz sinusoid. Although I am using a type of space vector approach. My problem is the long delay time. The accumulated delay can take seconds.

I wish to reduce my programming to eliminate unnecessary clock cycles.

How do you pre-calculate an array of switch times or make a static table?

Is there any way to ommit for loops and be replaced by something with faster processing?

How do you pre-calculate an array of switch times or make a static table?

You take out a piece of paper and a pencil and you do all the math and then just put the answers into an array in your program so your code just has to look up the answer instead of calculating it.

Hi,

Tom....

Delta_G:
You take out a piece of paper and a pencil and you do all the math and then just put the answers into an array in your program so your code just has to look up the answer instead of calculating it.

I didn't more than glance at the OP code - it looks so like not how I would have done it, but then I'm not doing it.

A table is the way to go, yes. Rather than limbering up your slide rule and sharpening some pencils, just take the code you have, and repurpose it to write the table for you!

I do this as it has been proven I am no longer capable of doing such with any consistent accuracy. That's what computers are for. Often I am putting a table where there was a function - the function can be used to write the table, then the original function call becomes an array reference.

Also - plenty of space, tables that are read-only like this go into PROGMEM.

a7

Delta_G:
You take out a piece of paper and a pencil and you do all the math and then just put the answers into an array in your program so your code just has to look up the answer instead of calculating it.

Sir, I tried that however if I put it on array, I will have about 360x360x60 elements or more. This will require a lot of memory.

TomGeorge:
Hi,

How to generate a sine wave from arduino or atmega 328 | eprojectszone

Tom....

Sir, I have encountered this site and is one of the reference for this idea. This uses some kind of a half wave sine triangle carrier approach using duty cycles however I needed it to advance further so I developed this code. This is for a project.

alto777:
I didn't more than glance at the OP code - it looks so like not how I would have done it, but then I'm not doing it.

A table is the way to go, yes. Rather than limbering up your slide rule and sharpening some pencils, just take the code you have, and repurpose it to write the table for you!

I do this as it has been proven I am no longer capable of doing such with any consistent accuracy. That's what computers are for. Often I am putting a table where there was a function - the function can be used to write the table, then the original function call becomes an array reference.

Also - plenty of space, tables that are read-only like this go into PROGMEM.

a7

Sir, I am going to try this approach if I can. I have just some worries such as: will the fetch and decode cause more delay? By generating a table, will it require more memory? I have used the function so that I can hold only one value for that certain amount of time thereby saving space

Time and space, isn't it always a tradeoff?

I have to think there would (also) be some symmetries or other exploitable patterns to cut your table size dramatically.

a7

alto777:
Time and space, isn't it always a tradeoff?

And money.

Haha, sometimes… show me where I can buy a few more years!

Time, the merciless resource.

a7

I am working on a new program based on alto777's suggestion. I will try to update what results I get once i test it on an oscilloscope.

So i finish the program. this is a section of the code

``````const PROGMEM uint16_t t1[] = {45, 44, 42, .... 42, 4};

//....

Serial.print(t1[i]);
``````

however when I print it, i get different values such as 47130 for i = 0, 1, 2, 3

JAJSentina:
So i finish the program. this is a section of the code

const PROGMEM uint16_t t1 = {45, 44, 42, … 42, 4};

Serial.print(t1*);*
how ever when I print it, i get different values such as 47130 for t where i = 0, 1, 2…
[/quote]
Why do you wonder, that is expected.
Did you look at an example using PROGMEM tables?
Did you look at the documentation of PROGMEM related programming?
use
`*_ <em>*Serial.print(pgm_read_word(&t1[i]));*</em> _*`