Import Mbed OS hard-float snapshot
This commit is contained in:
356
targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c
Normal file
356
targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/pwmout_api.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
|
||||
* integrated circuit in a product or a software update for such product, must reproduce
|
||||
* the above copyright notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary or object form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#if DEVICE_PWMOUT
|
||||
|
||||
#include "hal/pwmout_api.h"
|
||||
#include "PeripheralPins.h"
|
||||
#include "pinmap_ex.h"
|
||||
#include "nrfx_pwm.h"
|
||||
|
||||
#if 0
|
||||
#define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define DEBUG_PRINTF(...) {}
|
||||
#endif
|
||||
|
||||
/* 0x7FFF is the max of COUNTERTOP pulse for the PWM peripherial of the nRF52. */
|
||||
#define MAX_PWM_COUNTERTOP (0x7FFF)
|
||||
|
||||
/* The PWM is driven by a 1 MHz clock to fit the 1 us resolution expected by the API. */
|
||||
#define MAX_PWM_PERIOD_US (MAX_PWM_COUNTERTOP)
|
||||
#define MAX_PWM_PERIOD_MS (MAX_PWM_PERIOD_US / 1000)
|
||||
#define MAX_PWM_PERIOD_S ((float) MAX_PWM_PERIOD_US / 1000000.0f)
|
||||
|
||||
/* Sequence bit that denotes the polarity of the pwm waveform. */
|
||||
#define SEQ_POLARITY_BIT (0x8000)
|
||||
|
||||
/* Allocate PWM instances. */
|
||||
static nrfx_pwm_t nordic_nrf5_pwm_instance[] = {
|
||||
#if NRFX_PWM0_ENABLED
|
||||
NRFX_PWM_INSTANCE(0),
|
||||
#endif
|
||||
#if NRFX_PWM1_ENABLED
|
||||
NRFX_PWM_INSTANCE(1),
|
||||
#endif
|
||||
#if NRFX_PWM2_ENABLED
|
||||
NRFX_PWM_INSTANCE(2),
|
||||
#endif
|
||||
#if NRFX_PWM3_ENABLED
|
||||
NRFX_PWM_INSTANCE(3),
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Helper function for (re)initializing the PWM instance.
|
||||
*/
|
||||
static void nordic_pwm_init(pwmout_t *obj)
|
||||
{
|
||||
MBED_ASSERT(obj);
|
||||
|
||||
/* Default configuration:
|
||||
* 1 pin per instance, otherwise they would share base count.
|
||||
* 1 MHz clock source to match the 1 us resolution.
|
||||
*/
|
||||
nrfx_pwm_config_t config = {
|
||||
.output_pins = {
|
||||
obj->pin,
|
||||
NRFX_PWM_PIN_NOT_USED,
|
||||
NRFX_PWM_PIN_NOT_USED,
|
||||
NRFX_PWM_PIN_NOT_USED,
|
||||
},
|
||||
.irq_priority = PWM_DEFAULT_CONFIG_IRQ_PRIORITY,
|
||||
.base_clock = NRF_PWM_CLK_1MHz,
|
||||
.count_mode = NRF_PWM_MODE_UP,
|
||||
.top_value = obj->period,
|
||||
.load_mode = NRF_PWM_LOAD_COMMON,
|
||||
.step_mode = NRF_PWM_STEP_AUTO,
|
||||
};
|
||||
|
||||
/* Initialize instance with new configuration. */
|
||||
ret_code_t result = nrfx_pwm_init(&nordic_nrf5_pwm_instance[obj->instance],
|
||||
&config,
|
||||
NULL);
|
||||
|
||||
MBED_ASSERT(result == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
/* Helper function for reinitializing the PWM instance and setting the duty-cycle. */
|
||||
static void nordic_pwm_restart(pwmout_t *obj)
|
||||
{
|
||||
MBED_ASSERT(obj);
|
||||
|
||||
/* Uninitialize PWM instance */
|
||||
nrfx_pwm_uninit(&nordic_nrf5_pwm_instance[obj->instance]);
|
||||
|
||||
/* (Re)initialize PWM instance. */
|
||||
nordic_pwm_init(obj);
|
||||
|
||||
/* Set duty-cycle from object. */
|
||||
ret_code_t result = nrfx_pwm_simple_playback(&nordic_nrf5_pwm_instance[obj->instance],
|
||||
&obj->sequence,
|
||||
1,
|
||||
NRFX_PWM_FLAG_LOOP);
|
||||
|
||||
MBED_ASSERT(result == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
/** Initialize the pwm out peripheral and configure the pin
|
||||
*
|
||||
* Parameter obj The pwmout object to initialize
|
||||
* Parameter pin The pwmout pin to initialize
|
||||
*/
|
||||
void pwmout_init(pwmout_t *obj, PinName pin)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_init: %d\r\n", pin);
|
||||
|
||||
MBED_ASSERT(obj);
|
||||
|
||||
/* Get hardware instance from pinmap. */
|
||||
int instance = pin_instance_pwm(pin);
|
||||
|
||||
MBED_ASSERT(instance < (int) (sizeof(nordic_nrf5_pwm_instance) / sizeof(nrfx_pwm_t)));
|
||||
|
||||
/* Populate PWM object with default values. */
|
||||
obj->instance = instance;
|
||||
obj->pin = pin;
|
||||
obj->pulse = 0;
|
||||
obj->period = MAX_PWM_COUNTERTOP;
|
||||
obj->percent = 0;
|
||||
obj->sequence.values.p_common = &obj->pulse;
|
||||
obj->sequence.length = NRF_PWM_VALUES_LENGTH(obj->pulse);
|
||||
obj->sequence.repeats = 0;
|
||||
obj->sequence.end_delay = 0;
|
||||
|
||||
/* Set active low logic. */
|
||||
obj->pulse |= SEQ_POLARITY_BIT;
|
||||
|
||||
/* Initialize PWM instance. */
|
||||
nordic_pwm_init(obj);
|
||||
}
|
||||
|
||||
/** Deinitialize the pwmout object
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
*/
|
||||
void pwmout_free(pwmout_t *obj)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_free\r\n");
|
||||
|
||||
MBED_ASSERT(obj);
|
||||
|
||||
/* Uninitialize PWM instance. */
|
||||
nrfx_pwm_uninit(&nordic_nrf5_pwm_instance[obj->instance]);
|
||||
}
|
||||
|
||||
/** Set the output duty-cycle in range <0.0f, 1.0f>
|
||||
*
|
||||
* pulse 0.0f represents 0 percentage, 1.0f represents 100 percent.
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter percent The floating-point percentage number
|
||||
*/
|
||||
void pwmout_write(pwmout_t *obj, float percent)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_write: %f\r\n", percent);
|
||||
|
||||
/* Find counts based on period. */
|
||||
uint16_t pulse = obj->period * percent;
|
||||
|
||||
/* Clear sequence, but keep the polarity bit */
|
||||
obj->pulse &= SEQ_POLARITY_BIT;
|
||||
|
||||
/* Ensure we don't overcount. */
|
||||
obj->pulse |= (pulse > MAX_PWM_COUNTERTOP) ? MAX_PWM_COUNTERTOP : pulse;
|
||||
|
||||
/* Store actual percentage passed as parameter to avoid floating point rounding errors. */
|
||||
obj->percent = percent;
|
||||
|
||||
/* Set new duty-cycle. */
|
||||
ret_code_t result = nrfx_pwm_simple_playback(&nordic_nrf5_pwm_instance[obj->instance],
|
||||
&obj->sequence,
|
||||
1,
|
||||
NRFX_PWM_FLAG_LOOP);
|
||||
|
||||
MBED_ASSERT(result == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
/** Read the current float-point output duty-cycle
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Return A floating-point output duty-cycle
|
||||
*/
|
||||
float pwmout_read(pwmout_t *obj)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_read: %f\r\n", obj->percent);
|
||||
|
||||
/* Return percentage stored in object instead of calculating the value.
|
||||
* This prevents floating point rounding errors.
|
||||
*/
|
||||
return obj->percent;
|
||||
}
|
||||
|
||||
/** Set the PWM period specified in seconds, keeping the duty cycle the same
|
||||
*
|
||||
* Periods smaller than microseconds (the lowest resolution) are set to zero.
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter seconds The floating-point seconds period
|
||||
*/
|
||||
void pwmout_period(pwmout_t *obj, float period)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_period: %f\r\n", period);
|
||||
|
||||
/* Cap period if too large. */
|
||||
if (period > MAX_PWM_PERIOD_S) {
|
||||
period = MAX_PWM_PERIOD_S;
|
||||
}
|
||||
|
||||
/* Set new period. */
|
||||
pwmout_period_us(obj, period * 1000000);
|
||||
}
|
||||
|
||||
/** Set the PWM period specified in miliseconds, keeping the duty cycle the same
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter ms The milisecond period
|
||||
*/
|
||||
void pwmout_period_ms(pwmout_t *obj, int period)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_period_ms: %d\r\n", period);
|
||||
|
||||
/* Cap period if too large. */
|
||||
if (period > MAX_PWM_PERIOD_MS) {
|
||||
period = MAX_PWM_PERIOD_MS;
|
||||
}
|
||||
|
||||
/* Set new period. */
|
||||
pwmout_period_us(obj, period * 1000);
|
||||
}
|
||||
|
||||
/** Set the PWM period specified in microseconds, keeping the duty cycle the same
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter us The microsecond period
|
||||
*/
|
||||
void pwmout_period_us(pwmout_t *obj, int period)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_period_us: %d\r\n", period);
|
||||
|
||||
/* Cap period if too large. */
|
||||
if (period > MAX_PWM_PERIOD_US) {
|
||||
period = MAX_PWM_PERIOD_US;
|
||||
}
|
||||
|
||||
/* Scale new count based on stored duty-cycle and new period. */
|
||||
uint32_t pulse = (period * (obj->pulse & ~SEQ_POLARITY_BIT)) / obj->period;
|
||||
|
||||
/* Store new values in object. */
|
||||
obj->pulse &= SEQ_POLARITY_BIT;
|
||||
obj->pulse |= pulse;
|
||||
obj->period = period;
|
||||
obj->percent = (float) pulse / (float) period;
|
||||
|
||||
/* Restart instance with new values. */
|
||||
nordic_pwm_restart(obj);
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth specified in seconds, keeping the period the same.
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter seconds The floating-point pulsewidth in seconds
|
||||
*/
|
||||
void pwmout_pulsewidth(pwmout_t *obj, float pulse)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_pulsewidt: %f\r\n", pulse);
|
||||
|
||||
/* Cap pulsewidth to period before setting it. */
|
||||
if ((pulse * 1000000) > (float) obj->period) {
|
||||
obj->pulse &= SEQ_POLARITY_BIT;
|
||||
obj->pulse |= obj->period;
|
||||
pwmout_pulsewidth_us(obj, obj->pulse);
|
||||
} else {
|
||||
pwmout_pulsewidth_us(obj, pulse * 1000000);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth specified in miliseconds, keeping the period the same.
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter ms The floating-point pulsewidth in miliseconds
|
||||
*/
|
||||
void pwmout_pulsewidth_ms(pwmout_t *obj, int pulse)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_pulsewidth_ms: %d\r\n", ms);
|
||||
|
||||
/* Cap pulsewidth to period before setting it. */
|
||||
if ((pulse * 1000) > (int) obj->period) {
|
||||
obj->pulse &= SEQ_POLARITY_BIT;
|
||||
obj->pulse |= obj->period;
|
||||
pwmout_pulsewidth_us(obj, obj->pulse);
|
||||
} else {
|
||||
pwmout_pulsewidth_us(obj, pulse * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth specified in microseconds, keeping the period the same.
|
||||
*
|
||||
* Parameter obj The pwmout object
|
||||
* Parameter us The floating-point pulsewidth in microseconds
|
||||
*/
|
||||
void pwmout_pulsewidth_us(pwmout_t *obj, int pulse)
|
||||
{
|
||||
DEBUG_PRINTF("pwmout_pulsewidth_us: %d\r\n", pulse);
|
||||
|
||||
/* Cap pulsewidth to period. */
|
||||
if (pulse > obj->period) {
|
||||
pulse = obj->period;
|
||||
}
|
||||
|
||||
/* Store new values in object. */
|
||||
obj->pulse &= SEQ_POLARITY_BIT;
|
||||
obj->pulse |= pulse;
|
||||
obj->percent = (float) pulse / (float) obj->period;
|
||||
|
||||
/* Restart instance with new values. */
|
||||
nordic_pwm_restart(obj);
|
||||
}
|
||||
|
||||
const PinMap *pwmout_pinmap()
|
||||
{
|
||||
return PinMap_PWM_testing;
|
||||
}
|
||||
|
||||
#endif // DEVICE_PWMOUT
|
||||
Reference in New Issue
Block a user