UC3A PWM - running, but cannot change duty cycle

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It has taken me a couple of weeks to figure out - looking at numerous examples and the data sheet to get a PWM running under PLL while only using sysclk functions, not power manager.  But, as with most cases, I would like to change the duty cycle in order to control a motor.

 

I have read the ASF docs and examples, and they do not seem to say the same thing.  Many people state that you must use an interrupt to change the duty cycle, and others have stated that you can stop the PWM, change duty cycle, and then start it back up again.

 

ASF has a pwm_async_update_channel() function that should work on the fly - but when ever I try use it, I end up with a single pulse the half width of the frequency of the PWM  (17ns for a 21khz PWM).

 

Suggestions would be welcome.

Code below.

Kind regards,

David

#include <asf.h>
#include <delay.h>
#include <pwm.h>
#include <sysclk.h>
int main (void)
{
	int c;
	unsigned int channel_id;

	board_init();

	 pwm_opt_t pwm_opt;                                // PWM option config.
    avr32_pwm_channel_t pwm_channel = { .ccnt = 0 };  // One channel config.

    channel_id =FPR_PWM_CHANNEL_ID;
    gpio_enable_module_pin(FPR_PWM_PIN, FPR_PWM_FUNCTION);

    // PWM controller configuration.
    pwm_opt.diva = AVR32_PWM_DIVA_CLK_OFF;
    pwm_opt.divb = AVR32_PWM_DIVB_CLK_OFF;
    pwm_opt.prea = AVR32_PWM_PREA_MCK;
    pwm_opt.preb = AVR32_PWM_PREB_MCK;

    pwm_init(&pwm_opt);

    pwm_channel.CMR.calg = PWM_MODE_LEFT_ALIGNED;       // Channel mode.
    pwm_channel.CMR.cpol = PWM_POLARITY_LOW;            // Channel polarity.
    pwm_channel.CMR.cpd = PWM_UPDATE_DUTY;              // Update Duty Cycle
    pwm_channel.CMR.cpre =  AVR32_PWM_CPRE_MCK_DIV_4; //AVR32_PWM_CPRE_MCK_DIV_256;  // Channel prescaler.
    pwm_channel.cdty = 500;   // Channel duty cycle, should be < CPRD.
    pwm_channel.cprd = 1000;  // Channel period.
    pwm_channel.cupd = 0;   // Channel update not used here.

    pwm_channel_init(channel_id, &pwm_channel); // Set channel configuration to channel 0.

    pwm_start_channels(1 << channel_id);  // Start channel 0.
    pwm_channel.cupd = 1;   // Channel update  used here.
	while (1)
	{
	   for (c=100;c<999;c++)
	   {
			pwm_channel.cdty = c;   // Channel duty cycle, should be < CPRD.
			pwm_async_update_channel(channel_id,&pwm_channel);  
			delay_ms(10);
	   }
	}
}

---------------------------------------------------------------------
init.c
#include <asf.h>
#include <board.h>
#include <conf_board.h>
#include <pwm.h>
#include <sysclk.h>
void IO_Init(void);

void board_init(void)
{
	int c,d;
		sysclk_init();
		gpio_local_init();
		delay_init(66000000UL);
}
---------------------------------------------------------------------------
#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED

#define CONFIG_SYSCLK_SOURCE        SYSCLK_SRC_PLL0

/* Fbus = Fsys / (2 ^ BUS_div) */
#define CONFIG_SYSCLK_CPU_DIV         0
#define CONFIG_SYSCLK_PBA_DIV         0
#define CONFIG_SYSCLK_PBB_DIV         0

#define CONFIG_USBCLK_SOURCE          USBCLK_SRC_PLL1

/* Fusb = Fsys / USB_div */
#define CONFIG_USBCLK_DIV             1

#define CONFIG_PLL0_SOURCE          PLL_SRC_OSC0
//#define CONFIG_PLL0_SOURCE          PLL_SRC_OSC1

/* Fpll0 = (Fclk * PLL_mul) / PLL_div */
#define CONFIG_PLL0_MUL             7 //(48000000UL / BOARD_OSC0_HZ)
#define CONFIG_PLL0_DIV             1

#define CONFIG_PLL1_SOURCE            PLL_SRC_OSC0
//#define CONFIG_PLL1_SOURCE          PLL_SRC_OSC1

/* Fpll1 = (Fclk * PLL_mul) / PLL_div */
#define CONFIG_PLL1_MUL               (48000000UL / BOARD_OSC0_HZ)
#define CONFIG_PLL1_DIV               1

#endif /* CONF_CLOCK_H_INCLUDED */
---------------------------------------------------------------
#ifndef USER_BOARD_H
#define USER_BOARD_H

#include <conf_board.h>

/* Clock Speed */
#define APPLI_CPU_SPEED	66000000
#define APPLI_PBA_SPEED 66000000

/* These are documented in services/basic/clock/uc3b0_b1/osc.h */
#define BOARD_OSC0_HZ           12000000
#define BOARD_OSC0_STARTUP_US   17000
#define BOARD_OSC0_IS_XTAL      true
#define BOARD_OSC32_HZ          32768
#define BOARD_OSC32_STARTUP_US  71000
#define BOARD_OSC32_IS_XTAL     true
#define FOSC0					12000000

#define CLOCK_PBA_FREQ          66000000
	
#define FPR_PWM					AVR32_PIN_PB19
#define FPR_PWM_PIN             AVR32_PWM_0_PIN//AVR32_PWM_0_0_PIN
#define FPR_PWM_FUNCTION        AVR32_PWM_0_FUNCTION//AVR32_PWM_0_0_FUNCTION
#define FPR_PWM_CHANNEL_ID      0

#endif // USER_BOARD_H

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am guessing that this is for a UC3A or UC3B processor, the PWM module in a UC3C is different.
pwm_async_update_channel(,) will set the MR and CUPD registers of the selected channel.
Your goal is to change the duty-cycle (the on-time), therefore the new value of the on-time should be placed into the .cupd field of the channel.
Set the .CPD field in the channel MR to 0 (default) to cause what is in the .cupd field to be eventually placed into the CDTY register of the channel.
pwm_channel.cdty = c; does nothing, because 1) it does not write to the hardware and 2) pwm_async_update_channel(,) does not use .cdty

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks mikech - that was the answer - works as expected now!

David