ATTiny85; order of magnitude loss of speed when enabling map AnalogRead function

Hello again.

Jiggy-Ninja:
Woot!
Hollah!
What?

Were you able to control the pulse height before? Because looking over you code it looks like it was malfunctioning from the start. It appears that your intention is to ramp up to pwmmax, reverse direction, then ramp down to pwmmin, then pause for the dead-time. But the scope traces you are posting show the ramp going all the way to Vcc then straight back down to 0. I think the problem's here:

Yes, I was able to control the height on a previous version of the code. I have probably 30 versions now saved in the IDE. It is NOT working in this version. In the version it worked in , I was substituting an 'int variable' and not using map AnalogRead function.

You are correct, It must ramp up as a sawtooth type wave form and then ramp down.

I will attach screen shots of the 'pwmMin' value working at 630mv float voltage.
The 'pwmMin' does work, just in the shots I posted it was set at pwmMin=0 so the float voltage is Zero.

Also you are correct that in these scope shots, the pwm ramp always goes to Max pwm value and does NOT follow the code to reset and drop down when it gets to the less than Max 'pwmMax' value.

thanks again

take care, peace
lost_bro

You are correct, It must ramp up as a sawtooth type wave form and then ramp down.

You're still being too ambiguous. Sawtooth waves do not ramp down, they have a hard edge. I know how to use an oscilloscope, so you don't need to post the same screenshots every time.

To avoid further confusion, give me a ONE word answer: Based on the picture I already posted above, do you want the wave to be a sawtooth or triangle? Don't tell me the shape it is making, tell me what you want it to make.

I can't help you further until I get a clear answer to that.

Yes, I was able to control the height on a previous version of the code. I have probably 30 versions now saved in the IDE. It is NOT working in this version. In the version it worked in , I was substituting an 'int variable' and not using map AnalogRead function.

FSM only knows how many things have been revised between that unspecified previous working version and this current one, I guess. One at a time I guess.

Jiggy-Ninja:
To avoid further confusion, give me a ONE word answer:

+1

I am losing the will to live with this Thread. There are too many words and too little information.

At this stage I cannot even figure where the OP has got to with his code (or is it better not to know?).

...R

It's not that bad. I've been able to make sense of most everything else, that's the only thing left that I wasn't able to understand.

lost_bro:
I will attach screen shots of the 'pwmMin' value working at 630mv float voltage.
The 'pwmMin' does work, just in the shots I posted it was set at pwmMin=0 so the float voltage is Zero.

When you're debugging something, don't just play around in the same range of values that make sense. You also can't only rely on making a few random changes to your parameters and seeing if that works. There is a place for that, but to be systematic about it you should be actively looking for edge cases, parameters that are unusual or extreme in some way, but still legal.

The first place to start is with your adjustable parameters. The limits for these parameters are defined in your map statements, so you test those limits out by commenting out the pot read statements and fixing each value to every combination of the maximum and minimum values. With 3 values, that's 8 combinations. Know before-hand exactly how the output is supposed to look for each, and hook the scope up to verify all 8 of the value combinations.

But don't do that yet. That will be for your final validation checks after we think everything is working. You have an issue where changing the pwmmax value does not change your waveform like it should. Focus on that first.

You might need to be a bit more creative when debugging a specific issue, but the basic premise is the same: don't just use ordinary, safe values, step outside the norm and use values that are unusual, but still legal.

I suspect the problem is that, because you are setting Dir to +2 immediately before incrementing Pwm every loop cycle, your code is ignoring Pwmmax and blowing past it, overflowing past the top of a uint8_t and going back to 0. It stops for the delay when it goes back up (not down) to Pwmmin.

To test this, fix INTERVAL and rampLength to some sensible values, them screenshot a scope trace with PWMmin set to 0 and mx set to 50. Take another trace with min set to 200 and max set to 255. Optionally, take third scope trace with min = 100 and max = 150. Since I'm suspecting overflow, the point of these debug tests is to get the pwm limits as far away from the limits of the integer type as possible, so if the value is straying outside that limit in some way, it becomes blindingly obvious.

For all the shots you post, be precise about how what you are seeing is different from what should be created. Use numbers that you expect to measure. Mathematical expressions of the relationships of the measurements are fine too, as long as you are precise about it. For the second one of the tests, it might be like "Ramp from pwmmin (about 4V) to pwmmax (5V) in x microseconds, then ramp down from max to min in the same amount of time. Hold the min voltage for INTERVAL milliseconds, then repeat the cycle." That is a properly precise description.

