Hi, I am trying to generate PWM pulse based on sample application in GitHub. However instead of using different modes and multiple channels, I tried to simplify it to just configuring Timer2, one channel, and one output pin. I am trying to set the duty cycle value in BLE data handler, using 2 PPI channels to toggle a pin once when it reaches CC[0] (to set the duty cycle) and once to finish a complete period CC[1]. I'm not getting any pulse on my oscilloscope. Attached PWM part of the code below, any hint on what might be wrong? Could there be any dependencies with other peripherals initialization?
// PWM Timer Definitions
#define PWM_TIMER NRF_TIMER2
#define PWM_IRQHandler TIMER2_IRQHandler
#define PWM_IRQn TIMER2_IRQn
#define GPIOTE_CHANNEL_NO 2
#define PWM_MAX_VALUE 1000UL // 1 tick equals 1µ , multiply by 1000 for ms value
uint16_t pwm_value;
uint8_t pwm_running;
/**@brief Function for Starting PWM timer.
*/
static void pwm_init(void)
{
nrf_gpio_cfg_output(REGULATOR_PIN); // Set regulator pin as output
// Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input.
// nrf_gpiote_task_configure(GPIOTE_CHANNEL_NO, REGULATOR_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);
pwm_running = 0;
// Configure TIMER2 for compare[0] event every 1 ms.
PWM_TIMER->PRESCALER = 3; // Prescaler 4 results in 1 tick equals 1 microsecond.
PWM_TIMER->TASKS_CLEAR = 1;
PWM_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit; // 16 bit mode.
PWM_TIMER->CC[1] = PWM_MAX_VALUE; // 1 tick equals 1µ , multiply by 1000 for ms value
pwm_value = 300;
PWM_TIMER->CC[0] = pwm_value;
PWM_TIMER->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode.
PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;
PWM_TIMER->EVENTS_COMPARE[0] = PWM_TIMER->EVENTS_COMPARE[1] = 0;
// Configure PPI channel 0 to toggle REGULATOR_PIN on every TIMER2 COMPARE[0] match
sd_ppi_channel_assign(0, &(PWM_TIMER->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NO]));
// Enable PPI channel 0
sd_ppi_channel_enable_set(1 << 0);
// Configure PPI channel 1 to toggle REGULATOR_PIN on every TIMER2 COMPARE[1] match
sd_ppi_channel_assign(1, &(PWM_TIMER->EVENTS_COMPARE[1]), &(NRF_GPIOTE->TASKS_OUT[GPIOTE_CHANNEL_NO]));
// Enable PPI channel 1
sd_ppi_channel_enable_set(1 << 1);
sd_nvic_SetPriority(PWM_IRQn, 1); //must have to set the priority
// sd_nvic_ClearPendingIRQ(PWM_IRQn);
sd_nvic_EnableIRQ(PWM_IRQn);
__enable_irq();
/* Start clock */
PWM_TIMER->TASKS_START = 1;
}
/**@brief Sets the value for PWM
*
* @details Sets the variable for PWM value
* In next interrupt the value is updated to the timer register
*
*/
static void pwm_set_value(uint16_t value)
{
if(value <= PWM_MAX_VALUE)
{
pwm_value = value;
PWM_TIMER->EVENTS_COMPARE[1] = 0;
PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk | TIMER_SHORTS_COMPARE1_STOP_Msk;
if((PWM_TIMER->INTENSET & TIMER_INTENSET_COMPARE1_Msk) == 0)
{
PWM_TIMER->TASKS_STOP = 1;
PWM_TIMER->INTENSET = TIMER_INTENSET_COMPARE1_Msk;
}
PWM_TIMER->TASKS_START = 1;
}
}
/**@brief Function for handling Timer2 interrupt.
*
* @details This function will set the PWM value to CC register
* keeps the GPIO pin high/low at the max/min value of PWM respectively
*
*/
void PWM_IRQHandler(void)
{
PWM_TIMER->EVENTS_COMPARE[1] = 0;
PWM_TIMER->INTENCLR = 0xFFFFFFFF;
if(pwm_value == 0)
{
// nrf_gpiote_unconfig(2); Can anyone suggest what should be done here
// nrf_gpiote_task_disable(0);
nrf_gpio_pin_write(REGULATOR_PIN, 0);
pwm_running = 0;
}
else if (pwm_value >= PWM_MAX_VALUE)
{
// nrf_gpiote_unconfig(2); Can anyone suggest what should be done here
// nrf_gpiote_task_disable(0);
nrf_gpio_pin_write(REGULATOR_PIN, 1);
pwm_running = 0;
}
else
{
PWM_TIMER->CC[0] = pwm_value;
if(pwm_running == 0)
{
// Configure GPIOTE_CHANNEL_NUMBER to toggle the GPIO pin state with input.
nrf_gpiote_task_configure(GPIOTE_CHANNEL_NO, REGULATOR_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_HIGH);
pwm_running = 1;
}
}
PWM_TIMER->SHORTS = TIMER_SHORTS_COMPARE1_CLEAR_Msk;
PWM_TIMER->TASKS_START = 1;
}
/**@brief Application main function.
*/
int main(void)
{
uint32_t err_code;
bool erase_bonds;
uint8_t start_string[] = START_STRING;
// Initialize.
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
uart_init();
buttons_leds_init(&erase_bonds);
ble_stack_init();
gap_params_init();
services_init();
advertising_init();
conn_params_init();
pwm_init();
printf("%s",start_string);
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(err_code);
// Enter main loop.
for (;;)
{
power_manage();
}
}