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

PPI does not work with PWM

URGENT

First of all, I have to mention that I dont understand PPI.

I have application which uses PWM to control a pump which is connected to the nRF52. To the nRF52 is a sensor connected, which gives me a frequency.

To measure this frequency I use this example:

devzone.nordicsemi.com/.../

Now when I add this code to my application, then the pwm wont work anymore. Why?

What does PPI have to do with PWM?

Here is my setup of the pwm:

APP_PWM_INSTANCE(PWM1,0);

static void PWMinit(void)
{
 app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_1CH(9000,27);
 pwm1_cfg.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;
 app_pwm_init(&PWM1, &pwm1_cfg, pwm_ready_callback);
 app_pwm_enable(&PWM1);
}

And here the frequency measuring part:

static void timer_init()
{
 NRF_TIMER1->TASKS_STOP = 1;
 NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
 NRF_TIMER1->PRESCALER = 8;  // Fhck / 2^8 
 NRF_TIMER1->CC[0] = 62500;  // 62500 - 1s

 NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);   

 NRF_TIMER1->TASKS_CLEAR = 1;
 NRF_TIMER1->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);

 NRF_TIMER1->EVENTS_COMPARE[0] = 0;
}

static void counter_init()
{
 NRF_TIMER2->TASKS_STOP = 1; 
 NRF_TIMER2->MODE = TIMER_MODE_MODE_Counter;
 NRF_TIMER2->BITMODE = (TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos);
 NRF_TIMER2->TASKS_CLEAR = 1;
 NRF_TIMER2->EVENTS_COMPARE[0] = 0;
}

static void gpiote_init(uint32_t pin)
{
 NRF_GPIOTE->CONFIG[0]   =   0x01 << 0;                              // MODE: Event
 NRF_GPIOTE->CONFIG[0]   |=  pin << 8;                               // Pin number
 NRF_GPIOTE->CONFIG[0]   |=  GPIOTE_CONFIG_POLARITY_LoToHi  << 16;   // Event rising edge    
}

static void ppi_timer_stop_counter_init()
{
 NRF_PPI->CHEN |= 1 << 0;
 *(&(NRF_PPI->CH0_EEP)) = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
 *(&(NRF_PPI->CH0_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_STOP;
 NRF_PPI->CHENSET |= 1 << 0;
}

static void ppi_gpiote_counter_init()
{
 NRF_PPI->CHEN |= 1 << 1;
 *(&(NRF_PPI->CH1_EEP)) = (uint32_t)&NRF_GPIOTE->EVENTS_IN[0];
 *(&(NRF_PPI->CH1_TEP)) = (uint32_t)&NRF_TIMER2->TASKS_COUNT;
 NRF_PPI->CHENSET |= 1 << 1;
}

void TIMER1_IRQHandler(void) 
{
  if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
  {
    NRF_TIMER1->EVENTS_COMPARE[0] = 0;
    NRF_TIMER2->TASKS_CAPTURE[0] = 1;

   frequency = NRF_TIMER2->CC[0];

    NRF_TIMER1->TASKS_CLEAR = 1;
    NRF_TIMER2->TASKS_CLEAR = 1;    

    NRF_TIMER2->TASKS_START = 1;            
  }
}

Is it possible that they use the same PPI channel? How can I choose the channel of PWM PPI?

Any hints?

On what I have to pay attention when I use PWM and PPI?

UPDATE

I think the problem is not in the PPI. I changed all of them. And the same for the timers.

What else can I do?

The problem is between PWMinit() and gpiote_init functions.

But this is strange. Because in the gpiote_init function I only choose a mode,pin and polaritity.

Parents
  • The problem is probably that you are using GPIOTE channel 0 (NRF_GPIOTE->CONFIG[0]). The pwm library (app_pwm) will use the ppi and gpiote drivers which will dynamically allocate ppi channels and gpiote channels starting from the lowest available channel. If you use 1 channel pwm, then at least gpiote channel 0 will be occupied. The solution is to use the ppi and gpiote drivers instead of manipulating the registers directly, or to use the highest channels (gpiote channel 7 and ppi channel 18 if using SoftDevice) instead.

    As Võ said nRF52 has a PWM peripheral, so you can use this instead of the pwm library. The pwm driver (nrf_drv_pwm) uses the pwm peripheral. Here is a simple example of how to set a single duty cycle with the driver.

Reply
  • The problem is probably that you are using GPIOTE channel 0 (NRF_GPIOTE->CONFIG[0]). The pwm library (app_pwm) will use the ppi and gpiote drivers which will dynamically allocate ppi channels and gpiote channels starting from the lowest available channel. If you use 1 channel pwm, then at least gpiote channel 0 will be occupied. The solution is to use the ppi and gpiote drivers instead of manipulating the registers directly, or to use the highest channels (gpiote channel 7 and ppi channel 18 if using SoftDevice) instead.

    As Võ said nRF52 has a PWM peripheral, so you can use this instead of the pwm library. The pwm driver (nrf_drv_pwm) uses the pwm peripheral. Here is a simple example of how to set a single duty cycle with the driver.

Children
No Data
Related