No control over PWM max & deformed waveform

Hello all;

I need to have variable control over PWM maximum using a potentiometer (map AnalogRead function).
In the first version I have control over PWM but the wave form is distorted, it should be a perfect ramp wave (similar to a sawtooth). see pic.

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

#include <stdlib.h>
#include <avr/io.h>           // Adds useful constants


/// Define Variables ////

int pwmMin=30;               // minimum pwm voltage (0-255)
int basePwm=0;
int pwmMax;               // maximum pwm voltage (0-255)
int ramplength=15;            // us
int INTERVAL=30000;          // the repeat delay interval; ms.
int delayStartTime;
static uint32_t StartUs=micros();
static uint32_t StartMs=millis();
static uint8_t Pwm=0;

/// Define pins for ATTiny85  ///

volatile int outPin = 0;             // PhysicalPin 5; P0
int ledPin = 1;                      // PP 6; P1   
int pwmMaxPin = 1;                   // PP 7; P2           Sets Max Ramp hieght.
int ramplengthPin = 2;               // PP 3; P4           Sets Ramp length / Mark Time.
int intervalPin = 3;                 // PP 2; P3           Sets DeadTime inbetween Ramp signals.

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

void setup()
  {
    /*
    Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
    2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
    2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
    3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
    */
    TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
   
    /*
    Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
    0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
    1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
    */
    TCCR0B = 0<<WGM02 | 1<<CS00;
   
    /*
    Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
    TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
    0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
    0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
    1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
    */
    TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
   
    /*
    General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
    GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
    1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
    2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
    */
    GTCCR = 1<<PWM1B | 2<<COM1B0;
    
    pinMode(outPin, OUTPUT);
    pinMode(ledPin, OUTPUT); 
  }

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

void loop()
{   static int Dir=1;
   //static int8_t  Dir=1;
   if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    { 
     Pwm+=Dir;                          // Augment Pwm by Direction;
     analogWrite(ledPin, Pwm);          // Update LedPin;
          if(Pwm==pwmMin)               // if Pwm == pwmMin;
          {
            delay(200);                 // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);  // Squarewave rising edge start; 
            if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
            Dir=+1;                     // & start 'Ramp_Up';
          }  
     StartUs=micros();                  // reset micros to startmicros;
    }
  if(Pwm==basePwm) 
    { 
      delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
      delay(INTERVAL);           //delay *INTERVAL*
      delayStartTime = micros();
          do
          {
            INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
            pwmMax     = map(analogRead(pwmMaxPin),0,1023,160,255);                    // circuit layout & potentiomenters
            ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
          }
      while(micros()-delayStartTime<=INTERVAL);
    }
}

In the next versions of the code, it produces a 'double' ramp and only the first ramp is ajustable via mapAnalogread function: see pic.

void loop()
{
  static int8_t  Dir=1;
  if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
   { 
    Pwm+=Dir;                          // Augment Pwm by Direction;
    analogWrite(ledPin, Pwm);          // Update LedPin;
          if(Pwm==pwmMin)               // if Pwm == pwmMin;
          {
            delay(200);                 // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);  // Squarewave rising edge start; 
            for(int Pwm = basePwm ; Pwm <= pwmMax; Pwm +=Dir )  // & start 'Ramp_Up';
            analogWrite(ledPin, Pwm);           
            }  
    StartUs=micros();                  // reset micros to startmicros;
   }
  if(Pwm==basePwm) 
    { 
      delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
      delay(INTERVAL);           //delay *INTERVAL*
      delayStartTime = micros();
          do
          {
            INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
            pwmMax     = map(analogRead(pwmMaxPin),0,1023,60,255);                    // circuit layout & potentiomenters
            ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
          }
      while(micros()-delayStartTime<=INTERVAL);
       
    }
}

In the last version, I tried to link the pwmMax map AnalogRead function to the 'Dir' variable, but it does not respond. see pic.

void loop()
{
  static int8_t  Dir=1;
  if((micros()-StartUs) >= ramplength)   // Control ramplength variable;
   { 
    Pwm+=Dir;                            // Augment Pwm by Direction;
    analogWrite(ledPin, Pwm);            // Update LedPin;
          if(Pwm==pwmMin)                // if Pwm == pwmMin;
          {
            delay(200);                  // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);   // Squarewave rising edge start; 
            if(pwmMin <= Pwm <= pwmMax);
            Pwm+=Dir;                    // & start 'Ramp_Up';
           }  
     StartUs=micros();                   // reset micros to startmicros;
    }
  if(Pwm==basePwm) 
    { 
      delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
      delay(INTERVAL);           //delay *INTERVAL*
      delayStartTime = micros();
          do
          {
            INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
            pwmMax     = map(analogRead(pwmMaxPin),0,1023,60,255);                    // circuit layout & potentiomenters
            ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
          }
      while(micros()-delayStartTime<=INTERVAL);
    }
}

