mega32u4 pwm >= 20kHz timer4

Good morning,

I am attempting to drive a DC motor via a MOSFET, and trying to avoid the audible noise < 20kHz. Using this source code here: Fast PWM and setting up Timer4 pin6 for 23437 Hz works well, that is until you remove the USB cable. Once the Micro has restarted, it seems the noise is back so I assume the frequency has lowered some how. I do have reason to believe it’s related to the PLL Configuration?

I’m stuck now that I need Pin 6 to be roughly >= 20kHz

With an Arduino UNO, I can use the PWM freq. library from here and can see 20kHz on the pin, and at 255 I get an output of 5V.

I did try the following on the mega32u4, but at 255 it’s only giving me 3.3V out on the pin. Where have I gone wrong as I am really struggling to see.

in setup:

  const uint16_t pwmval = SYSCLOCK / 2000 / 20;
  TCCR4A                = (1 << PWM4A);
  TCCR4B                = _BV(CS40);
  TCCR4C                = 0;
  TCCR4D                = (1 << WGM40);
  TCCR4E                = 0;
  TC4H                  = pwmval >> 8;
  OCR4C                 = pwmval;
  TC4H                  = (pwmval / 3) >> 8;
  OCR4A                 = (pwmval / 3) & 255;

Then call:

// Set PWM to D6 (Timer4 D)
// Argument is PWM between 0 and 255
void pwmSet6(int value)
{
  OCR4D = value; // Set PWM value
  DDRD |= 1 << 7; // Set Output Mode D7
  TCCR4C |= 0x09; // Activate channel D
}

Once the Micro has restarted, it seems the noise is back so I assume the frequency has lowered some how.

I don't think this is a software problem. I guess once you remove the USB connection the micro is driven by the same power supply as the DC motor. If my guess is correct you probably have to stabilize the power supply of the micro to eliminate the sound.

pylon:
I don't think this is a software problem. I guess once you remove the USB connection the micro is driven by the same power supply as the DC motor. If my guess is correct you probably have to stabilize the power supply of the micro to eliminate the sound.

Hi pylon, I am using only the USB to power the micro right now. The DC supply for the motor is separate. Only ground is connected between the DC input, to the MOSFET and the GND of the micro.

Upload the code, it shows 23.43kHz... unplug the USB (micro now has no power)... reconnect the USB cable and I now get 11.71kHz. This also happens without a MOSFET / motor attached.

In this case post complete code.

So, this is the code from the first website I found which is having the issue once you re-connect the USB cable. Just as another test, I set the freq. mode for Timer4 to 46875 Hz, uploaded, I could see 46kHz. Reconnect the USB, and I could see 23kHz, it’s like it’s doing half every time. I’ve tried with another 2 micro’s to make sure it wasn’t just a fault with the micro.

// Frequency modes for TIMER4
#define PWM187k 1   // 187500 Hz
#define PWM94k  2   //  93750 Hz
#define PWM47k  3   //  46875 Hz
#define PWM23k  4   //  23437 Hz
#define PWM12k  5   //  11719 Hz
#define PWM6k   6   //   5859 Hz
#define PWM3k   7   //   2930 Hz
// Direct PWM change variables
#define PWM6        OCR4D
#define PWM13       OCR4A
// Terminal count
#define PWM6_13_MAX OCR4C
// Macro to converts from duty (0..100) to PWM (0..255)
#define DUTY2PWM(x)  ((255*(x))/100)


// Configure the PWM clock
// The argument is one of the 7 previously defined modes
void pwm613configure(int mode)
{
  // TCCR4A configuration
  TCCR4A = 0;

  // TCCR4B configuration
  TCCR4B = mode;

  // TCCR4C configuration
  TCCR4C = 0;

  // TCCR4D configuration
  TCCR4D = 0; // Fast PWM mode

  // TCCR4D configuration
  TCCR4D = 0;

  // TCCR4E configuration
  TCCR4E  = 0;                        // Not enhanced mode

  // PLL Configuration
  // Use 96MHz / 2 = 48MHz
  PLLFRQ = (PLLFRQ & 0xCF) | 0x30; // Route PLL to async clk
  // PLLFRQ=(PLLFRQ&0xCF)|0x10; // Will double all frequencies

  //while (! (PLLCSR & (1 << PLOCK))); // wait for pll to be active and stable.

  // Terminal count for Timer 4 PWM
  OCR4C = 255;
}


