Hello,
SDK: 15.3.0
Hardware: nRF52840-DK
I am attempting to make a simple dimmer with 2 pins/LEDs. I have used the following post.
https://devzone.nordicsemi.com/f/nordic-q-a/39314/pwm-update_function/152441#152441
I am attempting to do a very similar task, but software may need to adjust the duty cycle (sequence value) at any point to adjust the brightness of the LEDs. I have made several attempts. in all attempts I am using nrf_delay_ms(2000) to delay the program calls, and act as a time delay between when the program would call different update functions. pwm would always be on, and the LED would be off at seq_value = 0, and 100% Duty Cycle (Fully On) at seq_value = .top_value
Q1: There are various built in update functions like nrfx_pwm_sequence_values_update, both legacy, and not. Am I using the correct function to complete this goal?
Q2: Which method that I have attempted is the preferred method, and is there an alternative method that may be better?
Attempt 1: fails to build due to the 3rd param of nrfx_pwm_sequence_values_update(&m_pwm0,0, pwm_count); not matching
static void update_LED(uint16_t duty_cycle) { //Attempt 1 uint16_t pwm_count = 32768 *(duty_cycle / 100); nrfx_pwm_sequence_values_update(&m_pwm0,0, pwm_count); } static void demo3(void) { NRF_LOG_INFO("Demo 3"); /* * This demo uses only one channel, which is reflected on LED 1. * The LED blinks three times (200 ms on, 200 ms off), then it stays off * for one second. * This scheme is performed three times before the peripheral is stopped. */ nrf_drv_pwm_config_t const config0 = { .output_pins = { BSP_LED_0 | NRF_DRV_PWM_PIN_INVERTED, // channel 0 NRF_DRV_PWM_PIN_NOT_USED, // channel 1 NRF_DRV_PWM_PIN_NOT_USED, // channel 2 NRF_DRV_PWM_PIN_NOT_USED, // channel 3 }, .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = NRF_PWM_CLK_2MHz,//NRF_PWM_CLK_125kHz, .count_mode = NRF_PWM_MODE_UP, .top_value = 32768, // = 0x8000 .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); // This array cannot be allocated on stack (hence "static") and it must // be in RAM (hence no "const", though its content is not changed). static uint16_t /*const*/ seq_values[] = { 0x3000, // 0x2000, // 0x4000, // 0x6000, // 0x7FFF, // 0x8000 }; nrf_pwm_sequence_t const seq = { .values.p_common = seq_values, .length = NRF_PWM_VALUES_LENGTH(seq_values), .repeats = 0, .end_delay = 0 }; (void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 3, NRF_DRV_PWM_FLAG_LOOP); } int main(void) { ... demo3(); nrf_delay_ms(2000); update_LED(100); nrf_delay_ms(2000); update_LED(25); ... }
Attempt 2: still fails to build due to the 3rd param of nrfx_pwm_sequence_values_update(&m_pwm0,0, pwm_count); not matching
static void update_LED(uint16_t duty_cycle) { //Attempt 2 uint16_t pwm_count = 32768 *(duty_cycle / 100); nrf_pwm_values_common_t const *p_pwm_count = pwm_count; nrfx_pwm_sequence_values_update(&m_pwm0,0, p_pwm_count); } static void demo3(void) { NRF_LOG_INFO("Demo 3"); /* * This demo uses only one channel, which is reflected on LED 1. * The LED blinks three times (200 ms on, 200 ms off), then it stays off * for one second. * This scheme is performed three times before the peripheral is stopped. */ nrf_drv_pwm_config_t const config0 = { .output_pins = { BSP_LED_0 | NRF_DRV_PWM_PIN_INVERTED, // channel 0 NRF_DRV_PWM_PIN_NOT_USED, // channel 1 NRF_DRV_PWM_PIN_NOT_USED, // channel 2 NRF_DRV_PWM_PIN_NOT_USED, // channel 3 }, .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = NRF_PWM_CLK_2MHz,//NRF_PWM_CLK_125kHz, .count_mode = NRF_PWM_MODE_UP, .top_value = 32768, // = 0x8000 .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); // This array cannot be allocated on stack (hence "static") and it must // be in RAM (hence no "const", though its content is not changed). static uint16_t /*const*/ seq_values[] = { 0x3000, // 0x2000, // 0x4000, // 0x6000, // 0x7FFF, // 0x8000 }; nrf_pwm_sequence_t const seq = { .values.p_common = seq_values, .length = NRF_PWM_VALUES_LENGTH(seq_values), .repeats = 0, .end_delay = 0 }; (void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 3, NRF_DRV_PWM_FLAG_LOOP); } int main(void) { ... demo3(); nrf_delay_ms(2000); update_LED(100); nrf_delay_ms(2000); update_LED(25); ... }
Attempt 3: Build and runs, but not as expected, it is as if the update_LED function has updated the value at the same time, and the two duty cycles are overlapping. The result is a 2 second delay (expected), with a rapid blinking LED (not expected), followed by LED off.
nrf_pwm_values_individual_t seq_values_test[] = { 16384}; nrf_pwm_sequence_t const seq_test = { .values.p_common = seq_values_test, .length = NRF_PWM_VALUES_LENGTH(seq_values_test), .repeats = 0, .end_delay = 0 }; static void update_LED(uint16_t duty_cycle) { //Attempt 3 seq_values_test->channel_0 = pwm_count; nrf_drv_pwm_simple_playback(&m_pwm0, &seq_test, 1, NRF_DRV_PWM_FLAG_LOOP); } static void demo3(void) { NRF_LOG_INFO("Demo 3"); /* * This demo uses only one channel, which is reflected on LED 1. * The LED blinks three times (200 ms on, 200 ms off), then it stays off * for one second. * This scheme is performed three times before the peripheral is stopped. */ nrf_drv_pwm_config_t const config0 = { .output_pins = { BSP_LED_0 | NRF_DRV_PWM_PIN_INVERTED, // channel 0 NRF_DRV_PWM_PIN_NOT_USED, // channel 1 NRF_DRV_PWM_PIN_NOT_USED, // channel 2 NRF_DRV_PWM_PIN_NOT_USED, // channel 3 }, .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = NRF_PWM_CLK_2MHz,//NRF_PWM_CLK_125kHz, .count_mode = NRF_PWM_MODE_UP, .top_value = 32768, // = 0x8000 .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); } int main(void) { ... demo3(); nrf_delay_ms(2000); update_LED(100); nrf_delay_ms(2000); update_LED(25); ... }