I know that there is some fundamental mistake I am making with this.
Any comment would be really appreciated to get this up and running.

Thanks in advance
lost_bro

(deleted)

spycatcher2k:
Not how PWM Works - I suggest you Google it - You could try a Low Pass Filter - this will convert the PWM to an analog voltage.

Good day spycatcher2k

My bad!

Should have explained with posting the entire program:

/*
This Sketch will generate a variable volatage ramp signal
simultaneous to a syncronized boxed square wave.
//----------------------------------------------------//
Output: PP 7; P2 of ATTiny85 to a 'Low Pass Filter'
Values of cap & resistor to be calculated according to
roll-off frequency appropriate for working PWM freq.

ARDUINO_ATTiny ---///--- | ---- INPUT COMPARATOR
|


|
|
GROUND

This will produce a nice voltage ramp/saw tooth waveform.
Can be made variable by substituting appropriate potentio-
meter for resistor.
*/
//////////////////////////////////

Please see:

/*
    This Sketch will generate a variable volatage ramp signal 
    simultaneous to a syncronized *boxed* square wave.
    //----------------------------------------------------//
    Output: PP 7; P2 of ATTiny85 to a 'Low Pass Filter'
    Values of cap & resistor to be calculated according to 
    roll-off frequency appropriate for working PWM freq. 

    ARDUINO_ATTiny ---/\/\/\--- | ---- INPUT COMPARATOR
                              |
                             ---
                             ---
                              |
                              |
                            GROUND 
                           
   This will produce a *nice* voltage ramp/saw tooth waveform.
   Can be made *variable* by substituting appropriate potentio-
   meter for resistor.   
*/
//////////////////////////////////

#include <stdlib.h>
#include <avr/io.h>           // Adds useful constants


/// Define Variables ////

int pwmMin=30;               // minimum pwm voltage (0-255)
int basePwm=0;
int pwmMax;               // maximum pwm voltage (0-255)
int ramplength=15;            // us
int INTERVAL=30000;          // the repeat delay interval; ms.
int delayStartTime;
static uint32_t StartUs=micros();
static uint32_t StartMs=millis();
static uint8_t Pwm=0;

/// Define pins for ATTiny85  ///

volatile int outPin = 0;             // PhysicalPin 5; P0
int ledPin = 1;                      // PP 6; P1   
int pwmMaxPin = 1;                   // PP 7; P2           Sets Max Ramp hieght.
int ramplengthPin = 2;               // PP 3; P4           Sets Ramp length / Mark Time.
int intervalPin = 3;                 // PP 2; P3           Sets DeadTime inbetween Ramp signals.

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

void setup()
  {
    /*
    Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
    2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
    2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
    3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
    */
    TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
   
    /*
    Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
    0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
    1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
    */
    TCCR0B = 0<<WGM02 | 1<<CS00;
   
    /*
    Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
    TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
    0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
    0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
    1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
    */
    TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
   
    /*
    General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
    GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
    1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
    2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
    */
    GTCCR = 1<<PWM1B | 2<<COM1B0;
    
    pinMode(outPin, OUTPUT);
    pinMode(ledPin, OUTPUT); 
  }

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

void loop()
{   static int Dir=1;
   //static int8_t  Dir=1;
   if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    { 
     Pwm+=Dir;                          // Augment Pwm by Direction;
     analogWrite(ledPin, Pwm);          // Update LedPin;
          if(Pwm==pwmMin)               // if Pwm == pwmMin;
          {
            delay(200);                 // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);  // Squarewave rising edge start; 
            if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
            Dir=+1;                     // & start 'Ramp_Up';
          }  
     StartUs=micros();                  // reset micros to startmicros;
    }
  if(Pwm==basePwm) 
    { 
      delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
      delay(INTERVAL);           //delay *INTERVAL*
      delayStartTime = micros();
          do
          {
            INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
            pwmMax     = map(analogRead(pwmMaxPin),0,1023,160,255);                    // circuit layout & potentiomenters
            ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
          }
      while(micros()-delayStartTime<=INTERVAL);
    }
}

Actually I do use a first order low pass filter, and I do know how pwm works......

My question is in relation to the map Analog Read function NOT 'linking' to the 'pwmMax' variable in the code.

I have a very nice 'Ramp' wave output and it is exactly as I need the waveform for my 'LinearRampBuck Converter'.

Thanks
mjd

Is this just a continuation of the other thread you had? Some new issues popped up? How did your nice waveform at the end of that thread turn into these bizarre creatures? That's some weird glitching I'm seeing.

