This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Faster nrf53 PWM frequency update through Zephyr?

Hello!

I am a beginner at nrf programming and have just started using the NCS and Zephyr on an nrf5340 evaluation board. I understand that Zephyr seems to be more or less a prerequisite right now when programming the nrf53 but I may have a problem.

I want to design a controller where I can to change the frequency of a PWM signal (50% duty cycle) based on the input value from an analog pin.
The change must be very fast. Ideally below 1uS

I tried a very simple example by modifying the LED_PWM code into just switching between a 0% and a 100% pulse as quickly as possible to see the delay:

/**
 * @file Sample app to demonstrate PWM.
 */

#include <zephyr.h>
#include <sys/printk.h>
#include <device.h>
#include <drivers/pwm.h>

#define PWM_LED0_NODE	DT_ALIAS(pwm_led0)

#if DT_NODE_HAS_STATUS(PWM_LED0_NODE, okay)
#define PWM_CTLR	DT_PWMS_CTLR(PWM_LED0_NODE)
#define PWM_CHANNEL	DT_PWMS_CHANNEL(PWM_LED0_NODE)
#define PWM_FLAGS	DT_PWMS_FLAGS(PWM_LED0_NODE)
#else
#error "Unsupported board: pwm-led0 devicetree alias is not defined"
#define PWM_CTLR	DT_INVALID_NODE
#define PWM_CHANNEL	0
#define PWM_FLAGS	0
#endif

#define MIN_PERIOD_USEC	(USEC_PER_SEC / 64U)
#define MAX_PERIOD_USEC	USEC_PER_SEC

void main(void)
{
	const struct device *pwm;
	uint32_t period;
	int ret;

	printk("PWM-based blinky\n");

	pwm = DEVICE_DT_GET(PWM_CTLR);
	if (!device_is_ready(pwm)) {
		printk("Error: PWM device %s is not ready\n", pwm->name);
		return;
	}


	period = 100000U;
	while (1) {
		ret = pwm_pin_set_usec(pwm, PWM_CHANNEL,
				       period, period, PWM_FLAGS);


                ret = pwm_pin_set_usec(pwm, PWM_CHANNEL,
				       period, 0, PWM_FLAGS);


	}
}

The switch time between a 100% pulse and a 0% pulse turns out to be more than 10ms when measured through oscilloscope. The delay is independent on any pulse length I set.
I assume this is due to the overhead within Zephyr or is there a way to improve this?

If not, is it possible to program the nrf53 application core directly as described in the datasheet - Setting the COUNTERTOP registry and basically bypassing Zephyr - at least for a snippet of code?

Many thanks for any assistance or pointers to examples.

/Jonas

Parents Reply Children
  • Hi Jonas

    I wouldn't recommend programming the hardware directly, but it is possible to bypass the Zephyr PWM driver and use the nrfx_pwm driver instead. Then you are much closer to the hardware, but you don't need to spend a lot of time understanding how the hardware works. 

    As Jörg is hinting at it is possible to write directly to the RAM buffer assigned to the PWM, rather than starting the PWM explicitly each time you want to change it. 

    When using the nrfx_pwm driver you have to provide the buffer to the driver, which means you have access to it in the application and can update it without involving the driver. 

    The idea of connecting the ADC to the same buffer is interesting, but this is not something we have tested. Also, the drawback of this method is that you are not able to do any scaling, inversion or anything else that you might want to do to the data before you output it on the PWM. 

    Best regards
    Torbjørn

Related