mirror of https://github.com/ARMmbed/mbed-os.git
nrf52 PwmOut in progress.
parent
0d9dc1e079
commit
07ce12fcc5
|
@ -1773,6 +1773,6 @@
|
|||
"NRF52_PAN_62",
|
||||
"NRF52_PAN_63"
|
||||
],
|
||||
"device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE"]
|
||||
"device_has": ["ANALOGIN", "ERROR_PATTERN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,49 +44,249 @@
|
|||
|
||||
#if DEVICE_PWMOUT
|
||||
|
||||
// TODO - provide an implementation.
|
||||
#include "app_util_platform.h"
|
||||
#include "nrf_drv_pwm.h"
|
||||
|
||||
//#include "nrf_pwm.h"
|
||||
#define PWM_INSTANCE_COUNT 3
|
||||
|
||||
static nrf_drv_pwm_t m_pwm_driver[PWM_INSTANCE_COUNT] =
|
||||
{
|
||||
NRF_DRV_PWM_INSTANCE(0),
|
||||
NRF_DRV_PWM_INSTANCE(1),
|
||||
NRF_DRV_PWM_INSTANCE(2)
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t period_us;
|
||||
uint32_t duty_us;
|
||||
} pwm_signal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_pwm_t * p_pwm_driver;
|
||||
pwm_signal_t signal;
|
||||
} pwm_t;
|
||||
|
||||
static pwm_t m_pwm[PWM_INSTANCE_COUNT] =
|
||||
{
|
||||
{.p_pwm_driver = NULL},
|
||||
{.p_pwm_driver = NULL},
|
||||
{.p_pwm_driver = NULL}
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t period;
|
||||
uint16_t duty;
|
||||
nrf_pwm_clk_t pwm_clk;
|
||||
} pulsewidth_set_t;
|
||||
|
||||
|
||||
static void internal_pwmout_exe(pwmout_t *obj);
|
||||
|
||||
void pwmout_init(pwmout_t *obj, PinName pin)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; PWM_INSTANCE_COUNT; i++)
|
||||
{
|
||||
if (m_pwm[i].p_pwm_driver == NULL) // a driver instance not assigned to the obj?
|
||||
{
|
||||
obj->pin = pin;
|
||||
/// @todo obj->pwm_name =
|
||||
obj->pwm_channel = i;
|
||||
|
||||
m_pwm[i].p_pwm_driver = &m_pwm_driver[i];
|
||||
m_pwm[i].signal.period_us = 200000; // 0.02 s
|
||||
m_pwm[i].signal.duty_us = 100000;
|
||||
|
||||
obj->pwm_struct = &m_pwm[i];
|
||||
|
||||
internal_pwmout_exe(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MBED_ASSERT(i != PWM_INSTANCE_COUNT); // assert if free instance was not found.
|
||||
}
|
||||
|
||||
void pwmout_free(pwmout_t *obj)
|
||||
{
|
||||
nrf_drv_pwm_uninit( (nrf_drv_pwm_t*) obj->pwm_struct );
|
||||
|
||||
m_pwm[obj->pwm_channel].p_pwm_driver = NULL;
|
||||
/// @todo release gpio
|
||||
}
|
||||
|
||||
void pwmout_write(pwmout_t *obj, float percent)
|
||||
{
|
||||
|
||||
if (percent < 0)
|
||||
{
|
||||
percent = 0;
|
||||
}
|
||||
else if (percent > 100)
|
||||
{
|
||||
percent = 100;
|
||||
}
|
||||
|
||||
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
|
||||
|
||||
int us = (((int)p_pwm_signal->period_us) * percent) / 100;
|
||||
|
||||
pwmout_pulsewidth_us(obj, us);
|
||||
}
|
||||
|
||||
float pwmout_read(pwmout_t *obj)
|
||||
{
|
||||
return 0.0f;
|
||||
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
|
||||
|
||||
return (float)p_pwm_signal->duty_us / (float)p_pwm_signal->period_us * 100;
|
||||
}
|
||||
|
||||
void pwmout_period(pwmout_t *obj, float seconds)
|
||||
{
|
||||
// @todo saturation
|
||||
int us = seconds * 1000000;
|
||||
|
||||
pwmout_period_us(obj, us);
|
||||
}
|
||||
|
||||
void pwmout_period_ms(pwmout_t *obj, int ms)
|
||||
{
|
||||
int us = ms * 1000;
|
||||
|
||||
pwmout_period_us(obj, us);
|
||||
}
|
||||
|
||||
void pwmout_period_us(pwmout_t *obj, int us)
|
||||
{
|
||||
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
|
||||
|
||||
p_pwm_signal->period_us = us;
|
||||
|
||||
internal_pwmout_exe(obj);
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth(pwmout_t *obj, float seconds)
|
||||
{
|
||||
// @todo saturation
|
||||
int us = seconds * 1000000;
|
||||
|
||||
pwmout_pulsewidth_us(obj,us);
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
|
||||
{
|
||||
// @todo saturation
|
||||
int us = ms * 1000;
|
||||
|
||||
pwmout_pulsewidth_us(obj,us);
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
|
||||
{
|
||||
// @todo saturation
|
||||
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
|
||||
|
||||
p_pwm_signal->duty_us = us;
|
||||
|
||||
internal_pwmout_exe(obj);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static ret_code_t pulsewidth_us_set_get(int period_us, int duty_us, pulsewidth_set_t * const p_settings)
|
||||
{
|
||||
uint16_t div;
|
||||
nrf_pwm_clk_t pwm_clk = NRF_PWM_CLK_16MHz;
|
||||
|
||||
for(div = 1; div <= 128 ; div <<= 1)
|
||||
{
|
||||
if (0xFFFF >= period_us)
|
||||
{
|
||||
p_settings->period = period_us; // unit [us * div]
|
||||
p_settings->duty = duty_us; // unit [us * div]
|
||||
p_settings->pwm_clk = pwm_clk;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
period_us >>= 1;
|
||||
duty_us >>= 1;
|
||||
pwm_clk++;
|
||||
}
|
||||
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
static nrf_pwm_values_common_t seq_values[1];
|
||||
|
||||
static nrf_pwm_sequence_t const seq =
|
||||
{
|
||||
.values.p_common = seq_values,
|
||||
.length = NRF_PWM_VALUES_LENGTH(seq_values),
|
||||
.repeats = 0,
|
||||
.end_delay = 0
|
||||
};
|
||||
|
||||
static void internal_pwmout_exe(pwmout_t *obj)
|
||||
{
|
||||
pulsewidth_set_t pulsewidth_set;
|
||||
pwm_signal_t * p_pwm_signal;
|
||||
nrf_drv_pwm_t *p_pwm_driver;
|
||||
ret_code_t ret_code;
|
||||
|
||||
p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
|
||||
|
||||
if (NRF_SUCCESS == pulsewidth_us_set_get(p_pwm_signal->period_us,
|
||||
p_pwm_signal->duty_us,
|
||||
&pulsewidth_set))
|
||||
{
|
||||
//@todo apply pulsewidth_set
|
||||
p_pwm_driver = (((pwm_t*)obj->pwm_struct)->p_pwm_driver);
|
||||
|
||||
nrf_drv_pwm_config_t config0 =
|
||||
{
|
||||
.output_pins =
|
||||
{
|
||||
obj->pin, // channel 0
|
||||
NRF_DRV_PWM_PIN_NOT_USED, // channel 1
|
||||
NRF_DRV_PWM_PIN_NOT_USED, // channel 2
|
||||
NRF_DRV_PWM_PIN_NOT_USED, // channel 3
|
||||
},
|
||||
.irq_priority = APP_IRQ_PRIORITY_LOW,
|
||||
.base_clock = pulsewidth_set.pwm_clk,
|
||||
.count_mode = NRF_PWM_MODE_UP,
|
||||
.top_value = pulsewidth_set.period,
|
||||
.load_mode = NRF_PWM_LOAD_COMMON,
|
||||
.step_mode = NRF_PWM_STEP_AUTO
|
||||
};
|
||||
|
||||
|
||||
//printf("clock = %d, top = %d\r\n", pulsewidth_set.pwm_clk, pulsewidth_set.period);
|
||||
|
||||
nrf_drv_pwm_uninit(p_pwm_driver);
|
||||
|
||||
ret_code = nrf_drv_pwm_init( p_pwm_driver, &config0, NULL);
|
||||
|
||||
MBED_ASSERT(ret_code == NRF_SUCCESS); // assert if free instance was not found.
|
||||
|
||||
seq_values[0] = pulsewidth_set.duty;
|
||||
|
||||
nrf_drv_pwm_simple_playback(p_pwm_driver, &seq, 3, NRF_DRV_PWM_FLAG_LOOP);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MBED_ASSERT(0); // force assertion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // DEVICE_PWMOUT
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
|
||||
*
|
||||
* The information contained herein is property of Nordic Semiconductor ASA.
|
||||
* Terms and conditions of usage are described in detail in NORDIC
|
||||
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
|
||||
*
|
||||
* Licensees are granted free, non-transferable use of the information. NO
|
||||
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
|
||||
* the file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "nrf_drv_pwm.h"
|
||||
#include "nrf_drv_common.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include "app_util_platform.h"
|
||||
|
||||
#if (PWM_COUNT == 0)
|
||||
#error "No PWM instances enabled in the driver configuration file."
|
||||
#endif
|
||||
|
||||
|
||||
// Control block - driver instance local data.
|
||||
typedef struct
|
||||
{
|
||||
nrf_drv_pwm_handler_t handler;
|
||||
nrf_drv_state_t volatile state;
|
||||
} pwm_control_block_t;
|
||||
static pwm_control_block_t m_cb[PWM_COUNT];
|
||||
|
||||
static nrf_drv_pwm_config_t const m_default_config[PWM_COUNT] = {
|
||||
#if PWM0_ENABLED
|
||||
NRF_DRV_PWM_DEFAULT_CONFIG(0),
|
||||
#endif
|
||||
#if PWM1_ENABLED
|
||||
NRF_DRV_PWM_DEFAULT_CONFIG(1),
|
||||
#endif
|
||||
#if PWM2_ENABLED
|
||||
NRF_DRV_PWM_DEFAULT_CONFIG(2),
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
static void configure_pins(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_drv_pwm_config_t const * p_config)
|
||||
{
|
||||
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT];
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
|
||||
{
|
||||
uint8_t output_pin = p_config->output_pins[i];
|
||||
if (output_pin != NRF_DRV_PWM_PIN_NOT_USED)
|
||||
{
|
||||
bool inverted = output_pin & NRF_DRV_PWM_PIN_INVERTED;
|
||||
out_pins[i] = output_pin & ~NRF_DRV_PWM_PIN_INVERTED;
|
||||
|
||||
if (inverted)
|
||||
{
|
||||
nrf_gpio_pin_set(out_pins[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nrf_gpio_pin_clear(out_pins[i]);
|
||||
}
|
||||
|
||||
nrf_gpio_cfg_output(out_pins[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
nrf_pwm_pins_set(p_instance->p_registers, out_pins);
|
||||
}
|
||||
|
||||
|
||||
ret_code_t nrf_drv_pwm_init(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_drv_pwm_config_t const * p_config,
|
||||
nrf_drv_pwm_handler_t handler)
|
||||
{
|
||||
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
|
||||
|
||||
if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (p_config == NULL)
|
||||
{
|
||||
p_config = &m_default_config[p_instance->drv_inst_idx];
|
||||
}
|
||||
|
||||
p_cb->handler = handler;
|
||||
|
||||
configure_pins(p_instance, p_config);
|
||||
|
||||
nrf_pwm_enable(p_instance->p_registers);
|
||||
nrf_pwm_configure(p_instance->p_registers,
|
||||
p_config->base_clock, p_config->count_mode, p_config->top_value);
|
||||
nrf_pwm_decoder_set(p_instance->p_registers,
|
||||
p_config->load_mode, p_config->step_mode);
|
||||
|
||||
nrf_pwm_shorts_set(p_instance->p_registers, 0);
|
||||
nrf_pwm_int_set(p_instance->p_registers, 0);
|
||||
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_LOOPSDONE);
|
||||
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND0);
|
||||
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND1);
|
||||
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
|
||||
|
||||
if (p_cb->handler)
|
||||
{
|
||||
nrf_drv_common_irq_enable(nrf_drv_get_IRQn(p_instance->p_registers),
|
||||
p_config->irq_priority);
|
||||
}
|
||||
|
||||
p_cb->state = NRF_DRV_STATE_INITIALIZED;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void nrf_drv_pwm_uninit(nrf_drv_pwm_t const * const p_instance)
|
||||
{
|
||||
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
|
||||
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
|
||||
|
||||
nrf_drv_common_irq_disable(nrf_drv_get_IRQn(p_instance->p_registers));
|
||||
|
||||
nrf_pwm_disable(p_instance->p_registers);
|
||||
|
||||
p_cb->state = NRF_DRV_STATE_UNINITIALIZED;
|
||||
}
|
||||
|
||||
|
||||
static void start_playback(nrf_drv_pwm_t const * const p_instance,
|
||||
pwm_control_block_t * p_cb,
|
||||
uint8_t flags,
|
||||
nrf_pwm_task_t starting_task)
|
||||
{
|
||||
p_cb->state = NRF_DRV_STATE_POWERED_ON;
|
||||
|
||||
if (p_cb->handler)
|
||||
{
|
||||
// The notification about finished playback is by default enabled, but
|
||||
// this can be suppressed. The notification that the peripheral has been
|
||||
// stopped is always enable.
|
||||
uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK |
|
||||
NRF_PWM_INT_STOPPED_MASK;
|
||||
|
||||
if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0)
|
||||
{
|
||||
int_mask |= NRF_PWM_INT_SEQEND0_MASK;
|
||||
}
|
||||
if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1)
|
||||
{
|
||||
int_mask |= NRF_PWM_INT_SEQEND1_MASK;
|
||||
}
|
||||
if (flags & NRF_DRV_PWM_FLAG_NO_EVT_FINISHED)
|
||||
{
|
||||
int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK;
|
||||
}
|
||||
|
||||
nrf_pwm_int_set(p_instance->p_registers, int_mask);
|
||||
}
|
||||
|
||||
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
|
||||
|
||||
nrf_pwm_task_trigger(p_instance->p_registers, starting_task);
|
||||
}
|
||||
|
||||
|
||||
void nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_sequence_t const * p_sequence,
|
||||
uint16_t playback_count,
|
||||
uint32_t flags)
|
||||
{
|
||||
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
|
||||
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
|
||||
ASSERT(playback_count > 0);
|
||||
ASSERT(nrf_drv_is_in_RAM(p_sequence->values.p_raw));
|
||||
|
||||
// To take advantage of the looping mechanism, we need to use both sequences
|
||||
// (single sequence can be played back only once).
|
||||
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence);
|
||||
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence);
|
||||
bool odd = (playback_count & 1);
|
||||
nrf_pwm_loop_set(p_instance->p_registers, playback_count/2 + (odd ? 1 : 0));
|
||||
|
||||
uint32_t shorts_mask;
|
||||
if (flags & NRF_DRV_PWM_FLAG_STOP)
|
||||
{
|
||||
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
|
||||
}
|
||||
else if (flags & NRF_DRV_PWM_FLAG_LOOP)
|
||||
{
|
||||
shorts_mask = odd ? NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK
|
||||
: NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
shorts_mask = 0;
|
||||
}
|
||||
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
|
||||
|
||||
start_playback(p_instance, p_cb, flags, odd ? NRF_PWM_TASK_SEQSTART1
|
||||
: NRF_PWM_TASK_SEQSTART0);
|
||||
}
|
||||
|
||||
|
||||
void nrf_drv_pwm_complex_playback(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_sequence_t const * p_sequence_0,
|
||||
nrf_pwm_sequence_t const * p_sequence_1,
|
||||
uint16_t playback_count,
|
||||
uint32_t flags)
|
||||
{
|
||||
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
|
||||
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
|
||||
ASSERT(playback_count > 0);
|
||||
ASSERT(nrf_drv_is_in_RAM(p_sequence_0->values.p_raw));
|
||||
ASSERT(nrf_drv_is_in_RAM(p_sequence_1->values.p_raw));
|
||||
|
||||
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence_0);
|
||||
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence_1);
|
||||
nrf_pwm_loop_set(p_instance->p_registers, playback_count);
|
||||
|
||||
uint32_t shorts_mask;
|
||||
if (flags & NRF_DRV_PWM_FLAG_STOP)
|
||||
{
|
||||
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
|
||||
}
|
||||
else if (flags & NRF_DRV_PWM_FLAG_LOOP)
|
||||
{
|
||||
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
shorts_mask = 0;
|
||||
}
|
||||
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
|
||||
|
||||
start_playback(p_instance, p_cb, flags, NRF_PWM_TASK_SEQSTART0);
|
||||
}
|
||||
|
||||
|
||||
bool nrf_drv_pwm_stop(nrf_drv_pwm_t const * const p_instance,
|
||||
bool wait_until_stopped)
|
||||
{
|
||||
ASSERT(m_cb[p_instance->drv_inst_idx].state != NRF_DRV_STATE_UNINITIALIZED);
|
||||
|
||||
if (nrf_drv_pwm_is_stopped(p_instance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP);
|
||||
|
||||
do {
|
||||
if (nrf_drv_pwm_is_stopped(p_instance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} while (wait_until_stopped);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool nrf_drv_pwm_is_stopped(nrf_drv_pwm_t const * const p_instance)
|
||||
{
|
||||
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
|
||||
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
|
||||
|
||||
// If the event handler is used (interrupts are enabled), the state will
|
||||
// be changed in interrupt handler when the STOPPED event occurs.
|
||||
if (p_cb->state != NRF_DRV_STATE_POWERED_ON)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// If interrupts are disabled, we must check the STOPPED event here.
|
||||
if (nrf_pwm_event_check(p_instance->p_registers, NRF_PWM_EVENT_STOPPED))
|
||||
{
|
||||
p_cb->state = NRF_DRV_STATE_INITIALIZED;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void irq_handler(NRF_PWM_Type * p_pwm, pwm_control_block_t * p_cb)
|
||||
{
|
||||
ASSERT(p_cb->handler);
|
||||
|
||||
// The SEQEND0 and SEQEND1 events are only handled when the user asked for
|
||||
// it (by setting proper flags when starting the playback).
|
||||
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_SEQEND0_MASK) &&
|
||||
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND0))
|
||||
{
|
||||
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND0);
|
||||
p_cb->handler(NRF_DRV_PWM_EVT_END_SEQ0);
|
||||
}
|
||||
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_SEQEND1_MASK) &&
|
||||
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND1))
|
||||
{
|
||||
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND1);
|
||||
p_cb->handler(NRF_DRV_PWM_EVT_END_SEQ1);
|
||||
}
|
||||
|
||||
// The LOOPSDONE event is handled by default, but this can be disabled.
|
||||
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_LOOPSDONE_MASK) &&
|
||||
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_LOOPSDONE))
|
||||
{
|
||||
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_LOOPSDONE);
|
||||
p_cb->handler(NRF_DRV_PWM_EVT_FINISHED);
|
||||
}
|
||||
|
||||
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_STOPPED))
|
||||
{
|
||||
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_STOPPED);
|
||||
|
||||
p_cb->state = NRF_DRV_STATE_INITIALIZED;
|
||||
|
||||
p_cb->handler(NRF_DRV_PWM_EVT_STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if PWM0_ENABLED
|
||||
void PWM0_IRQHandler(void)
|
||||
{
|
||||
irq_handler(NRF_PWM0, &m_cb[PWM0_INSTANCE_INDEX]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PWM1_ENABLED
|
||||
void PWM1_IRQHandler(void)
|
||||
{
|
||||
irq_handler(NRF_PWM1, &m_cb[PWM1_INSTANCE_INDEX]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PWM2_ENABLED
|
||||
void PWM2_IRQHandler(void)
|
||||
{
|
||||
irq_handler(NRF_PWM2, &m_cb[PWM2_INSTANCE_INDEX]);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,426 @@
|
|||
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
|
||||
*
|
||||
* The information contained herein is property of Nordic Semiconductor ASA.
|
||||
* Terms and conditions of usage are described in detail in NORDIC
|
||||
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
|
||||
*
|
||||
* Licensees are granted free, non-transferable use of the information. NO
|
||||
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
|
||||
* the file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**@file
|
||||
* @addtogroup nrf_pwm PWM HAL and driver
|
||||
* @ingroup nrf_drivers
|
||||
* @brief @tagAPI52 Pulse Width Modulation (PWM) module APIs.
|
||||
*
|
||||
* @defgroup nrf_drv_pwm PWM driver
|
||||
* @{
|
||||
* @ingroup nrf_pwm
|
||||
* @brief @tagAPI52 Pulse Width Modulation (PWM) module driver.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NRF_DRV_PWM_H__
|
||||
#define NRF_DRV_PWM_H__
|
||||
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_drv_config.h"
|
||||
#include "nrf_pwm.h"
|
||||
#include "sdk_errors.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief PWM driver instance data structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
NRF_PWM_Type * p_registers; ///< Pointer to the structure with PWM peripheral instance registers.
|
||||
uint8_t drv_inst_idx; ///< Driver instance index.
|
||||
} nrf_drv_pwm_t;
|
||||
|
||||
/**
|
||||
* @brief Macro for creating a PWM driver instance.
|
||||
*/
|
||||
#define NRF_DRV_PWM_INSTANCE(id) \
|
||||
{ \
|
||||
.p_registers = CONCAT_2(NRF_PWM, id), \
|
||||
.drv_inst_idx = CONCAT_3(PWM, id, _INSTANCE_INDEX), \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This value can be provided instead of a pin number for any channel
|
||||
* to specify that its output is not used and therefore does not need
|
||||
* to be connected to a pin.
|
||||
*/
|
||||
#define NRF_DRV_PWM_PIN_NOT_USED 0xFF
|
||||
|
||||
/**
|
||||
* @brief This value can be added to a pin number to inverse its polarity
|
||||
* (set idle state = 1).
|
||||
*/
|
||||
#define NRF_DRV_PWM_PIN_INVERTED 0x80
|
||||
|
||||
/**
|
||||
* @brief PWM driver configuration structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t output_pins[NRF_PWM_CHANNEL_COUNT]; ///< Pin numbers for individual output channels (optional).
|
||||
/**< Use @ref NRF_DRV_PWM_PIN_NOT_USED
|
||||
* if a given output channel is not needed. */
|
||||
uint8_t irq_priority; ///< Interrupt priority.
|
||||
nrf_pwm_clk_t base_clock; ///< Base clock frequency.
|
||||
nrf_pwm_mode_t count_mode; ///< Operating mode of the pulse generator counter.
|
||||
uint16_t top_value; ///< Value up to which the pulse generator counter counts.
|
||||
nrf_pwm_dec_load_t load_mode; ///< Mode of loading sequence data from RAM.
|
||||
nrf_pwm_dec_step_t step_mode; ///< Mode of advancing the active sequence.
|
||||
} nrf_drv_pwm_config_t;
|
||||
|
||||
/**
|
||||
* @brief PWM driver default configuration.
|
||||
*/
|
||||
#define NRF_DRV_PWM_DEFAULT_CONFIG(id) \
|
||||
{ \
|
||||
.output_pins = { CONCAT_3(PWM, id, _CONFIG_OUT0_PIN), \
|
||||
CONCAT_3(PWM, id, _CONFIG_OUT1_PIN), \
|
||||
CONCAT_3(PWM, id, _CONFIG_OUT2_PIN), \
|
||||
CONCAT_3(PWM, id, _CONFIG_OUT3_PIN) }, \
|
||||
.irq_priority = CONCAT_3(PWM, id, _CONFIG_IRQ_PRIORITY), \
|
||||
.base_clock = CONCAT_3(PWM, id, _CONFIG_BASE_CLOCK), \
|
||||
.count_mode = CONCAT_3(PWM, id, _CONFIG_COUNT_MODE), \
|
||||
.top_value = CONCAT_3(PWM, id, _CONFIG_TOP_VALUE), \
|
||||
.load_mode = CONCAT_3(PWM, id, _CONFIG_LOAD_MODE), \
|
||||
.step_mode = CONCAT_3(PWM, id, _CONFIG_STEP_MODE), \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief PWM flags providing additional playback options.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DRV_PWM_FLAG_STOP = 0x01, /**< When the requested playback is finished,
|
||||
the peripheral should be stopped.
|
||||
@note The STOP task is triggered when
|
||||
the last value of the final sequence is
|
||||
loaded from RAM, and the peripheral stops
|
||||
at the end of the current PWM period.
|
||||
For sequences with configured repeating
|
||||
of duty cycle values, this might result in
|
||||
less than the requested number of repeats
|
||||
of the last value. */
|
||||
NRF_DRV_PWM_FLAG_LOOP = 0x02, /**< When the requested playback is finished,
|
||||
it should be started from the beginning.
|
||||
This flag is ignored if used together
|
||||
with @ref NRF_DRV_PWM_FLAG_STOP. */
|
||||
NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0 = 0x04, /**< The event handler should be
|
||||
called when the last value
|
||||
from sequence 0 is loaded. */
|
||||
NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1 = 0x08, /**< The event handler should be
|
||||
called when the last value
|
||||
from sequence 1 is loaded. */
|
||||
NRF_DRV_PWM_FLAG_NO_EVT_FINISHED = 0x10, /**< The playback finished event
|
||||
(enabled by default) should be
|
||||
suppressed. */
|
||||
} nrf_drv_pwm_flag_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief PWM driver event type.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_DRV_PWM_EVT_FINISHED, ///< Sequence playback finished.
|
||||
NRF_DRV_PWM_EVT_END_SEQ0, /**< End of sequence 0 reached. Its data can be
|
||||
safely modified now. */
|
||||
NRF_DRV_PWM_EVT_END_SEQ1, /**< End of sequence 1 reached. Its data can be
|
||||
safely modified now. */
|
||||
NRF_DRV_PWM_EVT_STOPPED, ///< The PWM peripheral has been stopped.
|
||||
} nrf_drv_pwm_evt_type_t;
|
||||
|
||||
/**
|
||||
* @brief PWM driver event handler type.
|
||||
*/
|
||||
typedef void (* nrf_drv_pwm_handler_t)(nrf_drv_pwm_evt_type_t event_type);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for initializing the PWM driver.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] p_config Pointer to the structure with initial configuration.
|
||||
* If NULL, the default configuration is used.
|
||||
* @param[in] handler Event handler provided by the user. If NULL is passed
|
||||
* instead, event notifications are not done and PWM
|
||||
* interrupts are disabled.
|
||||
*
|
||||
* @retval NRF_SUCCESS If initialization was successful.
|
||||
* @retval NRF_ERROR_INVALID_STATE If the driver was already initialized.
|
||||
*/
|
||||
ret_code_t nrf_drv_pwm_init(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_drv_pwm_config_t const * p_config,
|
||||
nrf_drv_pwm_handler_t handler);
|
||||
|
||||
/**
|
||||
* @brief Function for uninitializing the PWM driver.
|
||||
*
|
||||
* If any sequence playback is in progress, it is stopped immediately.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
*/
|
||||
void nrf_drv_pwm_uninit(nrf_drv_pwm_t const * const p_instance);
|
||||
|
||||
/**
|
||||
* @brief Function for starting a single sequence playback.
|
||||
*
|
||||
* To take advantage of the looping mechanism in the PWM peripheral, both
|
||||
* sequences must be used (single sequence can be played back only once by
|
||||
* the peripheral). Therefore, the provided sequence is internally set and
|
||||
* played back as both sequence 0 and sequence 1. Consequently, if end of
|
||||
* sequence notifications are required, events for both sequences should be
|
||||
* used (that means that both the @ref NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0 flag
|
||||
* and the @ref NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1 flag should be specified and
|
||||
* the @ref NRF_DRV_PWM_EVT_END_SEQ0 event and the @ref NRF_DRV_PWM_EVT_END_SEQ1
|
||||
* event should be handled in the same way).
|
||||
*
|
||||
* @note The array containing the duty cycle values for the specified sequence
|
||||
* must be in RAM and cannot be allocated on stack.
|
||||
* For detailed information, see @ref nrf_pwm_sequence_t.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] p_sequence Sequence to be played back.
|
||||
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
|
||||
* @param[in] flags Additional options. Pass any combination of
|
||||
* @ref nrf_drv_pwm_flag_t "playback flags", or 0
|
||||
* for default settings.
|
||||
*/
|
||||
void nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_sequence_t const * p_sequence,
|
||||
uint16_t playback_count,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Function for starting a two-sequence playback.
|
||||
*
|
||||
* @note The array containing the duty cycle values for the specified sequence
|
||||
* must be in RAM and cannot be allocated on stack.
|
||||
* For detailed information, see @ref nrf_pwm_sequence_t.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] p_sequence_0 First sequence to be played back.
|
||||
* @param[in] p_sequence_1 Second sequence to be played back.
|
||||
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
|
||||
* @param[in] flags Additional options. Pass any combination of
|
||||
* @ref nrf_drv_pwm_flag_t "playback flags", or 0
|
||||
* for default settings.
|
||||
*/
|
||||
void nrf_drv_pwm_complex_playback(nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_sequence_t const * p_sequence_0,
|
||||
nrf_pwm_sequence_t const * p_sequence_1,
|
||||
uint16_t playback_count,
|
||||
uint32_t flags);
|
||||
|
||||
/**
|
||||
* @brief Function for advancing the active sequence.
|
||||
*
|
||||
* This function only applies to @ref NRF_PWM_STEP_TRIGGERED mode.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_step(nrf_drv_pwm_t const * const p_instance);
|
||||
|
||||
/**
|
||||
* @brief Function for stopping the sequence playback.
|
||||
*
|
||||
* The playback is stopped at the end of the current PWM period.
|
||||
* This means that if the active sequence is configured to repeat each duty
|
||||
* cycle value for a certain number of PWM periods, the last played value
|
||||
* might appear on the output less times than requested.
|
||||
*
|
||||
* @note This function can be instructed to wait until the playback is stopped
|
||||
* (by setting @p wait_until_stopped to true). Note that, depending on
|
||||
* the length of the PMW period, this might take a significant amount of
|
||||
* time. Alternatively, the @ref nrf_drv_pwm_is_stopped function can be
|
||||
* used to poll the status, or the @ref NRF_DRV_PWM_EVT_STOPPED event can
|
||||
* be used to get the notification when the playback is stopped, provided
|
||||
* the event handler is defined.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] wait_until_stopped If true, the function will not return until
|
||||
* the playback is stopped.
|
||||
*
|
||||
* @retval true If the PWM peripheral is stopped.
|
||||
* @retval false If the PWM peripheral is not stopped.
|
||||
*/
|
||||
bool nrf_drv_pwm_stop(nrf_drv_pwm_t const * const p_instance,
|
||||
bool wait_until_stopped);
|
||||
|
||||
/**
|
||||
* @brief Function for checking the status of the PWM peripheral.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
*
|
||||
* @retval true If the PWM peripheral is stopped.
|
||||
* @retval false If the PWM peripheral is not stopped.
|
||||
*/
|
||||
bool nrf_drv_pwm_is_stopped(nrf_drv_pwm_t const * const p_instance);
|
||||
|
||||
/**
|
||||
* @brief Function for updating the sequence data during playback.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] p_sequence Pointer to the new sequence definition.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_sequence_t const * p_sequence);
|
||||
|
||||
/**
|
||||
* @brief Function for updating the pointer to the duty cycle values
|
||||
* in the specified sequence during playback.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] values New pointer to the duty cycle values.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_values_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_values_t values);
|
||||
|
||||
/**
|
||||
* @brief Function for updating the number of duty cycle values
|
||||
* in the specified sequence during playback.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] length New number of the duty cycle values.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_length_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Function for updating the number of repeats for duty cycle values
|
||||
* in specified sequence during playback.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] repeats New number of repeats.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_repeats_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint32_t repeats);
|
||||
|
||||
/**
|
||||
* @brief Function for updating the additional delay after the specified
|
||||
* sequence during playback.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] end_delay New end delay value (in PWM periods).
|
||||
*/
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_end_delay_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint32_t end_delay);
|
||||
|
||||
/**
|
||||
* @brief Function for returning the address of a specified PWM task that can
|
||||
* be used in PPI module.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] task Requested task.
|
||||
*
|
||||
* @return Task address.
|
||||
*/
|
||||
__STATIC_INLINE uint32_t nrf_drv_pwm_task_address_get(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_task_t task);
|
||||
|
||||
/**@brief Function for returning the address of a specified PWM event that can
|
||||
* be used in PPI module.
|
||||
*
|
||||
* @param[in] p_instance Pointer to the driver instance structure.
|
||||
* @param[in] event Requested event.
|
||||
*
|
||||
* @return Event address.
|
||||
*/
|
||||
__STATIC_INLINE uint32_t nrf_drv_pwm_event_address_get(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_event_t event);
|
||||
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_step(nrf_drv_pwm_t const * const p_instance)
|
||||
{
|
||||
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_NEXTSTEP);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_sequence_t const * p_sequence)
|
||||
{
|
||||
nrf_pwm_sequence_set(p_instance->p_registers, seq_id, p_sequence);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_values_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_values_t values)
|
||||
{
|
||||
nrf_pwm_seq_ptr_set(p_instance->p_registers, seq_id, values.p_raw);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_length_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint16_t length)
|
||||
{
|
||||
nrf_pwm_seq_cnt_set(p_instance->p_registers, seq_id, length);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_repeats_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint32_t repeats)
|
||||
{
|
||||
nrf_pwm_seq_refresh_set(p_instance->p_registers, seq_id, repeats);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_drv_pwm_sequence_end_delay_update(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
uint8_t seq_id,
|
||||
uint32_t end_delay)
|
||||
{
|
||||
nrf_pwm_seq_end_delay_set(p_instance->p_registers, seq_id, end_delay);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint32_t nrf_drv_pwm_task_address_get(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_task_t task)
|
||||
{
|
||||
return nrf_pwm_task_address_get(p_instance->p_registers, task);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint32_t nrf_drv_pwm_event_address_get(
|
||||
nrf_drv_pwm_t const * const p_instance,
|
||||
nrf_pwm_event_t event)
|
||||
{
|
||||
return nrf_pwm_event_address_get(p_instance->p_registers, event);
|
||||
}
|
||||
|
||||
#endif // SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
#endif // NRF_DRV_PWM_H__
|
||||
|
||||
/** @} */
|
|
@ -198,7 +198,7 @@
|
|||
#define PWM0_INSTANCE_INDEX 0
|
||||
#endif
|
||||
|
||||
#define PWM1_ENABLED 0
|
||||
#define PWM1_ENABLED 1
|
||||
|
||||
#if (PWM1_ENABLED == 1)
|
||||
#define PWM1_CONFIG_OUT0_PIN 2
|
||||
|
@ -215,7 +215,7 @@
|
|||
#define PWM1_INSTANCE_INDEX (PWM0_ENABLED)
|
||||
#endif
|
||||
|
||||
#define PWM2_ENABLED 0
|
||||
#define PWM2_ENABLED 1
|
||||
|
||||
#if (PWM2_ENABLED == 1)
|
||||
#define PWM2_CONFIG_OUT0_PIN 2
|
||||
|
|
|
@ -0,0 +1,665 @@
|
|||
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
|
||||
*
|
||||
* The information contained herein is property of Nordic Semiconductor ASA.
|
||||
* Terms and conditions of usage are described in detail in NORDIC
|
||||
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
|
||||
*
|
||||
* Licensees are granted free, non-transferable use of the information. NO
|
||||
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
|
||||
* the file.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup nrf_pwm_hal PWM HAL
|
||||
* @{
|
||||
* @ingroup nrf_pwm
|
||||
*
|
||||
* @brief @tagAPI52 Hardware access layer for managing the Pulse Width Modulation (PWM)
|
||||
* peripheral.
|
||||
*/
|
||||
|
||||
#ifndef NRF_PWM_H__
|
||||
#define NRF_PWM_H__
|
||||
|
||||
#ifdef NRF52
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nrf.h"
|
||||
#include "nrf_assert.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief This value can be provided as a parameter for the @ref nrf_pwm_pins_set
|
||||
* function call to specify that a given output channel shall not be
|
||||
* connected to a physical pin.
|
||||
*/
|
||||
#define NRF_PWM_PIN_NOT_CONNECTED 0xFFFFFFFF
|
||||
|
||||
/**
|
||||
* @brief Number of channels in each PWM instance.
|
||||
*/
|
||||
#define NRF_PWM_CHANNEL_COUNT 4
|
||||
|
||||
|
||||
/**
|
||||
* @brief PWM tasks.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/*lint -save -e30*/
|
||||
NRF_PWM_TASK_STOP = offsetof(NRF_PWM_Type, TASKS_STOP), ///< Stops PWM pulse generation on all channels at the end of the current PWM period, and stops the sequence playback.
|
||||
NRF_PWM_TASK_SEQSTART0 = offsetof(NRF_PWM_Type, TASKS_SEQSTART[0]), ///< Starts playback of sequence 0.
|
||||
NRF_PWM_TASK_SEQSTART1 = offsetof(NRF_PWM_Type, TASKS_SEQSTART[1]), ///< Starts playback of sequence 1.
|
||||
NRF_PWM_TASK_NEXTSTEP = offsetof(NRF_PWM_Type, TASKS_NEXTSTEP) ///< Steps by one value in the current sequence if the decoder is set to @ref NRF_PWM_STEP_TRIGGERED mode.
|
||||
/*lint -restore*/
|
||||
} nrf_pwm_task_t;
|
||||
|
||||
/**
|
||||
* @brief PWM events.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/*lint -save -e30*/
|
||||
NRF_PWM_EVENT_STOPPED = offsetof(NRF_PWM_Type, EVENTS_STOPPED), ///< Response to STOP task, emitted when PWM pulses are no longer generated.
|
||||
NRF_PWM_EVENT_SEQSTARTED0 = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[0]), ///< First PWM period started on sequence 0.
|
||||
NRF_PWM_EVENT_SEQSTARTED1 = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[1]), ///< First PWM period started on sequence 1.
|
||||
NRF_PWM_EVENT_SEQEND0 = offsetof(NRF_PWM_Type, EVENTS_SEQEND[0]), ///< Emitted at the end of every sequence 0 when its last value has been read from RAM.
|
||||
NRF_PWM_EVENT_SEQEND1 = offsetof(NRF_PWM_Type, EVENTS_SEQEND[1]), ///< Emitted at the end of every sequence 1 when its last value has been read from RAM.
|
||||
NRF_PWM_EVENT_PWMPERIODEND = offsetof(NRF_PWM_Type, EVENTS_PWMPERIODEND), ///< Emitted at the end of each PWM period.
|
||||
NRF_PWM_EVENT_LOOPSDONE = offsetof(NRF_PWM_Type, EVENTS_LOOPSDONE) ///< Concatenated sequences have been played the requested number of times.
|
||||
/*lint -restore*/
|
||||
} nrf_pwm_event_t;
|
||||
|
||||
/**
|
||||
* @brief PWM interrupts.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_INT_STOPPED_MASK = PWM_INTENSET_STOPPED_Msk, ///< Interrupt on STOPPED event.
|
||||
NRF_PWM_INT_SEQSTARTED0_MASK = PWM_INTENSET_SEQSTARTED0_Msk, ///< Interrupt on SEQSTARTED[0] event.
|
||||
NRF_PWM_INT_SEQSTARTED1_MASK = PWM_INTENSET_SEQSTARTED1_Msk, ///< Interrupt on SEQSTARTED[1] event.
|
||||
NRF_PWM_INT_SEQEND0_MASK = PWM_INTENSET_SEQEND0_Msk, ///< Interrupt on SEQEND[0] event.
|
||||
NRF_PWM_INT_SEQEND1_MASK = PWM_INTENSET_SEQEND1_Msk, ///< Interrupt on SEQEND[1] event.
|
||||
NRF_PWM_INT_PWMPERIODEND_MASK = PWM_INTENSET_PWMPERIODEND_Msk, ///< Interrupt on PWMPERIODEND event.
|
||||
NRF_PWM_INT_LOOPSDONE_MASK = PWM_INTENSET_LOOPSDONE_Msk ///< Interrupt on LOOPSDONE event.
|
||||
} nrf_pwm_int_mask_t;
|
||||
|
||||
/**
|
||||
* @brief PWM shortcuts.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_SHORT_SEQEND0_STOP_MASK = PWM_SHORTS_SEQEND0_STOP_Msk, ///< Shortcut between SEQEND[0] event and STOP task.
|
||||
NRF_PWM_SHORT_SEQEND1_STOP_MASK = PWM_SHORTS_SEQEND1_STOP_Msk, ///< Shortcut between SEQEND[1] event and STOP task.
|
||||
NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK = PWM_SHORTS_LOOPSDONE_SEQSTART0_Msk, ///< Shortcut between LOOPSDONE event and SEQSTART[0] task.
|
||||
NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK = PWM_SHORTS_LOOPSDONE_SEQSTART1_Msk, ///< Shortcut between LOOPSDONE event and SEQSTART[1] task.
|
||||
NRF_PWM_SHORT_LOOPSDONE_STOP_MASK = PWM_SHORTS_LOOPSDONE_STOP_Msk ///< Shortcut between LOOPSDONE event and STOP task.
|
||||
} nrf_pwm_short_mask_t;
|
||||
|
||||
/**
|
||||
* @brief PWM modes of operation.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_MODE_UP = PWM_MODE_UPDOWN_Up, ///< Up counter (edge-aligned PWM duty cycle).
|
||||
NRF_PWM_MODE_UP_AND_DOWN = PWM_MODE_UPDOWN_UpAndDown, ///< Up and down counter (center-aligned PWM duty cycle).
|
||||
} nrf_pwm_mode_t;
|
||||
|
||||
/**
|
||||
* @brief PWM base clock frequencies.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_CLK_16MHz = PWM_PRESCALER_PRESCALER_DIV_1, ///< 16 MHz / 1 = 16 MHz.
|
||||
NRF_PWM_CLK_8MHz = PWM_PRESCALER_PRESCALER_DIV_2, ///< 16 MHz / 2 = 8 MHz.
|
||||
NRF_PWM_CLK_4MHz = PWM_PRESCALER_PRESCALER_DIV_4, ///< 16 MHz / 4 = 4 MHz.
|
||||
NRF_PWM_CLK_2MHz = PWM_PRESCALER_PRESCALER_DIV_8, ///< 16 MHz / 8 = 2 MHz.
|
||||
NRF_PWM_CLK_1MHz = PWM_PRESCALER_PRESCALER_DIV_16, ///< 16 MHz / 16 = 1 MHz.
|
||||
NRF_PWM_CLK_500kHz = PWM_PRESCALER_PRESCALER_DIV_32, ///< 16 MHz / 32 = 500 kHz.
|
||||
NRF_PWM_CLK_250kHz = PWM_PRESCALER_PRESCALER_DIV_64, ///< 16 MHz / 64 = 250 kHz.
|
||||
NRF_PWM_CLK_125kHz = PWM_PRESCALER_PRESCALER_DIV_128 ///< 16 MHz / 128 = 125 kHz.
|
||||
} nrf_pwm_clk_t;
|
||||
|
||||
/**
|
||||
* @brief PWM decoder load modes.
|
||||
*
|
||||
* The selected mode determines how the sequence data is read from RAM and
|
||||
* spread to the compare registers.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_LOAD_COMMON = PWM_DECODER_LOAD_Common, ///< 1st half word (16-bit) used in all PWM channels (0-3).
|
||||
NRF_PWM_LOAD_GROUPED = PWM_DECODER_LOAD_Grouped, ///< 1st half word (16-bit) used in channels 0 and 1; 2nd word in channels 2 and 3.
|
||||
NRF_PWM_LOAD_INDIVIDUAL = PWM_DECODER_LOAD_Individual, ///< 1st half word (16-bit) used in channel 0; 2nd in channel 1; 3rd in channel 2; 4th in channel 3.
|
||||
NRF_PWM_LOAD_WAVE_FORM = PWM_DECODER_LOAD_WaveForm ///< 1st half word (16-bit) used in channel 0; 2nd in channel 1; ... ; 4th as the top value for the pulse generator counter.
|
||||
} nrf_pwm_dec_load_t;
|
||||
|
||||
/**
|
||||
* @brief PWM decoder next step modes.
|
||||
*
|
||||
* The selected mode determines when the next value from the active sequence
|
||||
* is loaded.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_PWM_STEP_AUTO = PWM_DECODER_MODE_RefreshCount, ///< Automatically after the current value is played and repeated the requested number of times.
|
||||
NRF_PWM_STEP_TRIGGERED = PWM_DECODER_MODE_NextStep ///< When the @ref NRF_PWM_TASK_NEXTSTEP task is triggered.
|
||||
} nrf_pwm_dec_step_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type used for defining duty cycle values for a sequence
|
||||
* loaded in @ref NRF_PWM_LOAD_COMMON mode.
|
||||
*/
|
||||
typedef uint16_t nrf_pwm_values_common_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for defining duty cycle values for a sequence
|
||||
* loaded in @ref NRF_PWM_LOAD_GROUPED mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t group_0; ///< Duty cycle value for group 0 (channels 0 and 1).
|
||||
uint16_t group_1; ///< Duty cycle value for group 1 (channels 2 and 3).
|
||||
} nrf_pwm_values_grouped_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for defining duty cycle values for a sequence
|
||||
* loaded in @ref NRF_PWM_LOAD_INDIVIDUAL mode.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16_t channel_0; ///< Duty cycle value for channel 0.
|
||||
uint16_t channel_1; ///< Duty cycle value for channel 1.
|
||||
uint16_t channel_2; ///< Duty cycle value for channel 2.
|
||||
uint16_t channel_3; ///< Duty cycle value for channel 3.
|
||||
} nrf_pwm_values_individual_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for defining duty cycle values for a sequence
|
||||
* loaded in @ref NRF_PWM_LOAD_WAVE_FORM mode.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t channel_0; ///< Duty cycle value for channel 0.
|
||||
uint16_t channel_1; ///< Duty cycle value for channel 1.
|
||||
uint16_t channel_2; ///< Duty cycle value for channel 2.
|
||||
uint16_t counter_top; ///< Top value for the pulse generator counter.
|
||||
} nrf_pwm_values_wave_form_t;
|
||||
|
||||
/**
|
||||
* @brief Union grouping pointers to arrays of duty cycle values applicable to
|
||||
* various loading modes.
|
||||
*/
|
||||
typedef union {
|
||||
nrf_pwm_values_common_t const * p_common; ///< Pointer to be used in @ref NRF_PWM_LOAD_COMMON mode.
|
||||
nrf_pwm_values_grouped_t const * p_grouped; ///< Pointer to be used in @ref NRF_PWM_LOAD_GROUPED mode.
|
||||
nrf_pwm_values_individual_t const * p_individual; ///< Pointer to be used in @ref NRF_PWM_LOAD_INDIVIDUAL mode.
|
||||
nrf_pwm_values_wave_form_t const * p_wave_form; ///< Pointer to be used in @ref NRF_PWM_LOAD_WAVE_FORM mode.
|
||||
uint16_t const * p_raw; ///< Pointer providing raw access to the values.
|
||||
} nrf_pwm_values_t;
|
||||
|
||||
/**
|
||||
* @brief Structure for defining a sequence of PWM duty cycles.
|
||||
*
|
||||
* When the sequence is set (by a call to @ref nrf_pwm_sequence_set), the
|
||||
* provided duty cycle values are not copied. The @p values pointer is stored
|
||||
* in the peripheral's internal register, and the values are loaded from RAM
|
||||
* during the sequence playback. Therefore, you must ensure that the values
|
||||
* do not change before and during the sequence playback (for example,
|
||||
* the values cannot be placed in a local variable that is allocated on stack).
|
||||
* If the sequence is played in a loop and the values should be updated
|
||||
* before the next iteration, it is safe to modify them when the corresponding
|
||||
* event signaling the end of sequence occurs (@ref NRF_PWM_EVENT_SEQEND0
|
||||
* or @ref NRF_PWM_EVENT_SEQEND1, respectively).
|
||||
*
|
||||
* @note The @p repeats and @p end_delay values (which are written to the
|
||||
* SEQ[n].REFRESH and SEQ[n].ENDDELAY registers in the peripheral,
|
||||
* respectively) are ignored at the end of a complex sequence
|
||||
* playback, indicated by the LOOPSDONE event.
|
||||
* See the @linkProductSpecification52 for more information.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
nrf_pwm_values_t values; ///< Pointer to an array with duty cycle values. This array must be in Data RAM.
|
||||
/**< This field is defined as an union of pointers
|
||||
* to provide a convenient way to define duty
|
||||
* cycle values in various loading modes
|
||||
* (see @ref nrf_pwm_dec_load_t).
|
||||
* In each value, the most significant bit (15)
|
||||
* determines the polarity of the output and the
|
||||
* others (14-0) compose the 15-bit value to be
|
||||
* compared with the pulse generator counter. */
|
||||
uint16_t length; ///< Number of 16-bit values in the array pointed by @p values.
|
||||
uint32_t repeats; ///< Number of times that each duty cycle should be repeated (after being played once). Ignored in @ref NRF_PWM_STEP_TRIGGERED mode.
|
||||
uint32_t end_delay; ///< Additional time (in PWM periods) that the last duty cycle is to be kept after the sequence is played. Ignored in @ref NRF_PWM_STEP_TRIGGERED mode.
|
||||
} nrf_pwm_sequence_t;
|
||||
|
||||
/**
|
||||
* @brief Helper macro for calculating the number of 16-bit values in specified
|
||||
* array of duty cycle values.
|
||||
*/
|
||||
#define NRF_PWM_VALUES_LENGTH(array) (sizeof(array)/sizeof(uint16_t))
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for activating a specific PWM task.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] task Task to activate.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_task_trigger(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_task_t task);
|
||||
|
||||
/**
|
||||
* @brief Function for getting the address of a specific PWM task register.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] task Requested task.
|
||||
*
|
||||
* @return Address of the specified task register.
|
||||
*/
|
||||
__STATIC_INLINE uint32_t nrf_pwm_task_address_get(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_task_t task);
|
||||
|
||||
/**
|
||||
* @brief Function for clearing a specific PWM event.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] event Event to clear.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_event_clear(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_event_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for checking the state of a specific PWM event.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] event Event to check.
|
||||
*
|
||||
* @retval true If the event is set.
|
||||
* @retval false If the event is not set.
|
||||
*/
|
||||
__STATIC_INLINE bool nrf_pwm_event_check(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_event_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for getting the address of a specific PWM event register.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] event Requested event.
|
||||
*
|
||||
* @return Address of the specified event register.
|
||||
*/
|
||||
__STATIC_INLINE uint32_t nrf_pwm_event_address_get(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_event_t event);
|
||||
|
||||
/**
|
||||
* @brief Function for enabling specified shortcuts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_shorts_mask Shortcuts to enable.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_shorts_enable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for disabling specified shortcuts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_shorts_mask Shortcuts to disable.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_shorts_disable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for setting the configuration of PWM shortcuts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_shorts_mask Shortcuts configuration to set.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_shorts_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for enabling specified interrupts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_int_mask Interrupts to enable.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_int_enable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for disabling specified interrupts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_int_mask Interrupts to disable.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_int_disable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for setting the configuration of PWM interrupts.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_int_mask Interrupts configuration to set.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_int_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask);
|
||||
|
||||
/**
|
||||
* @brief Function for retrieving the state of a given interrupt.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] pwm_int Interrupt to check.
|
||||
*
|
||||
* @retval true If the interrupt is enabled.
|
||||
* @retval false If the interrupt is not enabled.
|
||||
*/
|
||||
__STATIC_INLINE bool nrf_pwm_int_enable_check(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_int_mask_t pwm_int);
|
||||
|
||||
/**
|
||||
* @brief Function for enabling the PWM peripheral.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_enable(NRF_PWM_Type * p_pwm);
|
||||
|
||||
/**
|
||||
* @brief Function for disabling the PWM peripheral.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_disable(NRF_PWM_Type * p_pwm);
|
||||
|
||||
/**
|
||||
* @brief Function for assigning pins to PWM output channels.
|
||||
*
|
||||
* Usage of all PWM output channels is optional. If a given channel is not
|
||||
* needed, pass the @ref NRF_PWM_PIN_NOT_CONNECTED value instead of its pin
|
||||
* number.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] out_pins Array with pin numbers for individual PWM output channels.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_pins_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT]);
|
||||
|
||||
/**
|
||||
* @brief Function for configuring the PWM peripheral.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] base_clock Base clock frequency.
|
||||
* @param[in] mode Operating mode of the pulse generator counter.
|
||||
* @param[in] top_value Value up to which the pulse generator counter counts.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_configure(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_clk_t base_clock,
|
||||
nrf_pwm_mode_t mode,
|
||||
uint16_t top_value);
|
||||
|
||||
/**
|
||||
* @brief Function for defining a sequence of PWM duty cycles.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] p_seq Pointer to the sequence definition.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_sequence_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_sequence_t const * p_seq);
|
||||
|
||||
/**
|
||||
* @brief Function for modifying the pointer to the duty cycle values
|
||||
* in the specified sequence.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] p_values Pointer to an array with duty cycle values.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_seq_ptr_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint16_t const * p_values);
|
||||
|
||||
/**
|
||||
* @brief Function for modifying the total number of duty cycle values
|
||||
* in the specified sequence.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] length Number of duty cycle values.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_seq_cnt_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Function for modifying the additional number of PWM periods spent
|
||||
* on each duty cycle value in the specified sequence.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] refresh Number of additional PWM periods for each duty cycle value.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_seq_refresh_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint32_t refresh);
|
||||
|
||||
/**
|
||||
* @brief Function for modifying the additional time added after the sequence
|
||||
* is played.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] seq_id Identifier of the sequence (0 or 1).
|
||||
* @param[in] end_delay Number of PWM periods added at the end of the sequence.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_seq_end_delay_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint32_t end_delay);
|
||||
|
||||
/**
|
||||
* @brief Function for setting the mode of loading sequence data from RAM
|
||||
* and advancing the sequence.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] dec_load Mode of loading sequence data from RAM.
|
||||
* @param[in] dec_step Mode of advancing the active sequence.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_decoder_set(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_dec_load_t dec_load,
|
||||
nrf_pwm_dec_step_t dec_step);
|
||||
|
||||
/**
|
||||
* @brief Function for setting the number of times the sequence playback
|
||||
* should be performed.
|
||||
*
|
||||
* This function applies to two-sequence playback (concatenated sequence 0 and 1).
|
||||
* A single sequence can be played back only once.
|
||||
*
|
||||
* @param[in] p_pwm PWM instance.
|
||||
* @param[in] loop_count Number of times to perform the sequence playback.
|
||||
*/
|
||||
__STATIC_INLINE void nrf_pwm_loop_set(NRF_PWM_Type * p_pwm,
|
||||
uint16_t loop_count);
|
||||
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_task_trigger(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_task_t task)
|
||||
{
|
||||
*((volatile uint32_t *)((uint8_t *)p_pwm + (uint32_t)task)) = 0x1UL;
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint32_t nrf_pwm_task_address_get(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_task_t task)
|
||||
{
|
||||
return ((uint32_t)p_pwm + (uint32_t)task);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_event_clear(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_event_t event)
|
||||
{
|
||||
*((volatile uint32_t *)((uint8_t *)p_pwm + (uint32_t)event)) = 0x0UL;
|
||||
}
|
||||
|
||||
__STATIC_INLINE bool nrf_pwm_event_check(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_event_t event)
|
||||
{
|
||||
return (bool)*(volatile uint32_t *)((uint8_t *)p_pwm + (uint32_t)event);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint32_t nrf_pwm_event_address_get(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_event_t event)
|
||||
{
|
||||
return ((uint32_t)p_pwm + (uint32_t)event);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_shorts_enable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask)
|
||||
{
|
||||
p_pwm->SHORTS |= pwm_shorts_mask;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_shorts_disable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask)
|
||||
{
|
||||
p_pwm->SHORTS &= ~(pwm_shorts_mask);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_shorts_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_shorts_mask)
|
||||
{
|
||||
p_pwm->SHORTS = pwm_shorts_mask;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_int_enable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask)
|
||||
{
|
||||
p_pwm->INTENSET = pwm_int_mask;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_int_disable(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask)
|
||||
{
|
||||
p_pwm->INTENCLR = pwm_int_mask;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_int_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t pwm_int_mask)
|
||||
{
|
||||
p_pwm->INTEN = pwm_int_mask;
|
||||
}
|
||||
|
||||
__STATIC_INLINE bool nrf_pwm_int_enable_check(NRF_PWM_Type const * p_pwm,
|
||||
nrf_pwm_int_mask_t pwm_int)
|
||||
{
|
||||
return (bool)(p_pwm->INTENSET & pwm_int);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_enable(NRF_PWM_Type * p_pwm)
|
||||
{
|
||||
p_pwm->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_disable(NRF_PWM_Type * p_pwm)
|
||||
{
|
||||
p_pwm->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_pins_set(NRF_PWM_Type * p_pwm,
|
||||
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT])
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
|
||||
{
|
||||
p_pwm->PSEL.OUT[i] = out_pins[i];
|
||||
}
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_configure(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_clk_t base_clock,
|
||||
nrf_pwm_mode_t mode,
|
||||
uint16_t top_value)
|
||||
{
|
||||
ASSERT(top_value <= PWM_COUNTERTOP_COUNTERTOP_Msk);
|
||||
|
||||
p_pwm->PRESCALER = base_clock;
|
||||
p_pwm->MODE = mode;
|
||||
p_pwm->COUNTERTOP = top_value;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_sequence_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
nrf_pwm_sequence_t const * p_seq)
|
||||
{
|
||||
ASSERT(p_seq != NULL);
|
||||
|
||||
nrf_pwm_seq_ptr_set( p_pwm, seq_id, p_seq->values.p_raw);
|
||||
nrf_pwm_seq_cnt_set( p_pwm, seq_id, p_seq->length);
|
||||
nrf_pwm_seq_refresh_set( p_pwm, seq_id, p_seq->repeats);
|
||||
nrf_pwm_seq_end_delay_set(p_pwm, seq_id, p_seq->end_delay);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_seq_ptr_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint16_t const * p_values)
|
||||
{
|
||||
ASSERT(seq_id <= 1);
|
||||
ASSERT(p_values != NULL);
|
||||
p_pwm->SEQ[seq_id].PTR = (uint32_t)p_values;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_seq_cnt_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint16_t length)
|
||||
{
|
||||
ASSERT(seq_id <= 1);
|
||||
ASSERT(length != 0);
|
||||
ASSERT(length <= PWM_SEQ_CNT_CNT_Msk);
|
||||
p_pwm->SEQ[seq_id].CNT = length;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_seq_refresh_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint32_t refresh)
|
||||
{
|
||||
ASSERT(seq_id <= 1);
|
||||
ASSERT(refresh <= PWM_SEQ_REFRESH_CNT_Msk);
|
||||
p_pwm->SEQ[seq_id].REFRESH = refresh;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_seq_end_delay_set(NRF_PWM_Type * p_pwm,
|
||||
uint8_t seq_id,
|
||||
uint32_t end_delay)
|
||||
{
|
||||
ASSERT(seq_id <= 1);
|
||||
ASSERT(end_delay <= PWM_SEQ_ENDDELAY_CNT_Msk);
|
||||
p_pwm->SEQ[seq_id].ENDDELAY = end_delay;
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_decoder_set(NRF_PWM_Type * p_pwm,
|
||||
nrf_pwm_dec_load_t dec_load,
|
||||
nrf_pwm_dec_step_t dec_step)
|
||||
{
|
||||
p_pwm->DECODER = ((uint32_t)dec_load << PWM_DECODER_LOAD_Pos) |
|
||||
((uint32_t)dec_step << PWM_DECODER_MODE_Pos);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void nrf_pwm_loop_set(NRF_PWM_Type * p_pwm,
|
||||
uint16_t loop_count)
|
||||
{
|
||||
p_pwm->LOOP = loop_count;
|
||||
}
|
||||
|
||||
#endif // SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
#endif // NRF52
|
||||
|
||||
#endif // NRF_PWM_H__
|
||||
|
||||
/** @} */
|
Loading…
Reference in New Issue