I'll have a lot of things to type up about this once I get home from work, I just need to point this out.

if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???

"Das ist nicht nur nicht richtig, es ist nicht einmal falsch!"

Jiggy-Ninja:
Is this just a continuation of the other thread you had? Some new issues popped up? How did your nice waveform at the end of that thread turn into these bizarre creatures? That's some weird glitching I'm seeing.

I'll have a lot of things to type up about this once I get home from work, I just need to point this out.

if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???

"Das ist nicht nur nicht richtig, es ist nicht einmal falsch!"

Good day Jiggy-Ninja

Thanks for taking the time to answer:

Is this just a continuation of the other thread you had?

No, I experimented with the last waveform and apparently 'triangle waveform' has an issue that was not contemplated: that is the 'falling edge' of the waveform.

The output from the Attiny85, ie; rampwave is the 'input' to a liner buck converter.
This input must be a linear ramp and the triangle waveform does this just fine, the downside (pardon the pun) is the falling edge of the triangle waveform. The linear buck converter will output into an open load at the IGBT full bridge and the bridge is prone to HV failure at this point (magic smoke escapes). This is because the 'blue square wave' which is generated concurrently to the 'ramp' is used the signal on & off the IGBT bridge. Since I'm trying to mimic a 'staccato controller' I tried to switch off the the IGBT bridge at the apex, but now realize that it must switch off when the waveform is diminishing, but the majority of the waveform should be a positive going ramp to keep with the original idea, so I changed the code to kill the ramp at the apex and fall to 'basePwm' and at that moment switch off the buck converter via the concurrent squarewave.

so..... I now understand the necessity for the 'saw tooth' type waveform, being that the majority of the waveform is a positive going ramp and (see attached pic. neededwaveform_pwm_adjustnotworking) to avoid blowing the IGBT full bridge, I am now switching off at about pwmMin which is adjustable in the program and set to about 40-60volts at the bridge.

To answer the question: this is the same project (linear ramp buck converter) but I must modify the code to continue.

How did your nice waveform at the end of that thread turn into these bizarre creatures?

For the same reason, that I tried to make a sawtooth type 'adjustable' waveform and as you can see, from the three different versions that I attached, none gives exactly what I need.

I'll have a lot of things to type up about this once I get home from work, I just need to point this out.
** **if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???[/b]** **
This statement is from the ONLY version that has ALL three variables working, but the ramp is now a hunchback instead of a ramp. I realize that the pwmMax variable was not 'linked' to the 'Dir+=1' statement. I tried to link the to two together by introducing some type of statement in the loop.
You can see from the other versions, that I tried more appropriate code, and I know that that code does not do anything, but it does make the pwmMax work, albiet a very deformed waveform.
and yes, you are correct! That's not only not right, it is not even wrong! I think that's like a triple negative or something :slight_smile:
Anyway, I changed the triangle code by eliminating the 'Dir=-1' for the down ramp of the triangle, letting the ramp return to 'basePwm' at the end of the 'ramplength' loop.
when I used for(int Pwm = basePwm ; Pwm <= pwmMax; Pwm +=Dir ) // & start 'Ramp_Up';
** The ramp then produced a 'double ramp' with the first ramp being adjustable by map AnalogRead function...... The effect was to achieve some type of linking of the pwmMax and Pwm+=dir function.**
I've managed to generate some really wierd waveforms that might be useful in another project someday, but I really need to know how to make the adjustable 'sawtooth' waveform in the attached pic.
P.S. the small increase in pwm voltage which is seen at the very start of the ramp waveform is NOT a deformity, it is the 'warm up' period for the buck converter before the IGBT bridge kicks on.
see pic :o
Thanks again for taking the time.......
take care, peace
lost_bro

Why can't you just make the program cycle between states for each portion of the waveform
and calculate the output directly from the time (since start of state) mathematically? Each
state has its own rule for generating output voltage, code each in a separate function for
maximum clarity and flexibility.

MarkT:
Why can't you just make the program cycle between states for each portion of the waveform
and calculate the output directly from the time (since start of state) mathematically? Each
state has its own rule for generating output voltage, code each in a separate function for
maximum clarity and flexibility.

Good day MarkT

Not sure if I understand you correctly: I am using if((micros()-StartUs) >= ramplength) to time each part of my waveform as it moves thru the loop.

I have already produced the waveform that is required for the project with the above code.

I attached the above versions of the code to show my lack of progress with the map AnalogRead function[/i] via pwmMax variable and how it is NOT responding to the analog input.

The problem is ONLY how to get the map AnalogRead function via pwmMax variable linked to the loop so I can use the potentiometer to control the ramp height.

I already have a variable ramp length and a variable deadtime between ramps via potentiometers & map AnalogRead.