Hello Jiggy & Robin2
Sorry for being ambiguous.......

I have attached a mockup of the wanted two waveforms.

I appreciate the help.

I have made changes to the code.
I have attached the code.

I now have all three pots. working. :slight_smile:
This includes the pwmMax & pwmMin adjustment...... like I had it working in previous version.

but, now I have a triangle wave and the boxed square wave is NOT positioned properly.
Please see 'needed waveforms' pic.

I hope the 'needed waveform' pic will explain what I am trying to do.

Thanks again for your time and patience with me and my project.
take care, peace
lost_bro

/*
    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 pwmMax=255;               // maximum pwm voltage (0-255)
int ramplength=4;            // 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;
//static uint8_t Dir=1;

/// 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 uint8_t Dir=1;
 int static Dir=1;  
////// Increment/decrement PWM on ledPin with a period of 'x RampLength' in us. /////
  
  if((micros()-StartUs) >= ramplength)  //12=20ms; 8=14ms; 6=11ms; 5=ms; 1=3ms; OnTime of Ramp;
  
    {
   
    
    ////We arrived here every 'x ramplength' in microseconds////
    

        
        Pwm+=Dir;                                 //increment or decrement PWM depending of sign of Dir 
        
        analogWrite(ledPin, Pwm);                 //Update built-in LED
        
        if(Pwm==pwmMax) Dir=-1;                   //if PWM reaches the maximum: change direction 
        
        digitalWrite(outPin, HIGH);
        
        if(Pwm==pwmMin) 
                                                  //if PWM reaches the minimum://30=640mv float; 40=840mv float;
        {                                         // delay_ms(40)=36ms; (20)=20ms;
          digitalWrite(outPin, LOW);
          delay(INTERVAL);
          Dir=+1;                                 //delay *INTERVAL* & change direction 
          delayStartTime = micros();
              do
              {
                INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
                pwmMax     = map(analogRead(pwmMaxPin),0,1023,100,255);                    // circuit layout & potentiomenters
                ramplength = map(analogRead(ramplengthPin),0,1023,2,11800);               // adjust map for packetcount
              }
              while(micros()-delayStartTime<=INTERVAL);
                                                
        }                        
        //StartUs += ramplength;  //loose control of ramplengthPin & pwmMaxPin // only intervalPin works // with int Dir=2; min 4ms
                                //loose control of ramplengthPin  -- pwmMaxPin && intervalPin works  // with int static Dir=1; 
        
        StartUs=micros();         //loose control of pwmMaxPin // ramplenghtPin & intervalPin works      // with int Dir=2; min 4ms
  }                                 // All three work!!!! but....now Triangle wave!!!!!                   // with int static Dir=1; 
  
}

Good evening Jiggy-Ninja

Jiggy-Ninja:
To avoid further confusion, give me a ONE word answer: Based on the picture I already posted above, do you want the wave to be a sawtooth or triangle? Don't tell me the shape it is making, tell me what you want it to make.

To be precise, I would prefer the steeper dv/dt of the triangle wave for my experiment.

Please note that it is the superimposed position of the square wave which make the triangle or sawtooth wave useable for my purpose.

I am sorry for not explaining this earlier.

Please see the pic attached to previous post for a visual.
Take care, peace
lost_bro

Jiggy-Ninja:
It's not that bad. I've been able to make sense of most everything else, that's the only thing left that I wasn't able to understand.

I will happily leave it to you then.

...R

Jiggy-Ninja:
To avoid further confusion, give me a ONE word answer: Based on the picture I already posted above, do you want the wave to be a sawtooth or triangle? Don't tell me the shape it is making, tell me what you want it to make.

Good day Jiggy-Ninja

"Triangle",

Now I need to find the most efficient means to superimpose a 'squarewave' on top of the triangle wave.

The reason for the SquareWave is:

This is the digital 'High' signal that will activate the resonant feedback controller. During the marktime of the 'squarewave' the 'ramping edge' of the Triangle will be utilized by another circuit.

I hope this fills in the missing pieces so as not to confuse anyone.

I appreciate your suggestions, and will next change the micros() to millis() and test the actual timing as per your previous post.

Thanks
take care, peace
lost_bro

Jiggy-Ninja:
But don't do that yet. That will be for your final validation checks after we think everything is working. You have an issue where changing the pwmmax value does not change your waveform like it should. Focus on that first.

I suspect the problem is that, because you are setting Dir to +2 immediately before incrementing Pwm every loop cycle, your code is ignoring Pwmmax and blowing past it, overflowing past the top of a uint8_t and going back to 0. It stops for the delay when it goes back up (not down) to Pwmmin.

To test this, fix INTERVAL and rampLength to some sensible values, them screenshot a scope trace with PWMmin set to 0 and mx set to 50. Take another trace with min set to 200 and max set to 255. Optionally, take third scope trace with min = 100 and max = 150. Since I'm suspecting overflow, the point of these debug tests is to get the pwm limits as far away from the limits of the integer type as possible, so if the value is straying outside that limit in some way, it becomes blindingly obvious.

For all the shots you post, be precise about how what you are seeing is different from what should be created. Use numbers that you expect to measure. Mathematical expressions of the relationships of the measurements are fine too, as long as you are precise about it. For the second one of the tests, it might be like "Ramp from pwmmin (about 4V) to pwmmax (5V) in x microseconds, then ramp down from max to min in the same amount of time. Hold the min voltage for INTERVAL milliseconds, then repeat the cycle." That is a properly precise description.

Good day Jiggy-Ninja

Please see attached scope shots of the requested info. regarding pwmMin & pwmMax.
They are BOTH working and the values look to scale.

Thanks for the suggestion on that! :slight_smile:

take care, peace
lost_bro

Looks like some good progress has been made. what is left to fix?

Hello Jiggy-Ninja

First, thanks for all the great suggestions, yes we now have full control over the 'triangle waveform'.

What is the simplest code that can be used to 'superimpose' a square wave on top of only half of the triangle waveform?

I have attached a scope shot of the desired superimposed position of said squarewave.

It is the red color trace in the modified scope shot attached.

The project requires that only the rising edge be boxed by the squarewave.

I have tried various mod.s to get the squarewave to follow in sync with the triangle, but to no avail.

The only squarewave I can generate is the one in the screenshot, which spans both the rising & falling edges.

Let me know if I should start a new thread for this topic?

thanks
take care, peace
lost_bro

That's because you're setting it high on every increment up and down the ramp. You only need to set it high at the beginning of the ramp, and set it low again at the top.

You need to move your digitalWrite(out, HIGH); statement somewhere else in your loop. I'll let you have the fun of working out where.

Good day Jiggy-Ninja

Thanks for the advice:

I have modified the code again, and have made a minor advance, (I think).

Please see attached scope shot.

I am using the following code to turn off the square wave at the apex of the triangle wave:

ramplengthpause=(ramplength/3);
  if((Dir==-1) && (Dir != +1)) 
       {
         digitalWrite(outPin,LOW);
         delay(ramplengthpause);
       }

The result is seen in the same attached scope shot. The code will commence the square wave exactly where it should. :slight_smile:

And, the code will terminate the square wave at the apex.........

But.... simultaneous to the falling edge of the triangle wave, the code produces a fast pwm cycling (seen as the blue shaded area). Once pwmMin is reached, both waves seem to behave themselves.
If I can eliminate the fast pwm on the falling edge, then maybe I will have it working.

I also tried this code:

do
          {
            digitalWrite(outPin, LOW);
          }
            while((Dir==-1) && (Dir != +1));

It does not respond at all........

Here is the complete code as I ran it:

/*
    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 pwmMax=255;               // maximum pwm voltage (0-255)
int ramplength=4;            // us
int INTERVAL=30000;          // the repeat delay interval; ms.
int delayStartTime;
int rampDown;
int ramplengthpause;
static uint32_t StartUs=micros();
static uint32_t StartMs=millis();
static uint8_t Pwm=0;
//static uint8_t Dir=1;

/// 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()
{
  int static Dir=1; 
  digitalWrite(outPin,HIGH); 
  ramplengthpause=(ramplength/3);
  if((Dir==-1) && (Dir != +1)) 
       {
         digitalWrite(outPin,LOW);
         delay(ramplengthpause);
       }
  
  /*do
          {
            digitalWrite(outPin,LOW);
          }
            while((Dir==-1) && (Dir != +1));
  */
  if((micros()-StartUs) >= ramplength) 
      {                                           
        Pwm+=Dir;                 //increment or decrement PWM depending of sign of Dir 
        analogWrite(ledPin, Pwm); //Update built-in LED
        if(Pwm==pwmMax) Dir=-1;   //if PWM reaches the maximum: change direction 
       
       if(Pwm==pwmMin) 
        {                                         
          delay(INTERVAL);
          Dir=+1;                 //delay *INTERVAL* & change direction 
          delayStartTime = micros();
              do
              {
                INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
                pwmMax     = map(analogRead(pwmMaxPin),0,1023,100,255);                    // circuit layout & potentiomenters
                ramplength = map(analogRead(ramplengthPin),0,1023,2,11800);               // adjust map for packetcount
              }
              while(micros()-delayStartTime<=INTERVAL);
              
         }                        
          StartUs += ramplength;  //loose control of ramplengthPin & pwmMaxPin // only intervalPin works // with int Dir=2; min 4ms
                                  //loose control of ramplengthPin  -- pwmMaxPin && intervalPin works  // with int static Dir=1; 
         
        //StartUs=micros();         //loose control of pwmMaxPin // ramplenghtPin & intervalPin works      // with int Dir=2; min 4ms
  }                                 // All three work!!!! but....now Triangle wave!!!!!                   // with int static Dir=1; 
  
}

