Commit f288bcaf authored by Nicholas Lowell's avatar Nicholas Lowell Committed by Anas Nashif
Browse files

pwm: add set nanosecond period and pulse width function



For improved precision of high speed PWMs, the new
function will allow you to specify period and pulse
at the nanosecond resolution.

Signed-off-by: default avatarNicholas Lowell <nlowell@lexmark.com>
parent c6f04916
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -105,8 +105,8 @@ static inline int _impl_pwm_get_cycles_per_sec(struct device *dev, u32_t pwm,
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param pwm PWM pin.
 * @param period Period (in micro second) set to the PWM.
 * @param pulse Pulse width (in micro second) set to the PWM.
 * @param period Period (in microseconds) set to the PWM.
 * @param pulse Pulse width (in microseconds) set to the PWM.
 *
 * @retval 0 If successful.
 * @retval Negative errno code if failure.
@@ -134,6 +134,40 @@ static inline int pwm_pin_set_usec(struct device *dev, u32_t pwm,
				  (u32_t)pulse_cycles);
}

/**
 * @brief Set the period and pulse width for a single PWM output.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param pwm PWM pin.
 * @param period Period (in nanoseconds) set to the PWM.
 * @param pulse Pulse width (in nanoseconds) set to the PWM.
 *
 * @retval 0 If successful.
 * @retval Negative errno code if failure.
 */
static inline int pwm_pin_set_nsec(struct device *dev, u32_t pwm,
				   u32_t period, u32_t pulse)
{
	u64_t period_cycles, pulse_cycles, cycles_per_sec;

	if (pwm_get_cycles_per_sec(dev, pwm, &cycles_per_sec) != 0) {
		return -EIO;
	}

	period_cycles = (period * cycles_per_sec) / NSEC_PER_SEC;
	if (period_cycles >= ((u64_t)1 << 32)) {
		return -ENOTSUP;
	}

	pulse_cycles = (pulse * cycles_per_sec) / NSEC_PER_SEC;
	if (pulse_cycles >= ((u64_t)1 << 32)) {
		return -ENOTSUP;
	}

	return pwm_pin_set_cycles(dev, pwm, (u32_t)period_cycles,
				  (u32_t)pulse_cycles);
}

#ifdef __cplusplus
}
#endif
+44 −12
Original line number Diff line number Diff line
@@ -9,12 +9,12 @@
 * @{
 * @defgroup t_pwm_basic_operations test_pwm_sample
 * @brief TestPurpose: verify PWM can work well when configure
 *			through usec or cycle.
 *			through usec, nsec, or cycle.
 * @details
 * - Test Steps
 *   -# Bind PWM_0 port 0 (This case uses port 1 on D2000).
 *   -# Set PWM period and pulse using pwm_pin_set_cycles() or
 *	pwm_pin_set_usec().
 *   -# Set PWM period and pulse using pwm_pin_set_cycles(),
 *	pwm_pin_set_usec(), or pwm_pin_set_nsec().
 *   -# Use multimeter or other instruments to measure the output
 *	from PWM_OUT_0.
 * - Expected Results
@@ -45,11 +45,15 @@
#define DEFAULT_PULSE_CYCLE 512
#define DEFAULT_PERIOD_USEC 2000
#define DEFAULT_PULSE_USEC 500
#define DEFAULT_PERIOD_NSEC 2000000
#define DEFAULT_PULSE_NSEC 500000
#else
#define DEFAULT_PERIOD_CYCLE 64000
#define DEFAULT_PULSE_CYCLE 32000
#define DEFAULT_PERIOD_USEC 2000
#define DEFAULT_PULSE_USEC 1000
#define DEFAULT_PERIOD_NSEC 2000000
#define DEFAULT_PULSE_NSEC 1000000
#endif

#ifdef CONFIG_BOARD_QUARK_D2000_CRB
@@ -63,7 +67,11 @@
#define DEFAULT_PWM_PORT 0
#endif

static int test_task(u32_t port, u32_t period, u32_t pulse, bool cycle)
#define UNIT_CYCLES	0
#define UNIT_USECS	1
#define UNIT_NSECS	2

static int test_task(u32_t port, u32_t period, u32_t pulse, u8_t unit)
{
	TC_PRINT("[PWM]: %" PRIu8 ", [period]: %" PRIu32 ", [pulse]: %" PRIu32 "\n",
		port, period, pulse);
@@ -101,18 +109,24 @@ static int test_task(u32_t port, u32_t period, u32_t pulse, bool cycle)
	}
#endif

	if (cycle) {
	if (unit == UNIT_CYCLES) {
		/* Verify pwm_pin_set_cycles() */
		if (pwm_pin_set_cycles(pwm_dev, port, period, pulse)) {
			TC_PRINT("Fail to set the period and pulse width\n");
			return TC_FAIL;
		}
	} else {
	} else if (unit == UNIT_USECS) {
		/* Verify pwm_pin_set_usec() */
		if (pwm_pin_set_usec(pwm_dev, port, period, pulse)) {
			TC_PRINT("Fail to set the period and pulse width\n");
			return TC_FAIL;
		}
	} else { /* unit == UNIT_NSECS */
		/* Verify pwm_pin_set_nsec() */
		if (pwm_pin_set_nsec(pwm_dev, port, period, pulse)) {
			TC_PRINT("Fail to set the period and pulse width\n");
			return TC_FAIL;
		}
	}

	return TC_PASS;
@@ -122,17 +136,35 @@ void test_pwm_usec(void)
{
	/* Period : Pulse (2000 : 1000), unit (usec). Voltage : 1.65V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_USEC,
				DEFAULT_PULSE_USEC, false) == TC_PASS, NULL);
				DEFAULT_PULSE_USEC, UNIT_USECS) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (2000 : 2000), unit (usec). Voltage : 3.3V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_USEC,
				DEFAULT_PERIOD_USEC, false) == TC_PASS, NULL);
				DEFAULT_PERIOD_USEC, UNIT_USECS) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (2000 : 0), unit (usec). Voltage : 0V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_USEC,
				0, false) == TC_PASS, NULL);
				0, UNIT_USECS) == TC_PASS, NULL);
	k_sleep(1000);
}

void test_pwm_nsec(void)
{
	/* Period : Pulse (2000000 : 1000000), unit (nsec). Voltage : 1.65V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
				DEFAULT_PULSE_NSEC, UNIT_NSECS) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (2000000 : 2000000), unit (nsec). Voltage : 3.3V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
				DEFAULT_PERIOD_NSEC, UNIT_NSECS) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (2000000 : 0), unit (nsec). Voltage : 0V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_NSEC,
				0, UNIT_NSECS) == TC_PASS, NULL);
	k_sleep(1000);
}

@@ -140,15 +172,15 @@ void test_pwm_cycle(void)
{
	/* Period : Pulse (64000 : 32000), unit (cycle). Voltage : 1.65V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
				DEFAULT_PULSE_CYCLE, true) == TC_PASS, NULL);
				DEFAULT_PULSE_CYCLE, UNIT_CYCLES) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (64000 : 64000), unit (cycle). Voltage : 3.3V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
				DEFAULT_PERIOD_CYCLE, true) == TC_PASS, NULL);
				DEFAULT_PERIOD_CYCLE, UNIT_CYCLES) == TC_PASS, NULL);
	k_sleep(1000);

	/* Period : Pulse (64000 : 0), unit (cycle). Voltage : 0V */
	zassert_true(test_task(DEFAULT_PWM_PORT, DEFAULT_PERIOD_CYCLE,
				0, true) == TC_PASS, NULL);
				0, UNIT_CYCLES) == TC_PASS, NULL);
}