// Set PWM to D6 (Timer4 D)
// Argument is PWM between 0 and 255
void pwmSet6(int value)
{
  OCR4D = value; // Set PWM value
  DDRD |= 1 << 7; // Set Output Mode D7
  TCCR4C |= 0x09; // Activate channel D
}


void setup()
{
  pwm613configure(PWM23k);

  pwmSet6(255); //Just to test the Freq. output

}

void loop() { }

What board are you using? Leonardo board ties pin UVCC high to pin VCC, while SparkFun's Pro Micro does not.

See the ATmega16/32U4 datasheet for discussion of the Clock Switch Controller and the Clock Selection register. Timer4 timer/counter clock is different implementation than with other timer/counters found on ATmega32U4 or ATmega328P.

@borland: I am using the Arduino Micro (Genuine board)

OK. On your 3V problem... Product page suggest if you power the unit from non-USB, your supply needs to be at least 7V otherwise the on board regulator will supply less than 5V and possibly provide unreliable results. They suggest 7-12V supply.

SparkFun runs one version of Pro Micro at 3.3V, but at 8MHz.

I suggest you study the ATmega16/32U4 datasheet well or use a ATmega328P. Timer4 docs there are not very easy to understand.

Hey, The board is directly powered from the USB supply and nothing else. 3V is being supplied from pin 6 when trying the Timer4 code I pasted (but 5V pin is still at 5V as I would expect) but will supply 5V from pin 6 when using the normal analogWrite(6,255);

Yes, the Timer4 docs seem very hard to understand which is why I was hoping someone may of already done this and be able to provide a possible solution. I do have a nano on the way, if I can't get the micro working the way I would like.

I suggest that you print out the values of all the timer and pll registers you are using. I don't understand how, but I think that there is possibly some default register initialization with the usb reconnection which is changing what you want.

It seems the PLL register changes.

After upload: PLLFRQ: 1001010, apply the value, returns PLLFRQ: 1111010

Unplug & Plug back in, PLLFRQ: 100, apply the value, returns PLLFRQ: 110100

I don't understand the change in PLL lock frequency with the USB disconnect/reconnec, but the work around is to change how you apply the values to get what you want.

//PLLFRQ = (PLLFRQ & 0xCF) | 0x30; 
 PLLFRQ = B1111010;

If you are going to be working at this level, you need to have the Atmel data sheet for the ATmega32U4 handy. https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwiF6aHYxOTWAhWHqVQKHR8WCSoQFggoMAA&url=http%3A%2F%2Fwww.atmel.com%2FImages%2FAtmel-7766-8-bit-AVR-ATmega16U4-32U4_Datasheet.pdf&usg=AOvVaw2mnLLom_X0T_RXTAQdUqXG

The PLL frequency is used by the USB subsystem. Changing it may disable the USB functionality completely as the USB interface looses it's base clock source. Setting it directly as cattledog suggested may solve your problem but be prepared to disconnect your Micro to be able to upload sketches again.

If there is an issue with using Timer4 and USB, you can always achieve 20+KHz PWM with the 16 bit Timer 1 and Timer 3 using mode 14 (fast pwm with ICRn as top value). A clock presclar of 1 and ICRn = 639 (640 counts 0 referenced) will give 25KHz. You should not have a resolution problem for driving a motor at different speeds.

If you don't want to set this up yourself, the Timer1(pins 9,10,11) and Timer3(pin 5) libraries provide pwm on the leonardo.

https://www.pjrc.com/teensy/td_libs_TimerOne.html