Timer based PWM output for MAX326XXFTHR platforms
Dependents: MAX32620FTHR_PwmBlinky
Fork of MAX326XXFTHR_PwmOut by
This library provides PWM output using the MAX32620/MAX32630 32-bit timers.
The mbed PwmOut API implementation uses Pulse Train peripherals.
The tables below contain 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. On the MAX32630FTHR platform, timer 5 is used by the BLE API and will not be available for PWM output if the BLE API is used.
MAX32620FTHR 32-Bit Timer PWM Mapping
Timer | GPIO Port and Pin |
TMR1 | P0_1, P0_7, P1_5, P3_1, P4_5, P5_3 |
TMR2 | P0_2, P1_0, P1_6, P2_4, P3_2, P4_0, P4_6, P5_4 |
TMR3 | P0_3, P1_1, P1_7, P2_5, P3_3, P4_7, P5_5 |
TMR4 | P0_4, P1_2, P2_6, P3_4, P5_0, P5_6 |
TMR5 | P0_5, P1_3, P2_7, P3_5, P5_1, P5_7 |
MAX32630FTHR 32-Bit Timer PWM Mapping
Timer | GPIO Port and Pin |
TMR1 | P3_1, P5_3 |
TMR2 | P2_4, P3_2, P4_0, P5_4 |
TMR3 | P2_5, P3_3, P5_5 |
TMR4 | P2_6, P3_4, P5_0, P5_6 |
TMR5 | P3_5, P5_1 |
Note GPIO P2_4, P2_5 and P2_6 are connected to onboard LEDs 1, 2 and 3.
Revision 0:bb005bb0a24c, committed 2018-04-23
- Comitter:
- jessexm
- Date:
- Mon Apr 23 18:24:11 2018 +0000
- Commit message:
- Initial commit
Changed in this revision
MAX326XXFTHR_PwmOut.cpp | Show annotated file Show diff for this revision Revisions of this file |
MAX326XXFTHR_PwmOut.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r bb005bb0a24c MAX326XXFTHR_PwmOut.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX326XXFTHR_PwmOut.cpp Mon Apr 23 18:24:11 2018 +0000 @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (C) 2018 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + ******************************************************************************* + */ + +#include "MAX326XXFTHR_PwmOut.h" +#include "mbed_assert.h" +#include "pinmap.h" +#include "gpio_regs.h" +#include "tmr_regs.h" + +#define PWM_TMR_PRESCALE MXC_V_TMR_CTRL_PRESCALE_DIVIDE_BY_4 +#define PWM_TICKS_PER_US ((SystemCoreClock / 1000000) >> PWM_TMR_PRESCALE) +#define PWM_MAX_US (0xFFFFFFFFUL / PWM_TICKS_PER_US) + +#define MXC_GPIO_OUT_MODE_FIELD_WIDTH 4 +#define MXC_GPIO_OUT_MODE_FIELD_MASK ((uint32_t)0xFFFFFFFF >> (32 - MXC_GPIO_OUT_MODE_FIELD_WIDTH)) +#define MXC_GPIO_FUNC_SEL_FIELD_WIDTH 4 +#define MXC_GPIO_FUNC_SEL_FIELD_MASK ((uint32_t)0xFFFFFFFF >> (32 - MXC_GPIO_FUNC_SEL_FIELD_WIDTH)) + +static const PinMap PinMap_PWM[] = { +#if defined(TARGET_MAX32620FTHR) + // Timer 0 not available; used for micro-second ticker + { P0_1, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P0_2, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P0_3, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P0_4, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P0_5, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P0_7, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_0, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_1, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_2, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_3, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_5, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_6, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P1_7, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_4, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_5, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_6, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_7, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_1, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_2, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_3, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_4, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_5, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P4_0, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P4_5, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P4_6, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P4_7, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_0, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_1, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_3, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_4, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_5, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_6, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_7, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, +#elif defined(TARGET_MAX32630FTHR) + // Timer 0 not available; used for micro-second ticker + // Timer 5 not available if using BLE + { P2_4, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_5, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P2_6, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_1, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_2, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_3, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_4, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P3_5, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P4_0, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_0, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_1, MXC_BASE_TMR5, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_3, MXC_BASE_TMR1, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_4, MXC_BASE_TMR2, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_5, MXC_BASE_TMR3, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, + { P5_6, MXC_BASE_TMR4, MXC_V_GPIO_FUNC_SEL_MODE_TMR }, +#else + // Platform not supported +#endif + { NC, NC, 0 } +}; + +typedef struct { + mxc_tmr_regs_t *tmr; + uint32_t term_cnt32; + uint32_t pwm_cap32; + unsigned int port; + unsigned int port_pin; +} tmr_obj_t; + +static tmr_obj_t tmr_obj[MXC_CFG_TMR_INSTANCES]; + +static void tmr_handler(tmr_obj_t *obj) +{ + mxc_tmr_regs_t *tmr = obj->tmr; + + // Assert GPIO control to have steady state low/zero percent duty-cycle + // Update function required to restore timer control of pin + if (obj->pwm_cap32 == 0) { + MXC_GPIO->func_sel[obj->port] &= ~(MXC_GPIO_FUNC_SEL_FIELD_MASK << (MXC_GPIO_FUNC_SEL_FIELD_WIDTH * obj->port_pin)); + } else { + tmr->term_cnt32 = obj->term_cnt32; + tmr->pwm_cap32 = obj->pwm_cap32; + } + + tmr->intfl = 1; + tmr->inten = 0; +} + +static void tmr1_handler(void) { tmr_handler(&tmr_obj[1]); }; +static void tmr2_handler(void) { tmr_handler(&tmr_obj[2]); }; +static void tmr3_handler(void) { tmr_handler(&tmr_obj[3]); }; +static void tmr4_handler(void) { tmr_handler(&tmr_obj[4]); }; +static void tmr5_handler(void) { tmr_handler(&tmr_obj[5]); }; + +void MAX326XXFTHR_PwmOut::pwmout_update(void) +{ + uint32_t tcnt = (pwm_period * PWM_TICKS_PER_US); + uint32_t tcap = (pulse_width * PWM_TICKS_PER_US); + + // At init the timer will not be running + if (!(tmr->ctrl & MXC_F_TMR_CTRL_ENABLE0)) { + tmr->term_cnt32 = tcnt; + tmr->pwm_cap32 = tcap; + } else { + tmr_obj[tmr_idx].term_cnt32 = tcnt; + if (pulse_width == 0) { + tmr_obj[tmr_idx].pwm_cap32 = 0; + MXC_GPIO->out_val[tmr_obj[tmr_idx].port] &= ~(1 << tmr_obj[tmr_idx].port_pin); + } else if (pulse_width == pwm_period) { + tmr_obj[tmr_idx].pwm_cap32 = tcnt; + } else { + tmr_obj[tmr_idx].pwm_cap32 = tcap; + } + + if ((last_pulse_width == 0) && (pulse_width != 0)) { + MXC_GPIO->func_sel[tmr_obj[tmr_idx].port] |= (MXC_V_GPIO_FUNC_SEL_MODE_TMR << (MXC_GPIO_FUNC_SEL_FIELD_WIDTH * tmr_obj[tmr_idx].port_pin)); + } + + last_pulse_width = pulse_width; + + tmr->intfl = 1; + tmr->inten = 1; + } +} + +void MAX326XXFTHR_PwmOut::pwmout_init(PinName pin) +{ + int i; + + // Make sure the pin is free for GPIO use + unsigned int port = (unsigned int)pin >> PORT_SHIFT; + unsigned int port_pin = (unsigned int)pin & ~(0xFFFFFFFF << PORT_SHIFT); + MBED_ASSERT(MXC_GPIO->free[port] & (MXC_V_GPIO_FREE_AVAILABLE << port_pin)); + + // Make sure the pin is not associated with a PT or TIMER + int pin_func = (MXC_GPIO->func_sel[port] >> (MXC_GPIO_FUNC_SEL_FIELD_WIDTH * port_pin)) & MXC_GPIO_FUNC_SEL_FIELD_MASK; + MBED_ASSERT(pin_func == MXC_V_GPIO_FUNC_SEL_MODE_GPIO); + + // Search through PinMap to find the pin + for (i = 0; (PinMap_PWM[i].pin != NC) && (PinMap_PWM[i].pin != pin); i++); + MBED_ASSERT(PinMap_PWM[i].pin != NC); + + // Check timer is available + tmr = (mxc_tmr_regs_t*)PinMap_PWM[i].peripheral; + MBED_ASSERT(!(tmr->ctrl & MXC_F_TMR_CTRL_ENABLE0)); + + // Prep for interrupt handler + tmr_idx = MXC_TMR_GET_IDX(tmr); + switch (tmr_idx) { + case 1: + NVIC_SetVector(TMR1_0_IRQn, (uint32_t)tmr1_handler); + NVIC_EnableIRQ(TMR1_0_IRQn); + break; + case 2: + NVIC_SetVector(TMR2_0_IRQn, (uint32_t)tmr2_handler); + NVIC_EnableIRQ(TMR2_0_IRQn); + break; + case 3: + NVIC_SetVector(TMR3_0_IRQn, (uint32_t)tmr3_handler); + NVIC_EnableIRQ(TMR3_0_IRQn); + break; + case 4: + NVIC_SetVector(TMR4_0_IRQn, (uint32_t)tmr4_handler); + NVIC_EnableIRQ(TMR4_0_IRQn); + break; + case 5: + NVIC_SetVector(TMR5_0_IRQn, (uint32_t)tmr5_handler); + NVIC_EnableIRQ(TMR5_0_IRQn); + break; + case 0: + default: + MBED_ASSERT(0); + } + + tmr_obj[tmr_idx].tmr = tmr; + tmr_obj[tmr_idx].term_cnt32 = 0; + tmr_obj[tmr_idx].pwm_cap32 = 0; + tmr_obj[tmr_idx].port = port; + tmr_obj[tmr_idx].port_pin = port_pin; + + this->pin = pin; + + // Initial state + pwm_period = -1; + pulse_width = -1; + last_pulse_width = -1; + + // Disable timer/clear settings + tmr->ctrl = 0; + + // Set mode and polarity + tmr->ctrl = MXC_S_TMR_CTRL_MODE_PWM | + MXC_F_TMR_CTRL_POLARITY | + (PWM_TMR_PRESCALE << MXC_F_TMR_CTRL_PRESCALE_POS); + + // Reset counts + tmr->count32 = 1; + tmr->term_cnt32 = 0; + tmr->pwm_cap32 = 0; + + // Configure the pin + PinMode mode = (PinMode)PullNone; +#ifdef OPEN_DRAIN_LEDS + if ((pin == LED1) || (pin == LED2) || (pin == LED3) || (pin == LED4)) { + mode = (PinMode)OpenDrain; + MXC_IOMAN->use_vddioh_0 |= (1 << ((8 * port) + port_pin)); + } +#endif + pin_mode(pin, mode); + pin_function(pin, PinMap_PWM[i].function); + + // Default to 20ms: standard for servos, and fine for e.g. brightness control + pwmout_period_us(20000); + pwmout_write(0.0f); + + // Set the drive mode to normal + MXC_SET_FIELD(&MXC_GPIO->out_mode[port], + (MXC_GPIO_OUT_MODE_FIELD_MASK << (port_pin * MXC_GPIO_OUT_MODE_FIELD_WIDTH)), + (MXC_V_GPIO_OUT_MODE_NORMAL << (port_pin * MXC_GPIO_OUT_MODE_FIELD_WIDTH))); + + // Enable timer + tmr->ctrl |= MXC_F_TMR_CTRL_ENABLE0; +} + +void MAX326XXFTHR_PwmOut::pwmout_free() +{ + // GPIO control of pin + MXC_GPIO->func_sel[(unsigned int)pin >> PORT_SHIFT] &= + ~(MXC_GPIO_FUNC_SEL_FIELD_MASK << (MXC_GPIO_FUNC_SEL_FIELD_WIDTH * + (unsigned int)pin & ~(0xFFFFFFFF << PORT_SHIFT))); + // Disable timer + tmr->ctrl = 0; +} + +void MAX326XXFTHR_PwmOut::pwmout_write(float percent) +{ + // Saturate percent if outside of range + if (percent < 0.0f) { + percent = 0.0f; + } else if (percent > 1.0f) { + percent = 1.0f; + } + + // Resize the pulse width to set the duty cycle + pwmout_pulsewidth_us((int)(percent * pwm_period)); +} + +float MAX326XXFTHR_PwmOut::pwmout_read() +{ + // Check for when pulsewidth or period equals 0 + if((pulse_width == 0) || (pwm_period == 0)) { + return 0.0f; + } + + // Return the duty cycle + return ((float)pulse_width / (float)pwm_period); +} + +void MAX326XXFTHR_PwmOut::pwmout_period(float seconds) +{ + pwmout_period_us((int)(seconds * 1000000.0f)); +} + +void MAX326XXFTHR_PwmOut::pwmout_period_ms(int ms) +{ + pwmout_period_us(ms * 1000); +} + +void MAX326XXFTHR_PwmOut::pwmout_period_us(int us) +{ + // Check the range of the period + MBED_ASSERT((us >= 0) && (us <= (int)PWM_MAX_US)); + + // Set pulse width to half the period if uninitialized + if (pulse_width == -1) { + pulse_width = us / 2; + } + + // Save the period + pwm_period = us; + + // Update the registers + pwmout_update(); +} + +void MAX326XXFTHR_PwmOut::pwmout_pulsewidth(float seconds) +{ + pwmout_pulsewidth_us((int)(seconds * 1000000.0f)); +} + +void MAX326XXFTHR_PwmOut::pwmout_pulsewidth_ms(int ms) +{ + pwmout_pulsewidth_us(ms * 1000); +} + +void MAX326XXFTHR_PwmOut::pwmout_pulsewidth_us(int us) +{ + // Check the range of the pulsewidth + MBED_ASSERT((us >= 0) && (us <= (int)PWM_MAX_US)); + + // Initialize period to double the pulsewidth if uninitialized + if (pwm_period == -1) { + pwm_period = 2 * us; + } + + // Save the pulsewidth + pulse_width = us; + + // Update the register + pwmout_update(); +}
diff -r 000000000000 -r bb005bb0a24c MAX326XXFTHR_PwmOut.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX326XXFTHR_PwmOut.h Mon Apr 23 18:24:11 2018 +0000 @@ -0,0 +1,325 @@ +/* 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: + 23 April 2018 Maxim Integrated Products, Inc. + */ + +#ifndef _MAX326XXFTHR_PWMOUT_H_ +#define _MAX326XXFTHR_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 MAX326XXFTHR platform + * + * @details This library provides PWM output using the MAX326XX 32-bit timers. + * The mbed PwmOut API implementation uses the MAX326XX 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. On the MAX32630FTHR platform, + * timer 5 is used by the BLE API and will not be available for PWM output if + * the BLE API is used. + * + * MAX32620FTHR 32-Bit Timer PWM Mapping + * + * Timer | GPIO Port and Pin <br> + * TMR1 | P0_1, P0_7, P1_5, P3_1, P4_5, P5_3 <br> + * TMR2 | P0_2, P1_0, P1_6, P2_4, P3_2, P4_0, P4_6, P5_4 <br> + * TMR3 | P0_3 P1_1 P1_7, P2_5, P3_3, P4_7, P5_5 <br> + * TMR4 | P0_4 P1_2 P2_6, P3_4, P5_0, P5_6 <br> + * TMR5 | P0_5 P1_3 P2_7, P3_5, P5_1, P5_7 <br> + * + * MAX32630FTHR 32-Bit Timer PWM Mapping + * + * Timer | GPIO Port and Pin <br> + * TMR1 | P3_1, P5_3 <br> + * TMR2 | P2_4, P3_2, P4_0, P5_4 <br> + * TMR3 | P2_5, P3_3, P5_5 <br> + * TMR4 | P2_6, P3_4, P5_0, P5_6 <br> + * TMR5 | P3_5, P5_1 <br> + * + * Note that for MAX32620FTHR and MAX32630FTHR GPIOs P2_4, P2_5 and P2_6 are + * connected to onboard LEDs 1, 2 and 3. + * + * @code + * #include "mbed.h" + * #include "MAX326XXFTHR_PwmOut.h" + * + * MAX326XXFTHR_PwmOut led[] = { + * MAX326XXFTHR_PwmOut(LED1), + * MAX326XXFTHR_PwmOut(LED2), + * MAX326XXFTHR_PwmOut(LED3) + * }; + * + * int main() + * { + * float dc; + * unsigned int idx = 0; + * + * while (1) { + * for (dc = 0.0f; dc <= 1.0f; dc += 0.01f) { + * led[idx % 3].write(dc); + * led[(idx + 1) % 3].write(1.0f - dc); + * wait_ms(20); + * } + * idx++; + * } + * } + * @endcode + */ + +class MAX326XXFTHR_PwmOut +{ +public: + + /** Create a PwmOut connected to the specified pin + * + * @param pin PwmOut pin to connect to + */ + MAX326XXFTHR_PwmOut(PinName pin) : _deep_sleep_locked(false) { + core_util_critical_section_enter(); + pwmout_init(pin); + core_util_critical_section_exit(); + } + + ~MAX326XXFTHR_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() + */ + MAX326XXFTHR_PwmOut& operator= (float value) { + // Underlying call is thread safe + write(value); + return *this; + } + + /** A operator shorthand for write() + * \sa PwmOut::write() + */ + MAX326XXFTHR_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