What am I missing?
What should I try next?

Thanks again for your time.
take care, peace
lost_bro

Hello Jiggy-Ninja

Well, spent a few more hours with this:

Now have two separate square waves / triangle wave, these square waves box BOTH the rising and falling edges...... :o See attached scope shot.

[code]
  if((micros()-StartUs) >= ramplength) 
      {                                           
        Pwm+=Dir;                 //increment or decrement PWM depending of sign of Dir 
        analogWrite(ledPin, Pwm); //Update built-in LED
        if(Pwm==pwmMax) Dir=-1;   //if PWM reaches the maximum: change direction 
        if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplength);
        }
        if(Pwm==pwmMin) 
        { 
          digitalWrite(outPin,LOW);          
          delay(INTERVAL);
          
          Dir=+1;                 //delay *INTERVAL* & change direction 
          delayStartTime = micros();
          
              do
              {
                INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
                pwmMax     = map(analogRead(pwmMaxPin),0,1023,100,255);                    // circuit layout & potentiomenters
                ramplength = map(analogRead(ramplengthPin),0,1023,2,11800);               // adjust map for packetcount
              }
              while(micros()-delayStartTime<=INTERVAL);
              
         }                        
          //StartUs += ramplength;  //loose control of ramplengthPin & pwmMaxPin // only intervalPin works // with int Dir=2; min 4ms
                                  //loose control of ramplengthPin  -- pwmMaxPin && intervalPin works  // with int static Dir=1; 
         
            StartUs=micros();         //loose control of pwmMaxPin // ramplenghtPin & intervalPin works      // with int Dir=2; min 4ms
  }                                 // All three work!!!! but....now Triangle wave!!!!!                   // with int static Dir=1;

