This is the multi-page printable view of this section. Click here to print...

Return to the regular view of this page

As of 2025-09-10

mwf_periph_pwm - PWM, Timer

mwf_periph_pwm - PWM, Timer
    This is a peripheral object that summarizes the procedures for using PWM and timers.

    mwf_periph_pwm - PWM, Timer

    This is a peripheral object that summarizes the procedures for using PWM and timers.

    The the_pwm[] class object is used for operations. Although the class object is defined as an array, you can use PWM0 (the_pwm[0]) to PWM9 (the_pwm[9]).

    PWM10 is not supported by this library.

    Code Example

    The example below explicitly specifies the mwf:: namespace. If you want to omit it, write using namespace mwf;.

    #include "mwf_periph_pwm.hpp"
    
    // in some func.
    void func() {
    	// create instance of PMW0.
    	if (!the_pwm[0]) { // The class object of PMW0 is the_pwm[0].
    		timer_n_pwm::global_init_pwm_manager(
    		  0,   // PWM0
    		  timer_n_pwm::PIN::ALT,
    		       // The timer_n_pwm::PIN::PRIMARY will assign smaller PIO number PIO0 from PWM0,
    		       // or conversely, timer_n_pwm::PIN::::ALT assigns PIO12.
    		  true // set true to enable PWM output.
    	  );
    	}
    
    	// set `x' as an alias of the_pwm[0].
    	auto& x = the_pwm[0];
    
    	// Init the device
    	//x->init(); // not necessary, the constructor will call init() implicitly.
    
    	// if needs INT, set true. (default: false)
    	x->set_int_enabled(true);
    
    	// set prescale
    	x->set_prescale(6); // 0:32MHz 1:16Mhz 2:8Mhz ...
    
    	// set polarity: if false, set HIGH while active state. (default: false)
    	x->set_invert(false);
    
    	// set cycle
    	// note: 500Hz Duty 10% (Hi 0.2ms, Low 1.8ms)
    	x->set_cycle(
    		   100 // conut for an active state (HIGH)
    		,  999 // count for a period (+1)
    	);
    
    	// start PWM out
    	x->restart();
    }
    
    // INT handler (call set_int_enabled() before restart())
    // note: if TWENETcmpt library is not linked, the IRQ handlers for PWM1..9 shall be defined.
    extern "C" void PWM0_IRQHandler(void) {
      	... // some procedures.
     	PWM_ClearStatusFlags(PWM, kPWM_Pwm0);
    }

    class mwf::periph::timer_n_pwm

    global_init_pwm_manager()

    static void global_init_pwm_manager(
        		  uint8_t u8_pwm_id
    			, uint8_t u8_pin_number
    			, bool b_output_enabled = true
    		 );
    
    static void global_init_pwm_manager(
        		  uint8_t u8_pwm_id
        		, PIN e_pin
    			, bool b_output_enabled = true
    		);

    To construct the the_pwm[] class object, you specify the PWM number and the corresponding pin.

    The PWM number is specified as u8_pwm_id. Each PWM has two available pins (PWM5 only has PIO16). In this API, you can either specify the pin number directly as u8_pin_number or specify the lower pin number (timer_n_pwm::PIN::PRIMARY) or the other pin number (timer_n_pwm::PIN::ALT) from the available pins.

    The behavior is undefined if you specify a conflicting number.

    global_deinit_pwm_manager()

    static void global_deinit_pwm_manager(uint8_t u8_pwm_id);

    This function destroys the constructed the_pwm[] class object.

    set_pwm_output()

    void set_pwm_output(bool_t b_enable);
    bool get_pwm_output();

    Changes the output state of the pin. If b_enable is true, the output is enabled, and the hardware pin settings are also changed. If it is false, the pin is set to the default setting (conf::pin::conf_default()).

    • This function can be called while PWM is active.
    • If the output is already set by a parameter in global_init_pwm_manager(), there is no need to call this function again.

    set_int_enabled()

    void set_int_enabled(bool_t b_enable);
    bool get_int_enabled();

    This function sets the interrupt to be enabled or disabled. If b_enable is true, the interrupt is enabled; if it is false, it is disabled.

    • This function can be called while PWM is active.
    • Please refer to the “Interrupt Handler” section below.

    set_prescale(), set_divisor()

    void set_prescale(uint8_t u8_prescale);
    void set_divisor(uint16_t u16_div);

    These functions set the prescale for PWM control, which determines the PWM control frequency.

    • These functions can be called while PWM is active.
    • If set_prescale(u8_prescale) is specified, the control frequency is determined as follows: 0: 32MHz, 1: 16MHz, 2: 8MHz, …, 9: 62500Hz, 10: 31250Hz. Values 11 and above are undefined (assert in debug mode).
    • If set_divisor(u16_div) is specified, the control frequency is (32MHz / u16_div). The valid range is 1 to 1024, and the behavior is undefined if a value outside this range is specified.
    • The PWM period and duty cycle are determined by the parameters of set_cycle().
      • For example, if set_prescale(2) is specified, the control frequency is fb=8MHz. With this setting, if set_cycle(2, 10) is specified, the PWM period is fb/10 = 800kHz, and the pulse width is 2/fb = 2/8000000 = 250ns.

    set_cycle()

    void set_cycle(uint16_t ct_comp, uint16_t ct_period);
    uint16_t get_period_val(); // get total period count
    uint16_t get_comp_val();   // get active region count
    

    This function specifies the count values that determine one PWM cycle and the active period within it. The pin value changes during the active period, and an interrupt is generated at its end.

    ct_comp is the count for the active period, and ct_period is the total count for one cycle. For example, if ct_comp is 100 and ct_period is 1000, the PWM period will be 1000 counts at the PWM control frequency. With set_invert(false), the behavior will be HIGH for 100 counts and LOW for the remaining 900 counts.

    • This function can be called while PWM is active.
    • ct_comp is valid from 0 to ct_period - 1. The upper limit for the active period ratio is (ct_period - 1) / ct_period, and it cannot be set to 100%. set_duty() takes a 100% setting into consideration.
    • The count value for one cycle, ct_period, is set as ct_period - 1 in the hardware register. Please be careful not to specify the hardware register value directly in this function.

    set_duty()

    void set_duty(uint16_t u16duty, uint16_t u16duty_max = 1000);

    This function sets the PWM duty cycle.

    • You must have previously used set_cycle() to specify the count for one PWM cycle. If you omit this step, u16duty_max is set as the PWM cycle count.
    • The active period is set to a ratio of u16_duty/u16duty_max of the total cycle. For example, if set_duty(100) is specified, the active period is 10% of the cycle.
    • If u16duty is set to the same value as u16duty_max, the entire cycle becomes active, resulting in a HIGH level if the default non-inverted waveform output (set_invert(false)) is used. (Due to hardware constraints, the active period cannot be set to the entire cycle. Internally, the waveform output register is inverted, and the active period is set to 0.)
      • For this reason, if you call set_cycle() after setting the duty cycle to 100% with set_duty(), the waveform will be inverted. Please be careful not to mix their usage.

    set_invert()

    void set_invert(bool_t b_invert);
    bool get_invert();

    This function inverts the output waveform. When set to false (default), the active period is at a HIGH level. When set to true, it is at a LOW level.

    start(), stop()

    void start();
    void restart();
    void stop();

    These functions start, restart (with current settings), and stop the PWM output.

    • When stopped with stop(), the pin state is LOW if set_invert(false) (default) is set, and HIGH if set_invert(false) is set.

    class mwf::periph::timer_n_pwm (sys_ev_handler)

    sys_ev_handler is a procedure for before and after sleep.

    on_sleep()

    The PWM execution state is saved, and the pin state is returned to the default setting during sleep.

    on_wakeup()

    The state saved before sleep is restored.

    class mwf::periph::timer_n_pwm (sys_global_resource_handler)

    The sys_global_resource_handler<T> (where T is the timer_n_pwm class) is a procedure for performing necessary initialization and termination only once for multiple PWM class objects. It is used implicitly internally.

    • The constructor and on_wakeup() call sys_global_resource_handler<T>::init().
      • If it’s the first instance created, it calls T::global_init().
    • The destructor and on_sleep() call sys_global_resource_handler<T>::deinit().
      • If it’s the last instance to be destroyed, it calls T::global_deinit().

    T::global_init()

    Calls ::PWM_Init() to initialize the PWM.

    T::global_deinit()

    Calls ::PWM_DeInit() to terminate the use of the PWM.

    Interrupts

    When set_int_enabled(true) is set, an interrupt is generated at the end of the active period. The interrupt handler is provided by the system and is named PWMn_IRWHandler() (where n is the PWM channel).

                  Interrupt
                     V                 Interrupt
                     V
    Vcc    +----+                +----+
           |    |                |    |                t
    GND----+    +----------------+    +-------------->
           <----> Active Period
           <--------------------> One PWM Cycle
    

    The interrupt handler must be explicitly defined. The handler function that needs to be defined changes depending on whether the TWENETcmpt library is linked.

    • If TWENETcmpt is linked, only define the handler for the PWM channel you are using.
    • If TWENETcmpt is not linked, you must explicitly define interrupt handlers for all PWM channels from PWM0 to PWM9, even if you are not using an interrupt.

    Interrupt Handler

    When using TWENET, interrupts are converted into an interrupt function (cbToCoNet_u8HwInt()) and an event (cbToCoNet_vHwEvent()).

    If you want to define your own interrupt handler, you must define PWNn_IRQHandler() separately. The following example shows a definition for PWM1. When you define your own, TWENET interrupts and events will not be generated.

    // note: in c file, `extern "C"' should be removed.
    extern "C" void PWM1_IRQHandler(void) {
        PWM_ClearStatusFlags(PWM, kPWM_Pwm1);
    }