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

dim led to minimize current consumption

Hello, I am using nrf52832 custom board, with SDK 11.0.0 and s132_nrf52_2.0.0 and trying to dim led. It seems the only suggested solution is to use the pwm driver. I was wondering if there are any other simpler solutions?

My use case is to set led brightness to a min value to save current consumption.

Looking at a similar post I was able to follow the pwm_driver examples as well as suggestion in this link: devzone.nordicsemi.com/.../

  • However, it requires hardcoding the duration or setting the playback in continuous loop, also I do not need to gradually step up or down the brightness via a seq_values array and playback mechanism. Appreciate any suggestions.

  • The other issue I have seen with the example is that during resource intensive operations like flash write the driver doesn't seem to function, as the flash write fails also the playback stops much sooner than the set duration, possibly due to high cpu usage. Please confirm if this is expected.

Thanks in advanced.

#define LED_DIM_VALUE               900                                 /**< Brightness scale: 0->max, 1000->min. >**/
static nrf_drv_pwm_t                m_pwm0 = NRF_DRV_PWM_INSTANCE(0);   /**< Create an instance of PWM driver. >**/
static volatile bool                m_used = false;                     /**< PWM driver initilization status. >**/
                
void led_pwm(int pb_cnt)
{
    uint32_t err_code;
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            LED_PIN | 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_LOW,
        .base_clock   = NRF_PWM_CLK_125kHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 1000,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    if(m_used)
    {
       nrf_drv_pwm_uninit(&m_pwm0);
       m_used = false;
    }
    err_code = nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
    m_used = true;
    APP_ERROR_CHECK(err_code);

    // 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 nrf_pwm_values_common_t seq_values[] =
    {
       LED_DIM_VALUE
    };
    nrf_pwm_sequence_t const seq =
    {
       .values.p_common = seq_values,
       .length          = NRF_PWM_VALUES_LENGTH(seq_values),
       .repeats         = 100,
       .end_delay       = 0
    };
    nrf_drv_pwm_simple_playback(&m_pwm0, &seq, pb_cnt, NRF_DRV_PWM_FLAG_STOP);
    nrf_gpio_pin_clear(LED_PIN);
}

The duty cycle above would be 50% and the max playback duration I use is ~10 sec.

Parents
  • No, there is no real "simpler" solution then to alter GPIO high and low on the output line towards LED in time faster then your eye can notice so the effective duty cycle (time when line is HIGH divided by total time of one HIGH/LOW period) will determine how much "dim" it will look like. Now PWM is pretty straight forward solution as it should be able to run autonomously (thanks to things specific for nRF52 such as EasyDMA and PPI Tasks&Events) and thus no other activity should impact it (unless it blocks MCU for longer time then you can "program" in PWM registers). Quote from PWM driver documentation on Infocenter:

    Key features include:

    • Multi-instance support
    • Two kinds of playback:
      • Simple: a single sequence of duty cycle values
      • Complex: two concatenated sequences
    • Sequences are played back a specified number of times
    • Optionally, the whole playback can be repeated in a loop
    • A user-defined event handler can be used to perform additional actions when a sequence or the whole playback is finished
    • If no event handler is used, playbacks can be carried out without involving the CPU
Reply
  • No, there is no real "simpler" solution then to alter GPIO high and low on the output line towards LED in time faster then your eye can notice so the effective duty cycle (time when line is HIGH divided by total time of one HIGH/LOW period) will determine how much "dim" it will look like. Now PWM is pretty straight forward solution as it should be able to run autonomously (thanks to things specific for nRF52 such as EasyDMA and PPI Tasks&Events) and thus no other activity should impact it (unless it blocks MCU for longer time then you can "program" in PWM registers). Quote from PWM driver documentation on Infocenter:

    Key features include:

    • Multi-instance support
    • Two kinds of playback:
      • Simple: a single sequence of duty cycle values
      • Complex: two concatenated sequences
    • Sequences are played back a specified number of times
    • Optionally, the whole playback can be repeated in a loop
    • A user-defined event handler can be used to perform additional actions when a sequence or the whole playback is finished
    • If no event handler is used, playbacks can be carried out without involving the CPU
Children
  • Thanks for your help endnode, can you please provide more information about: "unless it blocks MCU for longer time then you can "program" in PWM registers". How can I check this? Please see the routine I am using above. I am using one instance of the pwm driver. And do not use handler that could block for a longer period. Would high duty cycle affect programming of registers?

  • Sorry, I'm not good in imagining just in my head how bunch of code works and I don't have time to test your code so I'm not sure what interrupts you really need to make your ode running continuously. In general all interrupt handling might get delayed if there is some higher priority execution blocking it, which might be the case when you use BLE stack (Soft Device) and it needs to do some radio-related processing. These things typically don't take more than 1-2ms, in extreme cases it can be 5~6ms or even more (if you use PDU extension + high throughput link and "stream" some data through the connection event). But I bet this is not really the problem for you right now so let's first make your code work in basic scenario (= FW boots and LED starts to dim and brighten with given period) and then you can test advanced use cases.

  • My golden rule so far is: if I don't understand how certain HW peripheral works, then I stick to SDK example (because Nordic guys know much better). I'm not sure if your code is not going too far from SDK without controlling the situation.

Related