Timer based PWM output for MAX32630FTHR platform

This library provides PWM output using the MAX32630 32-bit timers.

The mbed PwmOut API implementation uses the MAX32630 Pulse Train peripherals.

The table below contains the available GPIO pins that can be connected to the six 32-bit timers (TMR0-5). Timer 0 is used for the microsecond ticker API and is not available for PWM output. Timer 5 is used by the BLE API and will not be available for PWM output if the BLE API is used.

TimerGPIO Port and Pin
TMR1P3_1, P5_3
TMR2P2_4, P3_2, P4_0, P5_4
TMR3P2_5, P3_3, P5_5
TMR4P2_6, P3_4, P5_0, P5_6
TMR5P3_5, P5_1

Note GPIO P2_4, P2_5 and P2_6 are connected to onboard LEDs 1, 2 and 3.

MAX32630FTHR_PwmOut.h

Committer:
jessexm
Date:
2018-04-20
Revision:
2:77d9bb2fa44e
Parent:
1:27721b0d390b
Child:
3:717258c64304

File content as of revision 2:77d9bb2fa44e:

/* Original files PwmOut.h and pwmout_api.h contained the following copyright */
/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 /* Original files PwmOut.h and pwmout_api.h combined and modified:
    19 April 2018 Maxim Integrated Products, Inc.
 */
  
#ifndef _MAX32630FTHR_PWMOUT_H_
#define _MAX32630FTHR_PWMOUT_H_

#include "mbed.h"
#include "PinNames.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_power_mgmt.h"
#include "tmr_regs.h"

/**
 * @brief Timer based PWM output for the MAX32630FTHR platform
 *
 * @details This library provides PWM output using the MAX32630 32-bit timers.
 * The mbed PwmOut API implementation uses the MAX32630 Pulse Train peripherals.
 * The table below contains the available GPIO pins that can be connected to the
 * six 32-bit timers (TMR0-5). Timer 0 is used for the microsecond ticker API
 * and is not available for PWM output. Timer 5 is used by the BLE API and will
 * not be available for PWM output if the BLE API is used.
 * 
 * Timer | GPIO Port and Pin<br>
 * TMR1  | P3_1,              P5_3<br>
 * TMR2  | P3_2,  P4_0,        P5_4<br>
 * TMR3  | P3_3,              P5_5<br>
 * TMR4  | P3_4,        P5_0,  P5_6<br>
 * TMR5  | P3_5,        P5_1<br>
 *
 * @code
 * #include "mbed.h"
 * #include "MAX32630FTHR_PwmOut.h"
 *
 * DigitalOut led(LED1, LED_OFF);
 * MAX32630FTHR_PwmOut servo(P3_4);
 *
 * int main()
 * {
 *     while (1) {
 *         led = !led;
 *         for (float pw = 0.000f; pw <= 1.000f; pw += 0.001f) {
 *              servo.write(pw);
 *              wait_ms(100);
 *         }
 *         led = !led;
 *         for (float pw = 1.000f; pw >= 0.000f; pw -= 0.001f) {
 *              servo = pw;
 *              wait_ms(100);
 *         }
 *     }
 * }
 * @endcode
 */

class MAX32630FTHR_PwmOut
{
public:
    
    /** Create a PwmOut connected to the specified pin
     *
     *  @param pin PwmOut pin to connect to
     */
    MAX32630FTHR_PwmOut(PinName pin) : _deep_sleep_locked(false) {
        core_util_critical_section_enter();
        pwmout_init(pin);
        core_util_critical_section_exit();
    }

    ~MAX32630FTHR_PwmOut() {
        core_util_critical_section_enter();
        unlock_deep_sleep();
        core_util_critical_section_exit();
    }

    /** Set the ouput duty-cycle, specified as a percentage (float)
     *
     *  @param value A floating-point value representing the output duty-cycle,
     *    specified as a percentage. The value should lie between
     *    0.0f (representing on 0%) and 1.0f (representing on 100%).
     *    Values outside this range will be saturated to 0.0f or 1.0f.
     */
    void write(float value) {
        core_util_critical_section_enter();
        lock_deep_sleep();
        pwmout_write(value);
        core_util_critical_section_exit();
    }

    /** Return the current output duty-cycle setting, measured as a percentage (float)
     *
     *  @returns
     *    A floating-point value representing the current duty-cycle being output on the pin,
     *    measured as a percentage. The returned value will lie between
     *    0.0f (representing on 0%) and 1.0f (representing on 100%).
     *
     *  @note
     *  This value may not match exactly the value set by a previous write().
     */
    float read() {
        core_util_critical_section_enter();
        float val = pwmout_read();
        core_util_critical_section_exit();
        return val;
    }

    /** Set the PWM period, specified in seconds (float), keeping the duty cycle the same.
     *
     *  @param seconds Change the period of a PWM signal in seconds (float) without modifying the duty cycle
     *  @note
     *   The resolution is currently in microseconds; periods smaller than this
     *   will be set to zero.
     */
    void period(float seconds) {
        core_util_critical_section_enter();
        pwmout_period(seconds);
        core_util_critical_section_exit();
    }

