Creating a 1KHz clock O/P

I need the output of the pot to go from 0 to 10K over a 500ms time. Hence 1K will provide the 64 steps in that time. Depending on the CS and U/D pins will determine if it counts up or down (obviously) but once it reaches the limit further clock pulses won't do it harm. I can estimate at approx 500ms I can remove CS until it need to count in the opposite direction.

Wouldn't a 1kHz clock go from 0 to 10K in 64mS?

You want 7.8125mS/step if you want to traverse 64 steps in 500mS.

Why not just output 64 timed pulses? Some special reason? You have to time *CS and U/*D anyway, because CS should be made inactive when you're not switching. At the very least, you'd have to know when it's safe to change direction. In other words, know when the fade operation is finished. I assume that a failure to reach the end point would not be good. Wouldn't it be better to "know" by controlling it rather than to "estimate" the timing?

Yep. Correct. 1K was when I was thinking of using 256 steps but even then it would be 512Hz. Not sure where I got 1K from.

Obviously I need 128Hz.


I could possiblt do 64 timed pulses but I also need to consider the change of direction. At any time during the output the demand to go in the opposite direction could occur. I will be monitoring 2 inputs, if one is higher than the other (they will be either 0V or 5V or the other way around) then the output either increases or decreases.

If the input changes then all I have to do is change the U/D pin.

That seems like another problem with your approach that doesn't exist with a timed, controlled sequence. In fact, once you start the process you have no exact idea where the pot is set, because you depend on it over stepping the end to finish the operation.

If the direction suddenly changes with a timed application of tone(), you could double the time you waste, over stepping the end. To fix that, requires superfluous logic that would better be leveraged at controlling the steps individually.

With timed, measured pulses you always know exactly where the wiper is (because you can count steps), so when you reverse direction you know exactly how many steps you need to take.

Not knowing whether the travel will complete at the outset, requires that you allocate travel time for the worst case, 63 steps forward and 64 back. If you reset the tone() timer to avoid this, you are not simplifying the logic at all beyond basic discrete step control.

In the case where you reset the tone() timer every time you change direction, you will not be able to perform another operation for an unnecessarily long time, if the wiper barely moved before that happened.

The output is actually a voltage between 0V and 5V. This is supplied to the ECU of a motorbike. The current circuit I am using uses an NE555 to clock the pot and it doesn't seem to care if the clock pulses are there continuously. It has been working for about 5 years with no problem. Just me being a tinkerer I wanted to try and make it even smaller. If I can do it with an ATTiny 25/45/85 and the pot with a few other discrete components then I will be happy. So I can't see why I would need to count pulses, hence why I just wanted some form of clock pulse (now 128Hz) to clock the pot. CS can be set to be on permanently as it is now and control the U/D with the 85. I was trying to make it as small as I could with the smallest code.

I appreciate all the suggestions and it helps me learn although they did say you can't teach old dogs new tricks.

Also from reading the tutorial on Tone it runs in the background so you can perform other ops on the micro.

What is the input impedance of the control voltage input you're feeding with the pot? If it's quite high, you could eliminate the pot entirely, just low pass filter a PWM output with a resistor and capacitor, to emulate an analog control signal. Fewer and smaller parts...

This is written for a Mega2560 for demonstration purposes but should be adaptable to an ATTiny. It uses Timer1 to generate a 125Hz interrupt. In the ISR the current position of the POT is tracked. In the loop, the desired position variable is updated. When the two are not equal, the logic in the ISR ticks the pot as required. It'll go from 0 to 64 in 500mS.

 * Sketch:  sketch_nov15c
 * Target:  Mega2560

const uint8_t pinUD = 2;
const uint8_t pinCLK = 3;
const uint8_t pinDebug = 4;

static uint32_t
    timePot = 0ul;

volatile uint8_t
    desiredCnt = 0;
void setup() 
    //pins for U/nD and CLK
    pinMode( pinUD, OUTPUT );
    pinMode( pinCLK, OUTPUT );
    //for scoping
    pinMode( pinDebug, OUTPUT );

    //setup timer 1 to interrupt at 128Hz
    //  WGM 15; OCR1A is TOP
    //  /8 prescaler gives 2MHz ot 500nS tick
    //  128Hz is 7.8125mS
    //      7.8125mS / 500nS = 15625
    //      set OCR1A to 15625-1 
    TCCR1A = _BV(WGM11) | _BV(WGM10);
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);   //use /8 prescaler to give 2MHz clock
    OCR1A = 15624;
    //enable the timer1 compare interrupt
    TIMSK1 |=  _BV(OCIE1A); 

    //desired count is where we want the digital POT (DP) to be
    //we init desired to 0 and "current" in the ISR to 65 to ensure the 
    //DP is wound all the way to step '0' out of reset
    desiredCnt = 0;


void loop() 
    //for demo, set to ramp pot up and down once per second
    timeNow = millis();
    if( (timeNow - timePot) >= 1000ul )
        timePot = timeNow;
        //when we modify desiredCnt, do so in a critical section
        if( desiredCnt == 0 )
            desiredCnt = 64;
            desiredCnt = 0;

    //initialize current position to something bigger
    //than 64. with desired set to zero we'll clock out
    //enough ticks to set the DP to a known state (0)
    static uint8_t
        currentCnt = 65;

    //if desired and current are not the same...
    if( desiredCnt != currentCnt )
        digitalWrite( pinDebug, HIGH );               
        //set the U/nD pin LOW if the desired position is less than the
        //current (iow, we want to count down)
        //otherwise, desired is higher than current so set it high
        digitalWrite( pinUD, (desiredCnt < currentCnt) ? LOW : HIGH );
        //pulse the clock line
        digitalWrite( pinCLK, HIGH );
        digitalWrite( pinCLK, LOW );
        //and bump the current position up or down
        currentCnt = currentCnt + ((desiredCnt < currentCnt) ? -1:1);
        //the current == desired so we do nothing but clear the
        //debug pin
        digitalWrite( pinDebug, LOW );
}//ISR timer1 compare

Would the attached circuit work?

Schematic_Servo_eliminator_R6_2021-11-23.pdf (43.7 KB)

Maybe you clarified earlier but I missed it: I still don't know what you're doing. What is "12V_in_a" and "12V_in_b"? I assume "Ramp_out" from the AD5227 is going to the ECU but what is the ECU input? What is this all doing?

I see "Servo Eliminator" in the title block: Is this for a motorcycle exhaust valve or ... ?

The 12V in is the voltage to control the exhaust valve so you are correct in your assumption. The 2 voltages switch polarity depending on if it is opening or closing the valve. The ramp out simulates the resistance of the valve pot. What then input to the ECU is other than this ramp I don't know. Impedance? don't know but the existing CCT works fine so as far as the output from the AD5227 is concerned it should not change.

I looked closer and saw "R6" in the title and assume now that's a reference to the Yamaha R6. I ride a Tuono wave

I ditched the exhaust valve on mine with an Akrapovic slip-on and removed the servo. The Aprilia race-tune loaded thereafter automatically eliminated any service codes related to the absence of the servo.

Your circuit is likely okay. It might be a good idea to add some TVS (transient voltage suppression) diodes to the circuit where external connections are made. Is 5V supplied by the ECU?

Hehehe. R6 is the revision. Had a few failures :wink:

Yes the 5V is supplied by the ECU. These are actually for Suzuki's and Kwacka's.

1 Like

Can you see any problems with the circuit? Should I use a chip with more I/O pins, eg ATTiny841?

If the circuit does what you want it to do there's no need to add superfluous GPIOs.

As the basis for a prototype, I don't see any immediate problems with the circuit. Given the intent to use it in a hostile automotive (motorcycle counts...) I assume you'll do a lot of testing and qualification (e.g. tolerance to electrical and RF interference, operation at temperature extremes, vibration etc) before committing to use (personal) or sale (commercial.)

I was just a little concerned about using the programming pins as I/O as well.