Maybe I missed the point of your post, sorry.

Thanks
take care, peace
lost_bro

P.S. I am using an ATTiny85 so I have limited ram and need to make the code as streamline as possible, so far the code only consumes about 34%.

My question is in relation to the map Analog Read function NOT 'linking' to the 'pwmMax' variable in the code.

I am new to your threads, and may not be understanding, but try this

if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    { 
     Pwm+=Dir;// Augment Pwm by Direction;

     if (Pwm == pwmMax)//add this will check pot
     {Pwm = basePwm;}//add this will check pot

     analogWrite(ledPin, Pwm);          // Update LedPin;
          if(Pwm==pwmMin)               // if Pwm == pwmMin;
          {
            delay(200);                 // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);  // Squarewave rising edge start; 
           // if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
           // Dir=+1; // & start 'Ramp_Up';
          
          }  
     StartUs=micros();                  // reset micros to startmicros;
    }

Get rid of

// if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
           // Dir=+1; // & start 'Ramp_Up';

cattledog:
I am new to your threads, and may not be understanding, but try this

if((micros()-StartUs) >= ramplength)  // Control ramplength variable;

{
    Pwm+=Dir;// Augment Pwm by Direction;

if (Pwm == pwmMax)//add this will check pot
    {Pwm = basePwm;}//add this will check pot

analogWrite(ledPin, Pwm);          // Update LedPin;
         if(Pwm==pwmMin)               // if Pwm == pwmMin;
         {
           delay(200);                 // Buck-converer warm-up;
           digitalWrite(outPin,HIGH);  // Squarewave rising edge start;
          // if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
          // Dir=+1; // & start 'Ramp_Up';
         
         }  
    StartUs=micros();                  // reset micros to startmicros;
   }




Get rid of


// if(Pwm=pwmMax) Pwm==pwmMax; // I know this is NOT correct, but it gives some results???
          // Dir=+1; // & start 'Ramp_Up';

Good evening cattledog

OK, ran two versions of your suggested code:

 if((micros()-StartUs) >= ramplength)   // Control ramplength variable;
   { 
    Pwm+=Dir;                            // Augment Pwm by Direction;
    analogWrite(ledPin, Pwm);            // Update LedPin;
          if(Pwm==pwmMin)                // if Pwm == pwmMin;
          {
            delay(200);                  // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);   // Squarewave rising edge start; 
            if (Pwm == pwmMax)             //add this will check pot
            { 
              Pwm = basePwm;               //add this will check pot
            }
          } 
     StartUs=micros();

This version produces the desired waveform, but the ramp height does NOT respond to the map AnalogRead function: see pic.

and..... this version:

 if((micros()-StartUs) >= ramplength)   // Control ramplength variable;
   { 
    Pwm+=Dir;                            // Augment Pwm by Direction;
    analogWrite(ledPin, Pwm);            // Update LedPin;
          if(Pwm==pwmMin)                // if Pwm == pwmMin;
          {
            delay(200);                  // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);   // Squarewave rising edge start; 
          }
           if (Pwm == pwmMax)             //add this will check pot
            { 
              Pwm = basePwm;               //add this will check pot
            }
     StartUs=micros()

.....which gives an adjustable inverted ramp waveform.

so, I am confused as to what is happening now, because your code does seem logical......
see pic. :o

Open for further suggestions.
Thanks
take care, peace
lost_bro

I've rearranged your loop() function a little and removed some crap. Let me know how this works:

void loop()
   if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    {
		StartUs += ramplength;
     Pwm+=1;                          // Augment Pwm by Direction;
     analogWrite(ledPin, Pwm);          // Update LedPin;
          if(Pwm==pwmMin)               // if Pwm == pwmMin;
          {
            delay(200);                 // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);  // Squarewave rising edge start;                    // & start 'Ramp_Up';
			StartUs = micros();  // reset ramp interval after delay.
          }  
    }
  if(Pwm==pwmMax)
    {
		Pwm=basePwm;
      analogWrite(ledPin, Pwm);
      delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
      delay(INTERVAL);           //delay *INTERVAL*

            INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
            pwmMax     = map(analogRead(pwmMaxPin),0,1023,160,255);                    // circuit layout & potentiomenters
            ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
      StartUs = micros(); // reset ramp interval after delay.
    }
}

Also, initialize pwmMax to something when you declare it, don't just leave it at 0.

Jiggy-Ninja:
I've rearranged your loop() function a little and removed some crap. Let me know how this works:

void loop()

if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
   {
StartUs += ramplength;
    Pwm+=1;                          // Augment Pwm by Direction;
    analogWrite(ledPin, Pwm);          // Update LedPin;
         if(Pwm==pwmMin)               // if Pwm == pwmMin;
         {
           delay(200);                 // Buck-converer warm-up;
           digitalWrite(outPin,HIGH);  // Squarewave rising edge start;                    // & start 'Ramp_Up';
StartUs = micros();  // reset ramp interval after delay.
         }  
   }
 if(Pwm==pwmMax)
   {
Pwm=basePwm;
     analogWrite(ledPin, Pwm);
     delayMicroseconds(1000);   //Squarewave falling edge delay (buck-converter);
     digitalWrite(outPin,LOW);  //Squarewave falling edge trigger;
     delay(INTERVAL);           //delay INTERVAL

INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
           pwmMax     = map(analogRead(pwmMaxPin),0,1023,160,255);                    // circuit layout & potentiomenters
           ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     //5800=24ms          // adjust map for packetcount
     StartUs = micros(); // reset ramp interval after delay.
   }
}



