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

The PWM pluse width flutter on NRF52

    I want to drive a servo by the PWM on nrf52832. The pwm cycle is 20ms and the duty is 1.5ms. But i have a problem that the duty is not precise when the BLE is working. I need a precise PWM with 1500us duty, but the duty will flutter randomly among 1500us-1520us when the BLE is working. This problem will make the servo flutter synchronously. 

    I have make a lot of experiment as below:

    1. I combine two projects in the SDK to generate the PWM when the BLE is working. One is examples\ble_peripheral\ble_app_template and the other is examples\peripheral\pwm_driver. The PWM is generated by the PWM modulation.  The problem can be captured easily by the oscilloscope.

    2. I try another way to generate the PWM in which pwm is generate by TIMER+PPI+GPIOE. I combine examples\peripheral\pwm_library to examples\ble_peripheral\ble_app_template. And the problem is the same. 

    3. I try SDK11 and SDK15. The problem is the same.

    4. If I the BLE is not working, the pwm is very precisely without any flutter. 

    5. If I using the RADIO to receive 2.4G data(not using the BLE), the pwm is very precisely without any flutter.

    6. I have modify different pins to output the PWM. Each pins have the same problem.

    6. I have tested the problem on two NRF52-DK pca10040 evaluation board and 10 boards I designed. The pwm will flutter on all of them, BUT the amplitude of the flutter is different. On the NRF52-DK boards the amplitude is about 10us. On the boards I designed the amplitude is different, some is about 10us, some is about 15us, and the worst is about 20us.

    7. I have tried to write a uart programme to send a data which will make a waveform near the pwm i want. I find that the waveform will flutter a little the same as PWM.

    So I think the problem is not only in the PWM. I guess the problem is related to the clk of the chip, it seems that the chip miss a little clk randomly when BLE is working so that the duty of the PWM will longer than I set.

    How can I get a precise PWM when the BLE is working?

     

I using the PWM code as below, after I init the PWM I never the duty of the PWM.

#define PIN_PWM_SERVO				3
#define SERVO_PERIOD				(1000000 / 50)
static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
nrf_pwm_values_individual_t m_demo1_seq_values;
uint16_t ServoValue = 1500;
static uint8_t m_used = 0;
#define USED_PWM(idx) (1UL << idx)
static nrf_pwm_sequence_t const    m_demo1_seq =
{
    .values.p_individual = &m_demo1_seq_values,
    .length              = 1, 
    .repeats             = 0,
    .end_delay           = 0
};

void PwmInit()
{
	nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            PIN_PWM_SERVO,//BSP_LED_0 | NRF_DRV_PWM_PIN_INVERTED, // channel 0
            NRF_DRV_PWM_PIN_NOT_USED, //BSP_LED_1 | NRF_DRV_PWM_PIN_INVERTED, // channel 1
            NRF_DRV_PWM_PIN_NOT_USED, //BSP_LED_3 | NRF_DRV_PWM_PIN_INVERTED, // channel 2
            NRF_DRV_PWM_PIN_NOT_USED, //BSP_LED_2 | NRF_DRV_PWM_PIN_INVERTED  // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_1MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = SERVO_PERIOD,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    m_used |= USED_PWM(0);

    m_demo1_seq_values.channel_0 = 0;
    m_demo1_seq_values.channel_1 = 0;
    m_demo1_seq_values.channel_2 = 0;
    m_demo1_seq_values.channel_3 = 0;

    (void)nrf_drv_pwm_simple_playback(&m_pwm0, &m_demo1_seq, 1,
                                      NRF_DRV_PWM_FLAG_LOOP);
		
	m_demo1_seq_values.channel_0 = SERVO_PERIOD - ServoValue;
}

  • Hi,

    Both the PWM driver and PWM library should be as accurate as the HF clock. The reason is that the PWM peripheral (used by the driver) runs of the HF clock, and the PWM library use a TIMER which also use the HF clock, and controls the output via PPI, which is deterministic.

    Therefor I am tempted to think that the problem here could be related to your clock source. Can you try to request the HF clock with nrf_drv_clock_init() and nrf_drv_clock_hfclk_request() in the beginning of your application, and see if that helps? In that case the 32 MHz oscillator will always be used, instead of it being turned on only when the radio is on, and off otherwise. When this is enabled, the (average) accuracy of the PWM signal will be the same as the accuracy of your 32 MHz crystal (which is the reference for the 64 MHz HF clock).

  • Thank you for your reply!  I have try the two functions you mentioned, I put them in the beginning of the application. But they are not working, the problem is still. I have monitor the crystal waveform. The external 32MHz crystal is not always working. I think the softdevice is still switching the clock between the external 32MHz crystal and the interanl 64MHz oscillator.

  • Hi,

    I was not clear in my previous reply. You must move these function calls after initializing the SoftDevice for it to be persistent. If you do, the driver will use the SoftDevice API to request the clock, and this tells the SoftDevice to not disable the crystal oscillator when it no longer needs it. Can you try that?

  • It is awesome! It works I put the two functions after I initialize the SoftDevice. The pwm is never flutter. Many thanks!

    And I did another try one hour age, and it make the pwm no flutter too.

    I put the code below before I initialize the SoftDevice.

    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);

    I guess that when the softdevice is initializing. The softdevice will check the HFCLK status. If the HFCLK is started, the SoftDevice will no longer disable the external crystal oscillator; If the HFCLK is not start, the SoftDevice will manage the crystal oscillator and disable the external crystal oscillator when it no longer needs it.

    Do my guess correct?

    And which method is better and more reliable?

  • And I have a doubt that what is the input formal parameter of the function nrf_drv_clock_hfclk_request().

    I just use NULL, and it works. I am worry about that whether it will make the system unstable if I use NULL as the input parameter?

Related