Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWM Frequency change #142

Open
ltwin8 opened this issue Dec 29, 2022 · 10 comments
Open

PWM Frequency change #142

ltwin8 opened this issue Dec 29, 2022 · 10 comments

Comments

@ltwin8
Copy link

ltwin8 commented Dec 29, 2022

Hello MCUdude,

i would like to change the PWM Frequency for driving a special IC between 1 kHz (100 Hz up to 1.5 kHz are acceptable) and 3 kHz (2.5 kHz up to 5 kHz are acceptable)

could you please provide an example on how to do this?

Also is it possible to change PWM Frequency after PWM is running? so to speak "in the loop"?

@ltwin8
Copy link
Author

ltwin8 commented Dec 29, 2022

a short example:

    switch (mode) {
      case 0:
        //set PWM to 1 kHz
        analogWrite(Driver, 10);
        break;

      case 1:
        //set PWM to 1 kHz
        analogWrite(Driver, 30);
        break;

      case 2:
        //set PWM to 5 kHz
        analogWrite(Driver, 100);
        break;

      case 3:
        //set PWM to 5 kHz
        analogWrite(Driver, 150);
        break;

      case 4:
        //set PWM to 5 kHz
        analogWrite(Driver, 200);
        break;

      case 5:
        //set PWM to 5 kHz
        analogWrite(Driver, 0xff);
        break;
    }

reason for the change of PWM Frequency is to change the Drivers operating mode between PWM and Analog output current

@MCUdude
Copy link
Owner

MCUdude commented Dec 29, 2022

Have a look at the current analogWrite implementation. By default, PRESCALER_AUTO is defined. It's very easy to create your own function based off analogWrite

void analogWrite(uint8_t pin, uint8_t val)
{
// Set Timer0 prescaler
#if !defined(ENABLE_MICROS)
#if defined(PWM_PRESCALER_NONE) // PWM frequency = (F_CPU/256) / 1
TCCR0B = _BV(CS00);
#elif defined(PWM_PRESCALER_8) // PWM frequency = (F_CPU/256) / 8
TCCR0B = _BV(CS01);
#elif defined(PWM_PRESCALER_64) // PWM frequency = (F_CPU/256) / 64
TCCR0B = _BV(CS00) | _BV(CS01);
#elif defined(PWM_PRESCALER_256) // PWM frequency = (F_CPU/256) / 256
TCCR0B = _BV(CS02);
#elif defined(PWM_PRESCALER_1024) // PWM frequency = (F_CPU/256) / 1024
TCCR0B = _BV(CS00) | _BV(CS02);
#else // (PWM_PRESCALER_AUTO) // Automatic prescaler calculation
#if F_CPU >= 4800000L
TCCR0B = _BV(CS00) | _BV(CS01); // PWM frequency = (F_CPU/256) / 64
#else
TCCR0B = _BV(CS01); // PWM frequency = (F_CPU/256) / 8
#endif
#endif
#endif
// Set pin to output
DDRB |= _BV(pin);
// Handle off condition
if(val == 0)
{
turnOffPWM(pin); // Turn off PWM
digitalWrite(pin, LOW); // Set pin low
}
// Handle on condition
else if(val == 255)
{
turnOffPWM(pin); // Turn off PWM
digitalWrite(pin, HIGH); // Set pin high
}
// Otherwise setup the appropriate timer compare
else
{
if(pin == 0)
{
// Set waveform generation mode and output number
#if defined(PWM_PHASE_CORRECT)
TCCR0A |= _BV(WGM00) | _BV(COM0A1);
#else // (PWM_FAST)
TCCR0A |= _BV(WGM00) | _BV(WGM01) | _BV(COM0A1);
#endif
OCR0A = val;
}
else
{
// Set waveform generation mode and output number
#if defined(PWM_PHASE_CORRECT)
TCCR0A |= _BV(WGM00) | _BV(COM0B1);
#else // (PWM_FAST)
TCCR0A |= _BV(WGM00) | _BV(WGM01) | _BV(COM0B1);
#endif
OCR0B = val;
}
}
}

@ltwin8
Copy link
Author

ltwin8 commented Dec 29, 2022

thanks for the answer.

is the "F_CPU/256" necessary?

@ltwin8
Copy link
Author

ltwin8 commented Dec 29, 2022

i was hoping to run the Tiny @600KHz to save some power.

@MCUdude
Copy link
Owner

MCUdude commented Dec 29, 2022

is the "F_CPU/256" necessary?

That's just how the timer works. Alternatively, you can just PWM fast mode. You'll probably need to use this mode to achieve a fast enough speed when the processor is running at 600kHz. Read the datasheet and search for "AVR fast PWM". There are plenty of examples out there

@ltwin8
Copy link
Author

ltwin8 commented Dec 29, 2022

how can i set the prescaler during sketch? without it being reset after calling analkogWrite?

fastpwm is f OCnxPWM
f clk_I/O divided by Nx256

@MCUdude
Copy link
Owner

MCUdude commented Dec 29, 2022

how can i set the prescaler during sketch?

You write your own PWM function and use this instead of analogWrite. You can write to the registers directly, like so:
TCCR0B = _BV(CS00);. Everything can be changed on the fly in your sketch

@ltwin8
Copy link
Author

ltwin8 commented Dec 29, 2022

so i can comment out lines 33 zo 55

and can write as following?

switch (mode) {
      case 0:
        //set PWM to 1 kHz
        TCCR0B = _BV(CS00);
        analogWrite(Driver, 10);
        break;

      case 1:
        //set PWM to 1 kHz
        TCCR0B = _BV(CS01);
        analogWrite(Driver, 30);
        break;

      case 2:
        //set PWM to 5 kHz
        TCCR0B = _BV(CS00);
        analogWrite(Driver, 100);
        break;

      case 3:
        //set PWM to 5 kHz
        analogWrite(Driver, 150);
        break;

      case 4:
        //set PWM to 5 kHz
        analogWrite(Driver, 200);
        break;

      case 5:
        //set PWM to 5 kHz
        analogWrite(Driver, 0xff);
        break;
    }

where 1kHz is in reality 585Hz and 5 kHz in reality 4.68 kHz (@1.2 MHz clock)

@ltwin8
Copy link
Author

ltwin8 commented Jan 18, 2023

i have found my issue, i am on OC0A on the attiny13V, is it possible to get fast and slow pwm here?

@maxint-rd
Copy link

Hello @ltwin8 , you may find my FastPwmPin library useful (see my GitHub page). It supports the ATtiny13A as well as other MCU's. On the ATtiny13A @9.6 MHz I've measured frequencies from 38HZ up to 1.6MHz. Note at very high frequencies the PWM resolution is smaller and the signal can become less stable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants