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.

asked Jan 31, 2024 at 21:10
\$\endgroup\$
2
  • \$\begingroup\$ Just have it inside your existing interrupt handler \$\endgroup\$ Commented Jan 31, 2024 at 21:18
  • \$\begingroup\$ @BeB00 hmm, seems like a fundamental solution that i can't wrap my head around, any hints? \$\endgroup\$ Commented Jan 31, 2024 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)
 { ....}
}
answered Jan 31, 2024 at 22:03
\$\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\$ Commented Jan 31, 2024 at 22:12

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.