    /** Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same.
     *  @param ms Change the period of a PWM signal in milli-seconds without modifying the duty cycle
     */
    void period_ms(int ms) {
        core_util_critical_section_enter();
        pwmout_period_ms(ms);
        core_util_critical_section_exit();
    }

    /** Set the PWM period, specified in micro-seconds (int), keeping the duty cycle the same.
     *  @param us Change the period of a PWM signal in micro-seconds without modifying the duty cycle
     */
    void period_us(int us) {
        core_util_critical_section_enter();
        pwmout_period_us(us);
        core_util_critical_section_exit();
    }

    /** Set the PWM pulsewidth, specified in seconds (float), keeping the period the same.
     *  @param seconds Change the pulse width of a PWM signal specified in seconds (float)
     */
    void pulsewidth(float seconds) {
        core_util_critical_section_enter();
        pwmout_pulsewidth(seconds);
        core_util_critical_section_exit();
    }

    /** Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same.
     *  @param ms Change the pulse width of a PWM signal specified in milli-seconds
     */
    void pulsewidth_ms(int ms) {
        core_util_critical_section_enter();
        pwmout_pulsewidth_ms(ms);
        core_util_critical_section_exit();
    }

    /** Set the PWM pulsewidth, specified in micro-seconds (int), keeping the period the same.
     *  @param us Change the pulse width of a PWM signal specified in micro-seconds
     */
    void pulsewidth_us(int us) {
        core_util_critical_section_enter();
        pwmout_pulsewidth_us(us);
        core_util_critical_section_exit();
    }

    /** A operator shorthand for write()
     *  \sa PwmOut::write()
     */
    MAX32630FTHR_PwmOut& operator= (float value) {
        // Underlying call is thread safe
        write(value);
        return *this;
    }

    /** A operator shorthand for write()
     * \sa PwmOut::write()
     */
    MAX32630FTHR_PwmOut& operator= (PwmOut& rhs) {
        // Underlying call is thread safe
        write(rhs.read());
        return *this;
    }

    /** An operator shorthand for read()
     * \sa PwmOut::read()
     */
    operator float() {
        // Underlying call is thread safe
        return read();
    }

protected:
    /** Lock deep sleep only if it is not yet locked */
    void lock_deep_sleep() {
        if (_deep_sleep_locked == false) {
            sleep_manager_lock_deep_sleep();
            _deep_sleep_locked = true;
        }
    }

    /** Unlock deep sleep in case it is locked */
    void unlock_deep_sleep() {
        if (_deep_sleep_locked == true) {
            sleep_manager_unlock_deep_sleep();
            _deep_sleep_locked = false;
        }
    }

    bool _deep_sleep_locked;

private:
    /** Initialize the pwm out peripheral and configure the pin
     *
     * @param obj The pwmout object to initialize
     * @param pin The pwmout pin to initialize
     */
    void pwmout_init(PinName pin);

    /** Deinitialize the pwmout object
     *
     * @param obj The pwmout object
     */
    void pwmout_free();

    /** Set the output duty-cycle in range <0.0f, 1.0f>
     *
     * Value 0.0f represents 0 percentage, 1.0f represents 100 percent.
     * @param obj     The pwmout object
     * @param percent The floating-point percentage number
     */
    void pwmout_write(float percent);

    /** Read the current float-point output duty-cycle
     *
     * @param obj The pwmout object
     * @return A floating-point output duty-cycle
     */
    float pwmout_read();

    /** Set the PWM period specified in seconds, keeping the duty cycle the same
     *
     * Periods smaller than microseconds (the lowest resolution) are set to zero.
     * @param obj     The pwmout object
     * @param seconds The floating-point seconds period
     */
    void pwmout_period(float seconds);

    /** Set the PWM period specified in miliseconds, keeping the duty cycle the same
     *
     * @param obj The pwmout object
     * @param ms  The milisecond period
     */
    void pwmout_period_ms(int ms);

    /** Set the PWM period specified in microseconds, keeping the duty cycle the same
     *
     * @param obj The pwmout object
     * @param us  The microsecond period
     */
    void pwmout_period_us(int us);

    /** Set the PWM pulsewidth specified in seconds, keeping the period the same.
     *
     * @param obj     The pwmout object
     * @param seconds The floating-point pulsewidth in seconds
     */
    void pwmout_pulsewidth(float seconds);

    /** Set the PWM pulsewidth specified in miliseconds, keeping the period the same.
     *
     * @param obj The pwmout object
     * @param ms  The floating-point pulsewidth in miliseconds
     */
    void pwmout_pulsewidth_ms(int ms);

    /** Set the PWM pulsewidth specified in microseconds, keeping the period the same.
     *
     * @param obj The pwmout object
     * @param us  The floating-point pulsewidth in microseconds
     */
    void pwmout_pulsewidth_us(int us);


    PinName pin;
    mxc_tmr_regs_t *tmr;
    int tmr_idx;
    int pwm_period;
    int pulse_width;
    int last_pulse_width;
    void pwmout_update(void);
};

#endif