1
\$\begingroup\$

I'm using a NRF52810 to control an LED load and need to ramp up PWM frequency over the span of 6 seconds, like 0-1s : 6Hz, 1-2s : 7Hz, 2-3s : 8Hz, 4-5s : 9Hz, 5-6s : 10Hz.

At the moment, this is how I do PWM with fixed frequency:

#include "nrf.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"
#include "nrf_delay.h"
#include "nrfx_rtc.h"
#include "app_timer.h"
#include "low_power_pwm.h"
#include "boards.h"
#include <stdint.h>
#include <stdbool.h>
#include "nrf_mtx.h"
#include "math.h"

int ch1_period;
int ch1_ontime; 
float ch1_frequency;
float ch1_dutycycle;
float ch1_offset;
int ch1_int_offset;
int ch1_period_tmr; // keeps track of flash period
int ch1_ontime_tmr; // keeps track of LED on-time
bool ch1_on_flag = false;
bool ch1_enable = false;
const nrfx_rtc_t rtc1 = NRF_DRV_RTC_INSTANCE(1); // Create a handle that will point to the RTC1 of nrf device

void  gpio_init(){
      nrf_gpio_cfg_input(switch_mode1, NRF_GPIO_PIN_PULLUP); // configure the mode switch input, with pin pullup
      nrf_gpio_cfg_output(pwm_1); // configure the CH1 PWM output pin     
      nrf_gpio_pin_clear(pwm_1);  // init pin to low which disables the LED driver
}

void init_group1_flash_patterns(){
  ch1_enable = true;
  ch1_frequency = 6; //specify in Hertz.  Decimals are OK.
  ch1_dutycycle = 25; // specify in "% positive duty cycle".  Example: 45 = 45% On, 55% Off
}

void calc_flash_parameters(){
  float z;
  //determine channel flash pattern periods and flash duty cycles ("ontimes")
  ch1_period = round((1/ch1_frequency)/.001);   // period = frequency X .01sec
  ch1_ontime = round(1/ch1_frequency/.001 * ch1_dutycycle/100);

  // reset timers
  ch1_ontime_tmr = 0; 
  ch1_period_tmr = 0;
  }

// Initialize the low frequency clock which drives the real time counter
void lfclk_config(void){
  nrf_drv_clock_init(); // Initialize the low frequency clock 
  nrf_drv_clock_lfclk_request(NULL); // Request the clock to not generate events
}

// RTC1 interrupt handler which will be used to maintain the flash period and duty cycle for the led channel
void rtc1_handler(nrfx_rtc_int_type_t int_type){
      if(ch1_enable == true){ // Channel 1 handling
          ch1_period_tmr = ch1_period_tmr + 1; // increment the period timer
          if(ch1_period_tmr == ch1_period && nrf_gpio_pin_out_read(pwm_1) == false ){ //turn on LED at start of each period
                nrf_gpio_pin_set(pwm_1); // turn on the LED
                ch1_ontime_tmr = 0; 
            }
          ch1_ontime_tmr = ch1_ontime_tmr + 1;
          if(ch1_ontime_tmr == ch1_ontime && nrf_gpio_pin_out_read(pwm_1) == true){
                nrf_gpio_pin_clear(pwm_1);
            }
      }
}

// A function to configure and intialize the RTC1 which is used for generating the interrupt
void rtc1_config(void){
    nrfx_rtc_config_t rtc1_config = NRFX_RTC_DEFAULT_CONFIG; // Create a struct of type nrfx_rtc_config_t and assign it default values
    rtc1_config.prescaler = 32; // tick =  32768 / (32 + 1) = 16384Hz = 61usec (all approximate).                      
    nrfx_rtc_init(&rtc1, &rtc1_config, rtc1_handler); // Initialize the rtc and pass the configurations along with the interrupt handler
    nrfx_rtc_tick_enable(&rtc1, true);  // Enable a tick interrupt on each tick
    nrfx_rtc_overflow_disable(&rtc1); // don't know if this is necessary
    nrfx_rtc_enable(&rtc1);   // start the rtc 
}

int main(void){
      gpio_init(); // Initialize the gpio
      if(nrf_gpio_pin_read(switch_mode1) == 0){ //if mode 1 selected on the mode switch
          init_group1_flash_patterns(); //initialize the flash patterns
      }
      max_parameter_violation_check();
      lfclk_config(); // low frequency low power clock configuration
      nrfx_clock_lfclk_start();
      rtc1_config(); // rtc1 configuration
}

I'm stuck on how to implement this dynamic frequency - mostly on the side of triggering when to change the period, a way I think it could be implemented: to reset the the timer every 1000ms, and adjusting parameters for the next frequency. Hence, using another timer as that counter?

I can't seem to wrap my head around how to implement this.

\$\endgroup\$
2
  • \$\begingroup\$ Just have it inside your existing interrupt handler \$\endgroup\$
    – BeB00
    Commented Jan 31 at 21:18
  • \$\begingroup\$ @BeB00 hmm, seems like a fundamental solution that i can't wrap my head around, any hints? \$\endgroup\$
    – roaibrain
    Commented Jan 31 at 21:47

1 Answer 1

1
\$\begingroup\$

Something like this may get you going in the right direction. I'm sure there are more compact ways to write this, but this is one way. In your higher level functions, you would then control when to change periods.

// RTC1 interrupt handler which will be used to maintain the flash period and duty cycle for the led channel
void rtc1_handler(nrfx_rtc_int_type_t int_type){
      static int period = 0; // new

      if( period == 0 )
      {
        if(ch1_enable == true){ // Channel 1 handling
            ch1_period_tmr = ch1_period_tmr + 1; // increment the period timer
            if(ch1_period_tmr == ch1_period && nrf_gpio_pin_out_read(pwm_1) == false ){ //turn on LED at start of each period
                nrf_gpio_pin_set(pwm_1); // turn on the LED
                ch1_ontime_tmr = 0; 
            }
            ch1_ontime_tmr = ch1_ontime_tmr + 1;
            if(ch1_ontime_tmr == ch1_ontime && nrf_gpio_pin_out_read(pwm_1) == true){
                nrf_gpio_pin_clear(pwm_1);
            }
        }
      }
      else if (period == 1)
      { ....}
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the answer, this does help give direction. I think the main difficulty was in understanding how to control a change in periods at the higher levels - by matching the tick interrupt to the period and re-configuring rtc? \$\endgroup\$
    – roaibrain
    Commented Jan 31 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.