Also, initialize pwmMax to something when you declare it, don't just leave it at 0.

Good Day Jiggy-Ninja

Excellent job with the analysis....... you were spot on with mods to the code!

Thanks :slight_smile:

This is what I finally ended up running:

void loop()
{
   if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    {
     StartUs += ramplength;
     Pwm += 1;                           // Augment Pwm by Direction;
     analogWrite(ledPin, Pwm);           // Update LedPin;
          if(Pwm == pwmMin)              // if Pwm == pwmMin;
          {
            delay(200);                  // Buck-converer warm-up;
            digitalWrite(outPin,HIGH);   // Squarewave rising edge start;                    // & start 'Ramp_Up';
    StartUs = micros();          // reset ramp interval after delay.
          }  
    }
  if(Pwm == pwmMax)                      // if Pwm at pwmMax;
  
    {
      Pwm = basePwm;                    // Pwm falls to basePwm;
      analogWrite(ledPin, Pwm);
      delayMicroseconds(1000);          //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);          //Squarewave falling edge trigger;
      delay(INTERVAL);                    //delay *INTERVAL*
      INTERVAL   = map(analogRead(intervalPin),0,1023,5590,50000);       // adjust all maps according to
      pwmMax     = map(analogRead(pwmMaxPin),0,1023,60,255);           // circuit layout & 
      ramplength = map(analogRead(ramplengthPin),0,1023,1450,5800);    // ramplength input pot.
      StartMs = millis();               // reset interval after delay.
    }
}

The code will now control all three variables via the pots.

I checked your mods against my last iteration and found the fatal error:

void loop()
{
   
    if((micros()- StartUs) >= ramplength)   // Control ramplength variable;
    { 
      Pwm += 1;                                     // Augment Pwm by Direction;
      analogWrite(ledPin, Pwm);                // Update LedPin;
        if(Pwm == pwmMin)                     // if Pwm == pwmMin;
        {
          delay(200);                               // Buck-converer warm-up;
          digitalWrite(outPin,HIGH);            // Squarewave rising edge start; 
        } 
      StartUs = micros();                        // reset micros to startmicros;
    }
    if(Pwm == pwmMax)                               // this will check pot
    {                                                         //When Pwm hits 'pwmMax' then
      Pwm = basePwm;                                // ramp falls to 'basePwm';
    *********  MISSING THE ANALOGWRITE(LEDPIN, PWM);*****************
      delayMicroseconds(1000);                     //Squarewave falling edge delay (buck-converter);
      digitalWrite(outPin,LOW);                     //Squarewave falling edge trigger;
      delay(INTERVAL);                                //delay *INTERVAL*
      delayStartTime = micros();
        do
        {
          INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);     // adjust all maps according to
          pwmMax     = map(analogRead(pwmMaxPin),0,1023,60,255);        // circuit layout & 
          ramplength = map(analogRead(ramplengthPin),0,1023,377,5800);     
        }
      while(micros()- delayStartTime <= INTERVAL);
    }
}

The code was missing the analogWrite(ledPin, Pwm); immediately following the Pwm=basePwm call.

Without the analogwrite function, the ramp wave never returns to pwmBase which is equal to Zero, so it always stays HIGH and gives an inverted type waveform.

Now that all three potentiometers are functional, I noticed that the INTERVAL delay is NOT in Milliseconds.

It should be in Millis because the code uses the delay() function which should be in millis.

As of now the largest delay(INTERVAL) obtainable as seen on the scope is about 1.9Hz or about 526ms.
The problem is that the code is using INTERVAL = map(analogRead(intervalPin),0,1023,800,50000); which seems to me to be really large numbers.

If INTERVAL was in millis should it not be represented as such in the map analogRead function?

