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;
}