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

Why am I having problems driving an RGB LED with PWM from NRF52??!

Hello Nordic Community.

I'm having issues trying to control a simple RGB LED circuit with the NRF52. I have set up 2 timers and PWM instances Red and Green on PWM1 and Blue on PWM2 but it's just not working. What am I doing wrong?? Here is my code (modified from the NORDIC PWM example)

#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "app_error.h"
#include "bsp.h"
#include "nrf_delay.h"
#include "app_pwm.h"

static volatile bool ready_flag;            // A flag indicating PWM status.

bool enablePWM = true;
bool pausePWM = false;

void pwm_ready_callback(uint32_t pwm_id)    // PWM callback function
{
    ready_flag = true;
}


int main(void)
{
  uint32_t err_code;

    // Create the instance "PWM1" using TIMER1.
    APP_PWM_INSTANCE(PWM1,1);      
    // Create the instance "PWM2" using TIMER2.
    APP_PWM_INSTANCE(PWM2,2);             

    // RGB LED pins
    // (Common cathode)
    uint32_t pinR = 12;
    uint32_t pinG = 14;
    uint32_t pinB = 15;
   
    // 2-channel PWM, 200Hz
    app_pwm_config_t pwm1_cfg = 
      APP_PWM_DEFAULT_CONFIG_2CH(5000L, pinR, pinG);

    /* Initialize and enable PWM. */
    err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);
    APP_ERROR_CHECK(err_code);
    app_pwm_enable(&PWM1);     
 
    // 1-channel PWM, 200Hz
    app_pwm_config_t pwm2_cfg = 
      APP_PWM_DEFAULT_CONFIG_1CH(5000L, pinB);

    /* Initialize and enable PWM. */
    err_code = app_pwm_init(&PWM2,&pwm2_cfg,pwm_ready_callback);
    APP_ERROR_CHECK(err_code);
    app_pwm_enable(&PWM2);

    uint32_t value;
    while(1) {

        for (uint8_t i = 0; i < 40; ++i)
        {
            value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);

            //ready_flag = false;
            /* Set the duty cycle - keep trying until PWM is ready... */
            while (app_pwm_channel_duty_set(&PWM1, 0, value) == NRF_ERROR_BUSY);

            nrf_delay_ms(25);
        }

         for (uint8_t i = 0; i < 40; ++i)
        {
            value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);

            //ready_flag = false;
            /* Set the duty cycle - keep trying until PWM is ready... */
            while (app_pwm_channel_duty_set(&PWM1, 1, value) == NRF_ERROR_BUSY);

            nrf_delay_ms(25);
        }

         for (uint8_t i = 0; i < 40; ++i)
        {
            value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);

            //ready_flag = false;
            /* Set the duty cycle - keep trying until PWM is ready... */
            while (app_pwm_channel_duty_set(&PWM2, 0, value) == NRF_ERROR_BUSY);

            nrf_delay_ms(25);
        }

    }

}
  • it's just not working

    Tells us nothing.

    • What, exactly, were you expecting to happen?

    • What, exactly, is actually happening?

    • What testing/debugging have you done to explain the difference?

    www.catb.org/.../smart-questions.html

  • Since you are using nRF52 you should consider using the PWM driver, nrf_drv_pwm instead. This uses the PWM peripheral on the chip. Using the PWM library, app_pwm, on nRF52 you are wasting resources like timers and ppi and gpiote channels. Here is a snippet of code that sets the pwm driver to one duty cycle: devzone.nordicsemi.com/.../

    If you want to find out what is the problem with the code you are running now with app_pwm, you should go into debug mode and check that all the error codes are NRF_SUCCESS.

  • Thanks Ole and Awneil for your feedback. I used the PWM Driver instead as you suggested Ole and it worked perfectly. Here is my code which plays a test animation on 3 LEDS.

    #include <stdio.h>
    #include <string.h>
    #include "nrf_drv_pwm.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    #include "bsp.h"
    #include "app_timer.h"
    #include "nrf_drv_clock.h"
    #define NRF_LOG_MODULE_NAME "APP"
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    
    #include "nrf_delay.h"
    
    #define APP_TIMER_PRESCALER     0
    #define APP_TIMER_OP_QUEUE_SIZE 2
    
    int gLEDR = 12;
    int gLEDG = 14;
    int gLEDB = 15;
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    // static nrf_drv_pwm_t m_pwm1 = NRF_DRV_PWM_INSTANCE(1);
    //static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(2);
    
    static uint16_t const m_top  = 10000;
    
    
    //static nrf_pwm_values_individual_t  /*const*/ seq_values;
    static nrf_pwm_values_individual_t  /*const*/ seq_values;
    static nrf_pwm_sequence_t const seq =
        {
            .values.p_individual = &seq_values,
            .length              = NRF_PWM_VALUES_LENGTH(seq_values),
            .repeats             = 0,
            .end_delay           = 0
        };
    
    
    static void pwm_init(void)
    {
        uint32_t err_code;
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                gLEDR,// channel 0
                gLEDG, // channel 1
                gLEDB, // channel 2
                NRF_DRV_PWM_PIN_NOT_USED  // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_4MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = m_top,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        err_code = nrf_drv_pwm_init(&m_pwm0, &config0, NULL);
        APP_ERROR_CHECK(err_code);
        // 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).
    }
    
    void update_pwm(int16_t dutyR, int16_t dutyG, int16_t dutyB)
    {
        
        seq_values.channel_0 = m_top-dutyR;
        seq_values.channel_1 = m_top-dutyG;
        seq_values.channel_2 = m_top-dutyB;
        
    
        //seq_values = duty_cycle;
    
        //nrf_drv_pwm_simple_playback(&m_pwm0, &m_seq, 1, 0);
        //nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
        nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1,  NRF_DRV_PWM_FLAG_LOOP);
    }
    
    int main(void)
    {
      
      pwm_init();
    
        while(1){
    
            for (int i=0; i<100; i++){
                update_pwm(i*100,0,0);
                nrf_delay_ms(1);
            }
    
            for (int i=0; i<100; i++){
                update_pwm(10000,i*100,0);
                nrf_delay_ms(1);
            }
    
            for (int i=0; i<100; i++){
                update_pwm(10000,10000,i*100);
                nrf_delay_ms(1);
            }
    
            for (int i=100; i>0; i--){
                update_pwm(i*100,10000,10000);
                nrf_delay_ms(1);
            }
    
            for (int i=100; i>0; i--){
                update_pwm(0,i*100,10000);
                nrf_delay_ms(1);
            }
    
            for (int i=100; i>0; i--){
                update_pwm(0,0,i*100);
                nrf_delay_ms(1);
            }
    
            update_pwm(0,0,0);
            nrf_delay_ms(200);
    
            
       
        }
    
    
        
    }
    /**/
    
  • hi, i am running your application, if i give duty value in a function like update_pwm(0,0,0) it is still showing tri color. and also i am unable to uninit and unable to stop glowing LED once i glow LED.

Related