My concern is that I want to take the bps rate down to about .5Hz or about 2000millis for INTERVAL.
Do I need to link or make another statement in the loop to define INTERVAL units as millis?
Or is it recommended to instate a if((millis()-Startmillis) >= INTERVAL) function to linkINTERVAL to millis?

I really appreciate the assistance with this project, I thinks it's been a great learning experience so far.

take care, peace
lost_bro

int INTERVAL=30000;          // the repeat delay interval; ms.

Type interval long as you are mapping up to 50000 and you will get rollover.

If this doesn't work, please post your latest code with the declarations and setup as well as loop.

cattledog:

int INTERVAL=30000;          // the repeat delay interval; ms.

Type interval long as you are mapping up to 50000 and you will get rollover.

If this doesn't work, please post your latest code with the declarations and setup as well as loop.

Good day cattledog

Thanks for the response:

OK, just ran the code again, here are the results:

INTERVAL = map(analogRead(intervalPin),0,1023,5590,10000); gives 157ms
INTERVAL = map(analogRead(intervalPin),0,1023,5590,20000); gives 230ms
INTERVAL = map(analogRead(intervalPin),0,1023,5590,50000); gives 580-720ms

I tried with both unsigned long int INTERVAL=500; && long int INTERVAL=500; both giving the same results.

Here is the code:

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

#include <stdlib.h>
#include <avr/io.h>                // Adds useful constants

/// Define Variables ////

int pwmMin=30;                    // Pwm limit during Buck Converter Warm up period;
int basePwm=0;                    // Pwm limit during INTERVAL (ramp off);
int pwmMax=0;                     // maximum Ramp Pwm voltage (0-255)
int ramplength=15;                // us
unsigned long int INTERVAL=500;   
//long int INTERVAL=500;       // delay interval (ramp off); ms.
static uint32_t StartUs=micros();
static uint32_t StartMs=millis();
static uint8_t Pwm=0;

/// Define pins for ATTiny85  ///

volatile int outPin = 0;             // PhysicalPin 5; P0
int ledPin = 1;                      // PP 6; P1   
int pwmMaxPin = 1;                   // PP 7; P2           Sets Max Ramp hieght.
int ramplengthPin = 2;               // PP 3; P4           Sets Ramp length / Mark Time.
int intervalPin = 3;                 // PP 2; P3           Sets DeadTime inbetween Ramp signals.

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

void setup()
  {
    /*
    Control Register A for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0A is 8 bits: [COM0A1:COM0A0:COM0B1:COM0B0:unused:unused:WGM01:WGM00]
    2<<COM0A0: sets bits COM0A0 and COM0A1, which (in Fast PWM mode) clears OC0A on compare-match, and sets OC0A at BOTTOM
    2<<COM0B0: sets bits COM0B0 and COM0B1, which (in Fast PWM mode) clears OC0B on compare-match, and sets OC0B at BOTTOM
    3<<WGM00: sets bits WGM00 and WGM01, which (when combined with WGM02 from TCCR0B below) enables Fast PWM mode
    */
    TCCR0A = 2<<COM0A0 | 2<<COM0B0 | 3<<WGM00;
   
    /*
    Control Register B for Timer/Counter-0 (Timer/Counter-0 is configured using two registers: A and B)
    TCCR0B is 8 bits: [FOC0A:FOC0B:unused:unused:WGM02:CS02:CS01:CS00]
    0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode
    1<<CS00: sets bits CS01 (leaving CS01 and CS02 clear), which tells Timer/Counter-0 to not use a prescalar
    */
    TCCR0B = 0<<WGM02 | 1<<CS00;
   
    /*
    Control Register for Timer/Counter-1 (Timer/Counter-1 is configured with just one register: this one)
    TCCR1 is 8 bits: [CTC1:PWM1A:COM1A1:COM1A0:CS13:CS12:CS11:CS10]
    0<<PWM1A: bit PWM1A remains clear, which prevents Timer/Counter-1 from using pin OC1A (which is shared with OC0B)
    0<<COM1A0: bits COM1A0 and COM1A1 remain clear, which also prevents Timer/Counter-1 from using pin OC1A (see PWM1A above)
    1<<CS10: sets bit CS11 which tells Timer/Counter-1  to not use a prescalar
    */
    TCCR1 = 0<<PWM1A | 0<<COM1A0 | 1<<CS10;
   
    /*
    General Control Register for Timer/Counter-1 (this is for Timer/Counter-1 and is a poorly named register)
    GTCCR is 8 bits: [TSM:PWM1B:COM1B1:COM1B0:FOC1B:FOC1A:PSR1:PSR0]
    1<<PWM1B: sets bit PWM1B which enables the use of OC1B (since we disabled using OC1A in TCCR1)
    2<<COM1B0: sets bit COM1B1 and leaves COM1B0 clear, which (when in PWM mode) clears OC1B on compare-match, and sets at BOTTOM
    */
    GTCCR = 1<<PWM1B | 2<<COM1B0;
    
    pinMode(outPin, OUTPUT);
    pinMode(ledPin, OUTPUT); 
  }

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

