1

I am trying to follow Need help to set PWM frequency to 25kHz and generate the same 25khz on pin 8 of arduino mega which is controlled by TIMER 4; I dont see any success; could someone please help?

Given below is the code I have tried based on an answer by @EdgarBonet in the linked post and I tried on connecting fan pwm on each of the 3 pins 6, 7, 8 one by one and still cannot get the speed to change and the fan is just running at full speed;

void analogWrite25k(int value)
{
    OCR4A = value;
    OCR4B = value;
    OCR4C = value;
}

void setup()
{    
    TCCR4A = 0;           
    TCCR4B = 0;           
    TCCR4C = 0;           
    TCNT4  = 0;           
    TCCR4A = _BV(COM4A1)  
           | _BV(COM4B1)  
           | _BV(COM4C1)  
           | _BV(WGM11);  
    TCCR4B = _BV(WGM13)   
           | _BV(CS10);   
    TCCR4C = _BV(WGM13)   
           | _BV(CS10);   
    ICR4   = 320;         

    // Set the PWM pins as output.
    pinMode( 8, OUTPUT);
}

void loop()
{
    analogWrite25k(10);
    for (;;) ;  // infinite loop
}

edit2:

Thanks for the hints by @dannyf; I read the datasheet again and below is what I am trying now but even this is not working and I am really unable to figure out if something is not right in this; I am trying to set value of OCR4C only in analogWrite25k method since fan pwm line is connected to digital pin 8 of my Mega;

TCCR4A = 0;
TCCR4B = 0;
TCNT4  = 0;        
TCCR4A = _BV(COM4C1)  
      | _BV(WGM41);  
TCCR4B = _BV(WGM43)   
     | _BV(CS40);   
ICR4   = 320;         // TOP = 320
1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Majenko
    Sep 16, 2017 at 20:44

2 Answers 2

3

easy.

  1. find a copy of the datasheet for your mcu;

  2. go to the section about your timer;

  3. figure out a prescaler setting that yields the maximum roll-over count;

  4. pick the timer mode that supports the roll-over count;

  5. write your own analogWrite() function;

  6. [optional] if you wish to reuse the stock analogWrite(), make sure that roll-over count calculated in 3) is a valid data type for the stock analogWrite(). If not, increase the prescaler in 3) until it is.

  7. done.

edit: i decided to give it a try.

the following code:

void setup() {
  // put your setup code here, to run once:
  pwm1Set(TMR1_PS8x, F_CPU / F_PWM1 / 8);       //ps = 8x, top = F_CPU / F_PWM / 8 = 80
  analogWrite(9, 20);                           //dc = 20/80=25%
  analogWrite(10, 40);                          //dc = 40/80=50%
}

void loop() {
  // put your main code here, to run repeatedly:
}

produced the following output on an ATMega328p's TIMER1.

enter image description here

i'm reasonably sure that the output is indeed 25Khz.

the code itself however is capable of generating pwm at other frequencies.

edit2: the same code on mega2560 generating 25Khz pwm on pin6/7/8:

enter image description here

code used for that is as follows:

  //ps = 8x, top = F_CPU / F_PWM / 8 = 80
  //DC on Pin 6 = 20/80 = 25, 
  //DC on Pin 7 = 40/80 = 50,
  //DC on Pin 8 = 60/80 = 75,
  pwm4Set(TMR4_PS8x, F_CPU / F_PWM4 / 8); analogWrite(6, 20);  analogWrite(7, 40);  analogWrite(8, 60);

pwm4Set() is a copy of pwm1Set(). Both are simple enough: only 5 lines of code used.

2
  • thanks for the response but the question was specific to arduino mega 2560;
    – techniche
    Sep 15, 2017 at 6:15
  • 1
    @dannyf - thanks for the edit and help on mega but I am not sure where to get the pwm1Set or pwm4Set functions; are they builtin functions or part of some additional library?
    – techniche
    Sep 15, 2017 at 19:50
2

Found a properly working answer for the question finally; Thanks to KIV's answer on Need help to set PWM frequency to 25kHz on pin 8 of Arduino Mega to control speed of a 4-wire cpu fan an additional usful thing he has added is to allow setting of duty cycle from serial monitor input for convenience while testing;

void analogWrite25k(int value)
{
    OCR4C = value;
}

void setup()
{    
    TCCR4A = 0;
    TCCR4B = 0;
    TCNT4  = 0;

    // Mode 10: phase correct PWM with ICR4 as Top (= F_CPU/2/25000)
    // OC4C as Non-Inverted PWM output
    ICR4   = (F_CPU/25000)/2;
    OCR4C  = ICR4/2;                    // default: about 50:50
    TCCR4A = _BV(COM4C1) | _BV(WGM41);
    TCCR4B = _BV(WGM43) | _BV(CS40);

    Serial.begin(115200);

    // Set the PWM pin as output.
    pinMode( 8, OUTPUT);
}

void loop()
{
    int w = Serial.parseInt();
    if (w>0) {
        analogWrite25k(w);
        Serial.println(w);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.