I'm encountering some bizarre problems using the PWMs. Here's my setup code:
#define PWM_CHANNELS 3 #define PWM_MAX_TICK_COUNT 0xFF #define PWM_POLARITY_FLAG (1UL << 15) //#define PWM_POLARITY_FLAG 0 // Passed to PWM module, should only be updated in pwm handler static uint16_t pwm_tick_counts[NRF_PWM_CHANNEL_COUNT] = {[0 ... 3] = PWM_POLARITY_FLAG}; // This is some C99/gcc magic here // Value set on user input, copied to pwm_tick_counts in handler static uint16_t pwm_updates[PWM_CHANNELS] = {0}; static uint8_t update_pwm = 0; // Bit flags per channel set on user input // Define PWM instances static nrfx_pwm_t pwms[PWM_CHANNELS] = { NRFX_PWM_INSTANCE(0), NRFX_PWM_INSTANCE(1), // NRFX_PWM_INSTANCE(2), NRFX_PWM_INSTANCE(3), }; // This would be much easier if the callback took a context... #define PWM_EVENT_HANDLER_FACTORY(index) \ static void pwm_event_handler_ ## index(nrfx_pwm_evt_type_t event_type) { \ switch (event_type) { \ case NRFX_PWM_EVT_END_SEQ0: \ case NRFX_PWM_EVT_END_SEQ1: \ if (update_pwm & (1UL << index)) { \ pwm_tick_counts[index] = pwm_updates[index] | PWM_POLARITY_FLAG; \ update_pwm &= ~(1UL << index); \ } \ break; \ default: \ break; \ } \ } PWM_EVENT_HANDLER_FACTORY(0) PWM_EVENT_HANDLER_FACTORY(1) PWM_EVENT_HANDLER_FACTORY(2) //PWM_EVENT_HANDLER_FACTORY(3) static nrfx_pwm_handler_t pwm_event_handlers[PWM_CHANNELS] = { pwm_event_handler_0, pwm_event_handler_1, pwm_event_handler_2, // pwm_event_handler_3, }; static void pwm_init() { nrfx_pwm_config_t pwm_config = NRFX_PWM_DEFAULT_CONFIG; pwm_config.output_pins[0] = PWM0_PIN; // NRF_GPIO_PIN_MAP(0,12) pwm_config.output_pins[1] = PWM1_PIN; // NRF_GPIO_PIN_MAP(0,29) pwm_config.output_pins[2] = PWM2_PIN; // NRF_GPIO_PIN_MAP(1,7) pwm_config.output_pins[3] = PWM3_PIN; // NRF_GPIO_PIN_MAP(1,3) pwm_config.base_clock = NRF_PWM_CLK_16MHz; pwm_config.count_mode = NRF_PWM_MODE_UP; pwm_config.top_value = PWM_MAX_TICK_COUNT; // 0xFF pwm_config.load_mode = NRF_PWM_LOAD_INDIVIDUAL; pwm_config.step_mode = NRF_PWM_STEP_AUTO; for (int i = 0; i < PWM_CHANNELS; i++) { APP_ERROR_CHECK(nrfx_pwm_init(&pwms[i], &pwm_config, pwm_event_handlers[i])); NRF_LOG_PROCESS(); APP_ERROR_CHECK( nrfx_pwm_simple_playback(&pwms[i], &(nrf_pwm_sequence_t) { .values.p_raw = pwm_tick_counts, .length = NRF_PWM_VALUES_LENGTH(pwm_tick_counts), .repeats = 0, .end_delay = 0 }, 1, NRFX_PWM_FLAG_LOOP | NRFX_PWM_FLAG_SIGNAL_END_SEQ0 | NRFX_PWM_FLAG_SIGNAL_END_SEQ1 | NRFX_PWM_FLAG_NO_EVT_FINISHED)); NRF_LOG_PROCESS(); } NRF_LOG_DEBUG("pwm_init"); }
Now, my first problem is, as you might surmise from looking at my code, that I am not able to use PWM2, at least along with PWMs 0 & 1. I haven't tried all the various combinations, but 0 & 1 (almost) work, together, as do 0, 1, & 3 (sort of).
My next problem is that the PWM signals have a lot of jitter, almost like an 'echo', or two competing timers trying to control a single channel. The jitter is nearly identical on both the nRF52840 dev kit, and a custom board. The 'delay' of the 'echo' also changes when my code changes, but remains consistent across hardware.
The only other peripherals I'm using at the moment are USB (CDC ACM) and associated nrf_drv_clock, and timers 1 & 2. I'll be using additional timers, and using a soft-device (s140), as development continues.
I'm a bit at a loss as to how to proceed.