void loop()
{
   if((micros()-StartUs) >= ramplength)  // Control ramplength variable;
    {
     StartUs += ramplength;
     Pwm += 1;                           // Augment Pwm by Direction;
     analogWrite(ledPin, Pwm);           // Update LedPin;
          if(Pwm == pwmMin)              // if Pwm == pwmMin;
          {
            delay(200);                  // Buck-converter warm-up;
            digitalWrite(outPin,HIGH);   // Squarewave rising edge start;                    // & start 'Ramp_Up';
	    StartUs = micros();          // reset ramp interval after delay.
          }  
    }
   if(Pwm == pwmMax)                      // if Pwm at pwmMax;
     {
        Pwm = basePwm;                    // Pwm falls to basePwm;
        analogWrite(ledPin, Pwm);         // Update LedPin;
        delayMicroseconds(1000);          //Squarewave falling edge delay (buck-converter);
        digitalWrite(outPin,LOW);         //Squarewave falling edge trigger;
        delay(INTERVAL);                  //delay *INTERVAL*
        INTERVAL   = map(analogRead(intervalPin),0,1023,5590,10000);     // adjust all maps according to
        pwmMax     = map(analogRead(pwmMaxPin),0,1023,60,255);           // circuit layout & potentiomenters
        ramplength = map(analogRead(ramplengthPin),0,1023,1450,5800);    // ramplength input pot.
        StartMs = millis();               // reset interval after delay.
    }
}

Thanks
take care, peace
lost_bro

EDIT: OK, the code uses a fast timer option in the void setup(). Is this the issue?

"0<<WGM02: bit WGM02 remains clear, which (when combined with WGM00 and WGM01 from TCCR0A above) enables Fast PWM mode"

EDIT*2: Also tried *long INTERVAL=500; * same results.

I am not very familiar with the ATTiny 85, the core used to run it with the Arduino IDE, and the timer set up. You have also not said what CPU frequency you are using.

That said, I think that the millis() function is expecting Timer0 to have an overflow at 1024 micros seconds which is set by a prescaler of 64 at 16Mhz. I think micros() is also broken by the same factor, but delayMicroseconds() uses a different method.

For your pwm, you have set Timer0 for no prescaler. Very simply you can try adjusting(multiplying) all your timing values by 64 and see if you are closer. Certainly 157 X 64 is close to 10000.

I have seen reference to switching the millis() function to Timer 1 on an ATTiny if you need to do that.

What pwm frequency do you need for your voltage ramp?

I am pretty certain that the timer changes for PWM have broken your standard timing functions, because when I adapt your sketch to run on a UNO with serial output to monitor what is happening, I can see that the INTERVAL between ramps is working, and it is close to how it is set.

cattledog:
I am not very familiar with the ATTiny 85, the core used to run it with the Arduino IDE, and the timer set up. You have also not said what CPU frequency you are using.

That said, I think that the millis() function is expecting Timer0 to have an overflow at 1024 micros seconds which is set by a prescaler of 64 at 16Mhz. I think micros() is also broken by the same factor, but delayMicroseconds() uses a different method.

For your pwm, you have set Timer0 for no prescaler. Very simply you can try adjusting(multiplying) all your timing values by 64 and see if you are closer. Certainly 157 X 64 is close to 10000.

I have seen reference to switching the millis() function to Timer 1 on an ATTiny if you need to do that.

What pwm frequency do you need for your voltage ramp?

I am pretty certain that the timer changes for PWM have broken your standard timing functions, because when I adapt your sketch to run on a UNO with serial output to monitor what is happening, I can see that the INTERVAL between ramps is working, and it is close to how it is set.

Hello cattledog;
Thanks for taking the time to answer:

OK, I am using the 1.5.8.IDE which is setup/optimized for the Digispark 16.5Mhz ATTiny85 board with onboard micronucleus.

I am using Chinese made knock-offs, and I am using it as it came, meaning that I did NOT burn the bootloader to set the fuses. I am programming with the micronucleus option from the IDE.

I ran a simple delay sketch to test the timing function with delay() and it scoped out to be 953us for 1 millisecond for this same ATTiny85. Pretty close, but that was NOT using the timer mods that are used in this current code.

So I believe the ATTiny85 I have is clocked at 16.5Mhz from the results of the other delay() test.

I would like to hear your suggestion on changing the millis() function to Timer 1. I wonder if that change will break my fast pwm?

