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\$ 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) { ....} } 
\$\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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.