[/code]

Guess this is progress, but not how I envisaged it.

Now the pot. input for variable ramplengthPin only controls the pwmMax plateau of the triangle wave, making it no longer a triangle but a flat top triangle wave.

This wave form may be useful in future experiments, but not what is needed now.

I know that I am making some basic mistake with the format of this program.
I feel that I am close to making this work, I would definitely appreciate any pointer in the proper direction to expedite the process.

Thanks again.
take care, peace
lost_bro

Your latest snippet does not have digitalWrite(outPin,HIGH);. If it's the same as the first sketch you posted, you moved it to the wrong spot. Now you're setting it high on each pass through loop, not just each increment up the ramp. That's the opposite of what you need to do. You need to write the pin less often, not more. Once per pulse, not once per loop.

        if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplength);
        }

Why are you delaying here? This is what is causing the triangle to turn into a trapezoid. You have the right idea writing the pin LOW here, just ditch the delay.

do
{
  digitalWrite(outPin, LOW);
} while((Dir==-1) && (Dir != +1));

Why did you try a do-while loop here? Since you don't change any of the variables in the condition inside the loop, it will either exit after one run or never exit. The second half of the && expression is also redundant; It is logically impossible for Dir to be equal to both -1 and +1, so the result is determined completely by the first half of the expression.

You are close. Home stretch.

Jiggy-Ninja:
Your latest snippet does not have digitalWrite(outPin,HIGH);. If it's the same as the first sketch you posted, you moved it to the wrong spot. Now you're setting it high on each pass through loop, not just each increment up the ramp. That's the opposite of what you need to do. You need to write the pin less often, not more. Once per pulse, not once per loop.

        if(Pwm==pwmMax)