I had to do the timer mod to get a fast enough PWM output in order to derive/filter a decent/smooth voltage ramp. I tried the code with the standard pwm and would not cut it. I don't remember now what the final value was, as I started this project about a year ago. I scope it tomorrow and report back with the frequency of the fast pwm.........

thanks
take care,peace
lost_bro

I ran a simple delay sketch to test the timing function with delay() and it scoped out to be 953us for 1 millisecond for this same ATTiny85. Pretty close, but that was NOT using the timer mods that are used in this current code.

What timing do you see when you run your simple delay sketch to test the timing function when you use the timer settings you are using in the current code?

lost_bro:
I ran a simple delay sketch to test the timing function with delay() and it scoped out to be 953us for 1 millisecond for this same ATTiny85. Pretty close, but that was NOT using the timer mods that are used in this current code.

So do it with the timing mods. There's no point to saying "It worked before I screwed around with it!", we need to know how it's working after you modified it.

The code news is that the fix is just to apply a constant scaling factor to the delay times, so to figure that out code your out pin for something like 1,000 ms on/1,000 ms off and use your scope to measure the actual pulse width. Say it measures something like 300 ms. The correction then is to take the ms you want for the delay and * 1000 / 300.

Jiggy-Ninja:
So do it with the timing mods. There's no point to saying "It worked before I screwed around with it!", we need to know how it's working after you modified it.

The code news is that the fix is just to apply a constant scaling factor to the delay times, so to figure that out code your out pin for something like 1,000 ms on/1,000 ms off and use your scope to measure the actual pulse width. Say it measures something like 300 ms. The correction then is to take the ms you want for the delay and * 1000 / 300.

Good day Jiggy-Ninja & cattledog

Thanks for taking the time to answer

Quite right!(as Supertramp used to say) It was 1:30 in the morning when I posted last..... too late to turn the lab back on :slight_smile:

Ok, ran a small sample of variable delays using delay() with the time mod for said code:

I know from a statistical standpoint the sample group is NOT large enough to be super precise maybe not even valid, but it will have to suffice for my purposes..........

Sample delays < delay(90000); gave a mean value when factored of 66.51.

Sample delays >= delay(100000); gave a mean value when factored of 1.1189.

Attached a few scope shots :o

So, delay(1000); gives 14.65ms; 14.65ms/1000ms=1.465% or required value;
then 1000*1000/14.65 = 68259.4(corrected value);

Which when placed in INTERVAL = map(analogRead (intervalPin),0,1023,5590,68260); gives 952ms (almost same number from delay() test without fast pwm mod. :slight_smile:

delay(100000); gives 88200ms then 88,200ms/100,000ms=88.2% of required value;
100,000*100,000/88,200.=113,379.(corrected value);

Which when placed in INTERVAL = map(analogRead (intervalPin),0,1023,5590,113379); gives 99940ms

Of course using time divisions sooooo large on scope really sacrifices accuracy.

Seems somewhere around a value of 90000-100000 the accuracy changes, becomes almost normal(ie: 88-91% of required value). I don't really understand why this happens :confused:

Also attached scope shots of fast Pwm.
As configured in the code runs @ 64-65Khz. max. for the unfiltered pwm ramp.

I would like to thank everyone that posted, I really appreciate all pointers and constructive criticism.

If I ever finish this project, I will come back here to this thread and post some pic.s

Thanks again to all.
take care, peace
lost_bro

EDIT;; did not post the correct scope shot of 100000ms, now replaced

Seems somewhere around a value of 90000-100000 the accuracy changes, becomes almost normal(ie: 88-91% of required value). I don't really understand why this happens :confused:

I don't see this, and interpret the data differently. I look at the dt reported in the scope image

delay 1000/actual delay 14.65ms = 68.2
delay5000/actual delay 74.80ms = 66.8
delay100000/actual delay 1470ms = 68.0

All three data points are close enough for the difference of scaling factor of 64 with the inherent accuracy of the internal clock.

cattledog:
I don't see this, and interpret the data differently. I look at the dt reported in the scope image

delay 1000/actual delay 14.65ms = 68.2
delay5000/actual delay 74.80ms = 66.8
delay100000/actual delay 1470ms = 68.0

All three data points are close enough for the difference of scaling factor of 64 with the inherent accuracy of the internal clock.

Good day cattledog;

Thanks for taking the time to answer:

Brain fart, I was doing tests to get 1-3 minute delays, and was thinking that the value was 1.47minutes;

1.47minute601000=88200ms

Yes, that scope shot is 1.47seconds not minutes as the other test I did.......
1.47seconds*1000ms = 1470ms

I need to have another coffee maybe :frowning:

Is there a way to set an internal prescalar and not affect the fast pwm?

Thanks
take care , peace
lost_bro