Hello,
I'm working on some LED sequences using the NRFX PWM driver and I can't get the durations I want right.
Let's say that I want a semi-blinking LED (100% - 50% - 100%...) with a period of 500 ms on each state and I initialize the PWM driver as follows:
nrfx_pwm_config_t const pwm_config = { .output_pins = { led.red | led.polarity, // Channel 0 led.green | led.polarity, // Channel 1 led.blue | led.polarity, // Channel 2 NRFX_PWM_PIN_NOT_USED // Channel 3 }, .irq_priority = APP_IRQ_PRIORITY_LOW, .base_clock = NRF_PWM_CLK_16MHz, // NRF_PWM_CLK_125kHz, .count_mode = NRF_PWM_MODE_UP_AND_DOWN, // For symmetric color mixing .top_value = 255, .load_mode = NRF_PWM_LOAD_INDIVIDUAL, .step_mode = NRF_PWM_STEP_AUTO }; err_code = nrfx_pwm_init(&m_pwm0, &pwm_config, pwm_event_handler); APP_ERROR_CHECK(err_code);
As far as I understand I could do this to get my timing right:
void setup_single_color_sequence(nrf_pwm_sequence_t * sequence, color_t color, uint32_t duration_in_us) { uint32_t top = 255; uint32_t pwm_period = top / 16; // In µs (top / clock_frequency in MHz) uint16_t pwm_pulses_for_duration = duration_in_us / (pwm_period * NRF_PWM_VALUES_LENGTH(pwm_values_single_color)); for (uint8_t i = 0; i < 2; i++) { pwm_values_single_color[i].channel_0 = color.r; pwm_values_single_color[i].channel_1 = color.g; pwm_values_single_color[i].channel_2 = color.b; pwm_values_single_color[i].channel_3 = 0; } sequence->values.p_individual = pwm_values_single_color; sequence->length = NRF_PWM_VALUES_LENGTH(pwm_values_single_color); sequence->repeats = pwm_pulses_for_duration; sequence->end_delay = 0; }
That is using the .repeats field to make each duty cycle repeat in order to get my desired timing. That however doesn't really work, I get shorter periods.
My logic is: The PWM counts up to 255. If I'm running the PWM at 16 MHz, then each duty cycle has a duration of 255/16 MHz = ~16 us. If I want the PWM to stay at that level for 500 ms, then I divide that duration (in us) by the duration of the duty cycle and I get the number of times that I need to repeat each duty cycle in order to get my target duration.
Is that logic wrong?