{
          digitalWrite(outPin,LOW);
          delay(ramplength);
        }



**Why are you delaying here?** This is what is causing the triangle to turn into a trapezoid. You have the right idea writing the pin LOW here, just ditch the delay.



do
{
  digitalWrite(outPin, LOW);
} while((Dir==-1) && (Dir != +1));



**Why did you try a do-while loop here?** Since you don't change any of the variables in the condition inside the loop, it will either exit after one run or never exit. The second half of the && expression is also redundant; It is logically impossible for Dir to be equal to both -1 and +1, so the result is determined completely by the first half of the expression.

You are close. Home stretch.

Hello Jiggy-Ninja

Yes, the digitalWrite(outPin,HIGH); is in the same, wrong place. Actually I tried about every possible place in the program to place that statement to no avail. I've spent more than 20 hours in front of the oscope trying different combinations of code. :confused:

Why are you delaying here? I put the delay there because without delay the offtime is about 800us only, the code does respond, but the offtime is NOT sufficient.

Why did you try a do-while loop here? The do-while attempt was to make the offtime delay without using a delay....... I was trying to keep the squarewave low during the while time of the statement, so no delay would be necessary. I thought the delay would bog the loop down.

I don't really understand where you are suggesting to place the digitalWrite(outPin,HIGH); statement. It looks to be going high in the correct spot on the waveform ( ie. at the start of and concurrent with the rising edge of the triangle wave.).

The part I cannot figure out is how to make the square wave turn off exactly at the apex of the triangle wave and make it STAY off. So far I can make it go into a fast cycling PWM which terminates at the end of the falling edge of the triangle wave, or have two separate squarewaves, one for the rising edge and one for the falling edge.

The problem I am having is that I don't know which parameter should be used in the code to signal the turning off of the squarewave: the attiny is generating a fast variable pwm, which when integrated by means of a low pass filter shows the ramp in my scope shots.

The attiny85 does not see a ramp, it only knows the fast variable pwm which is composed of a rather large number of smaller squarewaves in rapid succession. pwmMax is the only parameter in the code that I see that could be used to trigger at the apex. And it does trigger:

if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplength);
        }

When I run this code, the squarewave does go low at the apex :slight_smile: but only stays low for the duration of the delay. Without the delay, it goes low for about 800us. This appears as a momentary negative going pulse at the apex. So............ the code does respond, but without some mechanism to hold the squarewave low it will not work as planned.

What am I missing?

If you could be a bit more specific as to any pointer you can give me, with pleasure I will test it.

I will try again tomorrow after work.......... :slight_smile:

take care, peace
lost_bro

P.S. thanks, and just attached the ino. file

Rising_Falling_edge_control.ino (6.03 KB)

I was trying to be a little coy and not give away the answer too easily, but I think I've been withholding too much.

I think the hangup you have over finding the right place for the digitalWrite(HIGH) statement is because you have a conception of the repeating sequence that is too rigid. Based on the code you're posting, you probably think of the sequence like this:

  1. Write output HIGH
  2. Increment PWM from min to max at rampLength intervals (positive ramp segment)
  3. Write output LOW
  4. Decrement PWM from max to min (negative ramp segment)
  5. Hold PWM at min for INTERVAL time period.

Because of this, I can see that you're keeping the output HIGH statement towards the top of loop(). It doesn't need to be there, and I'll run through the thinking I used to find a place that works.

This is one correct way to list of the steps, but because you are continuously looping through this sequence it is not the only unique way to list the steps. A loop makes the list circular: 1 -> 2 -> 3 -> 4 -> 5 -> 1 -> 2 -> 3 -> etc. The end of the loop wraps back to the beginning. Circles like that do not have a beginning, so I can choose ANY one of those 5 steps to label as #1, so there is a bit more freedom to restructure things to make implementation easier.

In this case, we only need to rotate everything up 1 space like this:

  1. Increment PWM from min to max at rampLength intervals (positive ramp segment)
  2. Write output LOW
  3. Decrement PWM from max to min (negative ramp segment)
  4. Hold PWM at min for INTERVAL time period.
  5. Write output HIGH

All of the steps are looped through in the exact same order, the only thing I have changed is which one we think of as #1. This frees you from thinking that the output HIGH statement has to be towards the top of the loop() function, and suggests a different place to try: immediately after the INTERVAL delay.

                ramplength = map(analogRead(ramplengthPin),0,1023,2,11800);               // adjust map for packetcount
              }
              while(micros()-delayStartTime<=INTERVAL);
              digitalWrite(output,HIGH);   <-- BOOM!! There is is!
              
         }                        
          StartUs += ramplength;  //loose control of ramplengthPin & pwmMaxPin // only intervalPin works // with int Dir=2; min 4ms
                                  //loose control of ramplengthPin  -- pwmMaxPin && intervalPin works  // with int static Dir=1; 
         
        //StartUs=micros();         //loose control of pwmMaxPin // ramplenghtPin & intervalPin works      // with int Dir=2; min 4ms
  }                                 // All three work!!!! but....now Triangle wave!!!!!                   // with int static Dir=1;

There is one small caveat to rotating the , which deals with the fact that microcontroller loops are not infinite. A microcontroller loop never terminates unless there is a power loss or malfunction, and those events are likely to happen independently of what step in the loop sequence you are in. The end of the loop is not defined, and can be thought of as unbounded in the future direction. However, they do have a defined beginning, which starts at power up. The steady-state behavior of the two ways of the two sequence lists will be identical, but the very first iteration will be different. For all sequence iterations except the first, the #1 step has had a #5 step immediately before it. The first iteration after power up though, is starting from scratch.

In this specific case, using the second sequence list, it means that on only the first pulse after startup, the output will not be HIGH for the positive ramp; all other iterations of the pulse will behave properly. You have two options: 1) Decide that this is acceptable behavior and leave it as it is, or 2) Add the "missing" beginning of the sequence to the end of setup(), like this:

    GTCCR = 1<<PWM1B | 2<<COM1B0;
    
    pinMode(outPin, OUTPUT);
    pinMode(ledPin, OUTPUT); 
    
    digitalWrite(outPin, HIGH); <-- Right there
}

I haven't tested it, but that should solve your problem. I hope this made sense, I've been trying to teach you the concept instead of just giving you a chunk of text to paste in without knowing how it works.

Also, just remove the do-while loop around the analog reads. Since you're using the delay function anyway, there's no point too it. Just read them once and move on.

Good day Jiggy-Ninja

Now we have it :slight_smile: See the attached scope shots.

I followed your advice, had to use one of older sketches which used the:

 if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplengthpause);
        }

This piece of code along with your suggestion to put:

  }
              while(micros()-delayStartTime<=INTERVAL);
              digitalWrite(outPin,HIGH);

here, made all the difference. Here's the final void() loop:

void loop()
{
  int static Dir=1; 
 
  if((micros()-StartUs) >= ramplength) 
      {                                           
        Pwm+=Dir;                 //increment or decrement PWM depending of sign of Dir 
        analogWrite(ledPin, Pwm); //Update built-in LED
        if(Pwm==pwmMax) Dir=-1;   //if PWM reaches the maximum: change direction 
        if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplengthpause);
        }
        if(Pwm==pwmMin) 
        { 
          digitalWrite(outPin,LOW);          
          delay(INTERVAL);
          
          Dir=+1;                 //delay *INTERVAL* & change direction 
          delayStartTime = micros();
          
              do
              {
                INTERVAL   = map(analogRead(intervalPin),0,1023,800,50000);               //800=16ms          // adjust all maps according to
                pwmMax     = map(analogRead(pwmMaxPin),0,1023,100,255);                    // circuit layout & potentiomenters
                ramplength = map(analogRead(ramplengthPin),0,1023,4,5800);     //5800=24ms          // adjust map for packetcount
                ramplengthpause==(ramplength/2);  
              }
              while(micros()-delayStartTime<=INTERVAL);
              digitalWrite(outPin,HIGH); 
         }                        
         
         StartUs=micros();         //loose control of pwmMaxPin // ramplenghtPin & intervalPin works      // with int Dir=2; min 4ms
  }                                 // All three work!!!! but....now Triangle wave!!!!!                   // with int static Dir=1; 
  
}

I might have to incorporate another do/while(micros()) function with this piece of code:

 if(Pwm==pwmMax)
        {
          digitalWrite(outPin,LOW);
          delay(ramplengthpause);
        }

because the minimum pwmMax ramp length is just over 6ms and I need 3-4ms. Not sure if it will help but I'll try tomorrow.

Thanks for the advice, and yes I did learn a lot from this code..... PM me and I'll buy you a beer.
take care, peace
lost_bro